stream_buffer.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. /*
  2. * FreeRTOS Kernel V10.2.1
  3. * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * http://www.FreeRTOS.org
  23. * http://aws.amazon.com/freertos
  24. *
  25. * 1 tab == 4 spaces!
  26. */
  27. /* Standard includes. */
  28. #include <stdint.h>
  29. #include <string.h>
  30. /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
  31. all the API functions to use the MPU wrappers. That should only be done when
  32. task.h is included from an application file. */
  33. #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
  34. /* FreeRTOS includes. */
  35. #include "FreeRTOS.h"
  36. #include "task.h"
  37. #include "stream_buffer.h"
  38. #if( configUSE_TASK_NOTIFICATIONS != 1 )
  39. #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
  40. #endif
  41. /* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified
  42. because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
  43. for the header files above, but not in this file, in order to generate the
  44. correct privileged Vs unprivileged linkage and placement. */
  45. #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
  46. /* If the user has not provided application specific Rx notification macros,
  47. or #defined the notification macros away, them provide default implementations
  48. that uses task notifications. */
  49. /*lint -save -e9026 Function like macros allowed and needed here so they can be overidden. */
  50. #ifndef sbRECEIVE_COMPLETED
  51. #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
  52. taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \
  53. { \
  54. if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
  55. { \
  56. ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \
  57. ( uint32_t ) 0, \
  58. eNoAction ); \
  59. ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
  60. } \
  61. } \
  62. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  63. #endif /* sbRECEIVE_COMPLETED */
  64. #ifndef sbRECEIVE_COMPLETED_FROM_ISR
  65. #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
  66. pxHigherPriorityTaskWoken ) \
  67. { \
  68. UBaseType_t uxSavedInterruptStatus; \
  69. \
  70. uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
  71. { \
  72. if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
  73. { \
  74. ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \
  75. ( uint32_t ) 0, \
  76. eNoAction, \
  77. pxHigherPriorityTaskWoken ); \
  78. ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
  79. } \
  80. } \
  81. portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
  82. }
  83. #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
  84. /* If the user has not provided an application specific Tx notification macro,
  85. or #defined the notification macro away, them provide a default implementation
  86. that uses task notifications. */
  87. #ifndef sbSEND_COMPLETED
  88. #define sbSEND_COMPLETED( pxStreamBuffer ) \
  89. taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \
  90. { \
  91. if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
  92. { \
  93. ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \
  94. ( uint32_t ) 0, \
  95. eNoAction ); \
  96. ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
  97. } \
  98. } \
  99. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  100. #endif /* sbSEND_COMPLETED */
  101. #ifndef sbSEND_COMPLETE_FROM_ISR
  102. #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
  103. { \
  104. UBaseType_t uxSavedInterruptStatus; \
  105. \
  106. uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
  107. { \
  108. if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
  109. { \
  110. ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
  111. ( uint32_t ) 0, \
  112. eNoAction, \
  113. pxHigherPriorityTaskWoken ); \
  114. ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
  115. } \
  116. } \
  117. portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
  118. }
  119. #endif /* sbSEND_COMPLETE_FROM_ISR */
  120. /*lint -restore (9026) */
  121. /* The number of bytes used to hold the length of a message in the buffer. */
  122. #define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
  123. /* Bits stored in the ucFlags field of the stream buffer. */
  124. #define sbFLAGS_IS_MESSAGE_BUFFER ( ( uint8_t ) 1 ) /* Set if the stream buffer was created as a message buffer, in which case it holds discrete messages rather than a stream. */
  125. #define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */
  126. /*-----------------------------------------------------------*/
  127. /* Structure that hold state information on the buffer. */
  128. typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
  129. {
  130. volatile size_t xTail; /* Index to the next item to read within the buffer. */
  131. volatile size_t xHead; /* Index to the next item to write within the buffer. */
  132. size_t xLength; /* The length of the buffer pointed to by pucBuffer. */
  133. size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
  134. volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
  135. volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
  136. uint8_t *pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
  137. uint8_t ucFlags;
  138. #if ( configUSE_TRACE_FACILITY == 1 )
  139. UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
  140. #endif
  141. portMUX_TYPE xStreamBufferMux; //Mutex required due to SMP
  142. } StreamBuffer_t;
  143. /*
  144. * The number of bytes available to be read from the buffer.
  145. */
  146. static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;
  147. /*
  148. * Add xCount bytes from pucData into the pxStreamBuffer message buffer.
  149. * Returns the number of bytes written, which will either equal xCount in the
  150. * success case, or 0 if there was not enough space in the buffer (in which case
  151. * no data is written into the buffer).
  152. */
  153. static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) PRIVILEGED_FUNCTION;
  154. /*
  155. * If the stream buffer is being used as a message buffer, then reads an entire
  156. * message out of the buffer. If the stream buffer is being used as a stream
  157. * buffer then read as many bytes as possible from the buffer.
  158. * prvReadBytesFromBuffer() is called to actually extract the bytes from the
  159. * buffer's data storage area.
  160. */
  161. static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer,
  162. void *pvRxData,
  163. size_t xBufferLengthBytes,
  164. size_t xBytesAvailable,
  165. size_t xBytesToStoreMessageLength ) PRIVILEGED_FUNCTION;
  166. /*
  167. * If the stream buffer is being used as a message buffer, then writes an entire
  168. * message to the buffer. If the stream buffer is being used as a stream
  169. * buffer then write as many bytes as possible to the buffer.
  170. * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's
  171. * data storage area.
  172. */
  173. static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
  174. const void * pvTxData,
  175. size_t xDataLengthBytes,
  176. size_t xSpace,
  177. size_t xRequiredSpace ) PRIVILEGED_FUNCTION;
  178. /*
  179. * Read xMaxCount bytes from the pxStreamBuffer message buffer and write them
  180. * to pucData.
  181. */
  182. static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer,
  183. uint8_t *pucData,
  184. size_t xMaxCount,
  185. size_t xBytesAvailable ) PRIVILEGED_FUNCTION;
  186. /*
  187. * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to
  188. * initialise the members of the newly created stream buffer structure.
  189. */
  190. static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
  191. uint8_t * const pucBuffer,
  192. size_t xBufferSizeBytes,
  193. size_t xTriggerLevelBytes,
  194. uint8_t ucFlags ) PRIVILEGED_FUNCTION;
  195. /*-----------------------------------------------------------*/
  196. #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
  197. StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer )
  198. {
  199. uint8_t *pucAllocatedMemory;
  200. uint8_t ucFlags;
  201. /* In case the stream buffer is going to be used as a message buffer
  202. (that is, it will hold discrete messages with a little meta data that
  203. says how big the next message is) check the buffer will be large enough
  204. to hold at least one message. */
  205. if( xIsMessageBuffer == pdTRUE )
  206. {
  207. /* Is a message buffer but not statically allocated. */
  208. ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
  209. configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
  210. }
  211. else
  212. {
  213. /* Not a message buffer and not statically allocated. */
  214. ucFlags = 0;
  215. configASSERT( xBufferSizeBytes > 0 );
  216. }
  217. configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
  218. /* A trigger level of 0 would cause a waiting task to unblock even when
  219. the buffer was empty. */
  220. if( xTriggerLevelBytes == ( size_t ) 0 )
  221. {
  222. xTriggerLevelBytes = ( size_t ) 1;
  223. }
  224. /* A stream buffer requires a StreamBuffer_t structure and a buffer.
  225. Both are allocated in a single call to pvPortMalloc(). The
  226. StreamBuffer_t structure is placed at the start of the allocated memory
  227. and the buffer follows immediately after. The requested size is
  228. incremented so the free space is returned as the user would expect -
  229. this is a quirk of the implementation that means otherwise the free
  230. space would be reported as one byte smaller than would be logically
  231. expected. */
  232. if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )
  233. {
  234. xBufferSizeBytes++;
  235. pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */
  236. }
  237. else
  238. {
  239. pucAllocatedMemory = NULL;
  240. }
  241. if( pucAllocatedMemory != NULL )
  242. {
  243. prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pucAllocatedMemory, /* Structure at the start of the allocated memory. */ /*lint !e9087 Safe cast as allocated memory is aligned. */ /*lint !e826 Area is not too small and alignment is guaranteed provided malloc() behaves as expected and returns aligned buffer. */
  244. pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */
  245. xBufferSizeBytes,
  246. xTriggerLevelBytes,
  247. ucFlags );
  248. traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );
  249. }
  250. else
  251. {
  252. traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
  253. }
  254. return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
  255. }
  256. #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
  257. /*-----------------------------------------------------------*/
  258. #if( configSUPPORT_STATIC_ALLOCATION == 1 )
  259. StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
  260. size_t xTriggerLevelBytes,
  261. BaseType_t xIsMessageBuffer,
  262. uint8_t * const pucStreamBufferStorageArea,
  263. StaticStreamBuffer_t * const pxStaticStreamBuffer )
  264. {
  265. StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
  266. StreamBufferHandle_t xReturn;
  267. uint8_t ucFlags;
  268. configASSERT( pucStreamBufferStorageArea );
  269. configASSERT( pxStaticStreamBuffer );
  270. configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
  271. /* A trigger level of 0 would cause a waiting task to unblock even when
  272. the buffer was empty. */
  273. if( xTriggerLevelBytes == ( size_t ) 0 )
  274. {
  275. xTriggerLevelBytes = ( size_t ) 1;
  276. }
  277. if( xIsMessageBuffer != pdFALSE )
  278. {
  279. /* Statically allocated message buffer. */
  280. ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
  281. }
  282. else
  283. {
  284. /* Statically allocated stream buffer. */
  285. ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
  286. }
  287. /* In case the stream buffer is going to be used as a message buffer
  288. (that is, it will hold discrete messages with a little meta data that
  289. says how big the next message is) check the buffer will be large enough
  290. to hold at least one message. */
  291. configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
  292. #if( configASSERT_DEFINED == 1 )
  293. {
  294. /* Sanity check that the size of the structure used to declare a
  295. variable of type StaticStreamBuffer_t equals the size of the real
  296. message buffer structure. */
  297. volatile size_t xSize = sizeof( StaticStreamBuffer_t );
  298. configASSERT( xSize == sizeof( StreamBuffer_t ) );
  299. } /*lint !e529 xSize is referenced is configASSERT() is defined. */
  300. #endif /* configASSERT_DEFINED */
  301. if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
  302. {
  303. prvInitialiseNewStreamBuffer( pxStreamBuffer,
  304. pucStreamBufferStorageArea,
  305. xBufferSizeBytes,
  306. xTriggerLevelBytes,
  307. ucFlags );
  308. /* Remember this was statically allocated in case it is ever deleted
  309. again. */
  310. pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
  311. traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
  312. xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
  313. }
  314. else
  315. {
  316. xReturn = NULL;
  317. traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
  318. }
  319. return xReturn;
  320. }
  321. #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
  322. /*-----------------------------------------------------------*/
  323. void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
  324. {
  325. StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
  326. configASSERT( pxStreamBuffer );
  327. traceSTREAM_BUFFER_DELETE( xStreamBuffer );
  328. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
  329. {
  330. #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
  331. {
  332. /* Both the structure and the buffer were allocated using a single call
  333. to pvPortMalloc(), hence only one call to vPortFree() is required. */
  334. vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */
  335. }
  336. #else
  337. {
  338. /* Should not be possible to get here, ucFlags must be corrupt.
  339. Force an assert. */
  340. configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
  341. }
  342. #endif
  343. }
  344. else
  345. {
  346. /* The structure and buffer were not allocated dynamically and cannot be
  347. freed - just scrub the structure so future use will assert. */
  348. ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
  349. }
  350. }
  351. /*-----------------------------------------------------------*/
  352. BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
  353. {
  354. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  355. BaseType_t xReturn = pdFAIL;
  356. #if( configUSE_TRACE_FACILITY == 1 )
  357. UBaseType_t uxStreamBufferNumber;
  358. #endif
  359. configASSERT( pxStreamBuffer );
  360. #if( configUSE_TRACE_FACILITY == 1 )
  361. {
  362. /* Store the stream buffer number so it can be restored after the
  363. reset. */
  364. uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
  365. }
  366. #endif
  367. /* Can only reset a message buffer if there are no tasks blocked on it. */
  368. taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  369. {
  370. if( pxStreamBuffer->xTaskWaitingToReceive == NULL )
  371. {
  372. if( pxStreamBuffer->xTaskWaitingToSend == NULL )
  373. {
  374. prvInitialiseNewStreamBuffer( pxStreamBuffer,
  375. pxStreamBuffer->pucBuffer,
  376. pxStreamBuffer->xLength,
  377. pxStreamBuffer->xTriggerLevelBytes,
  378. pxStreamBuffer->ucFlags );
  379. xReturn = pdPASS;
  380. #if( configUSE_TRACE_FACILITY == 1 )
  381. {
  382. pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
  383. }
  384. #endif
  385. traceSTREAM_BUFFER_RESET( xStreamBuffer );
  386. }
  387. }
  388. }
  389. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  390. return xReturn;
  391. }
  392. /*-----------------------------------------------------------*/
  393. BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel )
  394. {
  395. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  396. BaseType_t xReturn;
  397. configASSERT( pxStreamBuffer );
  398. /* It is not valid for the trigger level to be 0. */
  399. if( xTriggerLevel == ( size_t ) 0 )
  400. {
  401. xTriggerLevel = ( size_t ) 1;
  402. }
  403. /* The trigger level is the number of bytes that must be in the stream
  404. buffer before a task that is waiting for data is unblocked. */
  405. if( xTriggerLevel <= pxStreamBuffer->xLength )
  406. {
  407. pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
  408. xReturn = pdPASS;
  409. }
  410. else
  411. {
  412. xReturn = pdFALSE;
  413. }
  414. return xReturn;
  415. }
  416. /*-----------------------------------------------------------*/
  417. size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
  418. {
  419. const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  420. size_t xSpace;
  421. configASSERT( pxStreamBuffer );
  422. xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
  423. xSpace -= pxStreamBuffer->xHead;
  424. xSpace -= ( size_t ) 1;
  425. if( xSpace >= pxStreamBuffer->xLength )
  426. {
  427. xSpace -= pxStreamBuffer->xLength;
  428. }
  429. else
  430. {
  431. mtCOVERAGE_TEST_MARKER();
  432. }
  433. return xSpace;
  434. }
  435. /*-----------------------------------------------------------*/
  436. size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
  437. {
  438. const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  439. size_t xReturn;
  440. configASSERT( pxStreamBuffer );
  441. xReturn = prvBytesInBuffer( pxStreamBuffer );
  442. return xReturn;
  443. }
  444. /*-----------------------------------------------------------*/
  445. size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
  446. const void *pvTxData,
  447. size_t xDataLengthBytes,
  448. TickType_t xTicksToWait )
  449. {
  450. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  451. size_t xReturn, xSpace = 0;
  452. size_t xRequiredSpace = xDataLengthBytes;
  453. TimeOut_t xTimeOut;
  454. configASSERT( pvTxData );
  455. configASSERT( pxStreamBuffer );
  456. /* This send function is used to write to both message buffers and stream
  457. buffers. If this is a message buffer then the space needed must be
  458. increased by the amount of bytes needed to store the length of the
  459. message. */
  460. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  461. {
  462. xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
  463. /* Overflow? */
  464. configASSERT( xRequiredSpace > xDataLengthBytes );
  465. }
  466. else
  467. {
  468. mtCOVERAGE_TEST_MARKER();
  469. }
  470. if( xTicksToWait != ( TickType_t ) 0 )
  471. {
  472. vTaskSetTimeOutState( &xTimeOut );
  473. do
  474. {
  475. /* Wait until the required number of bytes are free in the message
  476. buffer. */
  477. taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  478. {
  479. xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
  480. if( xSpace < xRequiredSpace )
  481. {
  482. /* Clear notification state as going to wait for space. */
  483. ( void ) xTaskNotifyStateClear( NULL );
  484. /* Should only be one writer. */
  485. configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
  486. pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
  487. }
  488. else
  489. {
  490. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  491. break;
  492. }
  493. }
  494. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  495. traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
  496. ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
  497. pxStreamBuffer->xTaskWaitingToSend = NULL;
  498. } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
  499. }
  500. else
  501. {
  502. mtCOVERAGE_TEST_MARKER();
  503. }
  504. if( xSpace == ( size_t ) 0 )
  505. {
  506. xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
  507. }
  508. else
  509. {
  510. mtCOVERAGE_TEST_MARKER();
  511. }
  512. xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
  513. if( xReturn > ( size_t ) 0 )
  514. {
  515. traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
  516. /* Was a task waiting for the data? */
  517. if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
  518. {
  519. sbSEND_COMPLETED( pxStreamBuffer );
  520. }
  521. else
  522. {
  523. mtCOVERAGE_TEST_MARKER();
  524. }
  525. }
  526. else
  527. {
  528. mtCOVERAGE_TEST_MARKER();
  529. traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
  530. }
  531. return xReturn;
  532. }
  533. /*-----------------------------------------------------------*/
  534. size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
  535. const void *pvTxData,
  536. size_t xDataLengthBytes,
  537. BaseType_t * const pxHigherPriorityTaskWoken )
  538. {
  539. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  540. size_t xReturn, xSpace;
  541. size_t xRequiredSpace = xDataLengthBytes;
  542. configASSERT( pvTxData );
  543. configASSERT( pxStreamBuffer );
  544. /* This send function is used to write to both message buffers and stream
  545. buffers. If this is a message buffer then the space needed must be
  546. increased by the amount of bytes needed to store the length of the
  547. message. */
  548. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  549. {
  550. xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
  551. }
  552. else
  553. {
  554. mtCOVERAGE_TEST_MARKER();
  555. }
  556. xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
  557. xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
  558. if( xReturn > ( size_t ) 0 )
  559. {
  560. /* Was a task waiting for the data? */
  561. if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
  562. {
  563. sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
  564. }
  565. else
  566. {
  567. mtCOVERAGE_TEST_MARKER();
  568. }
  569. }
  570. else
  571. {
  572. mtCOVERAGE_TEST_MARKER();
  573. }
  574. traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
  575. return xReturn;
  576. }
  577. /*-----------------------------------------------------------*/
  578. static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
  579. const void * pvTxData,
  580. size_t xDataLengthBytes,
  581. size_t xSpace,
  582. size_t xRequiredSpace )
  583. {
  584. BaseType_t xShouldWrite;
  585. size_t xReturn;
  586. if( xSpace == ( size_t ) 0 )
  587. {
  588. /* Doesn't matter if this is a stream buffer or a message buffer, there
  589. is no space to write. */
  590. xShouldWrite = pdFALSE;
  591. }
  592. else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 )
  593. {
  594. /* This is a stream buffer, as opposed to a message buffer, so writing a
  595. stream of bytes rather than discrete messages. Write as many bytes as
  596. possible. */
  597. xShouldWrite = pdTRUE;
  598. xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
  599. }
  600. else if( xSpace >= xRequiredSpace )
  601. {
  602. /* This is a message buffer, as opposed to a stream buffer, and there
  603. is enough space to write both the message length and the message itself
  604. into the buffer. Start by writing the length of the data, the data
  605. itself will be written later in this function. */
  606. xShouldWrite = pdTRUE;
  607. ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH );
  608. }
  609. else
  610. {
  611. /* There is space available, but not enough space. */
  612. xShouldWrite = pdFALSE;
  613. }
  614. if( xShouldWrite != pdFALSE )
  615. {
  616. /* Writes the data itself. */
  617. xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alighment and access. */
  618. }
  619. else
  620. {
  621. xReturn = 0;
  622. }
  623. return xReturn;
  624. }
  625. /*-----------------------------------------------------------*/
  626. size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
  627. void *pvRxData,
  628. size_t xBufferLengthBytes,
  629. TickType_t xTicksToWait )
  630. {
  631. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  632. size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
  633. configASSERT( pvRxData );
  634. configASSERT( pxStreamBuffer );
  635. /* This receive function is used by both message buffers, which store
  636. discrete messages, and stream buffers, which store a continuous stream of
  637. bytes. Discrete messages include an additional
  638. sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
  639. message. */
  640. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  641. {
  642. xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
  643. }
  644. else
  645. {
  646. xBytesToStoreMessageLength = 0;
  647. }
  648. if( xTicksToWait != ( TickType_t ) 0 )
  649. {
  650. /* Checking if there is data and clearing the notification state must be
  651. performed atomically. */
  652. taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  653. {
  654. xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
  655. /* If this function was invoked by a message buffer read then
  656. xBytesToStoreMessageLength holds the number of bytes used to hold
  657. the length of the next discrete message. If this function was
  658. invoked by a stream buffer read then xBytesToStoreMessageLength will
  659. be 0. */
  660. if( xBytesAvailable <= xBytesToStoreMessageLength )
  661. {
  662. /* Clear notification state as going to wait for data. */
  663. ( void ) xTaskNotifyStateClear( NULL );
  664. /* Should only be one reader. */
  665. configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
  666. pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
  667. }
  668. else
  669. {
  670. mtCOVERAGE_TEST_MARKER();
  671. }
  672. }
  673. taskEXIT_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
  674. if( xBytesAvailable <= xBytesToStoreMessageLength )
  675. {
  676. /* Wait for data to be available. */
  677. traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
  678. ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
  679. pxStreamBuffer->xTaskWaitingToReceive = NULL;
  680. /* Recheck the data available after blocking. */
  681. xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
  682. }
  683. else
  684. {
  685. mtCOVERAGE_TEST_MARKER();
  686. }
  687. }
  688. else
  689. {
  690. xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
  691. }
  692. /* Whether receiving a discrete message (where xBytesToStoreMessageLength
  693. holds the number of bytes used to store the message length) or a stream of
  694. bytes (where xBytesToStoreMessageLength is zero), the number of bytes
  695. available must be greater than xBytesToStoreMessageLength to be able to
  696. read bytes from the buffer. */
  697. if( xBytesAvailable > xBytesToStoreMessageLength )
  698. {
  699. xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
  700. /* Was a task waiting for space in the buffer? */
  701. if( xReceivedLength != ( size_t ) 0 )
  702. {
  703. traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
  704. sbRECEIVE_COMPLETED( pxStreamBuffer );
  705. }
  706. else
  707. {
  708. mtCOVERAGE_TEST_MARKER();
  709. }
  710. }
  711. else
  712. {
  713. traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
  714. mtCOVERAGE_TEST_MARKER();
  715. }
  716. return xReceivedLength;
  717. }
  718. /*-----------------------------------------------------------*/
  719. size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
  720. {
  721. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  722. size_t xReturn, xBytesAvailable, xOriginalTail;
  723. configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
  724. configASSERT( pxStreamBuffer );
  725. /* Ensure the stream buffer is being used as a message buffer. */
  726. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  727. {
  728. xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
  729. if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
  730. {
  731. /* The number of bytes available is greater than the number of bytes
  732. required to hold the length of the next message, so another message
  733. is available. Return its length without removing the length bytes
  734. from the buffer. A copy of the tail is stored so the buffer can be
  735. returned to its prior state as the message is not actually being
  736. removed from the buffer. */
  737. xOriginalTail = pxStreamBuffer->xTail;
  738. ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );
  739. xReturn = ( size_t ) xTempReturn;
  740. pxStreamBuffer->xTail = xOriginalTail;
  741. }
  742. else
  743. {
  744. /* The minimum amount of bytes in a message buffer is
  745. ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
  746. less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
  747. value is 0. */
  748. configASSERT( xBytesAvailable == 0 );
  749. xReturn = 0;
  750. }
  751. }
  752. else
  753. {
  754. xReturn = 0;
  755. }
  756. return xReturn;
  757. }
  758. /*-----------------------------------------------------------*/
  759. size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
  760. void *pvRxData,
  761. size_t xBufferLengthBytes,
  762. BaseType_t * const pxHigherPriorityTaskWoken )
  763. {
  764. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  765. size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
  766. configASSERT( pvRxData );
  767. configASSERT( pxStreamBuffer );
  768. /* This receive function is used by both message buffers, which store
  769. discrete messages, and stream buffers, which store a continuous stream of
  770. bytes. Discrete messages include an additional
  771. sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
  772. message. */
  773. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  774. {
  775. xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
  776. }
  777. else
  778. {
  779. xBytesToStoreMessageLength = 0;
  780. }
  781. xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
  782. /* Whether receiving a discrete message (where xBytesToStoreMessageLength
  783. holds the number of bytes used to store the message length) or a stream of
  784. bytes (where xBytesToStoreMessageLength is zero), the number of bytes
  785. available must be greater than xBytesToStoreMessageLength to be able to
  786. read bytes from the buffer. */
  787. if( xBytesAvailable > xBytesToStoreMessageLength )
  788. {
  789. xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
  790. /* Was a task waiting for space in the buffer? */
  791. if( xReceivedLength != ( size_t ) 0 )
  792. {
  793. sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
  794. }
  795. else
  796. {
  797. mtCOVERAGE_TEST_MARKER();
  798. }
  799. }
  800. else
  801. {
  802. mtCOVERAGE_TEST_MARKER();
  803. }
  804. traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
  805. return xReceivedLength;
  806. }
  807. /*-----------------------------------------------------------*/
  808. static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer,
  809. void *pvRxData,
  810. size_t xBufferLengthBytes,
  811. size_t xBytesAvailable,
  812. size_t xBytesToStoreMessageLength )
  813. {
  814. size_t xOriginalTail, xReceivedLength, xNextMessageLength;
  815. configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
  816. if( xBytesToStoreMessageLength != ( size_t ) 0 )
  817. {
  818. /* A discrete message is being received. First receive the length
  819. of the message. A copy of the tail is stored so the buffer can be
  820. returned to its prior state if the length of the message is too
  821. large for the provided buffer. */
  822. xOriginalTail = pxStreamBuffer->xTail;
  823. ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );
  824. xNextMessageLength = ( size_t ) xTempNextMessageLength;
  825. /* Reduce the number of bytes available by the number of bytes just
  826. read out. */
  827. xBytesAvailable -= xBytesToStoreMessageLength;
  828. /* Check there is enough space in the buffer provided by the
  829. user. */
  830. if( xNextMessageLength > xBufferLengthBytes )
  831. {
  832. /* The user has provided insufficient space to read the message
  833. so return the buffer to its previous state (so the length of
  834. the message is in the buffer again). */
  835. pxStreamBuffer->xTail = xOriginalTail;
  836. xNextMessageLength = 0;
  837. }
  838. else
  839. {
  840. mtCOVERAGE_TEST_MARKER();
  841. }
  842. }
  843. else
  844. {
  845. /* A stream of bytes is being received (as opposed to a discrete
  846. message), so read as many bytes as possible. */
  847. xNextMessageLength = xBufferLengthBytes;
  848. }
  849. /* Read the actual data. */
  850. xReceivedLength = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xNextMessageLength, xBytesAvailable ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */
  851. return xReceivedLength;
  852. }
  853. /*-----------------------------------------------------------*/
  854. BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
  855. {
  856. const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  857. BaseType_t xReturn;
  858. size_t xTail;
  859. configASSERT( pxStreamBuffer );
  860. /* True if no bytes are available. */
  861. xTail = pxStreamBuffer->xTail;
  862. if( pxStreamBuffer->xHead == xTail )
  863. {
  864. xReturn = pdTRUE;
  865. }
  866. else
  867. {
  868. xReturn = pdFALSE;
  869. }
  870. return xReturn;
  871. }
  872. /*-----------------------------------------------------------*/
  873. BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
  874. {
  875. BaseType_t xReturn;
  876. size_t xBytesToStoreMessageLength;
  877. const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  878. configASSERT( pxStreamBuffer );
  879. /* This generic version of the receive function is used by both message
  880. buffers, which store discrete messages, and stream buffers, which store a
  881. continuous stream of bytes. Discrete messages include an additional
  882. sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
  883. if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
  884. {
  885. xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
  886. }
  887. else
  888. {
  889. xBytesToStoreMessageLength = 0;
  890. }
  891. /* True if the available space equals zero. */
  892. if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
  893. {
  894. xReturn = pdTRUE;
  895. }
  896. else
  897. {
  898. xReturn = pdFALSE;
  899. }
  900. return xReturn;
  901. }
  902. /*-----------------------------------------------------------*/
  903. BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken )
  904. {
  905. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  906. BaseType_t xReturn;
  907. UBaseType_t uxSavedInterruptStatus;
  908. configASSERT( pxStreamBuffer );
  909. uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
  910. {
  911. if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
  912. {
  913. ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
  914. ( uint32_t ) 0,
  915. eNoAction,
  916. pxHigherPriorityTaskWoken );
  917. ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
  918. xReturn = pdTRUE;
  919. }
  920. else
  921. {
  922. xReturn = pdFALSE;
  923. }
  924. }
  925. portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
  926. return xReturn;
  927. }
  928. /*-----------------------------------------------------------*/
  929. BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken )
  930. {
  931. StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
  932. BaseType_t xReturn;
  933. UBaseType_t uxSavedInterruptStatus;
  934. configASSERT( pxStreamBuffer );
  935. uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
  936. {
  937. if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
  938. {
  939. ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
  940. ( uint32_t ) 0,
  941. eNoAction,
  942. pxHigherPriorityTaskWoken );
  943. ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
  944. xReturn = pdTRUE;
  945. }
  946. else
  947. {
  948. xReturn = pdFALSE;
  949. }
  950. }
  951. portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
  952. return xReturn;
  953. }
  954. /*-----------------------------------------------------------*/
  955. static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount )
  956. {
  957. size_t xNextHead, xFirstLength;
  958. configASSERT( xCount > ( size_t ) 0 );
  959. xNextHead = pxStreamBuffer->xHead;
  960. /* Calculate the number of bytes that can be added in the first write -
  961. which may be less than the total number of bytes that need to be added if
  962. the buffer will wrap back to the beginning. */
  963. xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount );
  964. /* Write as many bytes as can be written in the first write. */
  965. configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength );
  966. ( void ) memcpy( ( void* ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */
  967. /* If the number of bytes written was less than the number that could be
  968. written in the first write... */
  969. if( xCount > xFirstLength )
  970. {
  971. /* ...then write the remaining bytes to the start of the buffer. */
  972. configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );
  973. ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
  974. }
  975. else
  976. {
  977. mtCOVERAGE_TEST_MARKER();
  978. }
  979. xNextHead += xCount;
  980. if( xNextHead >= pxStreamBuffer->xLength )
  981. {
  982. xNextHead -= pxStreamBuffer->xLength;
  983. }
  984. else
  985. {
  986. mtCOVERAGE_TEST_MARKER();
  987. }
  988. pxStreamBuffer->xHead = xNextHead;
  989. return xCount;
  990. }
  991. /*-----------------------------------------------------------*/
  992. static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, uint8_t *pucData, size_t xMaxCount, size_t xBytesAvailable )
  993. {
  994. size_t xCount, xFirstLength, xNextTail;
  995. /* Use the minimum of the wanted bytes and the available bytes. */
  996. xCount = configMIN( xBytesAvailable, xMaxCount );
  997. if( xCount > ( size_t ) 0 )
  998. {
  999. xNextTail = pxStreamBuffer->xTail;
  1000. /* Calculate the number of bytes that can be read - which may be
  1001. less than the number wanted if the data wraps around to the start of
  1002. the buffer. */
  1003. xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );
  1004. /* Obtain the number of bytes it is possible to obtain in the first
  1005. read. Asserts check bounds of read and write. */
  1006. configASSERT( xFirstLength <= xMaxCount );
  1007. configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );
  1008. ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */
  1009. /* If the total number of wanted bytes is greater than the number
  1010. that could be read in the first read... */
  1011. if( xCount > xFirstLength )
  1012. {
  1013. /*...then read the remaining bytes from the start of the buffer. */
  1014. configASSERT( xCount <= xMaxCount );
  1015. ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
  1016. }
  1017. else
  1018. {
  1019. mtCOVERAGE_TEST_MARKER();
  1020. }
  1021. /* Move the tail pointer to effectively remove the data read from
  1022. the buffer. */
  1023. xNextTail += xCount;
  1024. if( xNextTail >= pxStreamBuffer->xLength )
  1025. {
  1026. xNextTail -= pxStreamBuffer->xLength;
  1027. }
  1028. pxStreamBuffer->xTail = xNextTail;
  1029. }
  1030. else
  1031. {
  1032. mtCOVERAGE_TEST_MARKER();
  1033. }
  1034. return xCount;
  1035. }
  1036. /*-----------------------------------------------------------*/
  1037. static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
  1038. {
  1039. /* Returns the distance between xTail and xHead. */
  1040. size_t xCount;
  1041. xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
  1042. xCount -= pxStreamBuffer->xTail;
  1043. if ( xCount >= pxStreamBuffer->xLength )
  1044. {
  1045. xCount -= pxStreamBuffer->xLength;
  1046. }
  1047. else
  1048. {
  1049. mtCOVERAGE_TEST_MARKER();
  1050. }
  1051. return xCount;
  1052. }
  1053. /*-----------------------------------------------------------*/
  1054. static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
  1055. uint8_t * const pucBuffer,
  1056. size_t xBufferSizeBytes,
  1057. size_t xTriggerLevelBytes,
  1058. uint8_t ucFlags )
  1059. {
  1060. /* Assert here is deliberately writing to the entire buffer to ensure it can
  1061. be written to without generating exceptions, and is setting the buffer to a
  1062. known value to assist in development/debugging. */
  1063. #if( configASSERT_DEFINED == 1 )
  1064. {
  1065. /* The value written just has to be identifiable when looking at the
  1066. memory. Don't use 0xA5 as that is the stack fill value and could
  1067. result in confusion as to what is actually being observed. */
  1068. const BaseType_t xWriteValue = 0x55;
  1069. configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
  1070. } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
  1071. #endif
  1072. ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */
  1073. pxStreamBuffer->pucBuffer = pucBuffer;
  1074. pxStreamBuffer->xLength = xBufferSizeBytes;
  1075. pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
  1076. pxStreamBuffer->ucFlags = ucFlags;
  1077. vPortCPUInitializeMutex( &pxStreamBuffer->xStreamBufferMux );
  1078. }
  1079. #if ( configUSE_TRACE_FACILITY == 1 )
  1080. UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
  1081. {
  1082. return xStreamBuffer->uxStreamBufferNumber;
  1083. }
  1084. #endif /* configUSE_TRACE_FACILITY */
  1085. /*-----------------------------------------------------------*/
  1086. #if ( configUSE_TRACE_FACILITY == 1 )
  1087. void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber )
  1088. {
  1089. xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
  1090. }
  1091. #endif /* configUSE_TRACE_FACILITY */
  1092. /*-----------------------------------------------------------*/
  1093. #if ( configUSE_TRACE_FACILITY == 1 )
  1094. uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
  1095. {
  1096. return ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );
  1097. }
  1098. #endif /* configUSE_TRACE_FACILITY */
  1099. /*-----------------------------------------------------------*/