ringbuf.c
1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <stdlib.h> 16 #include <string.h> 17 #include "freertos/FreeRTOS.h" 18 #include "freertos/task.h" 19 #include "freertos/semphr.h" 20 #include "freertos/ringbuf.h" 21 22 //32-bit alignment macros 23 #define rbALIGN_SIZE( xSize ) ( ( xSize + portBYTE_ALIGNMENT_MASK ) & ~portBYTE_ALIGNMENT_MASK ) 24 #define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) ( pvPtr ) & portBYTE_ALIGNMENT_MASK ) == 0 ) 25 26 //Ring buffer flags 27 #define rbALLOW_SPLIT_FLAG ( ( UBaseType_t ) 1 ) //The ring buffer allows items to be split 28 #define rbBYTE_BUFFER_FLAG ( ( UBaseType_t ) 2 ) //The ring buffer is a byte buffer 29 #define rbBUFFER_FULL_FLAG ( ( UBaseType_t ) 4 ) //The ring buffer is currently full (write pointer == free pointer) 30 #define rbBUFFER_STATIC_FLAG ( ( UBaseType_t ) 8 ) //The ring buffer is statically allocated 31 32 //Item flags 33 #define rbITEM_FREE_FLAG ( ( UBaseType_t ) 1 ) //Item has been retrieved and returned by application, free to overwrite 34 #define rbITEM_DUMMY_DATA_FLAG ( ( UBaseType_t ) 2 ) //Data from here to end of the ring buffer is dummy data. Restart reading at start of head of the buffer 35 #define rbITEM_SPLIT_FLAG ( ( UBaseType_t ) 4 ) //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around 36 #define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus it is free to be read 37 38 //Static allocation related 39 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 40 #define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xTransSemStatic) ) 41 #define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xRecvSemStatic) ) 42 #else 43 #define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xTransSemHandle ) 44 #define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xRecvSemHandle ) 45 #endif 46 47 typedef struct { 48 //This size of this structure must be 32-bit aligned 49 size_t xItemLen; 50 UBaseType_t uxItemFlags; 51 } ItemHeader_t; 52 53 #define rbHEADER_SIZE sizeof(ItemHeader_t) 54 typedef struct RingbufferDefinition Ringbuffer_t; 55 typedef BaseType_t (*CheckItemFitsFunction_t)(Ringbuffer_t *pxRingbuffer, size_t xItemSize); 56 typedef void (*CopyItemFunction_t)(Ringbuffer_t *pxRingbuffer, const uint8_t *pcItem, size_t xItemSize); 57 typedef BaseType_t (*CheckItemAvailFunction_t) (Ringbuffer_t *pxRingbuffer); 58 typedef void *(*GetItemFunction_t)(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xMaxSize, size_t *pxItemSize); 59 typedef void (*ReturnItemFunction_t)(Ringbuffer_t *pxRingbuffer, uint8_t *pvItem); 60 typedef size_t (*GetCurMaxSizeFunction_t)(Ringbuffer_t *pxRingbuffer); 61 62 typedef struct RingbufferDefinition { 63 size_t xSize; //Size of the data storage 64 size_t xMaxItemSize; //Maximum item size 65 UBaseType_t uxRingbufferFlags; //Flags to indicate the type and status of ring buffer 66 67 CheckItemFitsFunction_t xCheckItemFits; //Function to check if item can currently fit in ring buffer 68 CopyItemFunction_t vCopyItem; //Function to copy item to ring buffer 69 GetItemFunction_t pvGetItem; //Function to get item from ring buffer 70 ReturnItemFunction_t vReturnItem; //Function to return item to ring buffer 71 GetCurMaxSizeFunction_t xGetCurMaxSize; //Function to get current free size 72 73 uint8_t *pucAcquire; //Acquire Pointer. Points to where the next item should be acquired. 74 uint8_t *pucWrite; //Write Pointer. Points to where the next item should be written 75 uint8_t *pucRead; //Read Pointer. Points to where the next item should be read from 76 uint8_t *pucFree; //Free Pointer. Points to the last item that has yet to be returned to the ring buffer 77 uint8_t *pucHead; //Pointer to the start of the ring buffer storage area 78 uint8_t *pucTail; //Pointer to the end of the ring buffer storage area 79 80 BaseType_t xItemsWaiting; //Number of items/bytes(for byte buffers) currently in ring buffer that have not yet been read 81 /* 82 * TransSem: Binary semaphore used to indicate to a blocked transmitting tasks 83 * that more free space has become available or that the block has 84 * timed out. 85 * 86 * RecvSem: Binary semaphore used to indicate to a blocked receiving task that 87 * new data/item has been written to the ring buffer. 88 * 89 * Note - When static allocation is enabled, the two semaphores are always 90 * statically stored in the ring buffer's control structure 91 * regardless of whether the ring buffer is allocated dynamically or 92 * statically. When static allocation is disabled, the two semaphores 93 * are allocated dynamically and their handles stored instead, thus 94 * making the ring buffer's control structure slightly smaller when 95 * static allocation is disabled. 96 */ 97 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 98 StaticSemaphore_t xTransSemStatic; 99 StaticSemaphore_t xRecvSemStatic; 100 #else 101 SemaphoreHandle_t xTransSemHandle; 102 SemaphoreHandle_t xRecvSemHandle; 103 #endif 104 portMUX_TYPE mux; //Spinlock required for SMP 105 } Ringbuffer_t; 106 107 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 108 #if __GNUC_PREREQ(4, 6) 109 _Static_assert(sizeof(StaticRingbuffer_t) == sizeof(Ringbuffer_t), "StaticRingbuffer_t != Ringbuffer_t"); 110 #endif 111 #endif 112 /* 113 Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in 114 FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we 115 would need to set the maximum to the maximum amount of times a null-byte unit first in the buffer, 116 which is quite high and so would waste a fair amount of memory. 117 */ 118 119 /* --------------------------- Static Declarations -------------------------- */ 120 /* 121 * WARNING: All of the following static functions (except generic functions) 122 * ARE NOT THREAD SAFE. Therefore they should only be called within a critical 123 * section (using spin locks) 124 */ 125 126 127 //Initialize a ring buffer after space has been allocated for it 128 static void prvInitializeNewRingbuffer(size_t xBufferSize, 129 RingbufferType_t xBufferType, 130 Ringbuffer_t *pxNewRingbuffer, 131 uint8_t *pucRingbufferStorage); 132 133 //Calculate current amount of free space (in bytes) in the ring buffer 134 static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer); 135 136 //Checks if an item/data is currently available for retrieval 137 static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer); 138 139 //Checks if an item will currently fit in a no-split/allow-split ring buffer 140 static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xItemSize); 141 142 //Checks if an item will currently fit in a byte buffer 143 static BaseType_t prvCheckItemFitsByteBuffer( Ringbuffer_t *pxRingbuffer, size_t xItemSize); 144 145 //Copies an item to a no-split ring buffer. Only call this function after calling prvCheckItemFitsDefault() 146 static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize); 147 148 //Copies an item to a allow-split ring buffer. Only call this function after calling prvCheckItemFitsDefault() 149 static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize); 150 151 //Copies an item to a byte buffer. Only call this function after calling prvCheckItemFitsByteBuffer() 152 static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize); 153 154 //Retrieve item from no-split/allow-split ring buffer. *pxIsSplit is set to pdTRUE if the retrieved item is split 155 static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, 156 BaseType_t *pxIsSplit, 157 size_t xUnusedParam, 158 size_t *pxItemSize); 159 160 //Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved 161 static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, 162 BaseType_t *pxUnusedParam, 163 size_t xMaxSize, 164 size_t *pxItemSize); 165 166 //Return an item to a split/no-split ring buffer 167 static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem); 168 169 //Return data to a byte buffer 170 static void prvReturnItemByteBuf(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem); 171 172 //Get the maximum size an item that can currently have if sent to a no-split ring buffer 173 static size_t prvGetCurMaxSizeNoSplit(Ringbuffer_t *pxRingbuffer); 174 175 //Get the maximum size an item that can currently have if sent to a allow-split ring buffer 176 static size_t prvGetCurMaxSizeAllowSplit(Ringbuffer_t *pxRingbuffer); 177 178 //Get the maximum size an item that can currently have if sent to a byte buffer 179 static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer); 180 181 /** 182 * Generic function used to retrieve an item/data from ring buffers. If called on 183 * an allow-split buffer, and pvItem2 and xItemSize2 are not NULL, both parts of 184 * a split item will be retrieved. xMaxSize will only take effect if called on 185 * byte buffers. 186 */ 187 static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, 188 void **pvItem1, 189 void **pvItem2, 190 size_t *xItemSize1, 191 size_t *xItemSize2, 192 size_t xMaxSize, 193 TickType_t xTicksToWait); 194 195 //Generic function used to retrieve an item/data from ring buffers in an ISR 196 static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, 197 void **pvItem1, 198 void **pvItem2, 199 size_t *xItemSize1, 200 size_t *xItemSize2, 201 size_t xMaxSize); 202 203 /* --------------------------- Static Definitions --------------------------- */ 204 205 static void prvInitializeNewRingbuffer(size_t xBufferSize, 206 RingbufferType_t xBufferType, 207 Ringbuffer_t *pxNewRingbuffer, 208 uint8_t *pucRingbufferStorage) 209 { 210 //Initialize values 211 pxNewRingbuffer->xSize = xBufferSize; 212 pxNewRingbuffer->pucHead = pucRingbufferStorage; 213 pxNewRingbuffer->pucTail = pucRingbufferStorage + xBufferSize; 214 pxNewRingbuffer->pucFree = pucRingbufferStorage; 215 pxNewRingbuffer->pucRead = pucRingbufferStorage; 216 pxNewRingbuffer->pucWrite = pucRingbufferStorage; 217 pxNewRingbuffer->pucAcquire = pucRingbufferStorage; 218 pxNewRingbuffer->xItemsWaiting = 0; 219 pxNewRingbuffer->uxRingbufferFlags = 0; 220 221 //Initialize type dependent values and function pointers 222 if (xBufferType == RINGBUF_TYPE_NOSPLIT) { 223 pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; 224 pxNewRingbuffer->vCopyItem = prvCopyItemNoSplit; 225 pxNewRingbuffer->pvGetItem = prvGetItemDefault; 226 pxNewRingbuffer->vReturnItem = prvReturnItemDefault; 227 /* 228 * Worst case scenario is when the read/write/acquire/free pointers are all 229 * pointing to the halfway point of the buffer. 230 */ 231 pxNewRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxNewRingbuffer->xSize / 2) - rbHEADER_SIZE; 232 pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit; 233 } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) { 234 pxNewRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG; 235 pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; 236 pxNewRingbuffer->vCopyItem = prvCopyItemAllowSplit; 237 pxNewRingbuffer->pvGetItem = prvGetItemDefault; 238 pxNewRingbuffer->vReturnItem = prvReturnItemDefault; 239 //Worst case an item is split into two, incurring two headers of overhead 240 pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize - (sizeof(ItemHeader_t) * 2); 241 pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit; 242 } else { //Byte Buffer 243 pxNewRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG; 244 pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer; 245 pxNewRingbuffer->vCopyItem = prvCopyItemByteBuf; 246 pxNewRingbuffer->pvGetItem = prvGetItemByteBuf; 247 pxNewRingbuffer->vReturnItem = prvReturnItemByteBuf; 248 //Byte buffers do not incur any overhead 249 pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize; 250 pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf; 251 } 252 xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxNewRingbuffer)); 253 vPortCPUInitializeMutex(&pxNewRingbuffer->mux); 254 } 255 256 static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) 257 { 258 size_t xReturn; 259 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 260 xReturn = 0; 261 } else { 262 BaseType_t xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; 263 //Check if xFreeSize has underflowed 264 if (xFreeSize <= 0) { 265 xFreeSize += pxRingbuffer->xSize; 266 } 267 xReturn = xFreeSize; 268 } 269 configASSERT(xReturn <= pxRingbuffer->xSize); 270 return xReturn; 271 } 272 273 static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xItemSize) 274 { 275 //Check arguments and buffer state 276 configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split/allow-split ring buffers 277 configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds 278 279 size_t xTotalItemSize = rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE; //Rounded up aligned item size with header 280 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { 281 //Buffer is either complete empty or completely full 282 return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; 283 } 284 if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { 285 //Free space does not wrap around 286 return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; 287 } 288 //Free space wraps around 289 if (xTotalItemSize <= pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) { 290 return pdTRUE; //Item fits without wrapping around 291 } 292 //Check if item fits by wrapping 293 if (pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG) { 294 //Allow split wrapping incurs an extra header 295 return (xTotalItemSize + rbHEADER_SIZE <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; 296 } else { 297 return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucHead) ? pdTRUE : pdFALSE; 298 } 299 } 300 301 static BaseType_t prvCheckItemFitsByteBuffer( Ringbuffer_t *pxRingbuffer, size_t xItemSize) 302 { 303 //Check arguments and buffer state 304 configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds 305 306 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { 307 //Buffer is either complete empty or completely full 308 return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; 309 } 310 if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { 311 //Free space does not wrap around 312 return (xItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; 313 } 314 //Free space wraps around 315 return (xItemSize <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; 316 } 317 318 static uint8_t* prvAcquireItemNoSplit(Ringbuffer_t *pxRingbuffer, size_t xItemSize) 319 { 320 //Check arguments and buffer state 321 size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size 322 size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer 323 configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split ring buffers 324 configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds 325 configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header 326 327 //If remaining length can't fit item, set as dummy data and wrap around 328 if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { 329 ItemHeader_t *pxDummy = (ItemHeader_t *)pxRingbuffer->pucAcquire; 330 pxDummy->uxItemFlags = rbITEM_DUMMY_DATA_FLAG; //Set remaining length as dummy data 331 pxDummy->xItemLen = 0; //Dummy data should have no length 332 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to wrap around 333 } 334 335 //Item should be guaranteed to fit at this point. Set item header and copy data 336 ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; 337 pxHeader->xItemLen = xItemSize; 338 pxHeader->uxItemFlags = 0; 339 340 //hold the buffer address without touching pucWrite 341 uint8_t* item_address = pxRingbuffer->pucAcquire + rbHEADER_SIZE; 342 pxRingbuffer->pucAcquire += rbHEADER_SIZE + xAlignedItemSize; //Advance pucAcquire past header and the item to next aligned address 343 344 //After the allocation, add some padding after the buffer and correct the flags 345 //If current remaining length can't fit a header, wrap around write pointer 346 if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { 347 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire 348 } 349 //Check if buffer is full 350 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { 351 //Mark the buffer as full to distinguish with an empty buffer 352 pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; 353 } 354 return item_address; 355 } 356 357 static void prvSendItemDoneNoSplit(Ringbuffer_t *pxRingbuffer, uint8_t* pucItem) 358 { 359 //Check arguments and buffer state 360 configASSERT(rbCHECK_ALIGNED(pucItem)); 361 configASSERT(pucItem >= pxRingbuffer->pucHead); 362 configASSERT(pucItem <= pxRingbuffer->pucTail); //Inclusive of pucTail in the case of zero length item at the very end 363 364 //Get and check header of the item 365 ItemHeader_t *pxCurHeader = (ItemHeader_t *)(pucItem - rbHEADER_SIZE); 366 configASSERT(pxCurHeader->xItemLen <= pxRingbuffer->xMaxItemSize); 367 configASSERT((pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) == 0); //Dummy items should never have been written 368 configASSERT((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) == 0); //Indicates item has already been written before 369 pxCurHeader->uxItemFlags &= ~rbITEM_SPLIT_FLAG; //Clear wrap flag if set (not strictly necessary) 370 pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as written 371 372 pxRingbuffer->xItemsWaiting++; 373 374 /* 375 * Items might not be written in the order they were acquired. Move the 376 * write pointer up to the next item that has not been marked as written (by 377 * written flag) or up till the acquire pointer. When advancing the write 378 * pointer, items that have already been written or items with dummy data 379 * should be skipped over 380 */ 381 pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; 382 //Skip over Items that have already been written or are dummy items 383 while (((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) || (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG)) && pxRingbuffer->pucWrite != pxRingbuffer->pucAcquire) { 384 if (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) { 385 pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as freed (not strictly necessary but adds redundancy) 386 pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around due to dummy data 387 } else { 388 //Item with data that has already been written, advance write pointer past this item 389 size_t xAlignedItemSize = rbALIGN_SIZE(pxCurHeader->xItemLen); 390 pxRingbuffer->pucWrite += xAlignedItemSize + rbHEADER_SIZE; 391 //Redundancy check to ensure write pointer has not overshot buffer bounds 392 configASSERT(pxRingbuffer->pucWrite <= pxRingbuffer->pucHead + pxRingbuffer->xSize); 393 } 394 //Check if pucAcquire requires wrap around 395 if ((pxRingbuffer->pucTail - pxRingbuffer->pucWrite) < rbHEADER_SIZE) { 396 pxRingbuffer->pucWrite = pxRingbuffer->pucHead; 397 } 398 pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; //Update header to point to item 399 } 400 } 401 402 static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) 403 { 404 uint8_t* item_addr = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); 405 memcpy(item_addr, pucItem, xItemSize); 406 prvSendItemDoneNoSplit(pxRingbuffer, item_addr); 407 } 408 409 static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) 410 { 411 //Check arguments and buffer state 412 size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size 413 size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer 414 configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in split ring buffers 415 configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds 416 configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header 417 418 //Split item if necessary 419 if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { 420 //Write first part of the item 421 ItemHeader_t *pxFirstHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; 422 pxFirstHeader->uxItemFlags = 0; 423 pxFirstHeader->xItemLen = xRemLen - rbHEADER_SIZE; //Fill remaining length with first part 424 pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance pucAcquire past header 425 xRemLen -= rbHEADER_SIZE; 426 if (xRemLen > 0) { 427 memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); 428 pxRingbuffer->xItemsWaiting++; 429 //Update item arguments to account for data already copied 430 pucItem += xRemLen; 431 xItemSize -= xRemLen; 432 xAlignedItemSize -= xRemLen; 433 pxFirstHeader->uxItemFlags |= rbITEM_SPLIT_FLAG; //There must be more data 434 } else { 435 //Remaining length was only large enough to fit header 436 pxFirstHeader->uxItemFlags |= rbITEM_DUMMY_DATA_FLAG; //Item will completely be stored in 2nd part 437 } 438 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer 439 } 440 441 //Item (whole or second part) should be guaranteed to fit at this point 442 ItemHeader_t *pxSecondHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; 443 pxSecondHeader->xItemLen = xItemSize; 444 pxSecondHeader->uxItemFlags = 0; 445 pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance acquire pointer past header 446 memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); 447 pxRingbuffer->xItemsWaiting++; 448 pxRingbuffer->pucAcquire += xAlignedItemSize; //Advance pucAcquire past item to next aligned address 449 450 //If current remaining length can't fit a header, wrap around write pointer 451 if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { 452 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire 453 } 454 //Check if buffer is full 455 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { 456 //Mark the buffer as full to distinguish with an empty buffer 457 pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; 458 } 459 460 //currently the Split mode is not supported, pucWrite tracks the pucAcquire 461 pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; 462 } 463 464 static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) 465 { 466 //Check arguments and buffer state 467 configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds 468 469 size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer 470 if (xRemLen < xItemSize) { 471 //Copy as much as possible into remaining length 472 memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); 473 pxRingbuffer->xItemsWaiting += xRemLen; 474 //Update item arguments to account for data already written 475 pucItem += xRemLen; 476 xItemSize -= xRemLen; 477 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer 478 } 479 //Copy all or remaining portion of the item 480 memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); 481 pxRingbuffer->xItemsWaiting += xItemSize; 482 pxRingbuffer->pucAcquire += xItemSize; 483 484 //Wrap around pucAcquire if it reaches the end 485 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucTail) { 486 pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; 487 } 488 //Check if buffer is full 489 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { 490 pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; //Mark the buffer as full to avoid confusion with an empty buffer 491 } 492 493 //Currently, acquiring memory is not supported in byte mode. pucWrite tracks the pucAcquire. 494 pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; 495 } 496 497 static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer) 498 { 499 if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && pxRingbuffer->pucRead != pxRingbuffer->pucFree) { 500 return pdFALSE; //Byte buffers do not allow multiple retrievals before return 501 } 502 if ((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))) { 503 return pdTRUE; //Items/data available for retrieval 504 } else { 505 return pdFALSE; //No items/data available for retrieval 506 } 507 } 508 509 static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, 510 BaseType_t *pxIsSplit, 511 size_t xUnusedParam, 512 size_t *pxItemSize) 513 { 514 //Check arguments and buffer state 515 ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead; 516 configASSERT(pxIsSplit != NULL); 517 configASSERT((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))); //Check there are items to be read 518 configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucRead)); //pucRead is always aligned in split ring buffers 519 configASSERT(pxRingbuffer->pucRead >= pxRingbuffer->pucHead && pxRingbuffer->pucRead < pxRingbuffer->pucTail); //Check read pointer is within bounds 520 configASSERT((pxHeader->xItemLen <= pxRingbuffer->xMaxItemSize) || (pxHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG)); 521 522 uint8_t *pcReturn; 523 //Wrap around if dummy data (dummy data indicates wrap around in no-split buffers) 524 if (pxHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) { 525 pxRingbuffer->pucRead = pxRingbuffer->pucHead; 526 //Check for errors with the next item 527 pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead; 528 configASSERT(pxHeader->xItemLen <= pxRingbuffer->xMaxItemSize); 529 } 530 pcReturn = pxRingbuffer->pucRead + rbHEADER_SIZE; //Get pointer to part of item containing data (point past the header) 531 if (pxHeader->xItemLen == 0) { 532 //Inclusive of pucTail for special case where item of zero length just fits at the end of the buffer 533 configASSERT(pcReturn >= pxRingbuffer->pucHead && pcReturn <= pxRingbuffer->pucTail); 534 } else { 535 //Exclusive of pucTali if length is larger than zero, pcReturn should never point to pucTail 536 configASSERT(pcReturn >= pxRingbuffer->pucHead && pcReturn < pxRingbuffer->pucTail); 537 } 538 *pxItemSize = pxHeader->xItemLen; //Get length of item 539 pxRingbuffer->xItemsWaiting --; //Update item count 540 *pxIsSplit = (pxHeader->uxItemFlags & rbITEM_SPLIT_FLAG) ? pdTRUE : pdFALSE; 541 542 pxRingbuffer->pucRead += rbHEADER_SIZE + rbALIGN_SIZE(pxHeader->xItemLen); //Update pucRead 543 //Check if pucRead requires wrap around 544 if ((pxRingbuffer->pucTail - pxRingbuffer->pucRead) < rbHEADER_SIZE) { 545 pxRingbuffer->pucRead = pxRingbuffer->pucHead; 546 } 547 return (void *)pcReturn; 548 } 549 550 static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, 551 BaseType_t *pxUnusedParam, 552 size_t xMaxSize, 553 size_t *pxItemSize) 554 { 555 //Check arguments and buffer state 556 configASSERT((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))); //Check there are items to be read 557 configASSERT(pxRingbuffer->pucRead >= pxRingbuffer->pucHead && pxRingbuffer->pucRead < pxRingbuffer->pucTail); //Check read pointer is within bounds 558 configASSERT(pxRingbuffer->pucRead == pxRingbuffer->pucFree); 559 560 uint8_t *ret = pxRingbuffer->pucRead; 561 if ((pxRingbuffer->pucRead > pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG)) { //Available data wraps around 562 //Return contiguous piece from read pointer until buffer tail, or xMaxSize 563 if (xMaxSize == 0 || pxRingbuffer->pucTail - pxRingbuffer->pucRead <= xMaxSize) { 564 //All contiguous data from read pointer to tail 565 *pxItemSize = pxRingbuffer->pucTail - pxRingbuffer->pucRead; 566 pxRingbuffer->xItemsWaiting -= pxRingbuffer->pucTail - pxRingbuffer->pucRead; 567 pxRingbuffer->pucRead = pxRingbuffer->pucHead; //Wrap around read pointer 568 } else { 569 //Return xMaxSize amount of data 570 *pxItemSize = xMaxSize; 571 pxRingbuffer->xItemsWaiting -= xMaxSize; 572 pxRingbuffer->pucRead += xMaxSize; //Advance read pointer past retrieved data 573 } 574 } else { //Available data is contiguous between read and write pointer 575 if (xMaxSize == 0 || pxRingbuffer->pucWrite - pxRingbuffer->pucRead <= xMaxSize) { 576 //Return all contiguous data from read to write pointer 577 *pxItemSize = pxRingbuffer->pucWrite - pxRingbuffer->pucRead; 578 pxRingbuffer->xItemsWaiting -= pxRingbuffer->pucWrite - pxRingbuffer->pucRead; 579 pxRingbuffer->pucRead = pxRingbuffer->pucWrite; 580 } else { 581 //Return xMaxSize data from read pointer 582 *pxItemSize = xMaxSize; 583 pxRingbuffer->xItemsWaiting -= xMaxSize; 584 pxRingbuffer->pucRead += xMaxSize; //Advance read pointer past retrieved data 585 586 } 587 } 588 return (void *)ret; 589 } 590 591 static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem) 592 { 593 //Check arguments and buffer state 594 configASSERT(rbCHECK_ALIGNED(pucItem)); 595 configASSERT(pucItem >= pxRingbuffer->pucHead); 596 configASSERT(pucItem <= pxRingbuffer->pucTail); //Inclusive of pucTail in the case of zero length item at the very end 597 598 //Get and check header of the item 599 ItemHeader_t *pxCurHeader = (ItemHeader_t *)(pucItem - rbHEADER_SIZE); 600 configASSERT(pxCurHeader->xItemLen <= pxRingbuffer->xMaxItemSize); 601 configASSERT((pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) == 0); //Dummy items should never have been read 602 configASSERT((pxCurHeader->uxItemFlags & rbITEM_FREE_FLAG) == 0); //Indicates item has already been returned before 603 pxCurHeader->uxItemFlags &= ~rbITEM_SPLIT_FLAG; //Clear wrap flag if set (not strictly necessary) 604 pxCurHeader->uxItemFlags |= rbITEM_FREE_FLAG; //Mark as free 605 606 /* 607 * Items might not be returned in the order they were retrieved. Move the free pointer 608 * up to the next item that has not been marked as free (by free flag) or up 609 * till the read pointer. When advancing the free pointer, items that have already been 610 * freed or items with dummy data should be skipped over 611 */ 612 pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucFree; 613 //Skip over Items that have already been freed or are dummy items 614 while (((pxCurHeader->uxItemFlags & rbITEM_FREE_FLAG) || (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG)) && pxRingbuffer->pucFree != pxRingbuffer->pucRead) { 615 if (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) { 616 pxCurHeader->uxItemFlags |= rbITEM_FREE_FLAG; //Mark as freed (not strictly necessary but adds redundancy) 617 pxRingbuffer->pucFree = pxRingbuffer->pucHead; //Wrap around due to dummy data 618 } else { 619 //Item with data that has already been freed, advance free pointer past this item 620 size_t xAlignedItemSize = rbALIGN_SIZE(pxCurHeader->xItemLen); 621 pxRingbuffer->pucFree += xAlignedItemSize + rbHEADER_SIZE; 622 //Redundancy check to ensure free pointer has not overshot buffer bounds 623 configASSERT(pxRingbuffer->pucFree <= pxRingbuffer->pucHead + pxRingbuffer->xSize); 624 } 625 //Check if pucRead requires wrap around 626 if ((pxRingbuffer->pucTail - pxRingbuffer->pucFree) < rbHEADER_SIZE) { 627 pxRingbuffer->pucFree = pxRingbuffer->pucHead; 628 } 629 pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucFree; //Update header to point to item 630 } 631 632 //Check if the buffer full flag should be reset 633 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 634 if (pxRingbuffer->pucFree != pxRingbuffer->pucAcquire) { 635 pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; 636 } else if (pxRingbuffer->pucFree == pxRingbuffer->pucAcquire && pxRingbuffer->pucFree == pxRingbuffer->pucRead) { 637 //Special case where a full buffer is completely freed in one go 638 pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; 639 } 640 } 641 } 642 643 static void prvReturnItemByteBuf(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem) 644 { 645 //Check pointer points to address inside buffer 646 configASSERT((uint8_t *)pucItem >= pxRingbuffer->pucHead); 647 configASSERT((uint8_t *)pucItem < pxRingbuffer->pucTail); 648 //Free the read memory. Simply moves free pointer to read pointer as byte buffers do not allow multiple outstanding reads 649 pxRingbuffer->pucFree = pxRingbuffer->pucRead; 650 //If buffer was full before, reset full flag as free pointer has moved 651 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 652 pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; 653 } 654 } 655 656 static size_t prvGetCurMaxSizeNoSplit(Ringbuffer_t *pxRingbuffer) 657 { 658 BaseType_t xFreeSize; 659 //Check if buffer is full 660 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 661 return 0; 662 } 663 if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { 664 //Free space is contiguous between pucAcquire and pucFree 665 xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; 666 } else { 667 //Free space wraps around (or overlapped at pucHead), select largest 668 //contiguous free space as no-split items require contiguous space 669 size_t xSize1 = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; 670 size_t xSize2 = pxRingbuffer->pucFree - pxRingbuffer->pucHead; 671 xFreeSize = (xSize1 > xSize2) ? xSize1 : xSize2; 672 } 673 674 //No-split ring buffer items need space for a header 675 xFreeSize -= rbHEADER_SIZE; 676 //Limit free size to be within bounds 677 if (xFreeSize > pxRingbuffer->xMaxItemSize) { 678 xFreeSize = pxRingbuffer->xMaxItemSize; 679 } else if (xFreeSize < 0) { 680 //Occurs when free space is less than header size 681 xFreeSize = 0; 682 } 683 return xFreeSize; 684 } 685 686 static size_t prvGetCurMaxSizeAllowSplit(Ringbuffer_t *pxRingbuffer) 687 { 688 BaseType_t xFreeSize; 689 //Check if buffer is full 690 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 691 return 0; 692 } 693 if (pxRingbuffer->pucAcquire == pxRingbuffer->pucHead && pxRingbuffer->pucFree == pxRingbuffer->pucHead) { 694 //Check for special case where pucAcquire and pucFree are both at pucHead 695 xFreeSize = pxRingbuffer->xSize - rbHEADER_SIZE; 696 } else if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { 697 //Free space is contiguous between pucAcquire and pucFree, requires single header 698 xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) - rbHEADER_SIZE; 699 } else { 700 //Free space wraps around, requires two headers 701 xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucHead) + 702 (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) - 703 (rbHEADER_SIZE * 2); 704 } 705 706 //Limit free size to be within bounds 707 if (xFreeSize > pxRingbuffer->xMaxItemSize) { 708 xFreeSize = pxRingbuffer->xMaxItemSize; 709 } else if (xFreeSize < 0) { 710 xFreeSize = 0; 711 } 712 return xFreeSize; 713 } 714 715 static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer) 716 { 717 BaseType_t xFreeSize; 718 //Check if buffer is full 719 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { 720 return 0; 721 } 722 723 /* 724 * Return whatever space is available depending on relative positions of the free 725 * pointer and Acquire pointer. There is no overhead of headers in this mode 726 */ 727 xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; 728 if (xFreeSize <= 0) { 729 xFreeSize += pxRingbuffer->xSize; 730 } 731 return xFreeSize; 732 } 733 734 static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, 735 void **pvItem1, 736 void **pvItem2, 737 size_t *xItemSize1, 738 size_t *xItemSize2, 739 size_t xMaxSize, 740 TickType_t xTicksToWait) 741 { 742 BaseType_t xReturn = pdFALSE; 743 BaseType_t xReturnSemaphore = pdFALSE; 744 TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait; 745 TickType_t xTicksRemaining = xTicksToWait; 746 while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end 747 //Block until more free space becomes available or timeout 748 if (xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { 749 xReturn = pdFALSE; //Timed out attempting to get semaphore 750 break; 751 } 752 753 //Semaphore obtained, check if item can be retrieved 754 portENTER_CRITICAL(&pxRingbuffer->mux); 755 if (prvCheckItemAvail(pxRingbuffer) == pdTRUE) { 756 //Item is available for retrieval 757 BaseType_t xIsSplit; 758 if (pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) { 759 //Second argument (pxIsSplit) is unused for byte buffers 760 *pvItem1 = pxRingbuffer->pvGetItem(pxRingbuffer, NULL, xMaxSize, xItemSize1); 761 } else { 762 //Third argument (xMaxSize) is unused for no-split/allow-split buffers 763 *pvItem1 = pxRingbuffer->pvGetItem(pxRingbuffer, &xIsSplit, 0, xItemSize1); 764 } 765 //Check for item split if configured to do so 766 if ((pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG) && (pvItem2 != NULL) && (xItemSize2 != NULL)) { 767 if (xIsSplit == pdTRUE) { 768 *pvItem2 = pxRingbuffer->pvGetItem(pxRingbuffer, &xIsSplit, 0, xItemSize2); 769 configASSERT(*pvItem2 < *pvItem1); //Check wrap around has occurred 770 configASSERT(xIsSplit == pdFALSE); //Second part should not have wrapped flag 771 } else { 772 *pvItem2 = NULL; 773 } 774 } 775 xReturn = pdTRUE; 776 if (pxRingbuffer->xItemsWaiting > 0) { 777 xReturnSemaphore = pdTRUE; 778 } 779 portEXIT_CRITICAL(&pxRingbuffer->mux); 780 break; 781 } 782 //No item available for retrieval, adjust ticks and take the semaphore again 783 if (xTicksToWait != portMAX_DELAY) { 784 xTicksRemaining = xTicksEnd - xTaskGetTickCount(); 785 } 786 portEXIT_CRITICAL(&pxRingbuffer->mux); 787 /* 788 * Gap between critical section and re-acquiring of the semaphore. If 789 * semaphore is given now, priority inversion might occur (see docs) 790 */ 791 } 792 793 if (xReturnSemaphore == pdTRUE) { 794 xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); //Give semaphore back so other tasks can retrieve 795 } 796 return xReturn; 797 } 798 799 static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, 800 void **pvItem1, 801 void **pvItem2, 802 size_t *xItemSize1, 803 size_t *xItemSize2, 804 size_t xMaxSize) 805 { 806 BaseType_t xReturn = pdFALSE; 807 BaseType_t xReturnSemaphore = pdFALSE; 808 809 portENTER_CRITICAL_ISR(&pxRingbuffer->mux); 810 if(prvCheckItemAvail(pxRingbuffer) == pdTRUE) { 811 BaseType_t xIsSplit; 812 if (pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) { 813 //Second argument (pxIsSplit) is unused for byte buffers 814 *pvItem1 = pxRingbuffer->pvGetItem(pxRingbuffer, NULL, xMaxSize, xItemSize1); 815 } else { 816 //Third argument (xMaxSize) is unused for no-split/allow-split buffers 817 *pvItem1 = pxRingbuffer->pvGetItem(pxRingbuffer, &xIsSplit, 0, xItemSize1); 818 } 819 //Check for item split if configured to do so 820 if ((pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG) && pvItem2 != NULL && xItemSize2 != NULL) { 821 if (xIsSplit == pdTRUE) { 822 *pvItem2 = pxRingbuffer->pvGetItem(pxRingbuffer, &xIsSplit, 0, xItemSize2); 823 configASSERT(*pvItem2 < *pvItem1); //Check wrap around has occurred 824 configASSERT(xIsSplit == pdFALSE); //Second part should not have wrapped flag 825 } else { 826 *pvItem2 = NULL; 827 } 828 } 829 xReturn = pdTRUE; 830 if (pxRingbuffer->xItemsWaiting > 0) { 831 xReturnSemaphore = pdTRUE; 832 } 833 } 834 portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); 835 836 if (xReturnSemaphore == pdTRUE) { 837 xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), NULL); //Give semaphore back so other tasks can retrieve 838 } 839 return xReturn; 840 } 841 842 /* --------------------------- Public Definitions --------------------------- */ 843 844 RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType) 845 { 846 configASSERT(xBufferSize > 0); 847 configASSERT(xBufferType < RINGBUF_TYPE_MAX); 848 849 //Allocate memory 850 if (xBufferType != RINGBUF_TYPE_BYTEBUF) { 851 xBufferSize = rbALIGN_SIZE(xBufferSize); //xBufferSize is rounded up for no-split/allow-split buffers 852 } 853 Ringbuffer_t *pxNewRingbuffer = calloc(1, sizeof(Ringbuffer_t)); 854 uint8_t *pucRingbufferStorage = malloc(xBufferSize); 855 if (pxNewRingbuffer == NULL || pucRingbufferStorage == NULL) { 856 goto err; 857 } 858 859 //Initialize Semaphores 860 #if ( configSUPPORT_STATIC_ALLOCATION == 1) 861 //We don't use the handles for static semaphores, and xSemaphoreCreateBinaryStatic will never fail thus no need to check static case 862 xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic)); 863 xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic)); 864 #else 865 pxNewRingbuffer->xTransSemHandle = xSemaphoreCreateBinary(); 866 pxNewRingbuffer->xRecvSemHandle = xSemaphoreCreateBinary(); 867 if (pxNewRingbuffer->xTransSemHandle == NULL || pxNewRingbuffer->xRecvSemHandle == NULL) { 868 if (pxNewRingbuffer->xTransSemHandle != NULL) { 869 vSemaphoreDelete(pxNewRingbuffer->xTransSemHandle); 870 } 871 if (pxNewRingbuffer->xRecvSemHandle != NULL) { 872 vSemaphoreDelete(pxNewRingbuffer->xRecvSemHandle); 873 } 874 goto err; 875 } 876 #endif 877 878 prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage); 879 return (RingbufHandle_t)pxNewRingbuffer; 880 881 err: 882 //An error has occurred, Free memory and return NULL 883 free(pxNewRingbuffer); 884 free(pucRingbufferStorage); 885 return NULL; 886 } 887 888 RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum) 889 { 890 return xRingbufferCreate((rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE) * xItemNum, RINGBUF_TYPE_NOSPLIT); 891 } 892 893 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 894 RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize, 895 RingbufferType_t xBufferType, 896 uint8_t *pucRingbufferStorage, 897 StaticRingbuffer_t *pxStaticRingbuffer) 898 { 899 //Check arguments 900 configASSERT(xBufferSize > 0); 901 configASSERT(xBufferType < RINGBUF_TYPE_MAX); 902 configASSERT(pucRingbufferStorage != NULL && pxStaticRingbuffer != NULL); 903 if (xBufferType != RINGBUF_TYPE_BYTEBUF) { 904 //No-split/allow-split buffer sizes must be 32-bit aligned 905 configASSERT(rbCHECK_ALIGNED(xBufferSize)); 906 } 907 908 Ringbuffer_t *pxNewRingbuffer = (Ringbuffer_t *)pxStaticRingbuffer; 909 xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic)); 910 xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic)); 911 prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage); 912 pxNewRingbuffer->uxRingbufferFlags |= rbBUFFER_STATIC_FLAG; 913 return (RingbufHandle_t)pxNewRingbuffer; 914 } 915 #endif 916 917 BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, size_t xItemSize, TickType_t xTicksToWait) 918 { 919 //Check arguments 920 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 921 configASSERT(pxRingbuffer); 922 configASSERT(ppvItem != NULL || xItemSize == 0); 923 //currently only supported in NoSplit buffers 924 configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); 925 926 *ppvItem = NULL; 927 if (xItemSize > pxRingbuffer->xMaxItemSize) { 928 return pdFALSE; //Data will never ever fit in the queue. 929 } 930 if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) { 931 return pdTRUE; //Sending 0 bytes to byte buffer has no effect 932 } 933 934 //Attempt to send an item 935 BaseType_t xReturn = pdFALSE; 936 BaseType_t xReturnSemaphore = pdFALSE; 937 TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait; 938 TickType_t xTicksRemaining = xTicksToWait; 939 while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end 940 //Block until more free space becomes available or timeout 941 if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { 942 xReturn = pdFALSE; 943 break; 944 } 945 946 //Semaphore obtained, check if item can fit 947 portENTER_CRITICAL(&pxRingbuffer->mux); 948 if(pxRingbuffer->xCheckItemFits(pxRingbuffer, xItemSize) == pdTRUE) { 949 //Item will fit, copy item 950 *ppvItem = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); 951 xReturn = pdTRUE; 952 //Check if the free semaphore should be returned to allow other tasks to send 953 if (prvGetFreeSize(pxRingbuffer) > 0) { 954 xReturnSemaphore = pdTRUE; 955 } 956 portEXIT_CRITICAL(&pxRingbuffer->mux); 957 break; 958 } 959 //Item doesn't fit, adjust ticks and take the semaphore again 960 if (xTicksToWait != portMAX_DELAY) { 961 xTicksRemaining = xTicksEnd - xTaskGetTickCount(); 962 } 963 portEXIT_CRITICAL(&pxRingbuffer->mux); 964 /* 965 * Gap between critical section and re-acquiring of the semaphore. If 966 * semaphore is given now, priority inversion might occur (see docs) 967 */ 968 } 969 970 if (xReturnSemaphore == pdTRUE) { 971 xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can acquire 972 } 973 return xReturn; 974 } 975 976 BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem) 977 { 978 //Check arguments 979 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 980 configASSERT(pxRingbuffer); 981 configASSERT(pvItem != NULL); 982 configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); 983 984 portENTER_CRITICAL(&pxRingbuffer->mux); 985 prvSendItemDoneNoSplit(pxRingbuffer, pvItem); 986 portEXIT_CRITICAL(&pxRingbuffer->mux); 987 988 xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); 989 return pdTRUE; 990 } 991 992 BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, 993 const void *pvItem, 994 size_t xItemSize, 995 TickType_t xTicksToWait) 996 { 997 //Check arguments 998 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 999 configASSERT(pxRingbuffer); 1000 configASSERT(pvItem != NULL || xItemSize == 0); 1001 if (xItemSize > pxRingbuffer->xMaxItemSize) { 1002 return pdFALSE; //Data will never ever fit in the queue. 1003 } 1004 if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) { 1005 return pdTRUE; //Sending 0 bytes to byte buffer has no effect 1006 } 1007 1008 //Attempt to send an item 1009 BaseType_t xReturn = pdFALSE; 1010 BaseType_t xReturnSemaphore = pdFALSE; 1011 TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait; 1012 TickType_t xTicksRemaining = xTicksToWait; 1013 while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end 1014 //Block until more free space becomes available or timeout 1015 if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { 1016 xReturn = pdFALSE; 1017 break; 1018 } 1019 //Semaphore obtained, check if item can fit 1020 portENTER_CRITICAL(&pxRingbuffer->mux); 1021 if(pxRingbuffer->xCheckItemFits(pxRingbuffer, xItemSize) == pdTRUE) { 1022 //Item will fit, copy item 1023 pxRingbuffer->vCopyItem(pxRingbuffer, pvItem, xItemSize); 1024 xReturn = pdTRUE; 1025 //Check if the free semaphore should be returned to allow other tasks to send 1026 if (prvGetFreeSize(pxRingbuffer) > 0) { 1027 xReturnSemaphore = pdTRUE; 1028 } 1029 portEXIT_CRITICAL(&pxRingbuffer->mux); 1030 break; 1031 } 1032 //Item doesn't fit, adjust ticks and take the semaphore again 1033 if (xTicksToWait != portMAX_DELAY) { 1034 xTicksRemaining = xTicksEnd - xTaskGetTickCount(); 1035 } 1036 portEXIT_CRITICAL(&pxRingbuffer->mux); 1037 /* 1038 * Gap between critical section and re-acquiring of the semaphore. If 1039 * semaphore is given now, priority inversion might occur (see docs) 1040 */ 1041 } 1042 1043 if (xReturn == pdTRUE) { 1044 //Indicate item was successfully sent 1045 xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); 1046 } 1047 if (xReturnSemaphore == pdTRUE) { 1048 xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can send 1049 } 1050 return xReturn; 1051 } 1052 1053 BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, 1054 const void *pvItem, 1055 size_t xItemSize, 1056 BaseType_t *pxHigherPriorityTaskWoken) 1057 { 1058 //Check arguments 1059 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1060 configASSERT(pxRingbuffer); 1061 configASSERT(pvItem != NULL || xItemSize == 0); 1062 if (xItemSize > pxRingbuffer->xMaxItemSize) { 1063 return pdFALSE; //Data will never ever fit in the queue. 1064 } 1065 if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) { 1066 return pdTRUE; //Sending 0 bytes to byte buffer has no effect 1067 } 1068 1069 //Attempt to send an item 1070 BaseType_t xReturn; 1071 BaseType_t xReturnSemaphore = pdFALSE; 1072 portENTER_CRITICAL_ISR(&pxRingbuffer->mux); 1073 if (pxRingbuffer->xCheckItemFits(xRingbuffer, xItemSize) == pdTRUE) { 1074 pxRingbuffer->vCopyItem(xRingbuffer, pvItem, xItemSize); 1075 xReturn = pdTRUE; 1076 //Check if the free semaphore should be returned to allow other tasks to send 1077 if (prvGetFreeSize(pxRingbuffer) > 0) { 1078 xReturnSemaphore = pdTRUE; 1079 } 1080 } else { 1081 xReturn = pdFALSE; 1082 } 1083 portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); 1084 1085 if (xReturn == pdTRUE) { 1086 //Indicate item was successfully sent 1087 xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); 1088 } 1089 if (xReturnSemaphore == pdTRUE) { 1090 xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); //Give back semaphore so other tasks can send 1091 } 1092 return xReturn; 1093 } 1094 1095 void *xRingbufferReceive(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait) 1096 { 1097 //Check arguments 1098 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1099 configASSERT(pxRingbuffer); 1100 1101 //Attempt to retrieve an item 1102 void *pvTempItem; 1103 size_t xTempSize; 1104 if (prvReceiveGeneric(pxRingbuffer, &pvTempItem, NULL, &xTempSize, NULL, 0, xTicksToWait) == pdTRUE) { 1105 if (pxItemSize != NULL) { 1106 *pxItemSize = xTempSize; 1107 } 1108 return pvTempItem; 1109 } else { 1110 return NULL; 1111 } 1112 } 1113 1114 void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) 1115 { 1116 //Check arguments 1117 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1118 configASSERT(pxRingbuffer); 1119 1120 //Attempt to retrieve an item 1121 void *pvTempItem; 1122 size_t xTempSize; 1123 if (prvReceiveGenericFromISR(pxRingbuffer, &pvTempItem, NULL, &xTempSize, NULL, 0) == pdTRUE) { 1124 if (pxItemSize != NULL) { 1125 *pxItemSize = xTempSize; 1126 } 1127 return pvTempItem; 1128 } else { 1129 return NULL; 1130 } 1131 } 1132 1133 BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, 1134 void **ppvHeadItem, 1135 void **ppvTailItem, 1136 size_t *pxHeadItemSize, 1137 size_t *pxTailItemSize, 1138 TickType_t xTicksToWait) 1139 { 1140 //Check arguments 1141 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1142 configASSERT(pxRingbuffer); 1143 configASSERT(pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG); 1144 configASSERT(ppvHeadItem != NULL && ppvTailItem != NULL); 1145 1146 //Attempt to retrieve multiple items 1147 void *pvTempHeadItem, *pvTempTailItem; 1148 size_t xTempHeadSize, xTempTailSize; 1149 if (prvReceiveGeneric(pxRingbuffer, &pvTempHeadItem, &pvTempTailItem, &xTempHeadSize, &xTempTailSize, 0, xTicksToWait) == pdTRUE) { 1150 //At least one item was retrieved 1151 *ppvHeadItem = pvTempHeadItem; 1152 if(pxHeadItemSize != NULL){ 1153 *pxHeadItemSize = xTempHeadSize; 1154 } 1155 //Check to see if a second item was also retrieved 1156 if (pvTempTailItem != NULL) { 1157 *ppvTailItem = pvTempTailItem; 1158 if (pxTailItemSize != NULL) { 1159 *pxTailItemSize = xTempTailSize; 1160 } 1161 } else { 1162 *ppvTailItem = NULL; 1163 } 1164 return pdTRUE; 1165 } else { 1166 //No items retrieved 1167 *ppvHeadItem = NULL; 1168 *ppvTailItem = NULL; 1169 return pdFALSE; 1170 } 1171 } 1172 1173 BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, 1174 void **ppvHeadItem, 1175 void **ppvTailItem, 1176 size_t *pxHeadItemSize, 1177 size_t *pxTailItemSize) 1178 { 1179 //Check arguments 1180 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1181 configASSERT(pxRingbuffer); 1182 configASSERT(pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG); 1183 configASSERT(ppvHeadItem != NULL && ppvTailItem != NULL); 1184 1185 //Attempt to retrieve multiple items 1186 void *pvTempHeadItem = NULL, *pvTempTailItem = NULL; 1187 size_t xTempHeadSize, xTempTailSize; 1188 if (prvReceiveGenericFromISR(pxRingbuffer, &pvTempHeadItem, &pvTempTailItem, &xTempHeadSize, &xTempTailSize, 0) == pdTRUE) { 1189 //At least one item was received 1190 *ppvHeadItem = pvTempHeadItem; 1191 if (pxHeadItemSize != NULL) { 1192 *pxHeadItemSize = xTempHeadSize; 1193 } 1194 //Check to see if a second item was also retrieved 1195 if (pvTempTailItem != NULL) { 1196 *ppvTailItem = pvTempTailItem; 1197 if (pxTailItemSize != NULL) { 1198 *pxTailItemSize = xTempTailSize; 1199 } 1200 } else { 1201 *ppvTailItem = NULL; 1202 } 1203 return pdTRUE; 1204 } else { 1205 *ppvHeadItem = NULL; 1206 *ppvTailItem = NULL; 1207 return pdFALSE; 1208 } 1209 } 1210 1211 void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, 1212 size_t *pxItemSize, 1213 TickType_t xTicksToWait, 1214 size_t xMaxSize) 1215 { 1216 //Check arguments 1217 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1218 configASSERT(pxRingbuffer); 1219 configASSERT(pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG); //This function should only be called for byte buffers 1220 if (xMaxSize == 0) { 1221 return NULL; 1222 } 1223 1224 //Attempt to retrieve up to xMaxSize bytes 1225 void *pvTempItem; 1226 size_t xTempSize; 1227 if (prvReceiveGeneric(pxRingbuffer, &pvTempItem, NULL, &xTempSize, NULL, xMaxSize, xTicksToWait) == pdTRUE) { 1228 if (pxItemSize != NULL) { 1229 *pxItemSize = xTempSize; 1230 } 1231 return pvTempItem; 1232 } else { 1233 return NULL; 1234 } 1235 } 1236 1237 void *xRingbufferReceiveUpToFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize, size_t xMaxSize) 1238 { 1239 //Check arguments 1240 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1241 configASSERT(pxRingbuffer); 1242 configASSERT(pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG); //This function should only be called for byte buffers 1243 if (xMaxSize == 0) { 1244 return NULL; 1245 } 1246 1247 //Attempt to retrieve up to xMaxSize bytes 1248 void *pvTempItem; 1249 size_t xTempSize; 1250 if (prvReceiveGenericFromISR(pxRingbuffer, &pvTempItem, NULL, &xTempSize, NULL, xMaxSize) == pdTRUE) { 1251 if (pxItemSize != NULL) { 1252 *pxItemSize = xTempSize; 1253 } 1254 return pvTempItem; 1255 } else { 1256 return NULL; 1257 } 1258 } 1259 1260 void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem) 1261 { 1262 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1263 configASSERT(pxRingbuffer); 1264 configASSERT(pvItem != NULL); 1265 1266 portENTER_CRITICAL(&pxRingbuffer->mux); 1267 pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem); 1268 portEXIT_CRITICAL(&pxRingbuffer->mux); 1269 xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); 1270 } 1271 1272 void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken) 1273 { 1274 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1275 configASSERT(pxRingbuffer); 1276 configASSERT(pvItem != NULL); 1277 1278 portENTER_CRITICAL_ISR(&pxRingbuffer->mux); 1279 pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem); 1280 portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); 1281 xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); 1282 } 1283 1284 void vRingbufferDelete(RingbufHandle_t xRingbuffer) 1285 { 1286 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1287 configASSERT(pxRingbuffer); 1288 1289 vSemaphoreDelete(rbGET_TX_SEM_HANDLE(pxRingbuffer)); 1290 vSemaphoreDelete(rbGET_RX_SEM_HANDLE(pxRingbuffer)); 1291 1292 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 1293 if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_STATIC_FLAG) { 1294 //Ring buffer was statically allocated, no need to free 1295 return; 1296 } 1297 #endif 1298 free(pxRingbuffer->pucHead); 1299 free(pxRingbuffer); 1300 } 1301 1302 size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer) 1303 { 1304 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1305 configASSERT(pxRingbuffer); 1306 return pxRingbuffer->xMaxItemSize; 1307 } 1308 1309 size_t xRingbufferGetCurFreeSize(RingbufHandle_t xRingbuffer) 1310 { 1311 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1312 configASSERT(pxRingbuffer); 1313 1314 size_t xFreeSize; 1315 portENTER_CRITICAL(&pxRingbuffer->mux); 1316 xFreeSize = pxRingbuffer->xGetCurMaxSize(pxRingbuffer); 1317 portEXIT_CRITICAL(&pxRingbuffer->mux); 1318 return xFreeSize; 1319 } 1320 1321 BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) 1322 { 1323 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1324 configASSERT(pxRingbuffer); 1325 1326 BaseType_t xReturn; 1327 portENTER_CRITICAL(&pxRingbuffer->mux); 1328 //Cannot add semaphore to queue set if semaphore is not empty. Temporarily hold semaphore 1329 BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0); 1330 xReturn = xQueueAddToSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet); 1331 if (xHoldSemaphore == pdTRUE) { 1332 //Return semaphore if temporarily held 1333 configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE); 1334 } 1335 portEXIT_CRITICAL(&pxRingbuffer->mux); 1336 return xReturn; 1337 } 1338 1339 BaseType_t xRingbufferCanRead(RingbufHandle_t xRingbuffer, QueueSetMemberHandle_t xMember) 1340 { 1341 //Check if the selected queue set member is the ring buffer's read semaphore 1342 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1343 configASSERT(pxRingbuffer); 1344 return (rbGET_RX_SEM_HANDLE(pxRingbuffer) == xMember) ? pdTRUE : pdFALSE; 1345 } 1346 1347 BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) 1348 { 1349 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1350 configASSERT(pxRingbuffer); 1351 1352 BaseType_t xReturn; 1353 portENTER_CRITICAL(&pxRingbuffer->mux); 1354 //Cannot remove semaphore from queue set if semaphore is not empty. Temporarily hold semaphore 1355 BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0); 1356 xReturn = xQueueRemoveFromSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet); 1357 if (xHoldSemaphore == pdTRUE) { 1358 //Return semaphore if temporarily held 1359 configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE); 1360 } 1361 portEXIT_CRITICAL(&pxRingbuffer->mux); 1362 return xReturn; 1363 } 1364 1365 void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, 1366 UBaseType_t *uxFree, 1367 UBaseType_t *uxRead, 1368 UBaseType_t *uxWrite, 1369 UBaseType_t *uxAcquire, 1370 UBaseType_t *uxItemsWaiting) 1371 { 1372 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1373 configASSERT(pxRingbuffer); 1374 1375 portENTER_CRITICAL(&pxRingbuffer->mux); 1376 if (uxFree != NULL) { 1377 *uxFree = (UBaseType_t)(pxRingbuffer->pucFree - pxRingbuffer->pucHead); 1378 } 1379 if (uxRead != NULL) { 1380 *uxRead = (UBaseType_t)(pxRingbuffer->pucRead - pxRingbuffer->pucHead); 1381 } 1382 if (uxWrite != NULL) { 1383 *uxWrite = (UBaseType_t)(pxRingbuffer->pucWrite - pxRingbuffer->pucHead); 1384 } 1385 if (uxAcquire != NULL) { 1386 *uxAcquire = (UBaseType_t)(pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); 1387 } 1388 if (uxItemsWaiting != NULL) { 1389 *uxItemsWaiting = (UBaseType_t)(pxRingbuffer->xItemsWaiting); 1390 } 1391 portEXIT_CRITICAL(&pxRingbuffer->mux); 1392 } 1393 1394 void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer) 1395 { 1396 Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; 1397 configASSERT(pxRingbuffer); 1398 printf("Rb size:%d\tfree: %d\trptr: %d\tfreeptr: %d\twptr: %d, aptr: %d\n", 1399 pxRingbuffer->xSize, prvGetFreeSize(pxRingbuffer), 1400 pxRingbuffer->pucRead - pxRingbuffer->pucHead, 1401 pxRingbuffer->pucFree - pxRingbuffer->pucHead, 1402 pxRingbuffer->pucWrite - pxRingbuffer->pucHead, 1403 pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); 1404 } 1405