/ components / esp_ringbuf / ringbuf.c
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