QP/C++  7.0.1
Real-Time Embedded Framework
qs_rx.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Embedded Framework (RTEF)
3// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
4//
5// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
6//
7// This software is dual-licensed under the terms of the open source GNU
8// General Public License version 3 (or any later version), or alternatively,
9// under the terms of one of the closed source Quantum Leaps commercial
10// licenses.
11//
12// The terms of the open source GNU General Public License version 3
13// can be found at: <www.gnu.org/licenses/gpl-3.0>
14//
15// The terms of the closed source Quantum Leaps commercial licenses
16// can be found at: <www.state-machine.com/licensing>
17//
18// Redistributions in source code must retain this top-level comment block.
19// Plagiarizing this software to sidestep the license obligations is illegal.
20//
21// Contact information:
22// <www.state-machine.com>
23// <info@state-machine.com>
24//============================================================================
30
31#define QP_IMPL // this is QP implementation
32#include "qs_port.hpp" // QS port
33#include "qs_pkg.hpp" // QS package-scope internal interface
34#include "qf_pkg.hpp" // QF package-scope internal interface
35#include "qassert.h" // QP assertions
36
37// unnamed namespace for local definitions with internal linkage
38namespace {
39
41
42} // unnamed namespace
43
44namespace QP {
45
46
47//============================================================================
48struct QS::QSrxPriv QS::rxPriv_; // QS-RX private data
49
50//============================================================================
51#if (QS_OBJ_PTR_SIZE == 1U)
52 using QSObj = std::uint8_t;
53#elif (QS_OBJ_PTR_SIZE == 2U)
54 using QSObj = std::uint16_t;
55#elif (QS_OBJ_PTR_SIZE == 4U)
56 using QSObj = std::uint32_t;
57#elif (QS_OBJ_PTR_SIZE == 8U)
58 using QSObj = std::uint64_t;
59#endif
60
64struct CmdVar {
65 std::uint32_t param1;
66 std::uint32_t param2;
67 std::uint32_t param3;
68 std::uint8_t idx;
69 std::uint8_t cmdId;
70};
71
72struct TickVar {
73 std::uint_fast8_t rate;
74};
75
76struct PeekVar {
77 std::uint16_t offs;
78 std::uint8_t size;
79 std::uint8_t num;
80 std::uint8_t idx;
81};
82
83struct PokeVar {
84 std::uint32_t data;
85 std::uint16_t offs;
86 std::uint8_t size;
87 std::uint8_t num;
88 std::uint8_t idx;
89 std::uint8_t fill;
90};
91
92struct FltVar {
93 std::uint8_t data[16];
94 std::uint8_t idx;
95 std::uint8_t recId; // global/local
96};
97
98struct ObjVar {
99 QSObj addr;
100 std::uint8_t idx;
101 std::uint8_t kind; // see qs.hpp, enum QSpyObjKind
102 std::uint8_t recId;
103};
104
105struct EvtVar {
106 QEvt *e;
107 std::uint8_t *p;
108 QSignal sig;
109 std::uint16_t len;
110 std::uint8_t prio;
111 std::uint8_t idx;
112};
113
114#ifdef Q_UTEST
115 #if (QS_FUN_PTR_SIZE == 1U)
116 using QSFun = std::uint8_t;
117 #elif (QS_FUN_PTR_SIZE == 2U)
118 using QSFun = std::uint16_t;
119 #elif (QS_FUN_PTR_SIZE == 4U)
120 using QSFun = std::uint32_t;
121 #elif (QS_FUN_PTR_SIZE == 8U)
122 using QSFun = std::uint64_t;
123 #endif
124
125 struct TPVar { // Test-Probe
126 QSFun addr;
127 std::uint32_t data;
128 std::uint8_t idx;
129 };
130
131 static struct TestData {
132 TPVar tpBuf[16]; // buffer of Test-Probes received so far
133 std::uint8_t tpNum; // current number of Test-Probes
134 QSTimeCtr testTime; // test time (tick counter)
135 } l_testData;
136
137#endif // Q_UTEST
138
139// extended-state variables for the current QS-RX state
140static struct ExtState {
141 union Variant {
142 CmdVar cmd;
143 TickVar tick;
144 PeekVar peek;
145 PokeVar poke;
146 FltVar flt;
147 ObjVar obj;
148 EvtVar evt;
149#ifdef Q_UTEST
150 TPVar tp;
151#endif // Q_UTEST
152 } var;
153 std::uint8_t state;
154 std::uint8_t esc;
155 std::uint8_t seq;
156 std::uint8_t chksum;
157} l_rx;
158
159enum RxStateEnum : std::uint8_t {
160 ERROR_STATE,
161 WAIT4_SEQ,
162 WAIT4_REC,
163 WAIT4_INFO_FRAME,
164 WAIT4_CMD_ID,
165 WAIT4_CMD_PARAM1,
166 WAIT4_CMD_PARAM2,
167 WAIT4_CMD_PARAM3,
168 WAIT4_CMD_FRAME,
169 WAIT4_RESET_FRAME,
170 WAIT4_TICK_RATE,
171 WAIT4_TICK_FRAME,
172 WAIT4_PEEK_OFFS,
173 WAIT4_PEEK_SIZE,
174 WAIT4_PEEK_NUM,
175 WAIT4_PEEK_FRAME,
176 WAIT4_POKE_OFFS,
177 WAIT4_POKE_SIZE,
178 WAIT4_POKE_NUM,
179 WAIT4_POKE_DATA,
180 WAIT4_POKE_FRAME,
181 WAIT4_FILL_DATA,
182 WAIT4_FILL_FRAME,
183 WAIT4_FILTER_LEN,
184 WAIT4_FILTER_DATA,
185 WAIT4_FILTER_FRAME,
186 WAIT4_OBJ_KIND,
187 WAIT4_OBJ_ADDR,
188 WAIT4_OBJ_FRAME,
189 WAIT4_QUERY_KIND,
190 WAIT4_QUERY_FRAME,
191 WAIT4_EVT_PRIO,
192 WAIT4_EVT_SIG,
193 WAIT4_EVT_LEN,
194 WAIT4_EVT_PAR,
195 WAIT4_EVT_FRAME,
196
197#ifdef Q_UTEST
198 WAIT4_TEST_SETUP_FRAME,
199 WAIT4_TEST_TEARDOWN_FRAME,
200 WAIT4_TEST_PROBE_DATA,
201 WAIT4_TEST_PROBE_ADDR,
202 WAIT4_TEST_PROBE_FRAME,
203 WAIT4_TEST_CONTINUE_FRAME,
204#endif // Q_UTEST
205};
206
207// internal helper functions...
208static void rxParseData_(std::uint8_t const b) noexcept;
209static void rxHandleBadFrame_(std::uint8_t const state) noexcept;
210static void rxReportAck_(enum QSpyRxRecords const recId) noexcept;
211static void rxReportError_(std::uint8_t const code) noexcept;
212static void rxReportDone_(enum QSpyRxRecords const recId) noexcept;
213static void rxPoke_(void) noexcept;
214
216static inline void tran_(RxStateEnum const target) noexcept {
217 l_rx.state = static_cast<std::uint8_t>(target);
218}
220
221//============================================================================
241void QS::rxInitBuf(std::uint8_t * const sto,
242 std::uint16_t const stoSize) noexcept
243{
244 rxPriv_.buf = &sto[0];
245 rxPriv_.end = static_cast<QSCtr>(stoSize);
246 rxPriv_.head = 0U;
247 rxPriv_.tail = 0U;
248
249 rxPriv_.currObj[QS::SM_OBJ] = nullptr;
250 rxPriv_.currObj[QS::AO_OBJ] = nullptr;
251 rxPriv_.currObj[QS::MP_OBJ] = nullptr;
252 rxPriv_.currObj[QS::EQ_OBJ] = nullptr;
253 rxPriv_.currObj[QS::TE_OBJ] = nullptr;
254 rxPriv_.currObj[QS::AP_OBJ] = nullptr;
255
256 tran_(WAIT4_SEQ);
257 l_rx.esc = 0U;
258 l_rx.seq = 0U;
259 l_rx.chksum = 0U;
260
261 beginRec_(static_cast<std::uint_fast8_t>(QS_OBJ_DICT));
262 QS_OBJ_PRE_(&rxPriv_);
263 QS_STR_PRE_("QS_RX");
264 endRec_();
265 // no QS_REC_DONE(), because QS is not running yet
266
267#ifdef Q_UTEST
268 l_testData.tpNum = 0U;
269 l_testData.testTime = 0U;
270#endif // Q_UTEST
271}
272
273//============================================================================
281std::uint16_t QS::rxGetNfree(void) noexcept {
282 QSCtr const head = rxPriv_.head;
283 if (head == rxPriv_.tail) { // buffer empty?
284 return static_cast<std::uint16_t>(rxPriv_.end - 1U);
285 }
286 else if (head < rxPriv_.tail) {
287 return static_cast<std::uint16_t>(rxPriv_.tail - head - 1U);
288 }
289 else {
290 return static_cast<std::uint16_t>(rxPriv_.end + rxPriv_.tail
291 - head - 1U);
292 }
293}
294
295//============================================================================
300void QS::setCurrObj(std::uint8_t obj_kind, void *obj_ptr) noexcept {
301 Q_REQUIRE_ID(100, obj_kind < Q_DIM(rxPriv_.currObj));
302 rxPriv_.currObj[obj_kind] = obj_ptr;
303}
304
305//============================================================================
311void QS::queryCurrObj(std::uint8_t obj_kind) noexcept {
312 Q_REQUIRE_ID(200, obj_kind < Q_DIM(rxPriv_.currObj));
313
314 if (QS::rxPriv_.currObj[obj_kind] != nullptr) {
316 QS_CRIT_E_();
317 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_QUERY_DATA));
318 QS_TIME_PRE_(); // timestamp
319 QS_U8_PRE_(obj_kind); // object kind
320 QS_OBJ_PRE_(QS::rxPriv_.currObj[obj_kind]); // object pointer
321 switch (obj_kind) {
322 case SM_OBJ: // intentionally fall through
323 case AO_OBJ:
325 reinterpret_cast<QHsm *>(
326 QS::rxPriv_.currObj[obj_kind])->getStateHandler());
327 break;
328 case QS::MP_OBJ:
329 QS_MPC_PRE_(reinterpret_cast<QMPool *>(
330 QS::rxPriv_.currObj[obj_kind])->m_nFree);
331 QS_MPC_PRE_(reinterpret_cast<QMPool *>(
332 QS::rxPriv_.currObj[obj_kind])->m_nMin);
333 break;
334 case QS::EQ_OBJ:
335 QS_EQC_PRE_(reinterpret_cast<QEQueue *>(
336 QS::rxPriv_.currObj[obj_kind])->m_nFree);
337 QS_EQC_PRE_(reinterpret_cast<QEQueue *>(
338 QS::rxPriv_.currObj[obj_kind])->m_nMin);
339 break;
340 case QS::TE_OBJ:
341 QS_OBJ_PRE_(reinterpret_cast<QTimeEvt *>(
342 QS::rxPriv_.currObj[obj_kind])->m_act);
343 QS_TEC_PRE_(reinterpret_cast<QTimeEvt *>(
344 QS::rxPriv_.currObj[obj_kind])->m_ctr);
345 QS_TEC_PRE_(reinterpret_cast<QTimeEvt *>(
346 QS::rxPriv_.currObj[obj_kind])->m_interval);
347 QS_SIG_PRE_(reinterpret_cast<QTimeEvt *>(
348 QS::rxPriv_.currObj[obj_kind])->sig);
349 QS_U8_PRE_ (reinterpret_cast<QTimeEvt *>(
350 QS::rxPriv_.currObj[obj_kind])->refCtr_);
351 break;
352 default:
353 break;
354 }
355 QS::endRec_();
356 QS_CRIT_X_();
357
358 QS_REC_DONE(); // user callback (if defined)
359 }
360 else {
361 rxReportError_(static_cast<std::uint8_t>(QS_RX_AO_FILTER));
362 }
363}
364
365//============================================================================
366void QS::rxParse(void) {
368 while (rxPriv_.head != tail) { // QS-RX buffer NOT empty?
369 std::uint8_t b = rxPriv_.buf[tail];
370
371 ++tail;
372 if (tail == rxPriv_.end) {
373 tail = 0U;
374 }
375 rxPriv_.tail = tail; // update the tail to a *valid* index
376
377 if (l_rx.esc != 0U) { // escaped byte arrived?
378 l_rx.esc = 0U;
379 b ^= QS_ESC_XOR;
380
381 l_rx.chksum += b;
382 rxParseData_(b);
383 }
384 else if (b == QS_ESC) {
385 l_rx.esc = 1U;
386 }
387 else if (b == QS_FRAME) {
388 // get ready for the next frame
389 b = l_rx.state; // save the current state in b
390 l_rx.esc = 0U;
391 tran_(WAIT4_SEQ);
392
393 if (l_rx.chksum == QS_GOOD_CHKSUM) {
394 l_rx.chksum = 0U;
396 }
397 else { // bad checksum
398 l_rx.chksum = 0U;
399 rxReportError_(0x41U);
401 }
402 }
403 else {
404 l_rx.chksum += b;
405 rxParseData_(b);
406 }
407 }
408}
409
410//============================================================================
411static void rxParseData_(std::uint8_t const b) noexcept {
412 switch (l_rx.state) {
413 case WAIT4_SEQ: {
414 ++l_rx.seq;
415 if (l_rx.seq != b) { // not the expected sequence?
416 rxReportError_(0x42U);
417 l_rx.seq = b; // update the sequence
418 }
419 tran_(WAIT4_REC);
420 break;
421 }
422 case WAIT4_REC: {
423 switch (b) {
424 case QS_RX_INFO:
425 tran_(WAIT4_INFO_FRAME);
426 break;
427 case QS_RX_COMMAND:
428 tran_(WAIT4_CMD_ID);
429 break;
430 case QS_RX_RESET:
431 tran_(WAIT4_RESET_FRAME);
432 break;
433 case QS_RX_TICK:
434 tran_(WAIT4_TICK_RATE);
435 break;
436 case QS_RX_PEEK:
437 if (QS::rxPriv_.currObj[QS::AP_OBJ] != nullptr) {
438 l_rx.var.peek.offs = 0U;
439 l_rx.var.peek.idx = 0U;
440 tran_(WAIT4_PEEK_OFFS);
441 }
442 else {
443 rxReportError_(static_cast<std::uint8_t>(QS_RX_PEEK));
444 tran_(ERROR_STATE);
445 }
446 break;
447 case QS_RX_POKE:
448 case QS_RX_FILL:
449 l_rx.var.poke.fill =
450 (b == static_cast<std::uint8_t>(QS_RX_FILL))
451 ? 1U
452 : 0U;
453 if (QS::rxPriv_.currObj[QS::AP_OBJ] != nullptr) {
454 l_rx.var.poke.offs = 0U;
455 l_rx.var.poke.idx = 0U;
456 tran_(WAIT4_POKE_OFFS);
457 }
458 else {
460 (l_rx.var.poke.fill != 0U)
461 ? static_cast<std::uint8_t>(QS_RX_FILL)
462 : static_cast<std::uint8_t>(QS_RX_POKE));
463 tran_(ERROR_STATE);
464 }
465 break;
466 case QS_RX_GLB_FILTER: // intentionally fall-through
467 case QS_RX_LOC_FILTER:
468 l_rx.var.flt.recId = b;
469 tran_(WAIT4_FILTER_LEN);
470 break;
471 case QS_RX_AO_FILTER: // intentionally fall-through
472 case QS_RX_CURR_OBJ:
473 l_rx.var.obj.recId = b;
474 tran_(WAIT4_OBJ_KIND);
475 break;
476 case QS_RX_QUERY_CURR:
477 l_rx.var.obj.recId =
478 static_cast<std::uint8_t>(QS_RX_QUERY_CURR);
479 tran_(WAIT4_QUERY_KIND);
480 break;
481 case QS_RX_EVENT:
482 tran_(WAIT4_EVT_PRIO);
483 break;
484
485#ifdef Q_UTEST
486 case QS_RX_TEST_SETUP:
487 tran_(WAIT4_TEST_SETUP_FRAME);
488 break;
490 tran_(WAIT4_TEST_TEARDOWN_FRAME);
491 break;
493 tran_(WAIT4_TEST_CONTINUE_FRAME);
494 break;
495 case QS_RX_TEST_PROBE:
496 if (l_testData.tpNum
497 < static_cast<std::uint8_t>(
498 (sizeof(l_testData.tpBuf)
499 / sizeof(l_testData.tpBuf[0]))))
500 {
501 l_rx.var.tp.data = 0U;
502 l_rx.var.tp.idx = 0U;
503 tran_(WAIT4_TEST_PROBE_DATA);
504 }
505 else { // the number of Test-Probes exceeded
507 static_cast<std::uint8_t>(QS_RX_TEST_PROBE));
508 tran_(ERROR_STATE);
509 }
510 break;
511#endif // Q_UTEST
512
513 default:
514 rxReportError_(0x43U);
515 tran_(ERROR_STATE);
516 break;
517 }
518 break;
519 }
520 case WAIT4_INFO_FRAME: {
521 // keep ignoring the data until a frame is collected
522 break;
523 }
524 case WAIT4_CMD_ID: {
525 l_rx.var.cmd.cmdId = b;
526 l_rx.var.cmd.idx = 0U;
527 l_rx.var.cmd.param1 = 0U;
528 l_rx.var.cmd.param2 = 0U;
529 l_rx.var.cmd.param3 = 0U;
530 tran_(WAIT4_CMD_PARAM1);
531 break;
532 }
533 case WAIT4_CMD_PARAM1: {
534 l_rx.var.cmd.param1 |=
535 (static_cast<std::uint32_t>(b) << l_rx.var.cmd.idx);
536 l_rx.var.cmd.idx += 8U;
537 if (l_rx.var.cmd.idx == (8U*4U)) {
538 l_rx.var.cmd.idx = 0U;
539 tran_(WAIT4_CMD_PARAM2);
540 }
541 break;
542 }
543 case WAIT4_CMD_PARAM2: {
544 l_rx.var.cmd.param2 |=
545 static_cast<std::uint32_t>(b) << l_rx.var.cmd.idx;
546 l_rx.var.cmd.idx += 8U;
547 if (l_rx.var.cmd.idx == (8U*4U)) {
548 l_rx.var.cmd.idx = 0U;
549 tran_(WAIT4_CMD_PARAM3);
550 }
551 break;
552 }
553 case WAIT4_CMD_PARAM3: {
554 l_rx.var.cmd.param3 |=
555 static_cast<std::uint32_t>(b) << l_rx.var.cmd.idx;
556 l_rx.var.cmd.idx += 8U;
557 if (l_rx.var.cmd.idx == (8U*4U)) {
558 l_rx.var.cmd.idx = 0U;
559 tran_(WAIT4_CMD_FRAME);
560 }
561 break;
562 }
563 case WAIT4_CMD_FRAME: {
564 // keep ignoring the data until a frame is collected
565 break;
566 }
567 case WAIT4_RESET_FRAME: {
568 // keep ignoring the data until a frame is collected
569 break;
570 }
571 case WAIT4_TICK_RATE: {
572 l_rx.var.tick.rate = static_cast<std::uint_fast8_t>(b);
573 tran_(WAIT4_TICK_FRAME);
574 break;
575 }
576 case WAIT4_TICK_FRAME: {
577 // keep ignoring the data until a frame is collected
578 break;
579 }
580 case WAIT4_PEEK_OFFS: {
581 if (l_rx.var.peek.idx == 0U) {
582 l_rx.var.peek.offs = static_cast<std::uint16_t>(b);
583 l_rx.var.peek.idx += 8U;
584 }
585 else {
586 l_rx.var.peek.offs |= static_cast<std::uint16_t>(
587 static_cast<std::uint16_t>(b) << 8U);
588 tran_(WAIT4_PEEK_SIZE);
589 }
590 break;
591 }
592 case WAIT4_PEEK_SIZE: {
593 if ((b == 1U) || (b == 2U) || (b == 4U)) {
594 l_rx.var.peek.size = b;
595 tran_(WAIT4_PEEK_NUM);
596 }
597 else {
598 rxReportError_(static_cast<std::uint8_t>(QS_RX_PEEK));
599 tran_(ERROR_STATE);
600 }
601 break;
602 }
603 case WAIT4_PEEK_NUM: {
604 l_rx.var.peek.num = b;
605 tran_(WAIT4_PEEK_FRAME);
606 break;
607 }
608 case WAIT4_PEEK_FRAME: {
609 // keep ignoring the data until a frame is collected
610 break;
611 }
612 case WAIT4_POKE_OFFS: {
613 if (l_rx.var.poke.idx == 0U) {
614 l_rx.var.poke.offs = static_cast<std::uint16_t>(b);
615 l_rx.var.poke.idx = 1U;
616 }
617 else {
618 l_rx.var.poke.offs |= static_cast<std::uint16_t>(
619 static_cast<std::uint16_t>(b) << 8U);
620 tran_(WAIT4_POKE_SIZE);
621 }
622 break;
623 }
624 case WAIT4_POKE_SIZE: {
625 if ((b == 1U)
626 || (b == 2U)
627 || (b == 4U))
628 {
629 l_rx.var.poke.size = b;
630 tran_(WAIT4_POKE_NUM);
631 }
632 else {
633 rxReportError_((l_rx.var.poke.fill != 0U)
634 ? static_cast<std::uint8_t>(QS_RX_FILL)
635 : static_cast<std::uint8_t>(QS_RX_POKE));
636 tran_(ERROR_STATE);
637 }
638 break;
639 }
640 case WAIT4_POKE_NUM: {
641 if (b > 0U) {
642 l_rx.var.poke.num = b;
643 l_rx.var.poke.data = 0U;
644 l_rx.var.poke.idx = 0U;
645 tran_((l_rx.var.poke.fill != 0U)
646 ? WAIT4_FILL_DATA
647 : WAIT4_POKE_DATA);
648 }
649 else {
650 rxReportError_((l_rx.var.poke.fill != 0U)
651 ? static_cast<std::uint8_t>(QS_RX_FILL)
652 : static_cast<std::uint8_t>(QS_RX_POKE));
653 tran_(ERROR_STATE);
654 }
655 break;
656 }
657 case WAIT4_FILL_DATA: {
658 l_rx.var.poke.data |=
659 static_cast<std::uint32_t>(b) << l_rx.var.poke.idx;
660 l_rx.var.poke.idx += 8U;
661 if ((l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
662 tran_(WAIT4_FILL_FRAME);
663 }
664 break;
665 }
666 case WAIT4_POKE_DATA: {
667 l_rx.var.poke.data |=
668 static_cast<std::uint32_t>(b) << l_rx.var.poke.idx;
669 l_rx.var.poke.idx += 8U;
670 if ((l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
671 rxPoke_();
672 --l_rx.var.poke.num;
673 if (l_rx.var.poke.num == 0U) {
674 tran_(WAIT4_POKE_FRAME);
675 }
676 }
677 break;
678 }
679 case WAIT4_FILL_FRAME: {
680 // keep ignoring the data until a frame is collected
681 break;
682 }
683 case WAIT4_POKE_FRAME: {
684 // keep ignoring the data until a frame is collected
685 break;
686 }
687 case WAIT4_FILTER_LEN: {
688 if (b == static_cast<std::uint8_t>(sizeof(l_rx.var.flt.data))) {
689 l_rx.var.flt.idx = 0U;
690 tran_(WAIT4_FILTER_DATA);
691 }
692 else {
693 rxReportError_(l_rx.var.flt.recId);
694 tran_(ERROR_STATE);
695 }
696 break;
697 }
698 case WAIT4_FILTER_DATA: {
699 l_rx.var.flt.data[l_rx.var.flt.idx] = b;
700 ++l_rx.var.flt.idx;
701 if (l_rx.var.flt.idx == sizeof(l_rx.var.flt.data)) {
702 tran_(WAIT4_FILTER_FRAME);
703 }
704 break;
705 }
706 case WAIT4_FILTER_FRAME: {
707 // keep ignoring the data until a frame is collected
708 break;
709 }
710 case WAIT4_OBJ_KIND: {
711 if (b <= static_cast<std::uint8_t>(QS::SM_AO_OBJ)) {
712 l_rx.var.obj.kind = b;
713 l_rx.var.obj.addr = 0U;
714 l_rx.var.obj.idx = 0U;
715 tran_(WAIT4_OBJ_ADDR);
716 }
717 else {
718 rxReportError_(l_rx.var.obj.recId);
719 tran_(ERROR_STATE);
720 }
721 break;
722 }
723 case WAIT4_OBJ_ADDR: {
724 l_rx.var.obj.addr |=
725 static_cast<QSObj>(b) << l_rx.var.obj.idx;
726 l_rx.var.obj.idx += 8U;
727 if (l_rx.var.obj.idx
728 == (8U * static_cast<unsigned>(QS_OBJ_PTR_SIZE)))
729 {
730 tran_(WAIT4_OBJ_FRAME);
731 }
732 break;
733 }
734 case WAIT4_OBJ_FRAME: {
735 // keep ignoring the data until a frame is collected
736 break;
737 }
738 case WAIT4_QUERY_KIND: {
739 if (b < static_cast<std::uint8_t>(QS::MAX_OBJ)) {
740 l_rx.var.obj.kind = b;
741 tran_(WAIT4_QUERY_FRAME);
742 }
743 else {
744 rxReportError_(l_rx.var.obj.recId);
745 tran_(ERROR_STATE);
746 }
747 break;
748 }
749 case WAIT4_QUERY_FRAME: {
750 // keep ignoring the data until a frame is collected
751 break;
752 }
753 case WAIT4_EVT_PRIO: {
754 l_rx.var.evt.prio = b;
755 l_rx.var.evt.sig = 0U;
756 l_rx.var.evt.idx = 0U;
757 tran_(WAIT4_EVT_SIG);
758 break;
759 }
760 case WAIT4_EVT_SIG: {
761 l_rx.var.evt.sig |= static_cast<QSignal>(
762 static_cast<std::uint32_t>(b) << l_rx.var.evt.idx);
763 l_rx.var.evt.idx += 8U;
764 if (l_rx.var.evt.idx
765 == (8U *static_cast<unsigned>(Q_SIGNAL_SIZE)))
766 {
767 l_rx.var.evt.len = 0U;
768 l_rx.var.evt.idx = 0U;
769 tran_(WAIT4_EVT_LEN);
770 }
771 break;
772 }
773 case WAIT4_EVT_LEN: {
774 l_rx.var.evt.len |= static_cast<std::uint16_t>(
775 static_cast<unsigned>(b) << l_rx.var.evt.idx);
776 l_rx.var.evt.idx += 8U;
777 if (l_rx.var.evt.idx == (8U * 2U)) {
778 if ((l_rx.var.evt.len + sizeof(QEvt))
779 <= static_cast<std::uint16_t>(QF::poolGetMaxBlockSize()))
780 {
781 // report Ack before generating any other QS records
783
784 l_rx.var.evt.e = QF::newX_(
785 (static_cast<std::uint_fast16_t>(l_rx.var.evt.len)
786 + sizeof(QEvt)),
787 0U, // margin
788 static_cast<enum_t>(l_rx.var.evt.sig));
789 // event allocated?
790 if (l_rx.var.evt.e != nullptr) {
791 l_rx.var.evt.p =
792 reinterpret_cast<std::uint8_t *>(l_rx.var.evt.e);
793 l_rx.var.evt.p = &l_rx.var.evt.p[sizeof(QEvt)];
794 if (l_rx.var.evt.len > 0U) {
795 tran_(WAIT4_EVT_PAR);
796 }
797 else {
798 tran_(WAIT4_EVT_FRAME);
799 }
800 }
801 else {
802 rxReportError_(static_cast<std::uint8_t>(QS_RX_EVENT));
803 tran_(ERROR_STATE);
804 }
805 }
806 else {
807 rxReportError_(static_cast<std::uint8_t>(QS_RX_EVENT));
808 tran_(ERROR_STATE);
809 }
810 }
811 break;
812 }
813 case WAIT4_EVT_PAR: { // event parameters
814 *l_rx.var.evt.p = b;
815 ++l_rx.var.evt.p;
816 --l_rx.var.evt.len;
817 if (l_rx.var.evt.len == 0U) {
818 tran_(WAIT4_EVT_FRAME);
819 }
820 break;
821 }
822 case WAIT4_EVT_FRAME: {
823 // keep ignoring the data until a frame is collected
824 break;
825 }
826
827#ifdef Q_UTEST
828 case WAIT4_TEST_SETUP_FRAME: {
829 // keep ignoring the data until a frame is collected
830 break;
831 }
832 case WAIT4_TEST_TEARDOWN_FRAME: {
833 // keep ignoring the data until a frame is collected
834 break;
835 }
836 case WAIT4_TEST_CONTINUE_FRAME: {
837 // keep ignoring the data until a frame is collected
838 break;
839 }
840 case WAIT4_TEST_PROBE_DATA: {
841 l_rx.var.tp.data |=
842 (static_cast<QSFun>(b) << l_rx.var.tp.idx);
843 l_rx.var.tp.idx += 8U;
844 if (l_rx.var.tp.idx == (8U * sizeof(std::uint32_t))) {
845 l_rx.var.tp.addr = 0U;
846 l_rx.var.tp.idx = 0U;
847 tran_(WAIT4_TEST_PROBE_ADDR);
848 }
849 break;
850 }
851 case WAIT4_TEST_PROBE_ADDR: {
852 l_rx.var.tp.addr |=
853 (static_cast<std::uint32_t>(b) << l_rx.var.tp.idx);
854 l_rx.var.tp.idx += 8U;
855 if (l_rx.var.tp.idx
856 == (8U * static_cast<unsigned>(QS_FUN_PTR_SIZE)))
857 {
858 tran_(WAIT4_TEST_PROBE_FRAME);
859 }
860 break;
861 }
862 case WAIT4_TEST_PROBE_FRAME: {
863 // keep ignoring the data until a frame is collected
864 break;
865 }
866#endif // Q_UTEST
867
868 case ERROR_STATE: {
869 // keep ignoring the data until a good frame is collected
870 break;
871 }
872 default: { // unexpected or unimplemented state
873 rxReportError_(0x45U);
874 tran_(ERROR_STATE);
875 break;
876 }
877 }
878}
879
880//============================================================================
881void QS::rxHandleGoodFrame_(std::uint8_t const state) {
882 std::uint8_t i;
883 std::uint8_t *ptr;
885
886 switch (state) {
887 case WAIT4_INFO_FRAME: {
888 // no need to report Ack or Done
889 QS_CRIT_E_();
890 QS_target_info_(0U); // send only Target info
891 QS_CRIT_X_();
892 break;
893 }
894 case WAIT4_RESET_FRAME: {
895 // no need to report Ack or Done, because Target resets
896 QS::onReset(); // reset the Target
897 break;
898 }
899 case WAIT4_CMD_PARAM1: // intentionally fall-through
900 case WAIT4_CMD_PARAM2: // intentionally fall-through
901 case WAIT4_CMD_PARAM3: // intentionally fall-through
902 case WAIT4_CMD_FRAME: {
904 QS::onCommand(l_rx.var.cmd.cmdId, l_rx.var.cmd.param1,
905 l_rx.var.cmd.param2, l_rx.var.cmd.param3);
906#ifdef Q_UTEST
907 QS::processTestEvts_(); // process all events produced
908#endif
910 break;
911 }
912 case WAIT4_TICK_FRAME: {
914#ifdef Q_UTEST
915 QS::tickX_(l_rx.var.tick.rate, &QS::rxPriv_); // process tick
916 QS::processTestEvts_(); // process all events produced
917#else
918 QF::tickX_(static_cast<std::uint_fast8_t>(l_rx.var.tick.rate),
919 &QS::rxPriv_);
920#endif
922 break;
923 }
924 case WAIT4_PEEK_FRAME: {
925 // no need to report Ack or Done
926 QS_CRIT_E_();
927 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_PEEK_DATA));
928 ptr = static_cast<std::uint8_t*>(
930 ptr = &ptr[l_rx.var.peek.offs];
931 QS_TIME_PRE_(); // timestamp
932 QS_U16_PRE_(l_rx.var.peek.offs); // data offset
933 QS_U8_PRE_(l_rx.var.peek.size); // data size
934 QS_U8_PRE_(l_rx.var.peek.num); // number of data items
935 for (i = 0U; i < l_rx.var.peek.num; ++i) {
936 switch (l_rx.var.peek.size) {
937 case 1:
938 QS_U8_PRE_(ptr[i]);
939 break;
940 case 2:
942 reinterpret_cast<std::uint16_t*>(ptr)[i]);
943 break;
944 case 4:
946 reinterpret_cast<std::uint32_t*>(ptr)[i]);
947 break;
948 default:
949 break;
950 }
951 }
952 QS::endRec_();
953 QS_CRIT_X_();
954
955 QS_REC_DONE(); // user callback (if defined)
956 break;
957 }
958 case WAIT4_POKE_DATA: {
959 // received less than expected poke data items
960 rxReportError_(static_cast<std::uint8_t>(QS_RX_POKE));
961 break;
962 }
963 case WAIT4_POKE_FRAME: {
965 // no need to report done
966 break;
967 }
968 case WAIT4_FILL_FRAME: {
970 ptr = static_cast<std::uint8_t *>(
972 ptr = &ptr[l_rx.var.poke.offs];
973 for (i = 0U; i < l_rx.var.poke.num; ++i) {
974 switch (l_rx.var.poke.size) {
975 case 1:
976 ptr[i] =
977 static_cast<std::uint8_t>(l_rx.var.poke.data);
978 break;
979 case 2:
980 reinterpret_cast<std::uint16_t *>(ptr)[i] =
981 static_cast<std::uint16_t>(l_rx.var.poke.data);
982 break;
983 case 4:
984 reinterpret_cast<std::uint32_t *>(ptr)[i] =
985 l_rx.var.poke.data;
986 break;
987 default:
988 break;
989 }
990 }
991 break;
992 }
993 case WAIT4_FILTER_FRAME: {
994 rxReportAck_(static_cast<enum QSpyRxRecords>(l_rx.var.flt.recId));
995
996 // apply the received filters
997 if (l_rx.var.flt.recId
998 == static_cast<std::uint8_t>(QS_RX_GLB_FILTER))
999 {
1000 for (i = 0U;
1001 i < static_cast<std::uint8_t>(sizeof(priv_.glbFilter));
1002 ++i)
1003 {
1004 priv_.glbFilter[i] = l_rx.var.flt.data[i];
1005 }
1006 // leave the "not maskable" filters enabled,
1007 // see qs.h, Miscellaneous QS records (not maskable)
1008 //
1009 priv_.glbFilter[0] |= 0x01U;
1010 priv_.glbFilter[7] |= 0xFCU;
1011 priv_.glbFilter[8] |= 0x7FU;
1012
1013 // never enable the last 3 records (0x7D, 0x7E, 0x7F)
1014 priv_.glbFilter[15] &= 0x1FU;
1015 }
1016 else if (l_rx.var.flt.recId
1017 == static_cast<std::uint8_t>(QS_RX_LOC_FILTER))
1018 {
1019 for (i = 0U; i < Q_DIM(priv_.locFilter); ++i) {
1020 priv_.locFilter[i] = l_rx.var.flt.data[i];
1021 }
1022 // leave QS_ID == 0 always on
1023 priv_.locFilter[0] |= 0x01U;
1024 }
1025 else {
1026 rxReportError_(l_rx.var.flt.recId);
1027 }
1028
1029 // no need to report Done
1030 break;
1031 }
1032 case WAIT4_OBJ_FRAME: {
1033 i = l_rx.var.obj.kind;
1034 if (i < static_cast<std::uint8_t>(QS::MAX_OBJ)) {
1035 if (l_rx.var.obj.recId
1036 == static_cast<std::uint8_t>(QS_RX_CURR_OBJ))
1037 {
1038 rxPriv_.currObj[i] =
1039 reinterpret_cast<void *>(l_rx.var.obj.addr);
1041 }
1042 else if (l_rx.var.obj.recId
1043 == static_cast<std::uint8_t>(QS_RX_AO_FILTER))
1044 {
1045 if (l_rx.var.obj.addr != 0U) {
1046 std::int_fast16_t const filter =
1047 static_cast<std::int_fast16_t>(
1048 reinterpret_cast<QActive *>(
1049 l_rx.var.obj.addr)->m_prio);
1050 locFilter_((i == 0)
1051 ? filter
1052 :-filter);
1054 }
1055 else {
1056 rxReportError_(static_cast<enum_t>(QS_RX_AO_FILTER));
1057 }
1058 }
1059 else {
1060 rxReportError_(l_rx.var.obj.recId);
1061 }
1062 }
1063 // both SM and AO
1064 else if (i == static_cast<std::uint8_t>(QS::SM_AO_OBJ)) {
1065 if (l_rx.var.obj.recId
1066 == static_cast<std::uint8_t>(QS_RX_CURR_OBJ))
1067 {
1069 = reinterpret_cast<void *>(l_rx.var.obj.addr);
1071 = reinterpret_cast<void *>(l_rx.var.obj.addr);
1072 }
1074 static_cast<enum QSpyRxRecords>(l_rx.var.obj.recId));
1075 }
1076 else {
1077 rxReportError_(l_rx.var.obj.recId);
1078 }
1079 break;
1080 }
1081 case WAIT4_QUERY_FRAME: {
1082 queryCurrObj(l_rx.var.obj.kind);
1083 break;
1084 }
1085 case WAIT4_EVT_FRAME: {
1086 // NOTE: Ack was already reported in the WAIT4_EVT_LEN state
1087#ifdef Q_UTEST
1088 QS::onTestEvt(l_rx.var.evt.e); // "massage" the event, if needed
1089#endif // Q_UTEST
1090 // use 'i' as status, 0 == success,no-recycle
1091 i = 0U;
1092
1093 if (l_rx.var.evt.prio == 0U) { // publish
1094 QF::publish_(l_rx.var.evt.e, &QS::rxPriv_, 0U);
1095 }
1096 else if (l_rx.var.evt.prio < QF_MAX_ACTIVE) {
1097 if (!QF::active_[l_rx.var.evt.prio]->POST_X(
1098 l_rx.var.evt.e,
1099 0U, // margin
1100 &QS::rxPriv_))
1101 {
1102 // failed QACTIVE_POST() recycles the event
1103 i = 0x80U; // failure, no recycle
1104 }
1105 }
1106 else if (l_rx.var.evt.prio == 255U) {
1107 // dispatch to the current SM object
1108 if (QS::rxPriv_.currObj[QS::SM_OBJ] != nullptr) {
1109 // increment the ref-ctr to simulate the situation
1110 // when the event is just retreived from a queue.
1111 // This is expected for the following QF::gc() call.
1112 //
1113 QF_EVT_REF_CTR_INC_(l_rx.var.evt.e);
1114
1115 static_cast<QHsm *>(QS::rxPriv_.currObj[QS::SM_OBJ])
1116 ->dispatch(l_rx.var.evt.e, 0U);
1117 i = 0x01U; // success, recycle
1118 }
1119 else {
1120 i = 0x81U; // failure, recycle
1121 }
1122 }
1123 else if (l_rx.var.evt.prio == 254U) {
1124 // init the current SM object"
1125 if (QS::rxPriv_.currObj[QS::SM_OBJ] != nullptr) {
1126 // increment the ref-ctr to simulate the situation
1127 // when the event is just retreived from a queue.
1128 // This is expected for the following QF::gc() call.
1129 //
1130 QF_EVT_REF_CTR_INC_(l_rx.var.evt.e);
1131
1132 static_cast<QHsm *>(QS::rxPriv_.currObj[QS::SM_OBJ])
1133 ->init(l_rx.var.evt.e, 0U);
1134 i = 0x01U; // success, recycle
1135 }
1136 else {
1137 i = 0x81U; // failure, recycle
1138 }
1139 }
1140 else if (l_rx.var.evt.prio == 253U) {
1141 // post to the current AO
1142 if (QS::rxPriv_.currObj[QS::AO_OBJ] != nullptr) {
1143 if (!static_cast<QActive *>(
1144 QS::rxPriv_.currObj[QS::AO_OBJ])->POST_X(
1145 l_rx.var.evt.e,
1146 0U, // margin
1147 &QS::rxPriv_))
1148 {
1149 // failed QACTIVE_POST() recycles the event
1150 i = 0x80U; // failure, no recycle
1151 }
1152 }
1153 else {
1154 i = 0x81U; // failure, recycle
1155 }
1156 }
1157 else {
1158 i = 0x81U; // failure, recycle
1159 }
1160
1161 // recycle needed?
1162 if ((i & 1U) != 0U) {
1163 QF::gc(l_rx.var.evt.e);
1164 }
1165 // failure?
1166 if ((i & 0x80U) != 0U) {
1167 rxReportError_(static_cast<std::uint8_t>(QS_RX_EVENT));
1168 }
1169 else {
1170#ifdef Q_UTEST
1171 QS::processTestEvts_(); // process all events produced
1172#endif
1174 }
1175 break;
1176 }
1177
1178#ifdef Q_UTEST
1179 case WAIT4_TEST_SETUP_FRAME: {
1181 l_testData.tpNum = 0U; // clear Test-Probes
1182 l_testData.testTime = 0U; //clear time tick
1183 // don't clear current objects
1184 QS::onTestSetup(); // application-specific test setup
1185 // no need to report Done
1186 break;
1187 }
1188 case WAIT4_TEST_TEARDOWN_FRAME: {
1190 QS::onTestTeardown(); // application-specific test teardown
1191 // no need to report Done
1192 break;
1193 }
1194 case WAIT4_TEST_CONTINUE_FRAME: {
1196 QS::rxPriv_.inTestLoop = false; // exit the QUTest loop
1197 // no need to report Done
1198 break;
1199 }
1200 case WAIT4_TEST_PROBE_FRAME: {
1202 Q_ASSERT_ID(815,
1203 l_testData.tpNum
1204 < (sizeof(l_testData.tpBuf) / sizeof(l_testData.tpBuf[0])));
1205 l_testData.tpBuf[l_testData.tpNum] = l_rx.var.tp;
1206 ++l_testData.tpNum;
1207 // no need to report Done
1208 break;
1209 }
1210#endif // Q_UTEST
1211
1212 case ERROR_STATE: {
1213 // keep ignoring all bytes until new frame
1214 break;
1215 }
1216 default: {
1217 rxReportError_(0x47U);
1218 break;
1219 }
1220 }
1221}
1222
1223//============================================================================
1224static void rxHandleBadFrame_(std::uint8_t const state) noexcept {
1225 rxReportError_(0x50U); // error for all bad frames
1226 switch (state) {
1227 case WAIT4_EVT_FRAME: {
1228 Q_ASSERT_ID(910, l_rx.var.evt.e != nullptr);
1229 QF::gc(l_rx.var.evt.e); // don't leak an allocated event
1230 break;
1231 }
1232 default: {
1233 break;
1234 }
1235 }
1236}
1237
1238//============================================================================
1239static void rxReportAck_(enum QSpyRxRecords const recId) noexcept {
1241 QS_CRIT_E_();
1242 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_RX_STATUS));
1243 QS_U8_PRE_(recId); // record ID
1244 QS::endRec_();
1245 QS_CRIT_X_();
1246
1247 QS_REC_DONE(); // user callback (if defined)
1248}
1249
1250//============================================================================
1251static void rxReportError_(std::uint8_t const code) noexcept {
1253 QS_CRIT_E_();
1254 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_RX_STATUS));
1255 QS_U8_PRE_(0x80U | code); // error code
1256 QS::endRec_();
1257 QS_CRIT_X_();
1258
1259 QS_REC_DONE(); // user callback (if defined)
1260}
1261
1262//============================================================================
1263static void rxReportDone_(enum QSpyRxRecords const recId) noexcept {
1265 QS_CRIT_E_();
1266 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_TARGET_DONE));
1267 QS_TIME_PRE_(); // timestamp
1268 QS_U8_PRE_(recId); // record ID
1269 QS::endRec_();
1270 QS_CRIT_X_();
1271
1272 QS_REC_DONE(); // user callback (if defined)
1273}
1274
1275//============================================================================
1276static void rxPoke_(void) noexcept {
1277 std::uint8_t * ptr =
1278 static_cast<std::uint8_t *>(QS::rxPriv_.currObj[QS::AP_OBJ]);
1279 ptr = &ptr[l_rx.var.poke.offs];
1280 switch (l_rx.var.poke.size) {
1281 case 1:
1282 *ptr = static_cast<std::uint8_t>(l_rx.var.poke.data);
1283 break;
1284 case 2:
1285 *reinterpret_cast<std::uint16_t *>(ptr)
1286 = static_cast<std::uint16_t>(l_rx.var.poke.data);
1287 break;
1288 case 4:
1289 *reinterpret_cast<std::uint32_t *>(ptr) = l_rx.var.poke.data;
1290 break;
1291 default:
1292 Q_ERROR_ID(900);
1293 break;
1294 }
1295
1296 l_rx.var.poke.data = 0U;
1297 l_rx.var.poke.idx = 0U;
1298 l_rx.var.poke.offs += static_cast<std::uint16_t>(l_rx.var.poke.size);
1299}
1300
1301//============================================================================
1302#ifdef Q_UTEST
1303
1304//============================================================================
1316std::uint32_t QS::getTestProbe_(void (* const api)(void)) noexcept {
1317 std::uint32_t data = 0U;
1318 for (std::uint8_t i = 0U; i < l_testData.tpNum; ++i) {
1319 if (l_testData.tpBuf[i].addr == reinterpret_cast<QSFun>(api)) {
1320 data = l_testData.tpBuf[i].data;
1321
1323 QS_CRIT_E_();
1324 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_TEST_PROBE_GET));
1325 QS_TIME_PRE_(); // timestamp
1326 QS_FUN_PRE_(api); // the calling API
1327 QS_U32_PRE_(data); // the Test-Probe data
1328 QS::endRec_();
1329 QS_CRIT_X_();
1330
1331 QS_REC_DONE(); // user callback (if defined)
1332
1333 --l_testData.tpNum; // one less Test-Probe
1334 // move all remaining entries in the buffer up by one
1335 for (std::uint8_t j = i; j < l_testData.tpNum; ++j) {
1336 l_testData.tpBuf[j] = l_testData.tpBuf[j + 1U];
1337 }
1338 break; // we are done (Test-Probe retreived)
1339 }
1340 }
1341 return data;
1342}
1343
1344//============================================================================
1346 return (++l_testData.testTime);
1347}
1348
1349#endif // Q_UTEST
1350
1351} // namespace QP
QActive active object (based on QP::QHsm implementation)
Definition: qf.hpp:136
Native QF Event Queue class.
Definition: qequeue.hpp:113
static void gc(QEvt const *const e) noexcept
Recycle a dynamic event.
Definition: qf_dyn.cpp:212
static QEvt * newX_(std::uint_fast16_t const evtSize, std::uint_fast16_t const margin, enum_t const sig) noexcept
Internal QF implementation of creating new dynamic event.
Definition: qf_dyn.cpp:133
static QActive * active_[QF_MAX_ACTIVE+1U]
array of registered active objects
Definition: qf.hpp:571
static std::uint_fast16_t poolGetMaxBlockSize(void) noexcept
Obtain the block size of any registered event pools.
Definition: qf_dyn.cpp:338
static void tickX_(std::uint_fast8_t const tickRate, void const *const sender) noexcept
Processes all armed time events at every clock tick.
Definition: qf_time.cpp:75
static void publish_(QEvt const *const e, void const *const sender, std::uint_fast8_t const qs_id) noexcept
Publish event to the framework.
Definition: qf_ps.cpp:117
Hierarchical State Machine base class.
Definition: qep.hpp:249
Native QF memory pool class.
Definition: qmpool.hpp:98
void * currObj[MAX_OBJ]
current objects
Definition: qs.hpp:522
static struct QP::QS::QSrxPriv rxPriv_
static void setCurrObj(std::uint8_t obj_kind, void *obj_ptr) noexcept
Set the "current object" in the Target.
Definition: qs_rx.cpp:300
static QS priv_
Definition: qs.hpp:519
static QSTimeCtr onGetTime(void)
Callback to obtain a timestamp for a QS record.
Definition: qs_rx.cpp:1345
static void rxHandleGoodFrame_(std::uint8_t const state)
internal function to handle incoming (QS-RX) packet
Definition: qs_rx.cpp:881
QSCtr volatile tail
offset of where next record will be extracted
Definition: qs.hpp:512
static void onTestTeardown(void)
callback to teardown after a unit test inside the Target
static std::uint32_t getTestProbe_(void(*const api)(void)) noexcept
internal function to get the Test-Probe for a given API
Definition: qs_rx.cpp:1316
static void beginRec_(std::uint_fast8_t const rec) noexcept
Mark the begin of a QS record rec.
Definition: qs.cpp:407
static void onTestSetup(void)
callback to setup a unit test inside the Target
@ SM_OBJ
state machine object for QEP
Definition: qs.hpp:481
@ EQ_OBJ
raw queue object
Definition: qs.hpp:484
@ AO_OBJ
active object
Definition: qs.hpp:482
@ TE_OBJ
time event object
Definition: qs.hpp:485
@ MAX_OBJ
Definition: qs.hpp:487
@ AP_OBJ
generic Application-specific object
Definition: qs.hpp:486
@ MP_OBJ
event pool object
Definition: qs.hpp:483
std::uint8_t locFilter[16]
lobal on/off QS filter
Definition: qs.hpp:507
static void onReset(void)
callback function to reset the Target (to be implemented in the BSP)
static void endRec_(void) noexcept
Mark the end of a QS record rec.
Definition: qs.cpp:433
bool inTestLoop
QUTest event loop is running.
Definition: qs.hpp:529
static void processTestEvts_(void)
internal function to process posted events during test
Definition: qutest.cpp:304
QSCtr end
offset of the end of the ring buffer
Definition: qs.hpp:524
static std::uint16_t rxGetNfree(void) noexcept
Obtain the number of free bytes in the QS RX data buffer.
Definition: qs_rx.cpp:281
static void locFilter_(std::int_fast16_t const filter) noexcept
Set/clear the local Filter for a given object-id.
Definition: qs.cpp:343
std::uint8_t glbFilter[16]
global on/off QS filter
Definition: qs.hpp:506
QSCtr volatile head
offset to where next byte will be inserted
Definition: qs.hpp:525
static void queryCurrObj(std::uint8_t obj_kind) noexcept
Query the "current object" in the Target.
Definition: qs_rx.cpp:311
static void onCommand(std::uint8_t cmdId, std::uint32_t param1, std::uint32_t param2, std::uint32_t param3)
Callback function to execute user commands (to be implemented in BSP)
static void rxInitBuf(std::uint8_t *const sto, std::uint16_t const stoSize) noexcept
Initialize the QS RX data buffer.
Definition: qs_rx.cpp:241
@ SM_AO_OBJ
combination of SM and AO
Definition: qs.hpp:491
static void tickX_(std::uint_fast8_t const tickRate, void const *const sender) noexcept
internal function to process armed time events during test
Definition: qutest.cpp:336
std::uint8_t * buf
pointer to the start of the ring buffer
Definition: qs.hpp:523
static void rxParse(void)
Parse all bytes present in the QS RX data buffer.
Definition: qs_rx.cpp:366
static void onTestEvt(QEvt *e)
callback to "massage" the test event before dispatching/posting it
Time Event class.
Definition: qf.hpp:395
namespace associated with the QP/C++ framework
Definition: exa_native.dox:1
static void rxParseData_(std::uint8_t const b) noexcept
Definition: qs_rx.cpp:411
constexpr std::uint8_t QS_ESC
Escape character of the QS output protocol.
Definition: qs_pkg.hpp:64
void QS_target_info_(std::uint8_t const isReset) noexcept
send the Target info (object sizes, build time-stamp, QP version)
Definition: qs.cpp:461
@ QS_TEST_PROBE_GET
reports that Test-Probe has been used
Definition: qs.hpp:143
@ QS_TARGET_DONE
reports completion of a user callback
Definition: qs.hpp:149
@ QS_OBJ_DICT
object dictionary entry
Definition: qs.hpp:145
@ QS_RX_STATUS
reports QS data receive status
Definition: qs.hpp:150
@ QS_QUERY_DATA
reports the data from "current object" query
Definition: qs.hpp:151
@ QS_PEEK_DATA
reports the data from the PEEK query
Definition: qs.hpp:152
constexpr std::uint8_t QS_ESC_XOR
Escape modifier of the QS output protocol.
Definition: qs_pkg.hpp:70
constexpr std::uint8_t QS_GOOD_CHKSUM
Escape character of the QS output protocol.
Definition: qs_pkg.hpp:73
std::uint_fast16_t QSCtr
QS ring buffer counter and offset type.
Definition: qs.hpp:250
constexpr std::uint8_t QS_FRAME
Frame character of the QS output protocol.
Definition: qs_pkg.hpp:61
static void rxReportDone_(enum QSpyRxRecords const recId) noexcept
Definition: qs_rx.cpp:1263
static void rxReportError_(std::uint8_t const code) noexcept
Definition: qs_rx.cpp:1251
static void rxPoke_(void) noexcept
Definition: qs_rx.cpp:1276
QSpyRxRecords
QS received record types (RX channel)
Definition: qs_pkg.hpp:40
@ QS_RX_RESET
reset the Target
Definition: qs_pkg.hpp:43
@ QS_RX_EVENT
inject an event to the Target (post/publish)
Definition: qs_pkg.hpp:57
@ QS_RX_LOC_FILTER
set local filters in the Target
Definition: qs_pkg.hpp:52
@ QS_RX_FILL
fill Target memory
Definition: qs_pkg.hpp:47
@ QS_RX_AO_FILTER
set local AO filter in the Target
Definition: qs_pkg.hpp:53
@ QS_RX_TICK
call QF_tick()
Definition: qs_pkg.hpp:44
@ QS_RX_PEEK
peek Target memory
Definition: qs_pkg.hpp:45
@ QS_RX_CURR_OBJ
set the "current-object" in the Target
Definition: qs_pkg.hpp:54
@ QS_RX_GLB_FILTER
set global filters in the Target
Definition: qs_pkg.hpp:51
@ QS_RX_POKE
poke Target memory
Definition: qs_pkg.hpp:46
@ QS_RX_INFO
query Target info (ver, config, tstamp)
Definition: qs_pkg.hpp:41
@ QS_RX_TEST_TEARDOWN
test teardown
Definition: qs_pkg.hpp:49
@ QS_RX_TEST_PROBE
set a Test-Probe in the Target
Definition: qs_pkg.hpp:50
@ QS_RX_TEST_SETUP
test setup
Definition: qs_pkg.hpp:48
@ QS_RX_COMMAND
execute a user-defined command in the Target
Definition: qs_pkg.hpp:42
@ QS_RX_TEST_CONTINUE
continue a test after QS_RX_TEST_WAIT()
Definition: qs_pkg.hpp:55
@ QS_RX_QUERY_CURR
query the "current object" in the Target
Definition: qs_pkg.hpp:56
static void rxReportAck_(enum QSpyRxRecords const recId) noexcept
Definition: qs_rx.cpp:1239
std::uint16_t QSignal
QSignal represents the signal of an event.
Definition: qep.hpp:129
static void rxHandleBadFrame_(std::uint8_t const state) noexcept
Definition: qs_rx.cpp:1224
void QF_EVT_REF_CTR_INC_(QEvt const *const e) noexcept
increment the refCtr_ of an event e
Definition: qf_pkg.hpp:142
std::uint8_t QSTimeCtr
Definition: qs.hpp:239
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:102
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:135
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:252
#define Q_DIM(array_)
Definition: qassert.h:307
#define Q_ERROR_ID(id_)
Definition: qassert.h:187
int enum_t
alias for enumerations used for event signals
Definition: qep.hpp:66
#define Q_SIGNAL_SIZE
The size (in bytes) of the signal of an event.
Definition: qep.hpp:56
Internal (package scope) QF/C++ interface.
#define QS_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qs.hpp:746
#define QS_TIME_PRE_()
Definition: qs.hpp:225
#define QS_REC_DONE()
macro to hook up user code when a QS record is produced
Definition: qs.hpp:702
#define QS_CRIT_X_()
This is an internal macro for exiting a critical section.
Definition: qs.hpp:766
#define QS_CRIT_E_()
This is an internal macro for entering a critical section.
Definition: qs.hpp:756
Internal (package scope) QS/C++ interface.
#define QS_U8_PRE_(data_)
Internal QS macro to output an unformatted uint8_t data element.
Definition: qs_pkg.hpp:157
#define QS_OBJ_PRE_(obj_)
Internal QS macro to output object pointer data element.
Definition: qs_pkg.hpp:178
#define QS_FUN_PRE_(fun_)
Internal QS macro to output an unformatted function pointer data element.
Definition: qs_pkg.hpp:199
#define QS_MPC_PRE_(ctr_)
Internal QS macro to output an unformatted memory pool block-counter data element.
Definition: qs_pkg.hpp:257
#define QS_TEC_PRE_(ctr_)
Internal QS macro to output an unformatted time event tick-counter data element.
Definition: qs_pkg.hpp:273
#define QS_U16_PRE_(data_)
Internal QS macro to output an unformatted uint16_t data element.
Definition: qs_pkg.hpp:166
#define QS_EQC_PRE_(ctr_)
Internal QS macro to output an unformatted event queue counter data element.
Definition: qs_pkg.hpp:208
#define QS_U32_PRE_(data_)
Internal QS macro to output an unformatted uint32_t data element.
Definition: qs_pkg.hpp:170
#define QS_STR_PRE_(msg_)
Internal QS macro to output a zero-terminated ASCII string data element.
Definition: qs_pkg.hpp:175
#define QF_MAX_ACTIVE
#define QS_FUN_PTR_SIZE
#define QS_OBJ_PTR_SIZE
QEvt base class.
Definition: qep.hpp:191