Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. //! \file triceDoubleBuffer.c
  2. //! \author Thomas.Hoehenleitner [at] seerose.net
  3. //! //////////////////////////////////////////////////////////////////////////
  4. #include "cobs.h"
  5. #include "tcobs.h"
  6. #include "trice.h"
  7. #if TRICE_BUFFER == TRICE_DOUBLE_BUFFER && TRICE_OFF == 0
  8. static void TriceOut(uint32_t *tb, size_t tLen);
  9. //! triceBuffer is a double buffer for better write speed.
  10. //! halfBufferStart writePosition
  11. //! ^-TRICE_DATA_OFFSET-^-restOf_TRICE_DEFERRED_BUFFER_SIZE-^-2ndBuf...
  12. //! ^-TRICE_DATA_OFFSET-^-restOf_TRICE_DEFERRED_BUFFER_SIZE-Limit
  13. static uint32_t triceBuffer[2][TRICE_DEFERRED_BUFFER_SIZE >> 3] = {0};
  14. #define TRICE_WRITE_START_HALF_BUFFER_0 (&triceBuffer[0][TRICE_DATA_OFFSET >> 2])
  15. #define TRICE_WRITE_LIMIT_HALF_BUFFER_0 (&triceBuffer[0][TRICE_DEFERRED_BUFFER_SIZE >> 3])
  16. #define TRICE_WRITE_START_HALF_BUFFER_1 (&triceBuffer[1][TRICE_DATA_OFFSET >> 2])
  17. #define TRICE_WRITE_LIMIT_HALF_BUFFER_1 (&triceBuffer[1][TRICE_DEFERRED_BUFFER_SIZE >> 3])
  18. static uint32_t *const triceWriteStartHalfBuffer0 = TRICE_WRITE_START_HALF_BUFFER_0;
  19. static uint32_t *const triceWriteStartHalfBuffer1 = TRICE_WRITE_START_HALF_BUFFER_1;
  20. #if TRICE_PROTECT == 1
  21. static uint32_t *const triceWriteLimitHalfBuffer0 = TRICE_WRITE_LIMIT_HALF_BUFFER_0;
  22. static uint32_t *const triceWriteLimitHalfBuffer1 = TRICE_WRITE_LIMIT_HALF_BUFFER_1;
  23. #endif
  24. //! triceActiveHalfBuffer is the index of the active write buffer. !triceActiveHalfBuffer is the active read buffer index.
  25. static int triceActiveHalfBuffer = 0;
  26. //! TriceBufferWritePosition is the active write position and is used by TRICE_PUT macros.
  27. uint32_t *TriceBufferWritePosition = TRICE_WRITE_START_HALF_BUFFER_0; // triceWriteStartHalfBuffer0;
  28. //! TriceBufferWritePositionStart is the begin of the active write buffer.
  29. uint32_t *TriceBufferWritePositionStart = TRICE_WRITE_START_HALF_BUFFER_0; // triceWriteStartHalfBuffer0;
  30. #if TRICE_PROTECT == 1
  31. //! TriceBufferWritePositionLimit is the first not usable address of the current written half buffer.
  32. static uint32_t *TriceBufferWritePositionLimit = TRICE_WRITE_LIMIT_HALF_BUFFER_0; // triceWriteLimitHalfBuffer0;
  33. //! TriceEnoughSpace checks, if at least TRICE_SINGLE_MAX_SIZE bytes available for the next trice.
  34. //! \retval 0, when not enough space
  35. //! \retval 1, when enough space
  36. int TriceEnoughSpace(void)
  37. {
  38. // space32 is the writable 32-bit value count in the current write buffer.
  39. int space32 = TriceBufferWritePositionLimit - TriceBufferWritePosition;
  40. // there need to be at least TRICE_SINGLE_MAX_SIZE bytes space in the current write buffer.
  41. if (space32 >= (TRICE_SINGLE_MAX_SIZE >> 2))
  42. {
  43. return 1;
  44. }
  45. else
  46. {
  47. #if TRICE_DIAGNOSTICS == 1
  48. TriceDeferredOverflowCount++;
  49. #endif
  50. return 0;
  51. }
  52. }
  53. #endif // #if TRICE_PROTECT == 1
  54. //! triceBufferSwap swaps the trice double buffer and returns the read buffer address.
  55. static uint32_t *triceBufferSwap(void)
  56. {
  57. if (triceActiveHalfBuffer == 0)
  58. {
  59. triceActiveHalfBuffer = 1;
  60. TriceBufferWritePositionStart = triceWriteStartHalfBuffer1;
  61. TriceBufferWritePosition = TriceBufferWritePositionStart;
  62. #if TRICE_PROTECT == 1
  63. TriceBufferWritePositionLimit = triceWriteLimitHalfBuffer1;
  64. #endif
  65. return triceWriteStartHalfBuffer0;
  66. }
  67. else
  68. {
  69. triceActiveHalfBuffer = 0;
  70. TriceBufferWritePositionStart = triceWriteStartHalfBuffer0;
  71. TriceBufferWritePosition = TriceBufferWritePositionStart;
  72. #if TRICE_PROTECT == 1
  73. TriceBufferWritePositionLimit = triceWriteLimitHalfBuffer0;
  74. #endif
  75. return triceWriteStartHalfBuffer1;
  76. }
  77. }
  78. #if TRICE_DIAGNOSTICS == 1
  79. //! TriceHalfBufferDepthMax is a diagnostics value usable to optimize buffer size.
  80. unsigned TriceHalfBufferDepthMax = 0;
  81. #endif
  82. //! TriceTransfer, if possible, swaps the double buffer and initiates a write.
  83. //! It is the responsibility of the app to call this function once every 10-100 milliseconds.
  84. void TriceTransfer(void)
  85. {
  86. if (0 == TriceOutDepth()) // transmission done for slowest output channel, so a swap is possible.
  87. {
  88. uint32_t *readBuf;
  89. size_t tLen32;
  90. TRICE_ENTER_CRITICAL_SECTION
  91. tLen32 = TriceBufferWritePosition - TriceBufferWritePositionStart;
  92. if (tLen32) // Some Trice data are available.
  93. {
  94. readBuf = triceBufferSwap();
  95. readBuf -= (TRICE_DATA_OFFSET >> 2);
  96. }
  97. TRICE_LEAVE_CRITICAL_SECTION
  98. if (tLen32)
  99. {
  100. TriceOut(readBuf, tLen32 << 2);
  101. }
  102. }
  103. }
  104. //! TriceNext expects at *buf 32-bit aligned trice messages and returns the next one in pStart and pLen.
  105. //! \todo: use this function only when MULTI
  106. //! \param buf points to 32-bit aligned trice messages and is filled with the advanced buf.
  107. //! \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.
  108. //! \param pStart points to the net start of the next trice.
  109. //! \param pLen contains the net length of the first trice.
  110. //! \retval is the trice ID on success or negative on error.
  111. //! The trices inside the double buffer start 32-bit aligned with maybe 1-3 padding bytes in-between.
  112. //! \li | ... | trice | trice | ... | trice |
  113. //! \li before: ^- buf
  114. //! \li before: <-------------- pSize -------------->
  115. //! \li after: ^- buf
  116. //! \li after: <-------- pSize ------>
  117. //! \li after: ^- pStart (is input buf or input buf + 2)
  118. //! \li after: <- pLen -> (maybe 1-3 bytes shorter)
  119. static int TriceNext(uint8_t **buf, size_t *pSize, const uint8_t **pStart, size_t *pLen)
  120. {
  121. uint16_t *pTID = (uint16_t *)*buf; // lint !e826, get TID address
  122. unsigned TID = TRICE_TTOHS(*pTID); // type and id
  123. int triceID = 0x3FFF & TID;
  124. int triceType = TID >> 14;
  125. unsigned offset;
  126. size_t size = *pSize;
  127. size_t triceSize;
  128. size_t len;
  129. switch (triceType)
  130. {
  131. case TRICE_TYPE_S0: // S0 = no stamp
  132. *pStart = *buf;
  133. offset = 0;
  134. len = 4 + triceDataLen(*pStart + 2); // tyId
  135. break;
  136. case TRICE_TYPE_S2: // S2 = 16-bit stamp
  137. *pStart = *buf; // see Id(n) macro definition
  138. *pStart += 2; // see Id(n) macro definition
  139. offset = 2;
  140. len = 6 + triceDataLen(*pStart + 4); // tyId ts16
  141. break;
  142. case TRICE_TYPE_S4: // S4 = 32-bit stamp
  143. *pStart = *buf;
  144. offset = 0;
  145. len = 8 + triceDataLen(*pStart + 6); // tyId ts32
  146. break;
  147. default: // impossible
  148. // fallthrugh
  149. case TRICE_TYPE_X0:
  150. TriceErrorCount++;
  151. *pStart = 0;
  152. *pLen = 0;
  153. return -__LINE__; // extended trices not supported (yet)
  154. }
  155. triceSize = (len + offset + 3) & ~3;
  156. // S16 case example: triceSize len t-0-3 t-o
  157. // 80id 80id 1616 00cc 8 6 3 6
  158. // 80id 80id 1616 01cc dd 12 7 7 10
  159. // 80id 80id 1616 02cc dd dd 12 8 7 10
  160. // 80id 80id 1616 03cc dd dd dd 12 9 7 10
  161. // 80id 80id 1616 04cc dd dd dd dd 12 10 7 10
  162. if (!(triceSize - (offset + 3) <= len && len <= triceSize - offset)) // corrupt data
  163. {
  164. TriceErrorCount++;
  165. return -__LINE__;
  166. }
  167. size -= triceSize;
  168. *buf += triceSize;
  169. *pSize = size;
  170. *pLen = len;
  171. return triceID;
  172. }
  173. uint8_t *firstNotModifiedAddress;
  174. int distance;
  175. int triceDataOffsetDepth;
  176. //! TriceOut encodes trices and writes them in one step to the output.
  177. //! This function is called only, when the slowest deferred output device has finished its last buffer.
  178. //! At the half buffer start tb are TRICE_DATA_OFFSET bytes space followed by a number of trice messages which all contain
  179. //! 0-3 padding bytes and therefore have a length of a multiple of 4. There is no additional space between these trice messages.
  180. //! When XTEA enabled, only (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE) is allowed, because the 4 bytes behind a trice messages
  181. //! 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.)
  182. //! \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.
  183. //! \param tLen is total length of several trice data. It is always a multiple of 4 because of 32-bit alignment and padding bytes.
  184. static void TriceOut(uint32_t *tb, size_t tLen)
  185. {
  186. uint8_t *enc = (uint8_t *)tb; // This is the later encoded data starting address.
  187. uint8_t *dat = enc + TRICE_DATA_OFFSET; // This is the start of 32-bit aligned trices.
  188. uint8_t *nxt = dat; // This is the start of next 32-bit aligned trices.
  189. size_t encLen = 0;
  190. #if (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE) && ((TRICE_PROTECT == 1) || (TRICE_DIAGNOSTICS == 1))
  191. uint8_t *dst = enc; // This value dst must not get > nxt to avoid overwrites.
  192. #endif
  193. int triceID = 0; // This assignment is only needed to silence compiler complains about being uninitialized.
  194. #if TRICE_DIAGNOSTICS == 1
  195. unsigned depth = tLen + TRICE_DATA_OFFSET;
  196. TriceHalfBufferDepthMax = depth < TriceHalfBufferDepthMax ? TriceHalfBufferDepthMax : depth;
  197. #endif
  198. // do it
  199. while (tLen)
  200. {
  201. #if TRICE_DIAGNOSTICS == 1
  202. firstNotModifiedAddress = enc + encLen;
  203. distance = nxt - firstNotModifiedAddress;
  204. triceDataOffsetDepth = TRICE_DATA_OFFSET - distance; // distance can get > TRICE_DATA_OFFSET, but that is no problem.
  205. TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
  206. #endif // #if TRICE_DIAGNOSTICS == 1
  207. const uint8_t *triceNettoStart;
  208. size_t triceNettoLen; // This is the trice netto length (without padding bytes).
  209. #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING != TRICE_FRAMING_NONE) && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_SINGLE_PACK_MODE)
  210. uint8_t *crypt = nxt - 4; // only 8-byte groups are encryptable
  211. #endif
  212. triceID = TriceNext(&nxt, &tLen, &triceNettoStart, &triceNettoLen);
  213. if (triceID <= 0) // on data error
  214. {
  215. TriceErrorCount++;
  216. break; // ignore following data
  217. }
  218. #if TRICE_DEFERRED_TRANSFER_MODE == TRICE_SINGLE_PACK_MODE
  219. uint8_t *dst = enc + encLen;
  220. #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS)
  221. memmove(crypt, triceNettoStart, triceNettoLen);
  222. size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
  223. memset((crypt)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
  224. XTEAEncrypt((uint32_t *)crypt, len8 >> 2);
  225. encLen += (size_t)TCOBSEncode(dst, crypt, len8); // encLen is re-used here
  226. dst[encLen++] = 0; // Add zero as package delimiter.
  227. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS)
  228. memmove(crypt, triceNettoStart, triceNettoLen);
  229. size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
  230. memset((crypt)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
  231. XTEAEncrypt((uint32_t *)crypt, len8 >> 2);
  232. encLen += (size_t)COBSEncode(dst, crypt, len8); // encLen is re-used here
  233. dst[encLen++] = 0; // Add zero as package delimiter.
  234. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE)
  235. #if TRICE_CONFIG_WARNINGS == 1
  236. #error configuration: The Trice tool does not support encryted data without COBS or TCOBS framing.
  237. #endif
  238. // memmove(dst, triceNettoStart, triceNettoLen );
  239. // size_t len8 = (triceNettoLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
  240. // memset((enc)+triceNettoLen, 0, len8 - triceNettoLen); // Clear padding space.
  241. // XTEAEncrypt( (uint32_t *)enc, len8>>2 );
  242. // encLen += len8; // encLen is re-used here
  243. // nextPosForEncoding = dst+encLen;
  244. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS)
  245. size_t len = (size_t)TCOBSEncode(dst, triceNettoStart, triceNettoLen);
  246. dst[len++] = 0; // Add zero as package delimiter.
  247. encLen += len;
  248. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS)
  249. size_t len = (size_t)COBSEncode(dst, triceNettoStart, triceNettoLen);
  250. dst[len++] = 0; // Add zero as package delimiter.
  251. encLen += len;
  252. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE)
  253. memmove(dst, triceNettoStart, triceNettoLen);
  254. encLen += triceNettoLen;
  255. #else
  256. #error configuration: unexpected
  257. #endif
  258. #elif TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
  259. // pack data
  260. uint8_t *packed = dat + encLen; // After the loop, the packed data start at dat.
  261. memmove(packed, triceNettoStart, triceNettoLen); // This action removes all padding bytes of the trices, compacting their sequence this way
  262. encLen += triceNettoLen;
  263. #endif // #elif TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
  264. #if (TRICE_PROTECT == 1) || (TRICE_DIAGNOSTICS == 1)
  265. dst = enc + encLen; // When several Trices in the double buffer, with each encoding the new dst could drift a bit closer towards triceNettoStart.
  266. int triceDataOffsetSpaceRemained = nxt - dst; // THe begin of unprocessed data MINUS next dst must not be negative.
  267. #endif
  268. #if (TRICE_PROTECT == 1)
  269. if (triceDataOffsetSpaceRemained < 0)
  270. {
  271. TriceErrorCount++;
  272. return; // discard broken data to avoid buffer overflow
  273. }
  274. #endif
  275. #if TRICE_DIAGNOSTICS == 1
  276. int triceDataOffsetDepth = TRICE_DATA_OFFSET - triceDataOffsetSpaceRemained;
  277. TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
  278. #endif
  279. }
  280. #if TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE
  281. // At this point the compacted trice messages start TRICE_DATA_OFFSET bytes after tb (now dat) and the encLen is their total netto length.
  282. // 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.
  283. // encLen = TriceEncode( TRICE_DEFERRED_XTEA_ENCRYPT, TRICE_DEFERRED_OUT_FRAMING, enc, dat, encLen );
  284. #if (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  285. // 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
  286. size_t len8 = (encLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
  287. memset(((uint8_t *)dat) + encLen, 0, len8 - encLen); // clear padding space: ATTENTION! OK only for this compiler switch setting.
  288. XTEAEncrypt((uint32_t *)dat, len8 >> 2);
  289. size_t eLen = (size_t)TCOBSEncode(enc, dat, len8); // encLen is re-used here
  290. enc[eLen++] = 0; // Add zero as package delimiter.
  291. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  292. // 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
  293. size_t len8 = (encLen + 7) & ~7; // Only multiple of 8 encryptable, so we adjust len.
  294. memset(((uint8_t *)dat) + encLen, 0, len8 - encLen); // clear padding space: ATTENTION! OK only for this compiler switch setting.
  295. XTEAEncrypt((uint32_t *)dat, len8 >> 2);
  296. size_t eLen = (size_t)COBSEncode(enc, dat, len8); // encLen is re-used here
  297. enc[eLen++] = 0; // Add zero as package delimiter.
  298. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 1) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  299. size_t eLen = TriceEncode(TRICE_DEFERRED_XTEA_ENCRYPT, TRICE_DEFERRED_OUT_FRAMING, enc, dat, encLen);
  300. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_TCOBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  301. size_t eLen = TCOBSEncode(enc, dat, encLen);
  302. enc[eLen++] = 0; // Add zero as package delimiter.
  303. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_COBS) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  304. size_t eLen = (size_t)COBSEncode(enc, dat, encLen);
  305. enc[eLen++] = 0; // Add zero as package delimiter.
  306. #elif (TRICE_DEFERRED_XTEA_ENCRYPT == 0) && (TRICE_DEFERRED_OUT_FRAMING == TRICE_FRAMING_NONE) // && (TRICE_DEFERRED_TRANSFER_MODE == TRICE_MULTI_PACK_MODE)
  307. enc = dat;
  308. size_t eLen = encLen;
  309. #else
  310. #error configuration:
  311. #endif
  312. #if TRICE_DIAGNOSTICS
  313. // before: space = enc[TRICE_DATA_OFFSET], data = dat[encLen]
  314. // after: date = enc[eLen], (dat [encLen])
  315. // Mostly eLen < encLen, but it could be eLen = encLen + 1 + (encLen>>5) in TCOBS worst case.
  316. // dat - enc = TRICE_DATA_OFFSET
  317. // if eLen > encLen, then TriceDataOffsetDepth = eLen - encLen
  318. int triceDataOffsetDepth = eLen - encLen; // usually negative
  319. TriceDataOffsetDepthMax = triceDataOffsetDepth < TriceDataOffsetDepthMax ? TriceDataOffsetDepthMax : triceDataOffsetDepth;
  320. #endif
  321. encLen = eLen;
  322. #endif
  323. // Reaching here means all trice data in the current half buffer are encoded
  324. // into a single continuous buffer having 0-delimiters between them or not but at the ent is a 0-delimiter.
  325. //
  326. // output
  327. TRICE_ENTER_CRITICAL_SECTION
  328. TriceNonBlockingDeferredWrite8(triceID, enc, encLen); // lint !e771 Info 771: Symbol 'triceID' conceivably not initialized. Comment: tLen is always > 0.
  329. TRICE_LEAVE_CRITICAL_SECTION
  330. }
  331. #endif // #if TRICE_BUFFER == TRICE_DOUBLE_BUFFER && TRICE_OFF == 0