qs.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /**
  2. * @file
  3. * @brief QS software tracing services
  4. * @ingroup qs
  5. * @cond
  6. ******************************************************************************
  7. * Last updated for version 5.4.0
  8. * Last updated on 2015-04-23
  9. *
  10. * Q u a n t u m L e a P s
  11. * ---------------------------
  12. * innovating embedded systems
  13. *
  14. * Copyright (C) Quantum Leaps, www.state-machine.com.
  15. *
  16. * This program is open source software: you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License as published
  18. * by the Free Software Foundation, either version 3 of the License, or
  19. * (at your option) any later version.
  20. *
  21. * Alternatively, this program may be distributed and modified under the
  22. * terms of Quantum Leaps commercial licenses, which expressly supersede
  23. * the GNU General Public License and are specifically designed for
  24. * licensees interested in retaining the proprietary status of their code.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU General Public License
  32. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  33. *
  34. * Contact information:
  35. * Web: www.state-machine.com
  36. * Email: info@state-machine.com
  37. ******************************************************************************
  38. * @endcond
  39. */
  40. #include "qs_port.h" /* QS port */
  41. #include "qs_pkg.h" /* QS package-scope interface */
  42. #include "qassert.h" /* QP embedded systems-friendly assertions */
  43. Q_DEFINE_THIS_MODULE("qs")
  44. /****************************************************************************/
  45. QSPriv QS_priv_; /* QS private data */
  46. /****************************************************************************/
  47. /**
  48. * @description
  49. * This function should be called from QS_onStartup() to provide QS with
  50. * the data buffer. The first parameter @p sto[] is the address of the memory
  51. * block, and the second parameter @p stoSize is the size of this block
  52. * in bytes. Currently the size of the QS buffer cannot exceed 64KB.
  53. *
  54. * @note QS can work with quite small data buffers, but you will start losing
  55. * data if the buffer is too small for the bursts of tracing activity.
  56. * The right size of the buffer depends on the data production rate and
  57. * the data output rate. QS offers flexible filtering to reduce the data
  58. * production rate.
  59. *
  60. * @note If the data output rate cannot keep up with the production rate,
  61. * QS will start overwriting the older data with newer data. This is
  62. * consistent with the "last-is-best" QS policy. The record sequence counters
  63. * and check sums on each record allow the QSPY host uitiliy to easily detect
  64. * any data loss.
  65. */
  66. void QS_initBuf(uint8_t sto[], uint_fast16_t stoSize) {
  67. uint8_t *buf = &sto[0];
  68. /* must be at least 8 bytes */
  69. Q_REQUIRE_ID(100, stoSize > (uint_fast16_t)8);
  70. /* The QS_initBuf() function clears the internal QS variables, so that
  71. * the tracing can start correctly even if the startup code fails
  72. * to clear the uninitialized data (as is required by the C Standard).
  73. */
  74. QF_bzero(&QS_priv_, (uint_fast16_t)sizeof(QS_priv_));
  75. QS_priv_.buf = buf;
  76. QS_priv_.end = (QSCtr)stoSize;
  77. QS_beginRec((uint_fast8_t)QS_EMPTY);
  78. QS_endRec();
  79. QS_beginRec((uint_fast8_t)QS_QP_RESET);
  80. QS_endRec();
  81. }
  82. /****************************************************************************/
  83. /**
  84. * @description
  85. * This function sets up the QS filter to enable the record type @p rec.
  86. * The argument @a #QS_ALL_RECORDS specifies to filter-in all records.
  87. * This function should be called indirectly through the macro QS_FILTER_ON.
  88. *
  89. * @note Filtering based on the record-type is only the first layer of
  90. * filtering. The second layer is based on the object-type. Both filter
  91. * layers must be enabled for the QS record to be inserted into the QS buffer.
  92. * @sa QS_filterOff(), QS_FILTER_SM_OBJ, QS_FILTER_AO_OBJ, QS_FILTER_MP_OBJ,
  93. * QS_FILTER_EQ_OBJ, and QS_FILTER_TE_OBJ.
  94. */
  95. void QS_filterOn(uint_fast8_t rec) {
  96. if (rec == QS_ALL_RECORDS) {
  97. uint_fast8_t i;
  98. for (i = (uint_fast8_t)0;
  99. i < (uint_fast8_t)(sizeof(QS_priv_.glbFilter) - 1U);
  100. ++i)
  101. {
  102. QS_priv_.glbFilter[i] = (uint8_t)0xFFU; /* set all bits */
  103. }
  104. /* never turn the last 3 records on (0x7D, 0x7E, 0x7F) */
  105. QS_priv_.glbFilter[sizeof(QS_priv_.glbFilter) - 1U] = (uint8_t)0x1F;
  106. }
  107. else {
  108. /* record numbers can't exceed QS_ESC, so they don't need escaping */
  109. Q_ASSERT_ID(210, rec < (uint_fast8_t)QS_ESC);
  110. QS_priv_.glbFilter[rec >> 3] |=
  111. (uint8_t)(1U << (rec & (uint_fast8_t)7));
  112. }
  113. }
  114. /****************************************************************************/
  115. /**
  116. * @description
  117. * This function sets up the QS filter to disable the record type @p rec.
  118. * The argument @a #QS_ALL_RECORDS specifies to suppress all records.
  119. * This function should be called indirectly through the macro QS_FILTER_OFF.
  120. *
  121. * @note Filtering records based on the record-type is only the first layer of
  122. * filtering. The second layer is based on the object-type. Both filter
  123. * layers must be enabled for the QS record to be inserted into the QS buffer.
  124. */
  125. void QS_filterOff(uint_fast8_t rec) {
  126. if (rec == QS_ALL_RECORDS) {
  127. uint8_t *glbFilter = &QS_priv_.glbFilter[0];
  128. /* the following unrolled loop is designed to stop collecting trace
  129. * very fast in order to prevent overwriting the interesting data.
  130. * The code assumes that the dimension of QS_priv_.glbFilter[] is 16.
  131. */
  132. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  133. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  134. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  135. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  136. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  137. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  138. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  139. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  140. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  141. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  142. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  143. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  144. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  145. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  146. *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
  147. *glbFilter = (uint8_t)0;
  148. }
  149. else {
  150. uint8_t tmp;
  151. /* record numbers can't exceed QS_ESC, so they don't need escaping */
  152. Q_ASSERT_ID(310, rec < (uint_fast8_t)QS_ESC);
  153. tmp = (uint8_t)(1U << (rec & (uint_fast8_t)0x07));
  154. tmp ^= (uint8_t)0xFFU; /* invert all bits */
  155. QS_priv_.glbFilter[rec >> 3] &= tmp;
  156. }
  157. }
  158. /****************************************************************************/
  159. /**
  160. * @description
  161. * This function must be called at the beginning of each QS record.
  162. * This function should be called indirectly through the macro #QS_BEGIN,
  163. * or #QS_BEGIN_NOCRIT, depending if it's called in a normal code or from
  164. * a critical section.
  165. */
  166. void QS_beginRec(uint_fast8_t rec) {
  167. uint8_t b = (uint8_t)(QS_priv_.seq + (uint8_t)1);
  168. uint8_t chksum = (uint8_t)0; /* reset the checksum */
  169. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  170. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  171. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  172. QS_priv_.seq = b; /* store the incremented sequence num */
  173. QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
  174. QS_INSERT_ESC_BYTE(b)
  175. chksum = (uint8_t)(chksum + (uint8_t)rec); /* update checksum */
  176. QS_INSERT_BYTE((uint8_t)rec) /* rec byte does not need escaping */
  177. QS_priv_.head = head; /* save the head */
  178. QS_priv_.chksum = chksum; /* save the checksum */
  179. }
  180. /****************************************************************************/
  181. /**
  182. * @description
  183. * This function must be called at the end of each QS record.
  184. * This function should be called indirectly through the macro #QS_END,
  185. * or #QS_END_NOCRIT, depending if it's called in a normal code or from
  186. * a critical section.
  187. */
  188. void QS_endRec(void) {
  189. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  190. QSCtr head = QS_priv_.head;
  191. QSCtr end = QS_priv_.end;
  192. uint8_t b = QS_priv_.chksum;
  193. b ^= (uint8_t)0xFFU; /* invert the bits in the checksum */
  194. QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
  195. if ((b != QS_FRAME) && (b != QS_ESC)) {
  196. QS_INSERT_BYTE(b)
  197. }
  198. else {
  199. QS_INSERT_BYTE(QS_ESC)
  200. QS_INSERT_BYTE(b ^ QS_ESC_XOR)
  201. ++QS_priv_.used; /* account for the ESC byte */
  202. }
  203. QS_INSERT_BYTE(QS_FRAME) /* do not escape this QS_FRAME */
  204. QS_priv_.head = head; /* save the head */
  205. /* overrun over the old data? */
  206. if (QS_priv_.used > end) {
  207. QS_priv_.used = end; /* the whole buffer is used */
  208. QS_priv_.tail = head; /* shift the tail to the old data */
  209. }
  210. }
  211. /****************************************************************************/
  212. /**
  213. * @description
  214. * @note This function is only to be used through macros, never in the
  215. * client code directly.
  216. */
  217. void QS_u8(uint8_t format, uint8_t d) {
  218. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  219. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  220. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  221. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  222. QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
  223. QS_INSERT_ESC_BYTE(format)
  224. QS_INSERT_ESC_BYTE(d)
  225. QS_priv_.head = head; /* save the head */
  226. QS_priv_.chksum = chksum; /* save the checksum */
  227. }
  228. /****************************************************************************/
  229. /**
  230. * @description
  231. * This function is only to be used through macros, never in the
  232. * client code directly.
  233. */
  234. void QS_u16(uint8_t format, uint16_t d) {
  235. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  236. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  237. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  238. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  239. QS_priv_.used += (QSCtr)3; /* 3 bytes about to be added */
  240. QS_INSERT_ESC_BYTE(format)
  241. format = (uint8_t)d;
  242. QS_INSERT_ESC_BYTE(format)
  243. d >>= 8;
  244. format = (uint8_t)d;
  245. QS_INSERT_ESC_BYTE(format)
  246. QS_priv_.head = head; /* save the head */
  247. QS_priv_.chksum = chksum; /* save the checksum */
  248. }
  249. /****************************************************************************/
  250. /**
  251. * @note This function is only to be used through macros, never in the
  252. * client code directly.
  253. */
  254. void QS_u32(uint8_t format, uint32_t d) {
  255. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  256. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  257. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  258. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  259. int_fast8_t i;
  260. QS_priv_.used += (QSCtr)5; /* 5 bytes about to be added */
  261. QS_INSERT_ESC_BYTE(format) /* insert the format byte */
  262. /* insert 4 bytes... */
  263. for (i = (int_fast8_t)4; i != (int_fast8_t)0; --i) {
  264. format = (uint8_t)d;
  265. QS_INSERT_ESC_BYTE(format)
  266. d >>= 8;
  267. }
  268. QS_priv_.head = head; /* save the head */
  269. QS_priv_.chksum = chksum; /* save the checksum */
  270. }
  271. /****************************************************************************/
  272. /*! output uint8_t data element without format information */
  273. /** @note This function is only to be used through macros, never in the
  274. * client code directly.
  275. */
  276. void QS_u8_(uint8_t d) {
  277. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  278. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  279. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  280. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  281. ++QS_priv_.used; /* 1 byte about to be added */
  282. QS_INSERT_ESC_BYTE(d)
  283. QS_priv_.head = head; /* save the head */
  284. QS_priv_.chksum = chksum; /* save the checksum */
  285. }
  286. /****************************************************************************/
  287. /** @note This function is only to be used through macros, never in the
  288. * client code directly.
  289. */
  290. void QS_u8u8_(uint8_t d1, uint8_t d2) {
  291. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  292. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  293. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  294. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  295. QS_priv_.used += (QSCtr)2; /* 2 bytes are about to be added */
  296. QS_INSERT_ESC_BYTE(d1)
  297. QS_INSERT_ESC_BYTE(d2)
  298. QS_priv_.head = head; /* save the head */
  299. QS_priv_.chksum = chksum; /* save the checksum */
  300. }
  301. /****************************************************************************/
  302. /**
  303. * @note This function is only to be used through macros, never in the
  304. * client code directly.
  305. */
  306. void QS_u16_(uint16_t d) {
  307. uint8_t b = (uint8_t)d;
  308. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  309. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  310. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  311. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  312. QS_priv_.used += (QSCtr)2; /* 2 bytes are about to be added */
  313. QS_INSERT_ESC_BYTE(b)
  314. d >>= 8;
  315. b = (uint8_t)d;
  316. QS_INSERT_ESC_BYTE(b)
  317. QS_priv_.head = head; /* save the head */
  318. QS_priv_.chksum = chksum; /* save the checksum */
  319. }
  320. /****************************************************************************/
  321. /** @note This function is only to be used through macros, never in the
  322. * client code directly.
  323. */
  324. void QS_u32_(uint32_t d) {
  325. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  326. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  327. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  328. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  329. int_fast8_t i;
  330. QS_priv_.used += (QSCtr)4; /* 4 bytes are about to be added */
  331. for (i = (int_fast8_t)4; i != (int_fast8_t)0; --i) {
  332. uint8_t b = (uint8_t)d;
  333. QS_INSERT_ESC_BYTE(b)
  334. d >>= 8;
  335. }
  336. QS_priv_.head = head; /* save the head */
  337. QS_priv_.chksum = chksum; /* save the checksum */
  338. }
  339. /****************************************************************************/
  340. /**
  341. * @note This function is only to be used through macros, never in the
  342. * client code directly.
  343. */
  344. void QS_str_(char_t const *s) {
  345. uint8_t b = (uint8_t)(*s);
  346. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  347. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  348. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  349. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  350. QSCtr used = QS_priv_.used; /* put in a temporary (register) */
  351. while (b != (uint8_t)(0)) {
  352. chksum = (uint8_t)(chksum + b); /* update checksum */
  353. QS_INSERT_BYTE(b) /* ASCII characters don't need escaping */
  354. QS_PTR_INC_(s);
  355. b = (uint8_t)(*s);
  356. ++used;
  357. }
  358. QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
  359. ++used;
  360. QS_priv_.head = head; /* save the head */
  361. QS_priv_.chksum = chksum; /* save the checksum */
  362. QS_priv_.used = used; /* save # of used buffer space */
  363. }
  364. /****************************************************************************/
  365. /**
  366. * @note This function is only to be used through macros, never in the
  367. * client code directly.
  368. */
  369. void QS_str_ROM_(char_t const Q_ROM *s) {
  370. uint8_t b = (uint8_t)Q_ROM_BYTE(*s);
  371. uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
  372. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  373. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  374. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  375. QSCtr used = QS_priv_.used; /* put in a temporary (register) */
  376. while (b != (uint8_t)(0)) {
  377. chksum = (uint8_t)(chksum + b); /* update checksum */
  378. QS_INSERT_BYTE(b) /* ASCII characters don't need escaping */
  379. QS_PTR_INC_(s);
  380. b = (uint8_t)Q_ROM_BYTE(*s);
  381. ++used;
  382. }
  383. QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
  384. ++used;
  385. QS_priv_.head = head; /* save the head */
  386. QS_priv_.chksum = chksum; /* save the checksum */
  387. QS_priv_.used = used; /* save # of used buffer space */
  388. }
  389. /****************************************************************************/
  390. /**
  391. * @description
  392. * This function delivers one byte at a time from the QS data buffer.
  393. *
  394. * @returns the byte in the least-significant 8-bits of the 16-bit return
  395. * value if the byte is available. If no more data is available at the time,
  396. * the function returns ::QS_EOD (End-Of-Data).
  397. *
  398. * @note QS_getByte() is __not__ protected with a critical section.
  399. */
  400. uint16_t QS_getByte(void) {
  401. uint16_t ret;
  402. if (QS_priv_.used == (QSCtr)0) {
  403. ret = QS_EOD; /* set End-Of-Data */
  404. }
  405. else {
  406. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  407. QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
  408. ret = (uint16_t)(*QS_PTR_AT_(tail)); /* set the byte to return */
  409. ++tail; /* advance the tail */
  410. if (tail == QS_priv_.end) { /* tail wrap around? */
  411. tail = (QSCtr)0;
  412. }
  413. QS_priv_.tail = tail; /* update the tail */
  414. --QS_priv_.used; /* one less byte used */
  415. }
  416. return ret; /* return the byte or EOD */
  417. }
  418. /****************************************************************************/
  419. /**
  420. * @description
  421. * This function delivers a contiguous block of data from the QS data buffer.
  422. * The function returns the pointer to the beginning of the block, and writes
  423. * the number of bytes in the block to the location pointed to by @p pNbytes.
  424. * The parameter @p pNbytes is also used as input to provide the maximum size
  425. * of the data block that the caller can accept.
  426. *
  427. * @returns if data is available, the function returns pointer to the
  428. * contiguous block of data and sets the value pointed to by @p pNbytes
  429. * to the # available bytes. If data is available at the time the function is
  430. * called, the function returns NULL pointer and sets the value pointed to by
  431. * @p pNbytes to zero.
  432. *
  433. * @note Only the NULL return from QS_getBlock() indicates that the QS buffer
  434. * is empty at the time of the call. The non-NULL return often means that
  435. * the block is at the end of the buffer and you need to call QS_getBlock()
  436. * again to obtain the rest of the data that "wrapped around" to the
  437. * beginning of the QS data buffer.
  438. *
  439. * @note QS_getBlock() is NOT protected with a critical section.
  440. */
  441. uint8_t const *QS_getBlock(uint16_t *pNbytes) {
  442. QSCtr used = QS_priv_.used; /* put in a temporary (register) */
  443. uint8_t *buf;
  444. /* any bytes used in the ring buffer? */
  445. if (used != (QSCtr)0) {
  446. QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
  447. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  448. QSCtr n = (QSCtr)(end - tail);
  449. if (n > used) {
  450. n = used;
  451. }
  452. if (n > (QSCtr)(*pNbytes)) {
  453. n = (QSCtr)(*pNbytes);
  454. }
  455. *pNbytes = (uint16_t)n; /* n-bytes available */
  456. buf = QS_priv_.buf;
  457. buf = QS_PTR_AT_(tail); /* the bytes are at the tail */
  458. QS_priv_.used = (QSCtr)(used - n);
  459. tail += n;
  460. if (tail == end) {
  461. tail = (QSCtr)0;
  462. }
  463. QS_priv_.tail = tail;
  464. }
  465. else { /* no bytes available */
  466. *pNbytes = (uint16_t)0; /* no bytes available right now */
  467. buf = (uint8_t *)0; /* no bytes available right now */
  468. }
  469. return buf;
  470. }
  471. /****************************************************************************/
  472. /** @note This function is only to be used through macro QS_SIG_DICTIONARY()
  473. */
  474. void QS_sig_dict(enum_t const sig, void const * const obj,
  475. char_t const Q_ROM * const name)
  476. {
  477. QS_CRIT_STAT_
  478. QS_CRIT_ENTRY_();
  479. QS_beginRec((uint_fast8_t)QS_SIG_DICT);
  480. QS_SIG_((QSignal)sig);
  481. QS_OBJ_(obj);
  482. QS_STR_ROM_(name);
  483. QS_endRec();
  484. QS_CRIT_EXIT_();
  485. QS_onFlush();
  486. }
  487. /****************************************************************************/
  488. /** @note This function is only to be used through macro QS_OBJ_DICTIONARY()
  489. */
  490. void QS_obj_dict(void const * const obj,
  491. char_t const Q_ROM * const name)
  492. {
  493. QS_CRIT_STAT_
  494. QS_CRIT_ENTRY_();
  495. QS_beginRec((uint_fast8_t)QS_OBJ_DICT);
  496. QS_OBJ_(obj);
  497. QS_STR_ROM_(name);
  498. QS_endRec();
  499. QS_CRIT_EXIT_();
  500. QS_onFlush();
  501. }
  502. /****************************************************************************/
  503. /** @note This function is only to be used through macro QS_FUN_DICTIONARY()
  504. */
  505. void QS_fun_dict(void (* const fun)(void),
  506. char_t const Q_ROM * const name)
  507. {
  508. QS_CRIT_STAT_
  509. QS_CRIT_ENTRY_();
  510. QS_beginRec((uint_fast8_t)QS_FUN_DICT);
  511. QS_FUN_(fun);
  512. QS_STR_ROM_(name);
  513. QS_endRec();
  514. QS_CRIT_EXIT_();
  515. QS_onFlush();
  516. }
  517. /****************************************************************************/
  518. /** @note This function is only to be used through macro QS_USR_DICTIONARY()
  519. */
  520. void QS_usr_dict(enum_t const rec,
  521. char_t const Q_ROM * const name)
  522. {
  523. QS_CRIT_STAT_
  524. QS_CRIT_ENTRY_();
  525. QS_beginRec((uint_fast8_t)QS_USR_DICT);
  526. QS_U8_((uint8_t)rec);
  527. QS_STR_ROM_(name);
  528. QS_endRec();
  529. QS_CRIT_EXIT_();
  530. QS_onFlush();
  531. }
  532. /****************************************************************************/
  533. /** @note This function is only to be used through macros, never in the
  534. * client code directly.
  535. */
  536. void QS_mem(uint8_t const *blk, uint8_t size) {
  537. uint8_t b = (uint8_t)(QS_MEM_T);
  538. uint8_t chksum = (uint8_t)(QS_priv_.chksum + b);
  539. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  540. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  541. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  542. QS_priv_.used += ((QSCtr)size + (QSCtr)2); /* size+2 bytes to be added */
  543. QS_INSERT_BYTE(b)
  544. QS_INSERT_ESC_BYTE(size)
  545. /* output the 'size' number of bytes */
  546. while (size != (uint8_t)0) {
  547. b = *blk;
  548. QS_INSERT_ESC_BYTE(b)
  549. QS_PTR_INC_(blk);
  550. --size;
  551. }
  552. QS_priv_.head = head; /* save the head */
  553. QS_priv_.chksum = chksum; /* save the checksum */
  554. }
  555. /****************************************************************************/
  556. /**
  557. * @note This function is only to be used through macros, never in the
  558. * client code directly.
  559. */
  560. void QS_str(char_t const *s) {
  561. uint8_t b = (uint8_t)(*s);
  562. uint8_t chksum = (uint8_t)(QS_priv_.chksum + (uint8_t)QS_STR_T);
  563. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  564. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  565. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  566. QSCtr used = QS_priv_.used; /* put in a temporary (register) */
  567. used += (QSCtr)2; /* account for the format byte and the terminating-0 */
  568. QS_INSERT_BYTE((uint8_t)QS_STR_T)
  569. while (b != (uint8_t)(0)) {
  570. /* ASCII characters don't need escaping */
  571. chksum = (uint8_t)(chksum + b); /* update checksum */
  572. QS_INSERT_BYTE(b)
  573. QS_PTR_INC_(s);
  574. b = (uint8_t)(*s);
  575. ++used;
  576. }
  577. QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
  578. QS_priv_.head = head; /* save the head */
  579. QS_priv_.chksum = chksum; /* save the checksum */
  580. QS_priv_.used = used; /* save # of used buffer space */
  581. }
  582. /****************************************************************************/
  583. /** @note This function is only to be used through macros, never in the
  584. * client code directly.
  585. */
  586. void QS_str_ROM(char_t const Q_ROM *s) {
  587. uint8_t b = (uint8_t)Q_ROM_BYTE(*s);
  588. uint8_t chksum = (uint8_t)(QS_priv_.chksum + (uint8_t)QS_STR_T);
  589. uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
  590. QSCtr head = QS_priv_.head; /* put in a temporary (register) */
  591. QSCtr end = QS_priv_.end; /* put in a temporary (register) */
  592. QSCtr used = QS_priv_.used; /* put in a temporary (register) */
  593. used += (QSCtr)2; /* account for the format byte and the terminating-0 */
  594. QS_INSERT_BYTE((uint8_t)QS_STR_T)
  595. while (b != (uint8_t)(0)) {
  596. /* ASCII characters don't need escaping */
  597. chksum = (uint8_t)(chksum + b); /* update checksum */
  598. QS_INSERT_BYTE(b)
  599. QS_PTR_INC_(s);
  600. b = (uint8_t)Q_ROM_BYTE(*s);
  601. ++used;
  602. }
  603. QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
  604. QS_priv_.head = head; /* save the head */
  605. QS_priv_.chksum = chksum; /* save the checksum */
  606. QS_priv_.used = used; /* save # of used buffer space */
  607. }