QP/C++  7.0.1
Real-Time Embedded Framework
qs.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 "qstamp.hpp" // QP time-stamp
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//============================================================================
47QS QS::priv_; // QS private data
48
49//============================================================================
68void QS::initBuf(std::uint8_t * const sto,
69 std::uint_fast16_t const stoSize) noexcept
70{
71 // the provided buffer must be at least 8 bytes long
72 Q_REQUIRE_ID(100, stoSize > 8U);
73
74 // This function initializes all the internal QS variables, so that the
75 // tracing can start correctly even if the startup code fails to clear
76 // any uninitialized data (as is required by the C Standard).
77 //
78 glbFilter_(-static_cast<enum_t>(QS_ALL_RECORDS));// all global filters OFF
79 locFilter_(static_cast<enum_t>(QS_ALL_IDS)); // all local filters ON
80 priv_.locFilter_AP = nullptr; // deprecated "AP-filter"
81
82 priv_.buf = sto;
83 priv_.end = static_cast<QSCtr>(stoSize);
84 priv_.head = 0U;
85 priv_.tail = 0U;
86 priv_.used = 0U;
87 priv_.seq = 0U;
88 priv_.chksum = 0U;
89 priv_.critNest = 0U;
90
91 // produce an empty record to "flush" the QS trace buffer
92 beginRec_(QS_REC_NUM_(QS_EMPTY));
93 endRec_();
94
95 // produce the Target info QS record
96 QS_target_info_(0xFFU);
97
98 // wait with flushing after successfull initialization (see QS_INIT())
99}
100
101//============================================================================
118void QS::glbFilter_(std::int_fast16_t const filter) noexcept {
119 bool const isRemove = (filter < 0);
120 std::uint16_t const rec = isRemove
121 ? static_cast<std::uint16_t>(-filter)
122 : static_cast<std::uint16_t>(filter);
123 switch (rec) {
124 case QS_ALL_RECORDS: {
125 std::uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
126 std::uint_fast8_t i;
127 // set all global filters (partially unrolled loop)
128 for (i = 0U; i < Q_DIM(priv_.glbFilter); i += 4U) {
129 priv_.glbFilter[i ] = tmp;
130 priv_.glbFilter[i + 1U] = tmp;
131 priv_.glbFilter[i + 2U] = tmp;
132 priv_.glbFilter[i + 3U] = tmp;
133 }
134 if (isRemove) {
135 // leave the "not maskable" filters enabled,
136 // see qs.h, Miscellaneous QS records (not maskable)
137 //
138 priv_.glbFilter[0] = 0x01U;
139 priv_.glbFilter[7] = 0xFCU;
140 priv_.glbFilter[8] = 0x7FU;
141 }
142 else {
143 // never turn the last 3 records on (0x7D, 0x7E, 0x7F)
144 priv_.glbFilter[15] = 0x1FU;
145 }
146 break;
147 }
148 case QS_SM_RECORDS:
149 if (isRemove) {
150 priv_.glbFilter[0] &=
151 static_cast<std::uint8_t>(~0xFEU & 0xFFU);
152 priv_.glbFilter[1] &=
153 static_cast<std::uint8_t>(~0x03U & 0xFFU);
154 priv_.glbFilter[6] &=
155 static_cast<std::uint8_t>(~0x80U & 0xFFU);
156 priv_.glbFilter[7] &=
157 static_cast<std::uint8_t>(~0x03U & 0xFFU);
158 }
159 else {
160 priv_.glbFilter[0] |= 0xFEU;
161 priv_.glbFilter[1] |= 0x03U;
162 priv_.glbFilter[6] |= 0x80U;
163 priv_.glbFilter[7] |= 0x03U;
164 }
165 break;
166 case QS_AO_RECORDS:
167 if (isRemove) {
168 priv_.glbFilter[1] &=
169 static_cast<std::uint8_t>(~0xFCU & 0xFFU);
170 priv_.glbFilter[2] &=
171 static_cast<std::uint8_t>(~0x07U & 0xFFU);
172 priv_.glbFilter[5] &=
173 static_cast<std::uint8_t>(~0x20U & 0xFFU);
174 }
175 else {
176 priv_.glbFilter[1] |= 0xFCU;
177 priv_.glbFilter[2] |= 0x07U;
178 priv_.glbFilter[5] |= 0x20U;
179 }
180 break;
181 case QS_EQ_RECORDS:
182 if (isRemove) {
183 priv_.glbFilter[2] &=
184 static_cast<std::uint8_t>(~0x78U & 0xFFU);
185 priv_.glbFilter[5] &=
186 static_cast<std::uint8_t>(~0x40U & 0xFFU);
187 }
188 else {
189 priv_.glbFilter[2] |= 0x78U;
190 priv_.glbFilter[5] |= 0x40U;
191 }
192 break;
193 case QS_MP_RECORDS:
194 if (isRemove) {
195 priv_.glbFilter[3] &=
196 static_cast<std::uint8_t>(~0x03U & 0xFFU);
197 priv_.glbFilter[5] &=
198 static_cast<std::uint8_t>(~0x80U & 0xFFU);
199 }
200 else {
201 priv_.glbFilter[3] |= 0x03U;
202 priv_.glbFilter[5] |= 0x80U;
203 }
204 break;
205 case QS_QF_RECORDS:
206 if (isRemove) {
207 priv_.glbFilter[2] &=
208 static_cast<std::uint8_t>(~0x80U & 0xFFU);
209 priv_.glbFilter[3] &=
210 static_cast<std::uint8_t>(~0xFCU & 0xFFU);
211 priv_.glbFilter[4] &=
212 static_cast<std::uint8_t>(~0xC0U & 0xFFU);
213 priv_.glbFilter[5] &=
214 static_cast<std::uint8_t>(~0x1FU & 0xFFU);
215 }
216 else {
217 priv_.glbFilter[2] |= 0x80U;
218 priv_.glbFilter[3] |= 0xFCU;
219 priv_.glbFilter[4] |= 0xC0U;
220 priv_.glbFilter[5] |= 0x1FU;
221 }
222 break;
223 case QS_TE_RECORDS:
224 if (isRemove) {
225 priv_.glbFilter[4] &=
226 static_cast<std::uint8_t>(~0x3FU & 0xFFU);
227 }
228 else {
229 priv_.glbFilter[4] |= 0x3FU;
230 }
231 break;
232 case QS_SC_RECORDS:
233 if (isRemove) {
234 priv_.glbFilter[6] &=
235 static_cast<std::uint8_t>(~0x7FU & 0xFFU);
236 }
237 else {
238 priv_.glbFilter[6] |= 0x7FU;
239 }
240 break;
241 case QS_U0_RECORDS:
242 if (isRemove) {
243 priv_.glbFilter[12] &=
244 static_cast<std::uint8_t>(~0xF0U & 0xFFU);
245 priv_.glbFilter[13] &=
246 static_cast<std::uint8_t>(~0x01U & 0xFFU);
247 }
248 else {
249 priv_.glbFilter[12] |= 0xF0U;
250 priv_.glbFilter[13] |= 0x01U;
251 }
252 break;
253 case QS_U1_RECORDS:
254 if (isRemove) {
255 priv_.glbFilter[13] &=
256 static_cast<std::uint8_t>(~0x3EU & 0xFFU);
257 }
258 else {
259 priv_.glbFilter[13] |= 0x3EU;
260 }
261 break;
262 case QS_U2_RECORDS:
263 if (isRemove) {
264 priv_.glbFilter[13] &=
265 static_cast<std::uint8_t>(~0xC0U & 0xFFU);
266 priv_.glbFilter[14] &=
267 static_cast<std::uint8_t>(~0x07U & 0xFFU);
268 }
269 else {
270 priv_.glbFilter[13] |= 0xC0U;
271 priv_.glbFilter[14] |= 0x07U;
272 }
273 break;
274 case QS_U3_RECORDS:
275 if (isRemove) {
276 priv_.glbFilter[14] &=
277 static_cast<std::uint8_t>(~0xF8U & 0xFFU);
278 }
279 else {
280 priv_.glbFilter[14] |= 0xF8U;
281 }
282 break;
283 case QS_U4_RECORDS:
284 if (isRemove) {
285 priv_.glbFilter[15] &= 0x1FU;
286 }
287 else {
288 priv_.glbFilter[15] |= 0x1FU;
289 }
290 break;
291 case QS_UA_RECORDS:
292 if (isRemove) {
293 priv_.glbFilter[12] &=
294 static_cast<std::uint8_t>(~0xF0U & 0xFFU);
295 priv_.glbFilter[13] = 0U;
296 priv_.glbFilter[14] = 0U;
297 priv_.glbFilter[15] &=
298 static_cast<std::uint8_t>(~0x1FU & 0xFFU);
299 }
300 else {
301 priv_.glbFilter[12] |= 0xF0U;
302 priv_.glbFilter[13] |= 0xFFU;
303 priv_.glbFilter[14] |= 0xFFU;
304 priv_.glbFilter[15] |= 0x1FU;
305 }
306 break;
307 default:
308 // QS rec number can't exceed 0x7D, so no need for escaping
309 Q_ASSERT_ID(210, rec < 0x7DU);
310
311 if (isRemove) {
312 priv_.glbFilter[rec >> 3U]
313 &= static_cast<std::uint8_t>(~(1U << (rec & 7U)) & 0xFFU);
314 }
315 else {
316 priv_.glbFilter[rec >> 3U]
317 |= static_cast<std::uint8_t>(1U << (rec & 7U));
318 // never turn the last 3 records on (0x7D, 0x7E, 0x7F)
319 priv_.glbFilter[15] &= 0x1FU;
320 }
321 break;
322 }
323}
324
325//============================================================================
343void QS::locFilter_(std::int_fast16_t const filter) noexcept {
344 bool const isRemove = (filter < 0);
345 std::uint16_t const qs_id = isRemove
346 ? static_cast<std::uint16_t>(-filter)
347 : static_cast<std::uint16_t>(filter);
348 std::uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
349 std::uint_fast8_t i;
350 switch (qs_id) {
351 case QS_ALL_IDS:
352 // set all global filters (partially unrolled loop)
353 for (i = 0U; i < Q_DIM(priv_.locFilter); i += 4U) {
354 priv_.locFilter[i ] = tmp;
355 priv_.locFilter[i + 1U] = tmp;
356 priv_.locFilter[i + 2U] = tmp;
357 priv_.locFilter[i + 3U] = tmp;
358 }
359 break;
360 case QS_AO_IDS:
361 for (i = 0U; i < 8U; i += 4U) {
362 priv_.locFilter[i ] = tmp;
363 priv_.locFilter[i + 1U] = tmp;
364 priv_.locFilter[i + 2U] = tmp;
365 priv_.locFilter[i + 3U] = tmp;
366 }
367 break;
368 case QS_EP_IDS:
369 i = 8U;
370 priv_.locFilter[i ] = tmp;
371 priv_.locFilter[i + 1U] = tmp;
372 break;
373 case QS_AP_IDS:
374 i = 12U;
375 priv_.locFilter[i ] = tmp;
376 priv_.locFilter[i + 1U] = tmp;
377 priv_.locFilter[i + 2U] = tmp;
378 priv_.locFilter[i + 3U] = tmp;
379 break;
380 default:
381 if (qs_id < 0x7FU) {
382 if (isRemove) {
383 priv_.locFilter[qs_id >> 3U] &=
384 static_cast<std::uint8_t>(
385 ~(1U << (qs_id & 7U)) & 0xFFU);
386 }
387 else {
388 priv_.locFilter[qs_id >> 3U]
389 |= (1U << (qs_id & 7U));
390 }
391 }
392 else {
393 Q_ERROR_ID(310); // incorrect qs_id
394 }
395 break;
396 }
397 priv_.locFilter[0] |= 0x01U; // leave QS_ID == 0 always on
398}
399
400//============================================================================
407void QS::beginRec_(std::uint_fast8_t const rec) noexcept {
408 std::uint8_t const b = priv_.seq + 1U;
409 std::uint8_t chksum_ = 0U; // reset the checksum
410 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
411 QSCtr head_ = priv_.head; // put in a temporary (register)
412 QSCtr const end_ = priv_.end; // put in a temporary (register)
413
414 priv_.seq = b; // store the incremented sequence num
415 priv_.used = (priv_.used + 2U); // 2 bytes about to be added
416
418
419 chksum_ += static_cast<std::uint8_t>(rec);
420 QS_INSERT_BYTE_(static_cast<std::uint8_t>(rec)) // no need for escaping
421
422 priv_.head = head_; // save the head
423 priv_.chksum = chksum_; // save the checksum
424}
425
426//============================================================================
433void QS::endRec_(void) noexcept {
434 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
435 QSCtr head_ = priv_.head;
436 QSCtr const end_ = priv_.end;
437 std::uint8_t b = priv_.chksum;
438 b ^= 0xFFU; // invert the bits in the checksum
439
440 priv_.used = (priv_.used + 2U); // 2 bytes about to be added
441
442 if ((b != QS_FRAME) && (b != QS_ESC)) {
444 }
445 else {
448 priv_.used = (priv_.used + 1U); // account for the ESC byte
449 }
450
451 QS_INSERT_BYTE_(QS_FRAME) // do not escape this QS_FRAME
452
453 priv_.head = head_; // save the head
454 if (priv_.used > end_) { // overrun over the old data?
455 priv_.used = end_; // the whole buffer is used
456 priv_.tail = head_; // shift the tail to the old data
457 }
458}
459
460//============================================================================
461void QS_target_info_(std::uint8_t const isReset) noexcept {
462 static constexpr std::uint8_t ZERO = static_cast<std::uint8_t>('0');
463 static std::uint8_t const * const TIME =
464 reinterpret_cast<std::uint8_t const *>(&BUILD_TIME[0]);
465 static std::uint8_t const * const DATE =
466 reinterpret_cast<std::uint8_t const *>(&BUILD_DATE[0]);
467
468 QS::beginRec_(static_cast<std::uint_fast8_t>(QS_TARGET_INFO));
469 QS::u8_raw_(isReset);
470
471 static union {
472 std::uint16_t u16;
473 std::uint8_t u8[2];
474 } endian_test;
475 endian_test.u16 = 0x0102U;
476 // big endian ? add the 0x8000U flag
477 QS_U16_PRE_(((endian_test.u8[0] == 0x01U)
478 ? (0x8000U | QP_VERSION)
479 : QP_VERSION)); // target endianness + version number
480
481 // send the object sizes...
483 | static_cast<std::uint8_t>(QF_EVENT_SIZ_SIZE << 4U));
484
485#ifdef QF_EQUEUE_CTR_SIZE
486 QS::u8_raw_(QF_EQUEUE_CTR_SIZE
487 | static_cast<std::uint8_t>(QF_TIMEEVT_CTR_SIZE << 4U));
488#else
489 QS::u8_raw_(static_cast<std::uint8_t>(QF_TIMEEVT_CTR_SIZE << 4U));
490#endif // ifdef QF_EQUEUE_CTR_SIZE
491
492#ifdef QF_MPOOL_CTR_SIZE
493 QS::u8_raw_(QF_MPOOL_SIZ_SIZE
494 | static_cast<std::uint8_t>(QF_MPOOL_CTR_SIZE << 4U));
495#else
496 QS::u8_raw_(0U);
497#endif // ifdef QF_MPOOL_CTR_SIZE
498
501
502 // send the limits...
504 QS::u8_raw_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE << 4U));
505
506 // send the build time in three bytes (sec, min, hour)...
507 QS::u8_raw_((10U * (TIME[6] - ZERO)) + (TIME[7] - ZERO));
508 QS::u8_raw_((10U * (TIME[3] - ZERO)) + (TIME[4] - ZERO));
509 if (BUILD_TIME[0] == static_cast<std::uint8_t>(' ')) {
510 QS::u8_raw_(TIME[1] - ZERO);
511 }
512 else {
513 QS::u8_raw_((10U * (TIME[0] - ZERO)) + (TIME[1] - ZERO));
514 }
515
516 // send the build date in three bytes (day, month, year) ...
517 if (BUILD_DATE[4] == static_cast<std::uint8_t>(' ')) {
518 QS::u8_raw_(DATE[5] - ZERO);
519 }
520 else {
521 QS::u8_raw_((10U * (DATE[4] - ZERO)) + (DATE[5] - ZERO));
522 }
523 // convert the 3-letter month to a number 1-12 ...
524 std::uint8_t b;
525 switch (DATE[0] + DATE[1] + DATE[2]) {
526 case 'J' + 'a' +'n':
527 b = 1U;
528 break;
529 case 'F' + 'e' + 'b':
530 b = 2U;
531 break;
532 case 'M' + 'a' +'r':
533 b = 3U;
534 break;
535 case 'A' + 'p' + 'r':
536 b = 4U;
537 break;
538 case 'M' + 'a' + 'y':
539 b = 5U;
540 break;
541 case 'J' + 'u' + 'n':
542 b = 6U;
543 break;
544 case 'J' + 'u' + 'l':
545 b = 7U;
546 break;
547 case 'A' + 'u' + 'g':
548 b = 8U;
549 break;
550 case 'S' + 'e' + 'p':
551 b = 9U;
552 break;
553 case 'O' + 'c' + 't':
554 b = 10U;
555 break;
556 case 'N' + 'o' + 'v':
557 b = 11U;
558 break;
559 case 'D' + 'e' + 'c':
560 b = 12U;
561 break;
562 default:
563 b = 0U;
564 break;
565 }
566 QS::u8_raw_(b); // store the month
567 QS::u8_raw_((10U * (DATE[9] - ZERO)) + (DATE[10] - ZERO));
568 QS::endRec_();
569}
570
571//============================================================================
576void QS::u8_fmt_(std::uint8_t const format, std::uint8_t const d) noexcept {
577 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
578 std::uint8_t *const buf_ = priv_.buf; // put in a temporary (register)
579 QSCtr head_ = priv_.head; // put in a temporary (register)
580 QSCtr const end_= priv_.end; // put in a temporary (register)
581
582 priv_.used = (priv_.used + 2U); // 2 bytes about to be added
583
584 QS_INSERT_ESC_BYTE_(format)
586
587 priv_.head = head_; // save the head
588 priv_.chksum = chksum_; // save the checksum
589}
590
591//============================================================================
596void QS::u16_fmt_(std::uint8_t format, std::uint16_t d) noexcept {
597 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
598 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
599 QSCtr head_ = priv_.head; // put in a temporary (register)
600 QSCtr const end_= priv_.end; // put in a temporary (register)
601
602 priv_.used = (priv_.used + 3U); // 3 bytes about to be added
603
604 QS_INSERT_ESC_BYTE_(format)
605
606 format = static_cast<std::uint8_t>(d);
607 QS_INSERT_ESC_BYTE_(format)
608
609 d >>= 8U;
610 format = static_cast<std::uint8_t>(d);
611 QS_INSERT_ESC_BYTE_(format)
612
613 priv_.head = head_; // save the head
614 priv_.chksum = chksum_; // save the checksum
615}
616
617//============================================================================
621void QS::u32_fmt_(std::uint8_t format, std::uint32_t d) noexcept {
622 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
623 std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
624 QSCtr head_ = priv_.head; // put in a temporary (register)
625 QSCtr const end_= priv_.end; // put in a temporary (register)
626
627 priv_.used = (priv_.used + 5U); // 5 bytes about to be added
628 QS_INSERT_ESC_BYTE_(format) // insert the format byte
629
630 for (std::uint_fast8_t i = 4U; i != 0U; --i) {
631 format = static_cast<std::uint8_t>(d);
632 QS_INSERT_ESC_BYTE_(format)
633 d >>= 8U;
634 }
635
636 priv_.head = head_; // save the head
637 priv_.chksum = chksum_; // save the checksum
638}
639
640//============================================================================
644 char const * const name) noexcept
645{
647 QS_CRIT_E_();
648 beginRec_(static_cast<std::uint_fast8_t>(QS_USR_DICT));
649 QS_U8_PRE_(rec);
650 QS_STR_PRE_(name);
651 endRec_();
652 QS_CRIT_X_();
653 onFlush();
654}
655
656//============================================================================
660void QS::mem_fmt_(std::uint8_t const *blk, std::uint8_t size) noexcept {
661 std::uint8_t b = static_cast<std::uint8_t>(MEM_T);
662 std::uint8_t chksum_ = priv_.chksum + b;
663 std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
664 QSCtr head_ = priv_.head; // put in a temporary (register)
665 QSCtr const end_= priv_.end; // put in a temporary (register)
666
667 priv_.used = (priv_.used + size + 2U); // size+2 bytes to be added
668
671
672 // output the 'size' number of bytes
673 for (; size != 0U; --size) {
674 b = *blk;
676 ++blk;
677 }
678
679 priv_.head = head_; // save the head
680 priv_.chksum = chksum_; // save the checksum
681}
682
683//============================================================================
687void QS::str_fmt_(char const *s) noexcept {
688 std::uint8_t b = static_cast<std::uint8_t>(*s);
689 std::uint8_t chksum_ = static_cast<std::uint8_t>(
690 priv_.chksum + static_cast<std::uint8_t>(STR_T));
691 std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
692 QSCtr head_ = priv_.head; // put in a temporary (register)
693 QSCtr const end_= priv_.end; // put in a temporary (register)
694 QSCtr used_ = priv_.used; // put in a temporary (register)
695
696 used_ += 2U; // the format byte and the terminating-0
697
698 QS_INSERT_BYTE_(static_cast<std::uint8_t>(STR_T))
699 while (b != 0U) {
700 // ASCII characters don't need escaping
701 chksum_ += b; // update checksum
703 ++s;
704 b = static_cast<std::uint8_t>(*s);
705 ++used_;
706 }
707 QS_INSERT_BYTE_(0U) // zero-terminate the string
708
709 priv_.head = head_; // save the head
710 priv_.chksum = chksum_; // save the checksum
711 priv_.used = used_; // save # of used buffer space
712}
713
714//============================================================================
718void QS::u8_raw_(std::uint8_t const d) noexcept {
719 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
720 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
721 QSCtr head_ = priv_.head; // put in a temporary (register)
722 QSCtr const end_= priv_.end; // put in a temporary (register)
723
724 priv_.used = (priv_.used + 1U); // 1 byte about to be added
726
727 priv_.head = head_; // save the head
728 priv_.chksum = chksum_; // save the checksum
729}
730
731//============================================================================
735void QS::u8u8_raw_(std::uint8_t const d1, std::uint8_t const d2) noexcept {
736 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
737 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
738 QSCtr head_ = priv_.head; // put in a temporary (register)
739 QSCtr const end_= priv_.end; // put in a temporary (register)
740
741 priv_.used = (priv_.used + 2U); // 2 bytes about to be added
744
745 priv_.head = head_; // save the head
746 priv_.chksum = chksum_; // save the checksum
747}
748
749//============================================================================
753void QS::u16_raw_(std::uint16_t d) noexcept {
754 std::uint8_t b = static_cast<std::uint8_t>(d);
755 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
756 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
757 QSCtr head_ = priv_.head; // put in a temporary (register)
758 QSCtr const end_= priv_.end; // put in a temporary (register)
759
760 priv_.used = (priv_.used + 2U); // 2 bytes about to be added
761
763
764 d >>= 8U;
765 b = static_cast<std::uint8_t>(d);
767
768 priv_.head = head_; // save the head
769 priv_.chksum = chksum_; // save the checksum
770}
771
772//============================================================================
776void QS::u32_raw_(std::uint32_t d) noexcept {
777 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
778 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
779 QSCtr head_ = priv_.head; // put in a temporary (register)
780 QSCtr const end_= priv_.end; // put in a temporary (register)
781
782 priv_.used = (priv_.used + 4U); // 4 bytes about to be added
783 for (std::uint_fast8_t i = 4U; i != 0U; --i) {
784 std::uint8_t const b = static_cast<std::uint8_t>(d);
786 d >>= 8U;
787 }
788
789 priv_.head = head_; // save the head
790 priv_.chksum = chksum_; // save the checksum
791}
792
793//============================================================================
797void QS::obj_raw_(void const * const obj) noexcept {
798#if (QS_OBJ_PTR_SIZE == 1U)
799 u8_raw_(reinterpret_cast<std::uint8_t>(obj));
800#elif (QS_OBJ_PTR_SIZE == 2U)
801 u16_raw_(reinterpret_cast<std::uint16_t>(obj));
802#elif (QS_OBJ_PTR_SIZE == 4U)
803 u32_raw_(reinterpret_cast<std::uint32_t>(obj));
804#elif (QS_OBJ_PTR_SIZE == 8U)
805 u64_raw_(reinterpret_cast<std::uint64_t>(obj));
806#else
807 u32_raw_(reinterpret_cast<std::uint32_t>(obj));
808#endif
809}
810
811//============================================================================
815void QS::str_raw_(char const *s) noexcept {
816 std::uint8_t b = static_cast<std::uint8_t>(*s);
817 std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
818 std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
819 QSCtr head_ = priv_.head; // put in a temporary (register)
820 QSCtr const end_= priv_.end; // put in a temporary (register)
821 QSCtr used_ = priv_.used; // put in a temporary (register)
822
823 while (b != 0U) {
824 chksum_ += b; // update checksum
825 QS_INSERT_BYTE_(b) // ASCII characters don't need escaping
826 ++s;
827 b = static_cast<std::uint8_t>(*s);
828 ++used_;
829 }
830 QS_INSERT_BYTE_(0U) // zero-terminate the string
831 ++used_;
832
833 priv_.head = head_; // save the head
834 priv_.chksum = chksum_; // save the checksum
835 priv_.used = used_; // save # of used buffer space
836}
837
838//============================================================================
848std::uint16_t QS::getByte(void) noexcept {
849 std::uint16_t ret;
850 if (priv_.used == 0U) {
851 ret = QS_EOD; // set End-Of-Data
852 }
853 else {
854 std::uint8_t const * const buf_ = priv_.buf; // put in a temporary
855 QSCtr tail_ = priv_.tail; // put in a temporary (register)
856
857 // the byte to return
858 ret = static_cast<std::uint16_t>(buf_[tail_]);
859
860 ++tail_; // advance the tail
861 if (tail_ == priv_.end) { // tail wrap around?
862 tail_ = 0U;
863 }
864 priv_.tail = tail_; // update the tail
865 priv_.used = (priv_.used - 1U); // one less byte used
866 }
867 return ret; // return the byte or EOD
868}
869
870//============================================================================
893std::uint8_t const *QS::getBlock(std::uint16_t * const pNbytes) noexcept {
894 QSCtr const used_ = priv_.used; // put in a temporary (register)
895 std::uint8_t *buf_;
896
897 // any bytes used in the ring buffer?
898 if (used_ == 0U) {
899 *pNbytes = 0U; // no bytes available right now
900 buf_ = nullptr; // no bytes available right now
901 }
902 else {
903 QSCtr tail_ = priv_.tail; // put in a temporary (register)
904 QSCtr const end_ = priv_.end; // put in a temporary (register)
905 QSCtr n = static_cast<QSCtr>(end_ - tail_);
906 if (n > used_) {
907 n = used_;
908 }
909 if (n > static_cast<QSCtr>(*pNbytes)) {
910 n = static_cast<QSCtr>(*pNbytes);
911 }
912 *pNbytes = static_cast<std::uint16_t>(n); // n-bytes available
913 buf_ = priv_.buf;
914 buf_ = &buf_[tail_]; // the bytes are at the tail
915
916 priv_.used = (priv_.used - n);
917 tail_ += n;
918 if (tail_ == end_) {
919 tail_ = 0U;
920 }
921 priv_.tail = tail_;
922 }
923 return buf_;
924}
925
926//============================================================================
929void QS::sig_dict_pre_(enum_t const sig, void const * const obj,
930 char const * const name) noexcept
931{
933
934 QS_CRIT_E_();
935 beginRec_(static_cast<std::uint_fast8_t>(QS_SIG_DICT));
936 QS_SIG_PRE_(sig);
937 QS_OBJ_PRE_(obj);
938 QS_STR_PRE_((*name == '&') ? &name[1] : name);
939 endRec_();
940 QS_CRIT_X_();
941 onFlush();
942}
943
944//============================================================================
947void QS::obj_dict_pre_(void const * const obj,
948 char const * const name) noexcept
949{
951
952 QS_CRIT_E_();
953 beginRec_(static_cast<std::uint_fast8_t>(QS_OBJ_DICT));
954 QS_OBJ_PRE_(obj);
955 QS_STR_PRE_((*name == '&') ? &name[1] : name);
956 endRec_();
957 QS_CRIT_X_();
958 onFlush();
959}
960
961//============================================================================
965void QS::obj_arr_dict_pre_(void const * const obj,
966 std::uint_fast16_t const idx,
967 char const * const name) noexcept
968{
969 Q_REQUIRE_ID(400, idx < 1000U);
970
971 // format idx into a char buffer as "xxx\0"
972 std::uint8_t idx_str[4];
973 std::uint_fast16_t tmp = idx;
974 std::uint8_t i;
975 idx_str[3] = 0U; // zero-terminate
976 idx_str[2] = static_cast<std::uint8_t>(
977 static_cast<std::uint8_t>('0') + (tmp % 10U));
978 tmp /= 10U;
979 idx_str[1] = static_cast<std::uint8_t>(
980 static_cast<std::uint8_t>('0') + (tmp % 10U));
981 if (idx_str[1] == static_cast<std::uint8_t>('0')) {
982 i = 2U;
983 }
984 else {
985 tmp /= 10U;
986 idx_str[0] = static_cast<std::uint8_t>(
987 static_cast<std::uint8_t>('0') + (tmp % 10U));
988 if (idx_str[0] == static_cast<std::uint8_t>('0')) {
989 i = 1U;
990 }
991 else {
992 i = 0U;
993 }
994 }
995
997 std::uint8_t j = ((*name == '&') ? 1U : 0U);
998
999 QS_CRIT_E_();
1000 beginRec_(static_cast<std::uint_fast8_t>(QS_OBJ_DICT));
1001 QS_OBJ_PRE_(obj);
1002 for (; name[j] != '\0'; ++j) {
1003 QS_U8_PRE_(name[j]);
1004 if (name[j] == '[') {
1005 ++j;
1006 break;
1007 }
1008 }
1009 for (; idx_str[i] != 0U; ++i) {
1010 QS_U8_PRE_(idx_str[i]);
1011 }
1012 // skip chars until ']'
1013 for (; name[j] != '\0'; ++j) {
1014 if (name[j] == ']') {
1015 break;
1016 }
1017 }
1018 for (; name[j] != '\0'; ++j) {
1019 QS_U8_PRE_(name[j]);
1020 }
1021 QS_U8_PRE_(0U); // zero-terminate
1022 endRec_();
1023 QS_CRIT_X_();
1024 onFlush();
1025}
1026
1027//============================================================================
1030void QS::fun_dict_pre_(void (* const fun)(void),
1031 char const * const name) noexcept
1032{
1034
1035 QS_CRIT_E_();
1036 beginRec_(static_cast<std::uint_fast8_t>(QS_FUN_DICT));
1037 QS_FUN_PRE_(fun);
1038 QS_STR_PRE_((*name == '&') ? &name[1] : name);
1039 endRec_();
1040 QS_CRIT_X_();
1041 onFlush();
1042}
1043
1044//============================================================================
1047void QS::assertion_pre_(char const * const module, int_t const loc,
1048 std::uint32_t const delay)
1049{
1051 QS_TIME_PRE_();
1052 QS_U16_PRE_(loc);
1053 QS_STR_PRE_((module != nullptr) ? module : "?");
1056 for (std::uint32_t volatile ctr = delay; ctr > 0U; ) {
1057 ctr = (ctr - 1U);
1058 }
1060}
1061
1062//............................................................................
1065 QS_TIME_PRE_();
1069}
1070
1071//............................................................................
1074 QS_TIME_PRE_();
1078}
1079
1080//............................................................................
1081void QS::isr_entry_pre_(std::uint8_t const isrnest,
1082 std::uint8_t const prio)
1083{
1085 QS_TIME_PRE_();
1086 QS_U8_PRE_(isrnest);
1087 QS_U8_PRE_(prio);
1089}
1090
1091//............................................................................
1092void QS::isr_exit_pre_(std::uint8_t const isrnest,
1093 std::uint8_t const prio)
1094{
1096 QS_TIME_PRE_();
1097 QS_U8_PRE_(isrnest);
1098 QS_U8_PRE_(prio);
1100}
1101
1102} // namespace QP
static void sig_dict_pre_(enum_t const sig, void const *const obj, char const *const name) noexcept
Output signal dictionary record.
Definition: qs.cpp:929
static void str_raw_(char const *s) noexcept
Output zero-terminated ASCII string element without format information.
Definition: qs.cpp:815
std::uint_fast8_t volatile critNest
critical section nesting level
Definition: qs.hpp:517
static void crit_entry_pre_(void)
internal function to produce the critical section entry record
Definition: qs.cpp:1063
static std::uint16_t getByte(void) noexcept
Byte-oriented interface to the QS data buffer.
Definition: qs.cpp:848
static void obj_arr_dict_pre_(void const *const obj, std::uint_fast16_t const idx, char const *const name) noexcept
Output predefined object-array dictionary record.
Definition: qs.cpp:965
static void onCleanup(void)
Callback to cleanup the QS facility.
static void assertion_pre_(char const *const module, int_t const loc, std::uint32_t const delay)
internal function to produce the assertion failure trace record
Definition: qs.cpp:1047
static void crit_exit_pre_(void)
internal function to produce the critical section exit record
Definition: qs.cpp:1072
static void u16_raw_(std::uint16_t d) noexcept
Output std::uint16_t data element without format information.
Definition: qs.cpp:753
static void usr_dict_pre_(enum_t const rec, char const *const name) noexcept
Output user dictionary record.
Definition: qs.cpp:643
static QS priv_
Definition: qs.hpp:519
static std::uint8_t const * getBlock(std::uint16_t *const pNbytes) noexcept
Block-oriented interface to the QS data buffer.
Definition: qs.cpp:893
static void onFlush(void)
Callback to flush the QS trace data to the host.
static void u32_fmt_(std::uint8_t format, std::uint32_t d) noexcept
Output std::uint32_t data element with format information.
Definition: qs.cpp:621
static void isr_exit_pre_(std::uint8_t const isrnest, std::uint8_t const prio)
internal function to produce the ISR exit record
Definition: qs.cpp:1092
static void glbFilter_(std::int_fast16_t const filter) noexcept
Set/clear the global Filter for a given QS record.
Definition: qs.cpp:118
static void beginRec_(std::uint_fast8_t const rec) noexcept
Mark the begin of a QS record rec.
Definition: qs.cpp:407
static void isr_entry_pre_(std::uint8_t const isrnest, std::uint8_t const prio)
internal function to produce the ISR entry record
Definition: qs.cpp:1081
static void u8_fmt_(std::uint8_t const format, std::uint8_t const d) noexcept
Output std::uint8_t data element with format information.
Definition: qs.cpp:576
static void obj_dict_pre_(void const *const obj, char const *const name) noexcept
Output object dictionary record.
Definition: qs.cpp:947
static void obj_raw_(void const *const obj) noexcept
Output obj pointer data element without format information.
Definition: qs.cpp:797
static void endRec_(void) noexcept
Mark the end of a QS record rec.
Definition: qs.cpp:433
static void u8_raw_(std::uint8_t const d) noexcept
output std::uint8_t data element without format information
Definition: qs.cpp:718
static void str_fmt_(char const *s) noexcept
Output zero-terminated ASCII string element with format information.
Definition: qs.cpp:687
static void fun_dict_pre_(void(*const fun)(void), char const *const name) noexcept
Output function dictionary record.
Definition: qs.cpp:1030
static void locFilter_(std::int_fast16_t const filter) noexcept
Set/clear the local Filter for a given object-id.
Definition: qs.cpp:343
static void u8u8_raw_(std::uint8_t const d1, std::uint8_t const d2) noexcept
output two std::uint8_t data elements without format information
Definition: qs.cpp:735
static void u32_raw_(std::uint32_t d) noexcept
Output std::uint32_t data element without format information.
Definition: qs.cpp:776
static void mem_fmt_(std::uint8_t const *blk, std::uint8_t size) noexcept
Output memory block of up to 255-bytes with format information.
Definition: qs.cpp:660
static void initBuf(std::uint8_t *const sto, std::uint_fast16_t const stoSize) noexcept
Initialize the QS data buffer.
Definition: qs.cpp:68
static void u16_fmt_(std::uint8_t format, std::uint16_t d) noexcept
output std::uint16_t data element with format information
Definition: qs.cpp:596
namespace associated with the QP/C++ framework
Definition: exa_native.dox:1
char const BUILD_DATE[12]
the calendar date of the last translation of the form: "Mmm dd yyyy"
Definition: qstamp.cpp:42
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_ASSERT_FAIL
assertion failed in the code
Definition: qs.hpp:153
@ QS_FUN_DICT
function dictionary entry
Definition: qs.hpp:146
@ QS_QF_CRIT_ENTRY
critical section was entered
Definition: qs.hpp:111
@ QS_QF_CRIT_EXIT
critical section was exited
Definition: qs.hpp:112
@ QS_OBJ_DICT
object dictionary entry
Definition: qs.hpp:145
@ QS_TARGET_INFO
reports the Target information
Definition: qs.hpp:148
@ QS_QF_ISR_ENTRY
an ISR was entered
Definition: qs.hpp:113
@ QS_QF_ISR_EXIT
an ISR was exited
Definition: qs.hpp:114
@ QS_EMPTY
QS record for cleanly starting a session.
Definition: qs.hpp:56
@ QS_SIG_DICT
signal dictionary entry
Definition: qs.hpp:144
@ QS_USR_DICT
user QS record dictionary entry
Definition: qs.hpp:147
constexpr std::uint16_t QS_EOD
Constant representing End-Of-Data condition returned from the QP::QS::getByte() function.
Definition: qs.hpp:254
char const BUILD_TIME[9]
the time of the last translation of the form: "hh:mm:ss"
Definition: qstamp.cpp:45
constexpr std::uint8_t QS_ESC_XOR
Escape modifier of the QS output protocol.
Definition: qs_pkg.hpp:70
@ QS_EP_IDS
event-pool IDs
Definition: qs.hpp:197
@ QS_AO_IDS
AO IDs (priorities)
Definition: qs.hpp:196
@ QS_ALL_IDS
all QS IDs
Definition: qs.hpp:195
@ QS_AP_IDS
Application-specific IDs.
Definition: qs.hpp:199
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
@ QS_U2_RECORDS
User Group 110-114 records.
Definition: qs.hpp:179
@ QS_MP_RECORDS
Memory Pools QS records.
Definition: qs.hpp:173
@ QS_TE_RECORDS
Time Events QS records.
Definition: qs.hpp:174
@ QS_SM_RECORDS
State Machine QS records.
Definition: qs.hpp:170
@ QS_U0_RECORDS
User Group 100-104 records.
Definition: qs.hpp:177
@ QS_U3_RECORDS
User Group 115-119 records.
Definition: qs.hpp:180
@ QS_U4_RECORDS
User Group 120-124 records.
Definition: qs.hpp:181
@ QS_AO_RECORDS
Active Object QS records.
Definition: qs.hpp:171
@ QS_QF_RECORDS
QF QS records.
Definition: qs.hpp:175
@ QS_SC_RECORDS
Scheduler QS records.
Definition: qs.hpp:176
@ QS_U1_RECORDS
User Group 105-109 records.
Definition: qs.hpp:178
@ QS_EQ_RECORDS
Event Queues QS records.
Definition: qs.hpp:172
@ QS_ALL_RECORDS
all QS records
Definition: qs.hpp:169
@ QS_UA_RECORDS
All User records.
Definition: qs.hpp:182
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 QP_VERSION
The current QP version as a decimal constant XXYZ, where XX is a 2-digit major version number,...
Definition: qep.hpp:38
int int_t
alias for line numbers in assertions and return from QF::run()
Definition: qep.hpp:63
#define Q_SIGNAL_SIZE
The size (in bytes) of the signal of an event.
Definition: qep.hpp:56
#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_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_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Internal QS macro to begin a predefined QS record without critical section.
Definition: qs_pkg.hpp:130
#define QS_INSERT_ESC_BYTE_(b_)
Internal QS macro to insert an escaped byte into the QS buffer.
Definition: qs_pkg.hpp:92
#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_REC_NUM_(enum_)
Internal QS macro to cast enumerated QS record number to uint8_t.
Definition: qs_pkg.hpp:288
#define QS_END_NOCRIT_PRE_()
Internal QS macro to end a predefiend QS record without critical section.
Definition: qs_pkg.hpp:138
#define QS_U16_PRE_(data_)
Internal QS macro to output an unformatted uint16_t data element.
Definition: qs_pkg.hpp:166
#define QS_INSERT_BYTE_(b_)
Internal QS macro to insert an un-escaped byte into the QS buffer.
Definition: qs_pkg.hpp:84
#define QS_STR_PRE_(msg_)
Internal QS macro to output a zero-terminated ASCII string data element.
Definition: qs_pkg.hpp:175
Application build time-stamp interface.
#define QF_MAX_TICK_RATE
#define QF_MAX_ACTIVE
#define QS_TIME_SIZE
#define QS_FUN_PTR_SIZE
#define QS_OBJ_PTR_SIZE