]> granicus.if.org Git - esp-idf/commitdiff
esp_ringbuf: Add static allocation, refactor, and update API reference
authorDarian Leung <darian@espressif.com>
Mon, 4 Mar 2019 06:27:06 +0000 (14:27 +0800)
committerDarian Leung <darian@espressif.com>
Wed, 26 Jun 2019 08:04:38 +0000 (16:04 +0800)
This commit updates does the following:
    - xRingbufferCreateStatic() added to allow ringbuffers via to be statically
      allocated. Docs and unit tests update accordingly. Closes #3064

    - Fix doc typos, closes #3248. Updated API reference regarding to mention
      item size limits of no-split buffers when calling
      xRingbufferGetCurFreeSize() or xRingbufferGetMaxItemSize(), closes #3117.

    - Remove the following deprecated types/functions for v4.0
        - xRingbufferIsNextItemWrapped()
        - xRingbufferAddToQueueSetWrite()
        - xRingbufferRemoveFromQueueSetWrite()

components/esp_ringbuf/include/freertos/ringbuf.h
components/esp_ringbuf/ringbuf.c
components/esp_ringbuf/test/test_ringbuf.c
docs/en/api-reference/system/freertos_additions.rst

index de8a3690952ea5a96b864a1a86adaae94bf27536..fd3407e4a4fb37d1fff3b935faf00a5e34c5d62e 100644 (file)
@@ -16,7 +16,7 @@
 #define FREERTOS_RINGBUF_H
 
 #ifndef INC_FREERTOS_H
-       #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h"
+    #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h"
 #endif
 
 #ifdef __cplusplus
@@ -33,27 +33,52 @@ extern "C" {
 typedef void * RingbufHandle_t;
 
 typedef enum {
-       /**
-        * No-split buffers will only store an item in contiguous memory and will
-        * never split an item. Each item requires an 8 byte overhead for a header
-        * and will always internally occupy a 32-bit aligned size of space.
-        */
-       RINGBUF_TYPE_NOSPLIT = 0,
-       /**
-        * Allow-split buffers will split an item into two parts if necessary in
-        * order to store it. Each item requires an 8 byte overhead for a header,
-        * splitting incurs an extra header. Each item will always internally occupy
-        * a 32-bit aligned size of space.
-        */
-       RINGBUF_TYPE_ALLOWSPLIT,
-       /**
-        * Byte buffers store data as a sequence of bytes and do not maintain separate
-        * items, therefore byte buffers have no overhead. All data is stored as a
-        * sequence of byte and any number of bytes can be sent or retrieved each
-        * time.
-        */
-       RINGBUF_TYPE_BYTEBUF
-} ringbuf_type_t;
+    /**
+     * No-split buffers will only store an item in contiguous memory and will
+     * never split an item. Each item requires an 8 byte overhead for a header
+     * and will always internally occupy a 32-bit aligned size of space.
+     */
+    RINGBUF_TYPE_NOSPLIT = 0,
+    /**
+     * Allow-split buffers will split an item into two parts if necessary in
+     * order to store it. Each item requires an 8 byte overhead for a header,
+     * splitting incurs an extra header. Each item will always internally occupy
+     * a 32-bit aligned size of space.
+     */
+    RINGBUF_TYPE_ALLOWSPLIT,
+    /**
+     * Byte buffers store data as a sequence of bytes and do not maintain separate
+     * items, therefore byte buffers have no overhead. All data is stored as a
+     * sequence of byte and any number of bytes can be sent or retrieved each
+     * time.
+     */
+    RINGBUF_TYPE_BYTEBUF,
+    RINGBUF_TYPE_MAX,
+} RingbufferType_t;
+
+/**
+ * @brief Struct that is equivalent in size to the ring buffer's data structure
+ *
+ * The contents of this struct are not meant to be used directly. This
+ * structure is meant to be used when creating a statically allocated ring
+ * buffer where this struct is of the exact size required to store a ring
+ * buffer's control data structure.
+ *
+ * @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled for
+ *       this structure to be available.
+ */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+typedef struct xSTATIC_RINGBUFFER {
+    /** @cond */    //Doxygen command to hide this structure from API Reference
+    size_t xDummy1[2];
+    UBaseType_t uxDummy2;
+    BaseType_t xDummy3;
+    void *pvDummy4[10];
+    StaticSemaphore_t xDummy5[2];
+    portMUX_TYPE muxDummy;
+    /** @endcond */
+} StaticRingbuffer_t;
+#endif
 
 /**
  * @brief       Create a ring buffer
@@ -66,7 +91,7 @@ typedef enum {
  *
  * @return  A handle to the created ring buffer, or NULL in case of error.
  */
-RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType);
+RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType);
 
 /**
  * @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size
@@ -81,11 +106,36 @@ RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType
  */
 RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum);
 
+
+/**
+ * @brief       Create a ring buffer but manually provide the required memory
+ *
+ * @param[in]   xBufferSize Size of the buffer in bytes.
+ * @param[in]   xBufferType Type of ring buffer, see documentation
+ * @param[in]   pucRingbufferStorage Pointer to the ring buffer's storage area.
+ *              Storage area must of the same size as specified by xBufferSize
+ * @param[in]   pxStaticRingbuffer Pointed to a struct of type StaticRingbuffer_t
+ *              which will be used to hold the ring buffer's data structure
+ *
+ * @note    The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled
+ *          for this to be available
+ *
+ * @note    xBufferSize of no-split/allow-split buffers MUST be 32-bit aligned.
+ *
+ * @return  A handle to the created ring buffer
+ */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize,
+                                        RingbufferType_t xBufferType,
+                                        uint8_t *pucRingbufferStorage,
+                                        StaticRingbuffer_t *pxStaticRingbuffer);
+#endif
+
 /**
  * @brief       Insert an item into the ring buffer
  *
  * Attempt to insert an item into the ring buffer. This function will block until
- * enough free space is available or until it timesout.
+ * enough free space is available or until it times out.
  *
  * @param[in]   xRingbuffer     Ring buffer to insert the item into
  * @param[in]   pvItem          Pointer to data to insert. NULL is allowed if xItemSize is 0.
@@ -101,7 +151,10 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum);
  *      - pdTRUE if succeeded
  *      - pdFALSE on time-out or when the data is larger than the maximum permissible size of the buffer
  */
-BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait);
+BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer,
+                           const void *pvItem,
+                           size_t xItemSize,
+                           TickType_t xTicksToWait);
 
 /**
  * @brief       Insert an item into the ring buffer in an ISR
@@ -123,13 +176,16 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
  *      - pdTRUE if succeeded
  *      - pdFALSE when the ring buffer does not have space.
  */
-BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken);
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
+                                  const void *pvItem,
+                                  size_t xItemSize,
+                                  BaseType_t *pxHigherPriorityTaskWoken);
 
 /**
  * @brief   Retrieve an item from the ring buffer
  *
  * Attempt to retrieve an item from the ring buffer. This function will block
- * until an item is available or until it timesout.
+ * until an item is available or until it times out.
  *
  * @param[in]   xRingbuffer     Ring buffer to retrieve the item from
  * @param[out]  pxItemSize      Pointer to a variable to which the size of the retrieved item will be written.
@@ -168,7 +224,7 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
  * Attempt to retrieve a split item from an allow-split ring buffer. If the item
  * is not split, only a single item is retried. If the item is split, both parts
  * will be retrieved. This function will block until an item is available or
- * until it timesout.
+ * until it times out.
  *
  * @param[in]   xRingbuffer     Ring buffer to retrieve the item from
  * @param[out]  ppvHeadItem     Double pointer to first part (set to NULL if no items were retrieved)
@@ -184,7 +240,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
  *      - pdTRUE if an item (split or unsplit) was retrieved
  *      - pdFALSE when no item was retrieved
  */
-BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait);
+BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer,
+                                   void **ppvHeadItem,
+                                   void **ppvTailItem,
+                                   size_t *pxHeadItemSize,
+                                   size_t *pxTailItemSize,
+                                   TickType_t xTicksToWait);
 
 /**
  * @brief   Retrieve a split item from an allow-split ring buffer in an ISR
@@ -207,14 +268,18 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt
  *      - pdTRUE if an item (split or unsplit) was retrieved
  *      - pdFALSE when no item was retrieved
  */
-BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize);
+BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer,
+                                          void **ppvHeadItem,
+                                          void **ppvTailItem,
+                                          size_t *pxHeadItemSize,
+                                          size_t *pxTailItemSize);
 
 /**
  * @brief   Retrieve bytes from a byte buffer, specifying the maximum amount of bytes to retrieve
  *
  * Attempt to retrieve data from a byte buffer whilst specifying a maximum number
  * of bytes to retrieve. This function will block until there is data available
- * for retrieval or until it timesout.
+ * for retrieval or until it times out.
  *
  * @param[in]   xRingbuffer     Ring buffer to retrieve the item from
  * @param[out]  pxItemSize      Pointer to a variable to which the size of the retrieved item will be written.
@@ -230,7 +295,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp
  *        the length of the item.
  *      - NULL on timeout, *pxItemSize is untouched in that case.
  */
-void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize);
+void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer,
+                             size_t *pxItemSize,
+                             TickType_t xTicksToWait,
+                             size_t xMaxSize);
 
 /**
  * @brief   Retrieve bytes from a byte buffer, specifying the maximum amount of
@@ -281,6 +349,10 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas
  * @brief   Delete a ring buffer
  *
  * @param[in]   xRingbuffer     Ring buffer to delete
+ *
+ * @note    This function will not deallocate any memory if the ring buffer was
+ *          created using xRingbufferCreateStatic(). Deallocation must be done
+ *          manually be the user.
  */
 void vRingbufferDelete(RingbufHandle_t xRingbuffer);
 
@@ -292,6 +364,12 @@ void vRingbufferDelete(RingbufHandle_t xRingbuffer);
  *
  * @param[in]   xRingbuffer     Ring buffer to query
  *
+ * @note    The max item size for a no-split buffer is limited to
+ *          ((buffer_size/2)-header_size). This limit is imposed so that an item
+ *          of max item size can always be sent to the an empty no-split buffer
+ *          regardless of the internal positions of the buffer's read/write/free
+ *          pointers.
+ *
  * @return  Maximum size, in bytes, of an item that can be placed in a ring buffer.
  */
 size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer);
@@ -307,6 +385,10 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer);
  *          the same ring buffer, it is the application's responsibility to
  *          ensure atomic access to this API and the subsequent Send
  *
+ * @note    An empty no-split buffer has a max current free size for an item
+ *          that is limited to ((buffer_size/2)-header_size). See API reference
+ *          for xRingbufferGetMaxItemSize().
+ *
  * @param[in]   xRingbuffer     Ring buffer to query
  *
  * @return  Current free size, in bytes, available for an entry
@@ -373,7 +455,11 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS
  * @param[out]  uxWrite         Pointer use to store write pointer position
  * @param[out]  uxItemsWaiting  Pointer use to store number of items (bytes for byte buffer) waiting to be retrieved
  */
-void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting);
+void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
+                        UBaseType_t *uxFree,
+                        UBaseType_t *uxRead,
+                        UBaseType_t *uxWrite,
+                        UBaseType_t *uxItemsWaiting);
 
 /**
  * @brief   Debugging function to print the internal pointers in the ring buffer
@@ -382,30 +468,9 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseT
  */
 void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer);
 
-/* -------------------------------- Deprecated Functions --------------------------- */
+/* ------------------------------- Deprecated ------------------------------- */
 
-/** @cond */    //Doxygen command to hide deprecated function from API Reference
-/*
- * Deprecated as function is not thread safe and does not check if an item is
- * actually available for retrieval. Use xRingbufferReceiveSplit() instead for
- * thread safe method of retrieve a split item.
- */
-bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer) __attribute__((deprecated));
-
-/*
- * Deprecated as queue sets are not meant to be used for writing to buffers. Adding
- * the ring buffer write semaphore to a queue set will break queue set usage rules,
- * as every read of a semaphore must be preceded by a call to xQueueSelectFromSet().
- * QueueSetWrite no longer supported.
- */
-BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated));
-
-/*
- * Deprecated as queue sets are not meant to be used for writing to buffers.
- * QueueSetWrite no longer supported.
- */
-BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated));
-/** @endcond */
+typedef RingbufferType_t ringbuf_type_t __attribute__((deprecated));
 
 #ifdef __cplusplus
 }
index 558b61c6d8508a9469ae4b69fca9fb51604e617c..b3b43b0aae2a6c5343fb18c94627039c8580238d 100644 (file)
 
 //32-bit alignment macros
 #define rbALIGN_SIZE( xSize )       ( ( xSize + portBYTE_ALIGNMENT_MASK ) & ~portBYTE_ALIGNMENT_MASK )
-#define rbCHECK_ALIGNED( pvPtr )    ( ( ( UBaseType_t ) pvPtr & portBYTE_ALIGNMENT_MASK ) == 0 )
+#define rbCHECK_ALIGNED( pvPtr )    ( ( ( UBaseType_t ) ( pvPtr ) & portBYTE_ALIGNMENT_MASK ) == 0 )
 
 //Ring buffer flags
 #define rbALLOW_SPLIT_FLAG          ( ( UBaseType_t ) 1 )   //The ring buffer allows items to be split
 #define rbBYTE_BUFFER_FLAG          ( ( UBaseType_t ) 2 )   //The ring buffer is a byte buffer
 #define rbBUFFER_FULL_FLAG          ( ( UBaseType_t ) 4 )   //The ring buffer is currently full (write pointer == free pointer)
+#define rbBUFFER_STATIC_FLAG        ( ( UBaseType_t ) 8 )   //The ring buffer is statically allocated
 
 //Item flags
 #define rbITEM_FREE_FLAG            ( ( UBaseType_t ) 1 )   //Item has been retrieved and returned by application, free to overwrite
 #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
 #define rbITEM_SPLIT_FLAG           ( ( UBaseType_t ) 4 )   //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around
 
+//Static allocation related
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xTransSemStatic) )
+#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xRecvSemStatic) )
+#else
+#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xTransSemHandle )
+#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xRecvSemHandle )
+#endif
+
 typedef struct {
     //This size of this structure must be 32-bit aligned
     size_t xItemLen;
@@ -40,7 +50,7 @@ typedef struct {
 } ItemHeader_t;
 
 #define rbHEADER_SIZE     sizeof(ItemHeader_t)
-typedef struct Ringbuffer_t Ringbuffer_t;
+typedef struct RingbufferDefinition Ringbuffer_t;
 typedef BaseType_t (*CheckItemFitsFunction_t)(Ringbuffer_t *pxRingbuffer, size_t xItemSize);
 typedef void (*CopyItemFunction_t)(Ringbuffer_t *pxRingbuffer, const uint8_t *pcItem, size_t xItemSize);
 typedef BaseType_t (*CheckItemAvailFunction_t) (Ringbuffer_t *pxRingbuffer);
@@ -48,10 +58,10 @@ typedef void *(*GetItemFunction_t)(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsS
 typedef void (*ReturnItemFunction_t)(Ringbuffer_t *pxRingbuffer, uint8_t *pvItem);
 typedef size_t (*GetCurMaxSizeFunction_t)(Ringbuffer_t *pxRingbuffer);
 
-struct Ringbuffer_t {
+typedef struct RingbufferDefinition {
     size_t xSize;                               //Size of the data storage
-    UBaseType_t uxRingbufferFlags;              //Flags to indicate the type and status of ring buffer
     size_t xMaxItemSize;                        //Maximum item size
+    UBaseType_t uxRingbufferFlags;              //Flags to indicate the type and status of ring buffer
 
     CheckItemFitsFunction_t xCheckItemFits;     //Function to check if item can currently fit in ring buffer
     CopyItemFunction_t vCopyItem;               //Function to copy item to ring buffer
@@ -66,11 +76,37 @@ struct Ringbuffer_t {
     uint8_t *pucTail;                           //Pointer to the end of the ring buffer storage area
 
     BaseType_t xItemsWaiting;                   //Number of items/bytes(for byte buffers) currently in ring buffer that have not yet been read
-    SemaphoreHandle_t xFreeSpaceSemaphore;      //Binary semaphore, wakes up writing threads when more free space becomes available or when another thread times out attempting to write
-    SemaphoreHandle_t xItemsBufferedSemaphore;  //Binary semaphore, indicates there are new packets in the circular buffer. See remark.
+    /*
+     * TransSem: Binary semaphore used to indicate to a blocked transmitting tasks
+     *           that more free space has become available or that the block has
+     *           timed out.
+     *
+     * RecvSem: Binary semaphore used to indicate to a blocked receiving task that
+     *          new data/item has been written to the ring buffer.
+     *
+     * Note - When static allocation is enabled, the two semaphores are always
+     *        statically stored in the ring buffer's control structure
+     *        regardless of whether the ring buffer is allocated dynamically or
+     *        statically. When static allocation is disabled, the two semaphores
+     *        are allocated dynamically and their handles stored instead, thus
+     *        making the ring buffer's control structure slightly smaller when
+     *        static allocation is disabled.
+     */
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+    StaticSemaphore_t xTransSemStatic;
+    StaticSemaphore_t xRecvSemStatic;
+#else
+    SemaphoreHandle_t xTransSemHandle;
+    SemaphoreHandle_t xRecvSemHandle;
+#endif
     portMUX_TYPE mux;                           //Spinlock required for SMP
-};
+} Ringbuffer_t;
 
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+#if __GNUC_PREREQ(4, 6)
+_Static_assert(sizeof(StaticRingbuffer_t) == sizeof(Ringbuffer_t), "StaticRingbuffer_t != Ringbuffer_t");
+#endif
+#endif
 /*
 Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in
 FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we
@@ -78,13 +114,20 @@ would need to set the maximum to the maximum amount of times a null-byte unit fi
 which is quite high and so would waste a fair amount of memory.
 */
 
-/* ------------------------------------------------ Static Declarations ------------------------------------------ */
+/* --------------------------- Static Declarations -------------------------- */
 /*
  * WARNING: All of the following static functions (except generic functions)
  * ARE NOT THREAD SAFE. Therefore they should only be called within a critical
  * section (using spin locks)
  */
 
+
+//Initialize a ring buffer after space has been allocated for it
+static void prvInitializeNewRingbuffer(size_t xBufferSize,
+                                       RingbufferType_t xBufferType,
+                                       Ringbuffer_t *pxNewRingbuffer,
+                                       uint8_t *pucRingbufferStorage);
+
 //Calculate current amount of free space (in bytes) in the ring buffer
 static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer);
 
@@ -107,10 +150,16 @@ static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *puc
 static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize);
 
 //Retrieve item from no-split/allow-split ring buffer. *pxIsSplit is set to pdTRUE if the retrieved item is split
-static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize);
+static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
+                               BaseType_t *pxIsSplit,
+                               size_t xUnusedParam,
+                               size_t *pxItemSize);
 
 //Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved
-static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize,  size_t *pxItemSize);
+static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer,
+                               BaseType_t *pxUnusedParam,
+                               size_t xMaxSize,
+                               size_t *pxItemSize);
 
 //Return an item to a split/no-split ring buffer
 static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem);
@@ -133,12 +182,73 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer);
  * a split item will be retrieved. xMaxSize will only take effect if called on
  * byte buffers.
  */
-static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait);
+static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
+                                    void **pvItem1,
+                                    void **pvItem2,
+                                    size_t *xItemSize1,
+                                    size_t *xItemSize2,
+                                    size_t xMaxSize,
+                                    TickType_t xTicksToWait);
 
 //Generic function used to retrieve an item/data from ring buffers in an ISR
-static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize);
+static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer,
+                                           void **pvItem1,
+                                           void **pvItem2,
+                                           size_t *xItemSize1,
+                                           size_t *xItemSize2,
+                                           size_t xMaxSize);
+
+/* --------------------------- Static Definitions --------------------------- */
+
+static void prvInitializeNewRingbuffer(size_t xBufferSize,
+                                       RingbufferType_t xBufferType,
+                                       Ringbuffer_t *pxNewRingbuffer,
+                                       uint8_t *pucRingbufferStorage)
+{
+    //Initialize values
+    pxNewRingbuffer->xSize = xBufferSize;
+    pxNewRingbuffer->pucHead = pucRingbufferStorage;
+    pxNewRingbuffer->pucTail = pucRingbufferStorage + xBufferSize;
+    pxNewRingbuffer->pucFree = pucRingbufferStorage;
+    pxNewRingbuffer->pucRead = pucRingbufferStorage;
+    pxNewRingbuffer->pucWrite = pucRingbufferStorage;
+    pxNewRingbuffer->xItemsWaiting = 0;
+    pxNewRingbuffer->uxRingbufferFlags = 0;
 
-/* ------------------------------------------------ Static Definitions ------------------------------------------- */
+    //Initialize type dependent values and function pointers
+    if (xBufferType == RINGBUF_TYPE_NOSPLIT) {
+        pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
+        pxNewRingbuffer->vCopyItem = prvCopyItemNoSplit;
+        pxNewRingbuffer->pvGetItem = prvGetItemDefault;
+        pxNewRingbuffer->vReturnItem = prvReturnItemDefault;
+        /*
+         * Worst case scenario is when the read/write/free pointers are all
+         * pointing to the halfway point of the buffer.
+         */
+        pxNewRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxNewRingbuffer->xSize / 2) - rbHEADER_SIZE;
+        pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit;
+    } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) {
+        pxNewRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG;
+        pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
+        pxNewRingbuffer->vCopyItem = prvCopyItemAllowSplit;
+        pxNewRingbuffer->pvGetItem = prvGetItemDefault;
+        pxNewRingbuffer->vReturnItem = prvReturnItemDefault;
+        //Worst case an item is split into two, incurring two headers of overhead
+        pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize - (sizeof(ItemHeader_t) * 2);
+        pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit;
+    } else { //Byte Buffer
+        pxNewRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG;
+        pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer;
+        pxNewRingbuffer->vCopyItem = prvCopyItemByteBuf;
+        pxNewRingbuffer->pvGetItem = prvGetItemByteBuf;
+        pxNewRingbuffer->vReturnItem = prvReturnItemByteBuf;
+        //Byte buffers do not incur any overhead
+        pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize;
+        pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf;
+    }
+    xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxNewRingbuffer));
+    vPortCPUInitializeMutex(&pxNewRingbuffer->mux);
+}
 
 static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer)
 {
@@ -333,7 +443,10 @@ static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer)
     }
 }
 
-static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize)
+static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer,
+                               BaseType_t *pxIsSplit,
+                               size_t xUnusedParam,
+                               size_t *pxItemSize)
 {
     //Check arguments and buffer state
     ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead;
@@ -371,7 +484,10 @@ static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit
     return (void *)pcReturn;
 }
 
-static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize,  size_t *pxItemSize)
+static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer,
+                               BaseType_t *pxUnusedParam,
+                               size_t xMaxSize,
+                               size_t *pxItemSize)
 {
     //Check arguments and buffer state
     configASSERT((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG)));   //Check there are items to be read
@@ -552,7 +668,13 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer)
     return xFreeSize;
 }
 
-static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait)
+static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer,
+                                    void **pvItem1,
+                                    void **pvItem2,
+                                    size_t *xItemSize1,
+                                    size_t *xItemSize2,
+                                    size_t xMaxSize,
+                                    TickType_t xTicksToWait)
 {
     BaseType_t xReturn = pdFALSE;
     BaseType_t xReturnSemaphore = pdFALSE;
@@ -560,7 +682,7 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1,
     TickType_t xTicksRemaining = xTicksToWait;
     while (xTicksRemaining <= xTicksToWait) {   //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
         //Block until more free space becomes available or timeout
-        if (xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, xTicksRemaining) != pdTRUE) {
+        if (xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) {
             xReturn = pdFALSE;     //Timed out attempting to get semaphore
             break;
         }
@@ -606,12 +728,17 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1,
     }
 
     if (xReturnSemaphore == pdTRUE) {
-        xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore);  //Give semaphore back so other tasks can retrieve
+        xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer));  //Give semaphore back so other tasks can retrieve
     }
     return xReturn;
 }
 
-static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize)
+static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer,
+                                           void **pvItem1,
+                                           void **pvItem2,
+                                           size_t *xItemSize1,
+                                           size_t *xItemSize2,
+                                           size_t xMaxSize)
 {
     BaseType_t xReturn = pdFALSE;
     BaseType_t xReturnSemaphore = pdFALSE;
@@ -644,95 +771,54 @@ static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pv
     portEXIT_CRITICAL_ISR(&pxRingbuffer->mux);
 
     if (xReturnSemaphore == pdTRUE) {
-        xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, NULL);  //Give semaphore back so other tasks can retrieve
+        xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), NULL);  //Give semaphore back so other tasks can retrieve
     }
     return xReturn;
 }
 
-/* ------------------------------------------------- Public Definitions -------------------------------------------- */
+/* --------------------------- Public Definitions --------------------------- */
 
-RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType)
+RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType)
 {
+    configASSERT(xBufferSize > 0);
+    configASSERT(xBufferType < RINGBUF_TYPE_MAX);
+
     //Allocate memory
-    Ringbuffer_t *pxRingbuffer = calloc(1, sizeof(Ringbuffer_t));
-    if (pxRingbuffer == NULL) {
-        goto err;
-    }
     if (xBufferType != RINGBUF_TYPE_BYTEBUF) {
         xBufferSize = rbALIGN_SIZE(xBufferSize);    //xBufferSize is rounded up for no-split/allow-split buffers
     }
-    pxRingbuffer->pucHead = malloc(xBufferSize);
-    if (pxRingbuffer->pucHead == NULL) {
+    Ringbuffer_t *pxNewRingbuffer = calloc(1, sizeof(Ringbuffer_t));
+    uint8_t *pucRingbufferStorage = malloc(xBufferSize);
+    if (pxNewRingbuffer == NULL || pucRingbufferStorage == NULL) {
         goto err;
     }
 
-    //Initialize values
-    pxRingbuffer->xSize = xBufferSize;
-    pxRingbuffer->pucTail = pxRingbuffer->pucHead + xBufferSize;
-    pxRingbuffer->pucFree = pxRingbuffer->pucHead;
-    pxRingbuffer->pucRead = pxRingbuffer->pucHead;
-    pxRingbuffer->pucWrite = pxRingbuffer->pucHead;
-    pxRingbuffer->xItemsWaiting = 0;
-    pxRingbuffer->xFreeSpaceSemaphore = xSemaphoreCreateBinary();
-    pxRingbuffer->xItemsBufferedSemaphore = xSemaphoreCreateBinary();
-    pxRingbuffer->uxRingbufferFlags = 0;
-
-    //Initialize type dependent values and function pointers
-    if (xBufferType == RINGBUF_TYPE_NOSPLIT) {
-        pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
-        pxRingbuffer->vCopyItem = prvCopyItemNoSplit;
-        pxRingbuffer->pvGetItem = prvGetItemDefault;
-        pxRingbuffer->vReturnItem = prvReturnItemDefault;
-        /*
-         * Buffer lengths are always aligned. No-split buffer (read/write/free)
-         * pointers are also always aligned. Therefore worse case scenario is
-         * the write pointer is at the most aligned halfway point.
-         */
-        pxRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxRingbuffer->xSize / 2) - rbHEADER_SIZE;
-        pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit;
-    } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) {
-        pxRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG;
-        pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault;
-        pxRingbuffer->vCopyItem = prvCopyItemAllowSplit;
-        pxRingbuffer->pvGetItem = prvGetItemDefault;
-        pxRingbuffer->vReturnItem = prvReturnItemDefault;
-        //Worst case an item is split into two, incurring two headers of overhead
-        pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize - (sizeof(ItemHeader_t) * 2);
-        pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit;
-    } else if (xBufferType == RINGBUF_TYPE_BYTEBUF) {
-        pxRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG;
-        pxRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer;
-        pxRingbuffer->vCopyItem = prvCopyItemByteBuf;
-        pxRingbuffer->pvGetItem = prvGetItemByteBuf;
-        pxRingbuffer->vReturnItem = prvReturnItemByteBuf;
-        //Byte buffers do not incur any overhead
-        pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize;
-        pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf;
-    } else {
-        //Unsupported type
-        configASSERT(0);
-    }
-
-    if (pxRingbuffer->xFreeSpaceSemaphore == NULL || pxRingbuffer->xItemsBufferedSemaphore == NULL) {
+    //Initialize Semaphores
+#if ( configSUPPORT_STATIC_ALLOCATION == 1)
+    //We don't use the handles for static semaphores, and xSemaphoreCreateBinaryStatic will never fail thus no need to check static case
+    xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic));
+    xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic));
+#else
+    pxNewRingbuffer->xTransSemHandle = xSemaphoreCreateBinary();
+    pxNewRingbuffer->xRecvSemHandle = xSemaphoreCreateBinary();
+    if (pxNewRingbuffer->xTransSemHandle == NULL || pxNewRingbuffer->xRecvSemHandle == NULL) {
+        if (pxNewRingbuffer->xTransSemHandle != NULL) {
+            vSemaphoreDelete(pxNewRingbuffer->xTransSemHandle);
+        }
+        if (pxNewRingbuffer->xRecvSemHandle != NULL) {
+            vSemaphoreDelete(pxNewRingbuffer->xRecvSemHandle);
+        }
         goto err;
     }
-    xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore);
-    vPortCPUInitializeMutex(&pxRingbuffer->mux);
+#endif
 
-    return (RingbufHandle_t)pxRingbuffer;
+    prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage);
+    return (RingbufHandle_t)pxNewRingbuffer;
 
 err:
-    //Some error has happened. Free/destroy all allocated things and return NULL.
-    if (pxRingbuffer) {
-        free(pxRingbuffer->pucHead);
-        if (pxRingbuffer->xFreeSpaceSemaphore) {
-            vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore);
-        }
-        if (pxRingbuffer->xItemsBufferedSemaphore) {
-            vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore);
-        }
-    }
-    free(pxRingbuffer);
+    //An error has occurred, Free memory and return NULL
+    free(pxNewRingbuffer);
+    free(pucRingbufferStorage);
     return NULL;
 }
 
@@ -741,7 +827,34 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum)
     return xRingbufferCreate((rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE) * xItemNum, RINGBUF_TYPE_NOSPLIT);
 }
 
-BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait)
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize,
+                                        RingbufferType_t xBufferType,
+                                        uint8_t *pucRingbufferStorage,
+                                        StaticRingbuffer_t *pxStaticRingbuffer)
+{
+    //Check arguments
+    configASSERT(xBufferSize > 0);
+    configASSERT(xBufferType < RINGBUF_TYPE_MAX);
+    configASSERT(pucRingbufferStorage != NULL && pxStaticRingbuffer != NULL);
+    if (xBufferType != RINGBUF_TYPE_BYTEBUF) {
+        //No-split/allow-split buffer sizes must be 32-bit aligned
+        configASSERT(rbCHECK_ALIGNED(xBufferSize));
+    }
+
+    Ringbuffer_t *pxNewRingbuffer = (Ringbuffer_t *)pxStaticRingbuffer;
+    xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic));
+    xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic));
+    prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage);
+    pxNewRingbuffer->uxRingbufferFlags |= rbBUFFER_STATIC_FLAG;
+    return (RingbufHandle_t)pxNewRingbuffer;
+}
+#endif
+
+BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer,
+                           const void *pvItem,
+                           size_t xItemSize,
+                           TickType_t xTicksToWait)
 {
     //Check arguments
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
@@ -761,7 +874,7 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
     TickType_t xTicksRemaining = xTicksToWait;
     while (xTicksRemaining <= xTicksToWait) {   //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end
         //Block until more free space becomes available or timeout
-        if (xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, xTicksRemaining) != pdTRUE) {
+        if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) {
             xReturn = pdFALSE;
             break;
         }
@@ -791,15 +904,18 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size
 
     if (xReturn == pdTRUE) {
         //Indicate item was successfully sent
-        xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore);
+        xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer));
     }
     if (xReturnSemaphore == pdTRUE) {
-        xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore);  //Give back semaphore so other tasks can send
+        xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer));  //Give back semaphore so other tasks can send
     }
     return xReturn;
 }
 
-BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken)
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer,
+                                  const void *pvItem,
+                                  size_t xItemSize,
+                                  BaseType_t *pxHigherPriorityTaskWoken)
 {
     //Check arguments
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
@@ -830,10 +946,10 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvIte
 
     if (xReturn == pdTRUE) {
         //Indicate item was successfully sent
-        xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, pxHigherPriorityTaskWoken);
+        xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken);
     }
     if (xReturnSemaphore == pdTRUE) {
-        xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken);  //Give back semaphore so other tasks can send
+        xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken);  //Give back semaphore so other tasks can send
     }
     return xReturn;
 }
@@ -876,7 +992,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize)
     }
 }
 
-BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait)
+BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer,
+                                   void **ppvHeadItem,
+                                   void **ppvTailItem,
+                                   size_t *pxHeadItemSize,
+                                   size_t *pxTailItemSize,
+                                   TickType_t xTicksToWait)
 {
     //Check arguments
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
@@ -911,7 +1032,11 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt
     }
 }
 
-BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize)
+BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer,
+                                          void **ppvHeadItem,
+                                          void **ppvTailItem,
+                                          size_t *pxHeadItemSize,
+                                          size_t *pxTailItemSize)
 {
     //Check arguments
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
@@ -945,7 +1070,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp
     }
 }
 
-void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize)
+void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer,
+                             size_t *pxItemSize,
+                             TickType_t xTicksToWait,
+                             size_t xMaxSize)
 {
     //Check arguments
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
@@ -1000,7 +1128,7 @@ void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem)
     portENTER_CRITICAL(&pxRingbuffer->mux);
     pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem);
     portEXIT_CRITICAL(&pxRingbuffer->mux);
-    xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore);
+    xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer));
 }
 
 void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken)
@@ -1012,7 +1140,7 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas
     portENTER_CRITICAL_ISR(&pxRingbuffer->mux);
     pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem);
     portEXIT_CRITICAL_ISR(&pxRingbuffer->mux);
-    xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken);
+    xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken);
 }
 
 void vRingbufferDelete(RingbufHandle_t xRingbuffer)
@@ -1020,15 +1148,16 @@ void vRingbufferDelete(RingbufHandle_t xRingbuffer)
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
     configASSERT(pxRingbuffer);
 
-    if (pxRingbuffer) {
-        free(pxRingbuffer->pucHead);
-        if (pxRingbuffer->xFreeSpaceSemaphore) {
-            vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore);
-        }
-        if (pxRingbuffer->xItemsBufferedSemaphore) {
-            vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore);
-        }
+    vSemaphoreDelete(rbGET_TX_SEM_HANDLE(pxRingbuffer));
+    vSemaphoreDelete(rbGET_RX_SEM_HANDLE(pxRingbuffer));
+
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+    if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_STATIC_FLAG) {
+        //Ring buffer was statically allocated, no need to free
+        return;
     }
+#endif
+    free(pxRingbuffer->pucHead);
     free(pxRingbuffer);
 }
 
@@ -1059,11 +1188,11 @@ BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHan
     BaseType_t xReturn;
     portENTER_CRITICAL(&pxRingbuffer->mux);
     //Cannot add semaphore to queue set if semaphore is not empty. Temporarily hold semaphore
-    BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0);
-    xReturn = xQueueAddToSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet);
+    BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0);
+    xReturn = xQueueAddToSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet);
     if (xHoldSemaphore == pdTRUE) {
         //Return semaphore if temporarily held
-        configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
+        configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE);
     }
     portEXIT_CRITICAL(&pxRingbuffer->mux);
     return xReturn;
@@ -1074,7 +1203,7 @@ BaseType_t xRingbufferCanRead(RingbufHandle_t xRingbuffer, QueueSetMemberHandle_
     //Check if the selected queue set member is the ring buffer's read semaphore
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
     configASSERT(pxRingbuffer);
-    return (pxRingbuffer->xItemsBufferedSemaphore == xMember) ? pdTRUE : pdFALSE;
+    return (rbGET_RX_SEM_HANDLE(pxRingbuffer) == xMember) ? pdTRUE : pdFALSE;
 }
 
 BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
@@ -1085,17 +1214,21 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS
     BaseType_t xReturn;
     portENTER_CRITICAL(&pxRingbuffer->mux);
     //Cannot remove semaphore from queue set if semaphore is not empty. Temporarily hold semaphore
-    BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0);
-    xReturn = xQueueRemoveFromSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet);
+    BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0);
+    xReturn = xQueueRemoveFromSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet);
     if (xHoldSemaphore == pdTRUE) {
         //Return semaphore if temporarily held
-        configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE);
+        configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE);
     }
     portEXIT_CRITICAL(&pxRingbuffer->mux);
     return xReturn;
 }
 
-void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting)
+void vRingbufferGetInfo(RingbufHandle_t xRingbuffer,
+                        UBaseType_t *uxFree,
+                        UBaseType_t *uxRead,
+                        UBaseType_t *uxWrite,
+                        UBaseType_t *uxItemsWaiting)
 {
     Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
     configASSERT(pxRingbuffer);
@@ -1127,58 +1260,3 @@ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer)
            pxRingbuffer->pucWrite - pxRingbuffer->pucHead);
 }
 
-/* --------------------------------- Deprecated Functions ------------------------------ */
-//Todo: Remove the following deprecated functions in next release
-
-bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer)
-{
-    //This function is deprecated, use xRingbufferReceiveSplit() instead
-    Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
-    configASSERT(pxRingbuffer);
-    bool is_wrapped;
-
-    portENTER_CRITICAL(&pxRingbuffer->mux);
-    ItemHeader_t *xHeader = (ItemHeader_t *)pxRingbuffer->pucRead;
-    is_wrapped = xHeader->uxItemFlags & rbITEM_SPLIT_FLAG;
-    portEXIT_CRITICAL(&pxRingbuffer->mux);
-    return is_wrapped;
-}
-
-BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
-{
-    //This function is deprecated. QueueSetWrite no longer supported
-    Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
-    configASSERT(pxRingbuffer);
-
-    BaseType_t xReturn;
-    portENTER_CRITICAL(&pxRingbuffer->mux);
-    //Cannot add semaphore to queue set if semaphore is not empty. Temporary hold semaphore
-    BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0);
-    xReturn = xQueueAddToSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet);
-    if (xHoldSemaphore == pdTRUE) {
-        //Return semaphore is temporarily held
-        configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);
-    }
-    portEXIT_CRITICAL(&pxRingbuffer->mux);
-    return xReturn;
-}
-
-BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet)
-{
-    //This function is deprecated. QueueSetWrite no longer supported
-    Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer;
-    configASSERT(pxRingbuffer);
-
-    BaseType_t xReturn;
-    portENTER_CRITICAL(&pxRingbuffer->mux);
-    //Cannot remove semaphore from queue set if semaphore is not empty. Temporary hold semaphore
-    BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0);
-    xReturn = xQueueRemoveFromSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet);
-    if (xHoldSemaphore == pdTRUE) {
-        //Return semaphore is temporarily held
-        configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE);
-    }
-    portEXIT_CRITICAL(&pxRingbuffer->mux);
-    return xReturn;
-}
-
index 4acf63ba84813ef3b976f734ab890fe18dee3b71..d48f54d279c4b2ae9aae5fd2560a4a9e4c2b49bd 100644 (file)
@@ -6,6 +6,7 @@
 #include "freertos/semphr.h"
 #include "freertos/ringbuf.h"
 #include "driver/timer.h"
+#include "esp_heap_caps.h"
 #include "esp_spi_flash.h"
 #include "unity.h"
 #include "test_utils.h"
@@ -165,7 +166,7 @@ static void receive_check_and_return_item_byte_buffer(RingbufHandle_t handle, co
  * 4) Receive and check the wrapped item
  */
 
-TEST_CASE("Test ring buffer No-Split", "[freertos]")
+TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]")
 {
     //Create buffer
     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT);
@@ -196,7 +197,7 @@ TEST_CASE("Test ring buffer No-Split", "[freertos]")
     vRingbufferDelete(buffer_handle);
 }
 
-TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
+TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]")
 {
     //Create buffer
     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT);
@@ -227,7 +228,7 @@ TEST_CASE("Test ring buffer Allow-Split", "[freertos]")
     vRingbufferDelete(buffer_handle);
 }
 
-TEST_CASE("Test ring buffer Byte Buffer", "[freertos]")
+TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]")
 {
     //Create buffer
     RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF);
@@ -304,7 +305,7 @@ static void queue_set_receiving_task(void *queue_set_handle)
     vTaskDelete(NULL);
 }
 
-TEST_CASE("Test ring buffer with queue sets", "[freertos]")
+TEST_CASE("Test ring buffer with queue sets", "[esp_ringbuf]")
 {
     QueueSetHandle_t queue_set = xQueueCreateSet(NO_OF_RB_TYPES);
     done_sem = xSemaphoreCreateBinary();
@@ -421,7 +422,7 @@ static void cleanup_timer()
     esp_intr_free(ringbuffer_isr_handle);
 }
 
-TEST_CASE("Test ring buffer ISR", "[freertos]")
+TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]")
 {
     for (int i = 0; i < NO_OF_RB_TYPES; i++) {
         buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i);
@@ -461,11 +462,12 @@ static const char continuous_data[] = {"A_very_long_string_that_will_be_split_in
                                        "be_increased_over_multiple_iterations_in_this"
                                        "_test"};
 #define CONT_DATA_LEN                   sizeof(continuous_data)
-#define CONT_DATA_TEST_BUFF_LEN         (CONT_DATA_LEN/2)   //This will guarantee that the buffer must do a wrap around at some point
+//32-bit aligned size that guarantees a wrap around at some point
+#define CONT_DATA_TEST_BUFF_LEN         (((CONT_DATA_LEN/2) + 0x03) & ~0x3)
 
 typedef struct {
     RingbufHandle_t buffer;
-    ringbuf_type_t type;
+    RingbufferType_t type;
 } task_args_t;
 
 static SemaphoreHandle_t tasks_done;
@@ -494,7 +496,7 @@ static void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size)
     }
 }
 
-static void read_from_buffer(RingbufHandle_t buffer, ringbuf_type_t buf_type, size_t max_rec_size)
+static void read_from_buffer(RingbufHandle_t buffer, RingbufferType_t buf_type, size_t max_rec_size)
 {
     for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) {
         size_t bytes_rec = 0;      //Number of data bytes received in this iteration
@@ -568,20 +570,33 @@ static void rec_task(void *args)
     vTaskDelete(NULL);
 }
 
-TEST_CASE("Test ring buffer SMP", "[freertos]")
+static void setup()
 {
-    ets_printf("size of buf %d\n", CONT_DATA_LEN);
+    ets_printf("Size of test data: %d\n", CONT_DATA_LEN);
     tx_done = xSemaphoreCreateBinary();                 //Semaphore to indicate send is done for a particular iteration
     rx_done = xSemaphoreCreateBinary();                 //Semaphore to indicate receive is done for a particular iteration
-    tasks_done = xSemaphoreCreateBinary();                //Semaphore used to to indicate send and receive tasks completed running
+    tasks_done = xSemaphoreCreateBinary();              //Semaphore used to to indicate send and receive tasks completed running
     srand(SRAND_SEED);                                  //Seed RNG
+}
+
+static void cleanup()
+{
+    //Cleanup
+    vSemaphoreDelete(tx_done);
+    vSemaphoreDelete(rx_done);
+    vSemaphoreDelete(tasks_done);
+}
 
+TEST_CASE("Test ring buffer SMP", "[esp_ringbuf]")
+{
+    setup();
     //Iterate through buffer types (No split, split, then byte buff)
-    for (ringbuf_type_t buf_type = 0; buf_type <= RINGBUF_TYPE_BYTEBUF; buf_type++) {
+    for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
         //Create buffer
         task_args_t task_args;
         task_args.buffer = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, buf_type); //Create buffer of selected type
         task_args.type = buf_type;
+        TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
 
         for (int prior_mod = -1; prior_mod < 2; prior_mod++) {  //Test different relative priorities
             //Test every permutation of core affinity
@@ -600,12 +615,59 @@ TEST_CASE("Test ring buffer SMP", "[freertos]")
         vRingbufferDelete(task_args.buffer);
         vTaskDelay(10);
     }
+    cleanup();
+}
 
-    //Cleanup
-    vSemaphoreDelete(tx_done);
-    vSemaphoreDelete(rx_done);
-    vSemaphoreDelete(tasks_done);
+#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
+TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]")
+{
+    setup();
+    //Iterate through buffer types (No split, split, then byte buff)
+    for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) {
+        StaticRingbuffer_t *buffer_struct;
+        uint8_t *buffer_storage;
+        //Allocate memory and create semaphores
+#if CONFIG_SPIRAM_USE_CAPS_ALLOC   //When SPIRAM can only be allocated using heap_caps_malloc()
+        buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
+        buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN, MALLOC_CAP_SPIRAM);
+#else   //Case where SPIRAM is disabled or when SPIRAM is allocatable through malloc()
+        buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t));
+        buffer_storage = (uint8_t *)malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN);
+#endif
+        TEST_ASSERT(buffer_struct != NULL && buffer_storage != NULL);
+
+        //Create buffer
+        task_args_t task_args;
+        task_args.buffer = xRingbufferCreateStatic(CONT_DATA_TEST_BUFF_LEN, buf_type, buffer_storage, buffer_struct); //Create buffer of selected type
+        task_args.type = buf_type;
+        TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer");
+
+        for (int prior_mod = -1; prior_mod < 2; prior_mod++) {  //Test different relative priorities
+            //Test every permutation of core affinity
+            for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) {
+                for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) {
+                    ets_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core);
+                    xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core);
+                    xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core);
+                    xSemaphoreTake(tasks_done, portMAX_DELAY);
+                    vTaskDelay(5);  //Allow idle to clean up
+                }
+            }
+        }
+
+        //Delete ring buffer
+        vRingbufferDelete(task_args.buffer);
+
+        //Deallocate memory
+        free(buffer_storage);
+        free(buffer_struct);
+        vTaskDelay(10);
+    }
+    cleanup();
 }
+#endif
+
+/* -------------------------- Test ring buffer IRAM ------------------------- */
 
 static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test()
 {
@@ -621,7 +683,7 @@ static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test()
     return result;
 }
 
-TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[freertos]")
+TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ringbuf]")
 {
     TEST_ASSERT( iram_ringbuf_test() );
 }
index 969a7ce14a199af9e2cedb39022719bc181fb561..337bf3bb2656403c58dc248b6fb99abebe26ba82 100644 (file)
@@ -323,6 +323,51 @@ The following example demonstrates queue set usage with ring buffers.
             ...
         }
 
+Ring Buffers with Static Allocation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with specific memory requirements (such as a ring buffer being allocated in external RAM). All blocks of memory used by a ring buffer must be manually allocated beforehand then passed to the :cpp:func:`xRingbufferCreateStatic` to be initialized as a ring buffer. These blocks include the following:
+
+- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
+- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
+
+The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM). 
+
+.. note::
+    The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
+
+.. note::
+    When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
+    the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
+
+The code snippet below demonstrates a ring buffer being allocated entirely in external RAM.
+
+.. code-block:: c
+
+    #include "freertos/ringbuf.h"
+    #include "freertos/semphr.h"
+    #include "esp_heap_caps.h"
+
+    #define BUFFER_SIZE     400      //32-bit aligned size
+    #define BUFFER_TYPE     RINGBUF_TYPE_NOSPLIT
+    ...
+
+    //Allocate ring buffer data structure and storage area into external RAM
+    StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
+    uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*BUFFER_SIZE, MALLOC_CAP_SPIRAM);
+
+    //Create a ring buffer with manually allocated memory
+    RingbufHandle_t handle = xRingbufferCreateStatic(BUFFER_SIZE, BUFFER_TYPE, buffer_storage, buffer_struct);
+
+    ...
+
+    //Delete the ring buffer after used
+    vRingbufferDelete(handle);
+
+    //Manually free all blocks of memory
+    free(buffer_struct);
+    free(buffer_storage);
+
 
 Ring Buffer API Reference
 -------------------------