| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- //! \file triceDoubleBuffer.c
- //! \author Thomas.Hoehenleitner [at] seerose.net
- //! //////////////////////////////////////////////////////////////////////////
- #include "cobs.h"
- #include "tcobs.h"
- #include "trice.h"
-
- #if TRICE_BUFFER == TRICE_DOUBLE_BUFFER && TRICE_OFF == 0
-
- static void TriceOut(uint32_t *tb, size_t tLen);
-
- //! triceBuffer is a double buffer for better write speed.
- //! halfBufferStart writePosition
- //! ^-TRICE_DATA_OFFSET-^-restOf_TRICE_DEFERRED_BUFFER_SIZE-^-2ndBuf...
- //! ^-TRICE_DATA_OFFSET-^-restOf_TRICE_DEFERRED_BUFFER_SIZE-Limit
- static uint32_t triceBuffer[2][TRICE_DEFERRED_BUFFER_SIZE >> 3] = {0};
-
- #define TRICE_WRITE_START_HALF_BUFFER_0 (&triceBuffer[0][TRICE_DATA_OFFSET >> 2])
- #define TRICE_WRITE_LIMIT_HALF_BUFFER_0 (&triceBuffer[0][TRICE_DEFERRED_BUFFER_SIZE >> 3])
- #define TRICE_WRITE_START_HALF_BUFFER_1 (&triceBuffer[1][TRICE_DATA_OFFSET >> 2])
- #define TRICE_WRITE_LIMIT_HALF_BUFFER_1 (&triceBuffer[1][TRICE_DEFERRED_BUFFER_SIZE >> 3])
-
- static uint32_t *const triceWriteStartHalfBuffer0 = TRICE_WRITE_START_HALF_BUFFER_0;
- static uint32_t *const triceWriteStartHalfBuffer1 = TRICE_WRITE_START_HALF_BUFFER_1;
- #if TRICE_PROTECT == 1
- static uint32_t *const triceWriteLimitHalfBuffer0 = TRICE_WRITE_LIMIT_HALF_BUFFER_0;
- static uint32_t *const triceWriteLimitHalfBuffer1 = TRICE_WRITE_LIMIT_HALF_BUFFER_1;
- #endif
-
- //! triceActiveHalfBuffer is the index of the active write buffer. !triceActiveHalfBuffer is the active read buffer index.
- static int triceActiveHalfBuffer = 0;
-
- //! TriceBufferWritePosition is the active write position and is used by TRICE_PUT macros.
- uint32_t *TriceBufferWritePosition = TRICE_WRITE_START_HALF_BUFFER_0; // triceWriteStartHalfBuffer0;
-
- //! TriceBufferWritePositionStart is the begin of the active write buffer.
- uint32_t *TriceBufferWritePositionStart = TRICE_WRITE_START_HALF_BUFFER_0; // triceWriteStartHalfBuffer0;
-
- #if TRICE_PROTECT == 1
- //! TriceBufferWritePositionLimit is the first not usable address of the current written half buffer.
- static uint32_t *TriceBufferWritePositionLimit = TRICE_WRITE_LIMIT_HALF_BUFFER_0; // triceWriteLimitHalfBuffer0;
-
- //! TriceEnoughSpace checks, if at least TRICE_SINGLE_MAX_SIZE bytes available for the next trice.
- //! \retval 0, when not enough space
- //! \retval 1, when enough space
- int TriceEnoughSpace(void)
- {
- // space32 is the writable 32-bit value count in the current write buffer.
- int space32 = TriceBufferWritePositionLimit - TriceBufferWritePosition;
- // there need to be at least TRICE_SINGLE_MAX_SIZE bytes space in the current write buffer.
- if (space32 >= (TRICE_SINGLE_MAX_SIZE >> 2))
- {
- return 1;
- }
- else
- {
- #if TRICE_DIAGNOSTICS == 1
- TriceDeferredOverflowCount++;
- #endif
- return 0;
- }
- }
-
- #endif // #if TRICE_PROTECT == 1
-
- //! triceBufferSwap swaps the trice double buffer and returns the read buffer address.
- static uint32_t *triceBufferSwap(void)
- {
- if (triceActiveHalfBuffer == 0)
- {
- triceActiveHalfBuffer = 1;
- TriceBufferWritePositionStart = triceWriteStartHalfBuffer1;
- TriceBufferWritePosition = TriceBufferWritePositionStart;
- #if TRICE_PROTECT == 1
- TriceBufferWritePositionLimit = triceWriteLimitHalfBuffer1;
- #endif
- return triceWriteStartHalfBuffer0;
- }
- else
- {
- triceActiveHalfBuffer = 0;
- TriceBufferWritePositionStart = triceWriteStartHalfBuffer0;
- TriceBufferWritePosition = TriceBufferWritePositionStart;
- #if TRICE_PROTECT == 1
- TriceBufferWritePositionLimit = triceWriteLimitHalfBuffer0;
- #endif
- return triceWriteStartHalfBuffer1;
- }
- }
-
- #if TRICE_DIAGNOSTICS == 1
- //! TriceHalfBufferDepthMax is a diagnostics value usable to optimize buffer size.
- unsigned TriceHalfBufferDepthMax = 0;
- #endif
-
- //! TriceTransfer, if possible, swaps the double buffer and initiates a write.
- //! It is the responsibility of the app to call this function once every 10-100 milliseconds.
- void TriceTransfer(void)
- {
- if (0 == TriceOutDepth()) // transmission done for slowest output channel, so a swap is possible.
- {
- uint32_t *readBuf;
- size_t tLen32;
- TRICE_ENTER_CRITICAL_SECTION
- tLen32 = TriceBufferWritePosition - TriceBufferWritePositionStart;
- if (tLen32) // Some Trice data are available.
- {
- readBuf = triceBufferSwap();
- readBuf -= (TRICE_DATA_OFFSET >> 2);
- }
- TRICE_LEAVE_CRITICAL_SECTION
- if (tLen32)
- {
- TriceOut(readBuf, tLen32 << 2);
- }
- }
- }
-
- //! TriceNext expects at *buf 32-bit aligned trice messages and returns the next one in pStart and pLen.
- //! \todo: use this function only when MULTI
- //! \param buf points to 32-bit aligned trice messages and is filled with the advanced buf.
- //! \param pSize contains the total size of all following trices including padding bytes to 32-bit alignments and gets the by next trice reduced value.
- //! \param pStart points to the net start of the next trice.
- //! \param pLen contains the net length of the first trice.
- //! \retval is the trice ID on success or negative on error.
- //! The trices inside the double buffer start 32-bit aligned with maybe 1-3 padding bytes in-between.
- //! \li | ... | trice | trice | ... | trice |
- //! \li before: ^- buf
- //! \li before: <-------------- pSize -------------->
- //! \li after: ^- buf
- //! \li after: <-------- pSize ------>
- //! \li after: ^- pStart (is input buf or input buf + 2)
- //! \li after: <- pLen -> (maybe 1-3 bytes shorter)
- static int TriceNext(uint8_t **buf, size_t *pSize, const uint8_t **pStart, size_t *pLen)
- {
- uint16_t *pTID = (uint16_t *)*buf; // lint !e826, get TID address
- unsigned TID = TRICE_TTOHS(*pTID); // type and id
- int triceID = 0x3FFF & TID;
- int triceType = TID >> 14;
- unsigned offset;
- size_t size = *pSize;
- size_t triceSize;
- size_t len;
- switch (triceType)
- {
- case TRICE_TYPE_S0: // S0 = no stamp
- *pStart = *buf;
- offset = 0;
- len = 4 + triceDataLen(*pStart + 2); // tyId
- break;
- case TRICE_TYPE_S2: // S2 = 16-bit stamp
- *pStart = *buf; // see Id(n) macro definition
- *pStart += 2; // see Id(n) macro definition
- offset = 2;
- len = 6 + triceDataLen(*pStart + 4); // tyId ts16
- break;
- case TRICE_TYPE_S4: // S4 = 32-bit stamp
- *pStart = *buf;
- offset = 0;
- len = 8 + triceDataLen(*pStart + 6); // tyId ts32
- break;
- default: // impossible
- // fallthrugh
- case TRICE_TYPE_X0:
- TriceErrorCount++;
- *pStart = 0;
- *pLen = 0;
- return -__LINE__; // extended trices not supported (yet)
- }
- triceSize = (len + offset + 3) & ~3;
- // S16 case example: triceSize len t-0-3 t-o
- // 80id 80id 1616 00cc 8 6 3 6
- // 80id 80id 1616 01cc dd 12 7 7 10
- // 80id 80id 1616 02cc dd dd 12 8 7 10
- // 80id 80id 1616 03cc dd dd dd 12 9 7 10
- // 80id 80id 1616 04cc dd dd dd dd 12 10 7 10
- if (!(triceSize - (offset + 3) <= len && len <= triceSize - offset)) // corrupt data
- {
- TriceErrorCount++;
- return -__LINE__;
- }
- size -= triceSize;
- *buf += triceSize;
- *pSize = size;
- *pLen = len;
- return triceID;
- }
-
- uint8_t *firstNotModifiedAddress;
- int distance;
- int triceDataOffsetDepth;
-
- //! TriceOut encodes trices and writes them in one step to the output.
- //! This function is called only, when the slowest deferred output device has finished its last buffer.
- //! At the half buffer start tb are TRICE_DATA_OFFSET bytes space followed by a number of trice messages which all contain
- //! 0-3 padding bytes and therefore have a length of a multiple of 4. There is no additional space between these trice messages.
- //! When XTEA enabled, only (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE) is allowed, because the 4 bytes behind a trice messages
- //! are changed, when the trice length is not a multiple of 8, but only of 4. (XTEA can encrypt only multiple of 8 length packages.)
- //! \param tb is start of uint32_t* trice buffer. The space TRICE_DATA_OFFSET at the tb start is for in-buffer encoding of the trice data.
- //! \param tLen is total length of several trice data. It is always a multiple of 4 because of 32-bit alignment and padding bytes.
- static void TriceOut(uint32_t *tb, size_t tLen)
- {
- uint8_t *enc = (uint8_t *)tb; // This is the later encoded data starting address.
- uint8_t *dat = enc + TRICE_DATA_OFFSET; // This is the start of 32-bit aligned trices.
- uint8_t *nxt = dat; // This is the start of next 32-bit aligned trices.
- size_t encLen = 0;
- #if (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE) && ((TRICE_PROTECT == 1) || (TRICE_DIAGNOSTICS == 1))
- uint8_t *dst = enc; // This value dst must not get > nxt to avoid overwrites.
- #endif
- int triceID = 0; // This assignment is only needed to silence compiler complains about being uninitialized.
- #if TRICE_DIAGNOSTICS == 1
- unsigned depth = tLen + TRICE_DATA_OFFSET;
- TriceHalfBufferDepthMax = depth < TriceHalfBufferDepthMax ? TriceHalfBufferDepthMax : depth;
- #endif
- // do it
- while (tLen)
- {
- #if TRICE_DIAGNOSTICS == 1
- firstNotModifiedAddress = enc + encLen;
- distance = nxt - firstNotModifiedAddress;
- triceDataOffsetDepth = TRICE_DATA_OFFSET - distance; // distance can get > TRICE_DATA_OFFSET, but that is no problem.
- TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
- #endif // #if TRICE_DIAGNOSTICS == 1
- const uint8_t *triceNettoStart;
- size_t triceNettoLen; // This is the trice netto length (without padding bytes).
- #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING != TRICE_FRAMING_NONE) && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_SINGLE_PACK_MODE)
- uint8_t *crypt = nxt - 4; // only 8-byte groups are encryptable
- #endif
- triceID = TriceNext(&nxt, &tLen, &triceNettoStart, &triceNettoLen);
- if (triceID <= 0) // on data error
- {
- TriceErrorCount++;
- break; // ignore following data
- }
- #if TRICE_DEFERRED_TRANSFER_MODE == TRICE_SINGLE_PACK_MODE
- uint8_t *dst = enc + encLen;
- #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS)
- memmove(crypt, triceNettoStart, triceNettoLen);
- size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
- memset((crypt)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
- XTEAEncrypt((uint32_t *)crypt, len8 >> 2);
- encLen += (size_t)TCOBSEncode(dst, crypt, len8); // encLen is re-used here
- dst[encLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS)
- memmove(crypt, triceNettoStart, triceNettoLen);
- size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
- memset((crypt)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
- XTEAEncrypt((uint32_t *)crypt, len8 >> 2);
- encLen += (size_t)COBSEncode(dst, crypt, len8); // encLen is re-used here
- dst[encLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE)
- #if TRICE_CONFIG_WARNINGS == 1
- #error configuration: The Trice tool does not support encryted data without COBS or TCOBS framing.
- #endif
- // memmove(dst, triceNettoStart, triceNettoLen );
- // size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
- // memset((enc)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
- // XTEAEncrypt( (uint32_t *)enc, len8>>2 );
- // encLen += len8; // encLen is re-used here
- // nextPosForEncoding = dst+encLen;
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS)
- size_t len = (size_t)TCOBSEncode(dst, triceNettoStart, triceNettoLen);
- dst[len++] = 0; // Add zero as package delimiter.
- encLen += len;
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS)
- size_t len = (size_t)COBSEncode(dst, triceNettoStart, triceNettoLen);
- dst[len++] = 0; // Add zero as package delimiter.
- encLen += len;
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE)
- memmove(dst, triceNettoStart, triceNettoLen);
- encLen += triceNettoLen;
- #else
- #error configuration: unexpected
- #endif
- #elif TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
- // pack data
- uint8_t *packed = dat + encLen; // After the loop, the packed data start at dat.
- memmove(packed, triceNettoStart, triceNettoLen); // This action removes all padding bytes of the trices, compacting their sequence this way
- encLen += triceNettoLen;
- #endif // #elif TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
- #if (TRICE_PROTECT == 1) || (TRICE_DIAGNOSTICS == 1)
- dst = enc + encLen; // When several Trices in the double buffer, with each encoding the new dst could drift a bit closer towards triceNettoStart.
- int triceDataOffsetSpaceRemained = nxt - dst; // THe begin of unprocessed data MINUS next dst must not be negative.
- #endif
- #if (TRICE_PROTECT == 1)
- if (triceDataOffsetSpaceRemained < 0)
- {
- TriceErrorCount++;
- return; // discard broken data to avoid buffer overflow
- }
- #endif
- #if TRICE_DIAGNOSTICS == 1
- int triceDataOffsetDepth = TRICE_DATA_OFFSET - triceDataOffsetSpaceRemained;
- TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
- #endif
- }
- #if TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
- // At this point the compacted trice messages start TRICE_DATA_OFFSET bytes after tb (now dat) and the encLen is their total netto length.
- // Behind this up to 7 bytes can be used as scratch pad when XTEA is active. That is ok, because the half buffer should not get totally filled.
- // encLen = TriceEncode( TRICE_DEFERRED_XTEA_ENCRYPT, TRICE_DEFERRED_OUT_FRAMING, enc, dat, encLen );
- #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- // special case: The data are at dat and can be big, are compacted and behind them is space. So we can encrypt them in space
- size_t len8 = (encLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
- memset(((uint8_t *)dat) + encLen, 0, len8 - encLen); // clear padding space: ATTENTION! OK only for this compiler switch setting.
- XTEAEncrypt((uint32_t *)dat, len8 >> 2);
- size_t eLen = (size_t)TCOBSEncode(enc, dat, len8); // encLen is re-used here
- enc[eLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- // special case: The data are at dat and can be big, are compacted and behind them is space. So we can encrypt them in space
- size_t len8 = (encLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
- memset(((uint8_t *)dat) + encLen, 0, len8 - encLen); // clear padding space: ATTENTION! OK only for this compiler switch setting.
- XTEAEncrypt((uint32_t *)dat, len8 >> 2);
- size_t eLen = (size_t)COBSEncode(enc, dat, len8); // encLen is re-used here
- enc[eLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- size_t eLen = TriceEncode(TRICE_DEFERRED_XTEA_ENCRYPT, TRICE_DEFERRED_OUT_FRAMING, enc, dat, encLen);
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- size_t eLen = TCOBSEncode(enc, dat, encLen);
- enc[eLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- size_t eLen = (size_t)COBSEncode(enc, dat, encLen);
- enc[eLen++] = 0; // Add zero as package delimiter.
- #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
- enc = dat;
- size_t eLen = encLen;
- #else
- #error configuration:
- #endif
- #if TRICE_DIAGNOSTICS
- // before: space = enc[TRICE_DATA_OFFSET], data = dat[encLen]
- // after: date = enc[eLen], (dat [encLen])
- // Mostly eLen < encLen, but it could be eLen = encLen + 1 + (encLen>>5) in TCOBS worst case.
- // dat - enc = TRICE_DATA_OFFSET
- // if eLen > encLen, then TriceDataOffsetDepth = eLen - encLen
- int triceDataOffsetDepth = eLen - encLen; // usually negative
- TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
- #endif
- encLen = eLen;
- #endif
-
- // Reaching here means all trice data in the current half buffer are encoded
- // into a single continuous buffer having 0-delimiters between them or not but at the ent is a 0-delimiter.
- //
- // output
- TRICE_ENTER_CRITICAL_SECTION
- TriceNonBlockingDeferredWrite8(triceID, enc, encLen); // lint !e771 Info 771: Symbol 'triceID' conceivably not initialized. Comment: tLen is always > 0.
- TRICE_LEAVE_CRITICAL_SECTION
- }
-
- #endif // #if TRICE_BUFFER == TRICE_DOUBLE_BUFFER && TRICE_OFF == 0
|