| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- /**
- * @file
- * @brief QS software tracing services
- * @ingroup qs
- * @cond
- ******************************************************************************
- * Last updated for version 5.4.0
- * Last updated on 2015-04-23
- *
- * Q u a n t u m L e a P s
- * ---------------------------
- * innovating embedded systems
- *
- * Copyright (C) Quantum Leaps, www.state-machine.com.
- *
- * This program is open source software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alternatively, this program may be distributed and modified under the
- * terms of Quantum Leaps commercial licenses, which expressly supersede
- * the GNU General Public License and are specifically designed for
- * licensees interested in retaining the proprietary status of their code.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Contact information:
- * Web: www.state-machine.com
- * Email: info@state-machine.com
- ******************************************************************************
- * @endcond
- */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- Q_DEFINE_THIS_MODULE("qs")
- /****************************************************************************/
- QSPriv QS_priv_; /* QS private data */
- /****************************************************************************/
- /**
- * @description
- * This function should be called from QS_onStartup() to provide QS with
- * the data buffer. The first parameter @p sto[] is the address of the memory
- * block, and the second parameter @p stoSize is the size of this block
- * in bytes. Currently the size of the QS buffer cannot exceed 64KB.
- *
- * @note QS can work with quite small data buffers, but you will start losing
- * data if the buffer is too small for the bursts of tracing activity.
- * The right size of the buffer depends on the data production rate and
- * the data output rate. QS offers flexible filtering to reduce the data
- * production rate.
- *
- * @note If the data output rate cannot keep up with the production rate,
- * QS will start overwriting the older data with newer data. This is
- * consistent with the "last-is-best" QS policy. The record sequence counters
- * and check sums on each record allow the QSPY host uitiliy to easily detect
- * any data loss.
- */
- void QS_initBuf(uint8_t sto[], uint_fast16_t stoSize) {
- uint8_t *buf = &sto[0];
- /* must be at least 8 bytes */
- Q_REQUIRE_ID(100, stoSize > (uint_fast16_t)8);
- /* The QS_initBuf() function clears the internal QS variables, so that
- * the tracing can start correctly even if the startup code fails
- * to clear the uninitialized data (as is required by the C Standard).
- */
- QF_bzero(&QS_priv_, (uint_fast16_t)sizeof(QS_priv_));
- QS_priv_.buf = buf;
- QS_priv_.end = (QSCtr)stoSize;
- QS_beginRec((uint_fast8_t)QS_EMPTY);
- QS_endRec();
- QS_beginRec((uint_fast8_t)QS_QP_RESET);
- QS_endRec();
- }
- /****************************************************************************/
- /**
- * @description
- * This function sets up the QS filter to enable the record type @p rec.
- * The argument @a #QS_ALL_RECORDS specifies to filter-in all records.
- * This function should be called indirectly through the macro QS_FILTER_ON.
- *
- * @note Filtering based on the record-type is only the first layer of
- * filtering. The second layer is based on the object-type. Both filter
- * layers must be enabled for the QS record to be inserted into the QS buffer.
- * @sa QS_filterOff(), QS_FILTER_SM_OBJ, QS_FILTER_AO_OBJ, QS_FILTER_MP_OBJ,
- * QS_FILTER_EQ_OBJ, and QS_FILTER_TE_OBJ.
- */
- void QS_filterOn(uint_fast8_t rec) {
- if (rec == QS_ALL_RECORDS) {
- uint_fast8_t i;
- for (i = (uint_fast8_t)0;
- i < (uint_fast8_t)(sizeof(QS_priv_.glbFilter) - 1U);
- ++i)
- {
- QS_priv_.glbFilter[i] = (uint8_t)0xFFU; /* set all bits */
- }
- /* never turn the last 3 records on (0x7D, 0x7E, 0x7F) */
- QS_priv_.glbFilter[sizeof(QS_priv_.glbFilter) - 1U] = (uint8_t)0x1F;
- }
- else {
- /* record numbers can't exceed QS_ESC, so they don't need escaping */
- Q_ASSERT_ID(210, rec < (uint_fast8_t)QS_ESC);
- QS_priv_.glbFilter[rec >> 3] |=
- (uint8_t)(1U << (rec & (uint_fast8_t)7));
- }
- }
- /****************************************************************************/
- /**
- * @description
- * This function sets up the QS filter to disable the record type @p rec.
- * The argument @a #QS_ALL_RECORDS specifies to suppress all records.
- * This function should be called indirectly through the macro QS_FILTER_OFF.
- *
- * @note Filtering records based on the record-type is only the first layer of
- * filtering. The second layer is based on the object-type. Both filter
- * layers must be enabled for the QS record to be inserted into the QS buffer.
- */
- void QS_filterOff(uint_fast8_t rec) {
- if (rec == QS_ALL_RECORDS) {
- uint8_t *glbFilter = &QS_priv_.glbFilter[0];
- /* the following unrolled loop is designed to stop collecting trace
- * very fast in order to prevent overwriting the interesting data.
- * The code assumes that the dimension of QS_priv_.glbFilter[] is 16.
- */
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0; QS_PTR_INC_(glbFilter);
- *glbFilter = (uint8_t)0;
- }
- else {
- uint8_t tmp;
- /* record numbers can't exceed QS_ESC, so they don't need escaping */
- Q_ASSERT_ID(310, rec < (uint_fast8_t)QS_ESC);
- tmp = (uint8_t)(1U << (rec & (uint_fast8_t)0x07));
- tmp ^= (uint8_t)0xFFU; /* invert all bits */
- QS_priv_.glbFilter[rec >> 3] &= tmp;
- }
- }
- /****************************************************************************/
- /**
- * @description
- * This function must be called at the beginning of each QS record.
- * This function should be called indirectly through the macro #QS_BEGIN,
- * or #QS_BEGIN_NOCRIT, depending if it's called in a normal code or from
- * a critical section.
- */
- void QS_beginRec(uint_fast8_t rec) {
- uint8_t b = (uint8_t)(QS_priv_.seq + (uint8_t)1);
- uint8_t chksum = (uint8_t)0; /* reset the checksum */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.seq = b; /* store the incremented sequence num */
- QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
- QS_INSERT_ESC_BYTE(b)
- chksum = (uint8_t)(chksum + (uint8_t)rec); /* update checksum */
- QS_INSERT_BYTE((uint8_t)rec) /* rec byte does not need escaping */
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @description
- * This function must be called at the end of each QS record.
- * This function should be called indirectly through the macro #QS_END,
- * or #QS_END_NOCRIT, depending if it's called in a normal code or from
- * a critical section.
- */
- void QS_endRec(void) {
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head;
- QSCtr end = QS_priv_.end;
- uint8_t b = QS_priv_.chksum;
- b ^= (uint8_t)0xFFU; /* invert the bits in the checksum */
- QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
- if ((b != QS_FRAME) && (b != QS_ESC)) {
- QS_INSERT_BYTE(b)
- }
- else {
- QS_INSERT_BYTE(QS_ESC)
- QS_INSERT_BYTE(b ^ QS_ESC_XOR)
- ++QS_priv_.used; /* account for the ESC byte */
- }
- QS_INSERT_BYTE(QS_FRAME) /* do not escape this QS_FRAME */
- QS_priv_.head = head; /* save the head */
- /* overrun over the old data? */
- if (QS_priv_.used > end) {
- QS_priv_.used = end; /* the whole buffer is used */
- QS_priv_.tail = head; /* shift the tail to the old data */
- }
- }
- /****************************************************************************/
- /**
- * @description
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u8(uint8_t format, uint8_t d) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += (QSCtr)2; /* 2 bytes about to be added */
- QS_INSERT_ESC_BYTE(format)
- QS_INSERT_ESC_BYTE(d)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @description
- * This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u16(uint8_t format, uint16_t d) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += (QSCtr)3; /* 3 bytes about to be added */
- QS_INSERT_ESC_BYTE(format)
- format = (uint8_t)d;
- QS_INSERT_ESC_BYTE(format)
- d >>= 8;
- format = (uint8_t)d;
- QS_INSERT_ESC_BYTE(format)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u32(uint8_t format, uint32_t d) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- int_fast8_t i;
- QS_priv_.used += (QSCtr)5; /* 5 bytes about to be added */
- QS_INSERT_ESC_BYTE(format) /* insert the format byte */
- /* insert 4 bytes... */
- for (i = (int_fast8_t)4; i != (int_fast8_t)0; --i) {
- format = (uint8_t)d;
- QS_INSERT_ESC_BYTE(format)
- d >>= 8;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /*! output uint8_t data element without format information */
- /** @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u8_(uint8_t d) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- ++QS_priv_.used; /* 1 byte about to be added */
- QS_INSERT_ESC_BYTE(d)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /** @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u8u8_(uint8_t d1, uint8_t d2) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += (QSCtr)2; /* 2 bytes are about to be added */
- QS_INSERT_ESC_BYTE(d1)
- QS_INSERT_ESC_BYTE(d2)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u16_(uint16_t d) {
- uint8_t b = (uint8_t)d;
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += (QSCtr)2; /* 2 bytes are about to be added */
- QS_INSERT_ESC_BYTE(b)
- d >>= 8;
- b = (uint8_t)d;
- QS_INSERT_ESC_BYTE(b)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /** @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_u32_(uint32_t d) {
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- int_fast8_t i;
- QS_priv_.used += (QSCtr)4; /* 4 bytes are about to be added */
- for (i = (int_fast8_t)4; i != (int_fast8_t)0; --i) {
- uint8_t b = (uint8_t)d;
- QS_INSERT_ESC_BYTE(b)
- d >>= 8;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_str_(char_t const *s) {
- uint8_t b = (uint8_t)(*s);
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- while (b != (uint8_t)(0)) {
- chksum = (uint8_t)(chksum + b); /* update checksum */
- QS_INSERT_BYTE(b) /* ASCII characters don't need escaping */
- QS_PTR_INC_(s);
- b = (uint8_t)(*s);
- ++used;
- }
- QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
- ++used;
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */
- }
- /****************************************************************************/
- /**
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_str_ROM_(char_t const Q_ROM *s) {
- uint8_t b = (uint8_t)Q_ROM_BYTE(*s);
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- while (b != (uint8_t)(0)) {
- chksum = (uint8_t)(chksum + b); /* update checksum */
- QS_INSERT_BYTE(b) /* ASCII characters don't need escaping */
- QS_PTR_INC_(s);
- b = (uint8_t)Q_ROM_BYTE(*s);
- ++used;
- }
- QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
- ++used;
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */
- }
- /****************************************************************************/
- /**
- * @description
- * This function delivers one byte at a time from the QS data buffer.
- *
- * @returns the byte in the least-significant 8-bits of the 16-bit return
- * value if the byte is available. If no more data is available at the time,
- * the function returns ::QS_EOD (End-Of-Data).
- *
- * @note QS_getByte() is __not__ protected with a critical section.
- */
- uint16_t QS_getByte(void) {
- uint16_t ret;
- if (QS_priv_.used == (QSCtr)0) {
- ret = QS_EOD; /* set End-Of-Data */
- }
- else {
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
- ret = (uint16_t)(*QS_PTR_AT_(tail)); /* set the byte to return */
- ++tail; /* advance the tail */
- if (tail == QS_priv_.end) { /* tail wrap around? */
- tail = (QSCtr)0;
- }
- QS_priv_.tail = tail; /* update the tail */
- --QS_priv_.used; /* one less byte used */
- }
- return ret; /* return the byte or EOD */
- }
- /****************************************************************************/
- /**
- * @description
- * This function delivers a contiguous block of data from the QS data buffer.
- * The function returns the pointer to the beginning of the block, and writes
- * the number of bytes in the block to the location pointed to by @p pNbytes.
- * The parameter @p pNbytes is also used as input to provide the maximum size
- * of the data block that the caller can accept.
- *
- * @returns if data is available, the function returns pointer to the
- * contiguous block of data and sets the value pointed to by @p pNbytes
- * to the # available bytes. If data is available at the time the function is
- * called, the function returns NULL pointer and sets the value pointed to by
- * @p pNbytes to zero.
- *
- * @note Only the NULL return from QS_getBlock() indicates that the QS buffer
- * is empty at the time of the call. The non-NULL return often means that
- * the block is at the end of the buffer and you need to call QS_getBlock()
- * again to obtain the rest of the data that "wrapped around" to the
- * beginning of the QS data buffer.
- *
- * @note QS_getBlock() is NOT protected with a critical section.
- */
- uint8_t const *QS_getBlock(uint16_t *pNbytes) {
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- uint8_t *buf;
- /* any bytes used in the ring buffer? */
- if (used != (QSCtr)0) {
- QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr n = (QSCtr)(end - tail);
- if (n > used) {
- n = used;
- }
- if (n > (QSCtr)(*pNbytes)) {
- n = (QSCtr)(*pNbytes);
- }
- *pNbytes = (uint16_t)n; /* n-bytes available */
- buf = QS_priv_.buf;
- buf = QS_PTR_AT_(tail); /* the bytes are at the tail */
- QS_priv_.used = (QSCtr)(used - n);
- tail += n;
- if (tail == end) {
- tail = (QSCtr)0;
- }
- QS_priv_.tail = tail;
- }
- else { /* no bytes available */
- *pNbytes = (uint16_t)0; /* no bytes available right now */
- buf = (uint8_t *)0; /* no bytes available right now */
- }
- return buf;
- }
- /****************************************************************************/
- /** @note This function is only to be used through macro QS_SIG_DICTIONARY()
- */
- void QS_sig_dict(enum_t const sig, void const * const obj,
- char_t const Q_ROM * const name)
- {
- QS_CRIT_STAT_
- QS_CRIT_ENTRY_();
- QS_beginRec((uint_fast8_t)QS_SIG_DICT);
- QS_SIG_((QSignal)sig);
- QS_OBJ_(obj);
- QS_STR_ROM_(name);
- QS_endRec();
- QS_CRIT_EXIT_();
- QS_onFlush();
- }
- /****************************************************************************/
- /** @note This function is only to be used through macro QS_OBJ_DICTIONARY()
- */
- void QS_obj_dict(void const * const obj,
- char_t const Q_ROM * const name)
- {
- QS_CRIT_STAT_
- QS_CRIT_ENTRY_();
- QS_beginRec((uint_fast8_t)QS_OBJ_DICT);
- QS_OBJ_(obj);
- QS_STR_ROM_(name);
- QS_endRec();
- QS_CRIT_EXIT_();
- QS_onFlush();
- }
- /****************************************************************************/
- /** @note This function is only to be used through macro QS_FUN_DICTIONARY()
- */
- void QS_fun_dict(void (* const fun)(void),
- char_t const Q_ROM * const name)
- {
- QS_CRIT_STAT_
- QS_CRIT_ENTRY_();
- QS_beginRec((uint_fast8_t)QS_FUN_DICT);
- QS_FUN_(fun);
- QS_STR_ROM_(name);
- QS_endRec();
- QS_CRIT_EXIT_();
- QS_onFlush();
- }
- /****************************************************************************/
- /** @note This function is only to be used through macro QS_USR_DICTIONARY()
- */
- void QS_usr_dict(enum_t const rec,
- char_t const Q_ROM * const name)
- {
- QS_CRIT_STAT_
- QS_CRIT_ENTRY_();
- QS_beginRec((uint_fast8_t)QS_USR_DICT);
- QS_U8_((uint8_t)rec);
- QS_STR_ROM_(name);
- QS_endRec();
- QS_CRIT_EXIT_();
- QS_onFlush();
- }
- /****************************************************************************/
- /** @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_mem(uint8_t const *blk, uint8_t size) {
- uint8_t b = (uint8_t)(QS_MEM_T);
- uint8_t chksum = (uint8_t)(QS_priv_.chksum + b);
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += ((QSCtr)size + (QSCtr)2); /* size+2 bytes to be added */
- QS_INSERT_BYTE(b)
- QS_INSERT_ESC_BYTE(size)
- /* output the 'size' number of bytes */
- while (size != (uint8_t)0) {
- b = *blk;
- QS_INSERT_ESC_BYTE(b)
- QS_PTR_INC_(blk);
- --size;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- }
- /****************************************************************************/
- /**
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_str(char_t const *s) {
- uint8_t b = (uint8_t)(*s);
- uint8_t chksum = (uint8_t)(QS_priv_.chksum + (uint8_t)QS_STR_T);
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- used += (QSCtr)2; /* account for the format byte and the terminating-0 */
- QS_INSERT_BYTE((uint8_t)QS_STR_T)
- while (b != (uint8_t)(0)) {
- /* ASCII characters don't need escaping */
- chksum = (uint8_t)(chksum + b); /* update checksum */
- QS_INSERT_BYTE(b)
- QS_PTR_INC_(s);
- b = (uint8_t)(*s);
- ++used;
- }
- QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */
- }
- /****************************************************************************/
- /** @note This function is only to be used through macros, never in the
- * client code directly.
- */
- void QS_str_ROM(char_t const Q_ROM *s) {
- uint8_t b = (uint8_t)Q_ROM_BYTE(*s);
- uint8_t chksum = (uint8_t)(QS_priv_.chksum + (uint8_t)QS_STR_T);
- uint8_t *buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- used += (QSCtr)2; /* account for the format byte and the terminating-0 */
- QS_INSERT_BYTE((uint8_t)QS_STR_T)
- while (b != (uint8_t)(0)) {
- /* ASCII characters don't need escaping */
- chksum = (uint8_t)(chksum + b); /* update checksum */
- QS_INSERT_BYTE(b)
- QS_PTR_INC_(s);
- b = (uint8_t)Q_ROM_BYTE(*s);
- ++used;
- }
- QS_INSERT_BYTE((uint8_t)0) /* zero-terminate the string */
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */
- }
|