Added ability to change task notification index for streambuffers (#939)

* Added possibility to change notification index for streambuffers

* Uncrustify: triggered by comment.

* Minor code review suggestions.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

---------

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Co-authored-by: Gaurav Aggarwal <aggarg@amazon.com>
diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h
index 6eb498c..d7c458d 100644
--- a/include/FreeRTOS.h
+++ b/include/FreeRTOS.h
@@ -2509,6 +2509,22 @@
     #define traceRETURN_xStreamBufferReceiveCompletedFromISR( xReturn )
 #endif
 
+#ifndef traceENTER_uxStreamBufferGetStreamBufferNotificationIndex
+    #define traceENTER_uxStreamBufferGetStreamBufferNotificationIndex( xStreamBuffer )
+#endif
+
+#ifndef traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex
+    #define traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex( uxNotificationIndex )
+#endif
+
+#ifndef traceENTER_vStreamBufferSetStreamBufferNotificationIndex
+    #define traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex )
+#endif
+
+#ifndef traceRETURN_vStreamBufferSetStreamBufferNotificationIndex
+    #define traceRETURN_vStreamBufferSetStreamBufferNotificationIndex()
+#endif
+
 #ifndef traceENTER_uxStreamBufferGetStreamBufferNumber
     #define traceENTER_uxStreamBufferGetStreamBufferNumber( xStreamBuffer )
 #endif
@@ -3271,6 +3287,7 @@
     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
         void * pvDummy5[ 2 ];
     #endif
+    UBaseType_t uxDummy6;
 } StaticStreamBuffer_t;
 
 /* Message buffers are built on stream buffers. */
diff --git a/include/stream_buffer.h b/include/stream_buffer.h
index 68d12e0..2ff584e 100644
--- a/include/stream_buffer.h
+++ b/include/stream_buffer.h
@@ -911,6 +911,57 @@
 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
                                                  BaseType_t * pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
 
+/**
+ * stream_buffer.h
+ *
+ * @code{c}
+ * UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer );
+ * @endcode
+ *
+ * Get the task notification index used for the supplied stream buffer which can
+ * be set using vStreamBufferSetStreamBufferNotificationIndex. If the task
+ * notification index for the stream buffer is not changed using
+ * vStreamBufferSetStreamBufferNotificationIndex, this function returns the
+ * default value (tskDEFAULT_INDEX_TO_NOTIFY).
+ *
+ * @param xStreamBuffer The handle of the stream buffer for which the task
+ * notification index is retrieved.
+ *
+ * @return The task notification index for the stream buffer.
+ *
+ * \defgroup uxStreamBufferGetStreamBufferNotificationIndex uxStreamBufferGetStreamBufferNotificationIndex
+ * \ingroup StreamBufferManagement
+ */
+UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
+
+/**
+ * stream_buffer.h
+ *
+ * @code{c}
+ * void vStreamBufferSetStreamBufferNotificationIndex ( StreamBuffer_t xStreamBuffer, UBaseType_t uxNotificationIndex );
+ * @endcode
+ *
+ * Set the task notification index used for the supplied stream buffer.
+ * Successive calls to stream buffer APIs (like xStreamBufferSend or
+ * xStreamBufferReceive) for this stream buffer will use this new index for
+ * their task notifications.
+ *
+ * If this function is not called, the default index (tskDEFAULT_INDEX_TO_NOTIFY)
+ * is used for task notifications. It is recommended to call this function
+ * before attempting to send or receive data from the stream buffer to avoid
+ * inconsistencies.
+ *
+ * @param xStreamBuffer The handle of the stream buffer for which the task
+ * notification index is set.
+ *
+ * @param uxNotificationIndex The task notification index to set.
+ *
+ * \defgroup vStreamBufferSetStreamBufferNotificationIndex vStreamBufferSetStreamBufferNotificationIndex
+ * \ingroup StreamBufferManagement
+ */
+void vStreamBufferSetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer,
+                                                    UBaseType_t uxNotificationIndex ) PRIVILEGED_FUNCTION;
+
 /* Functions below here are not part of the public API. */
 StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
                                                  size_t xTriggerLevelBytes,
diff --git a/stream_buffer.c b/stream_buffer.c
index 3ea7baa..00306fa 100644
--- a/stream_buffer.c
+++ b/stream_buffer.c
@@ -56,20 +56,21 @@
  * or #defined the notification macros away, then provide default implementations
  * that uses task notifications. */
 #ifndef sbRECEIVE_COMPLETED
-    #define sbRECEIVE_COMPLETED( pxStreamBuffer )                             \
-    do                                                                        \
-    {                                                                         \
-        vTaskSuspendAll();                                                    \
-        {                                                                     \
-            if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )              \
-            {                                                                 \
-                ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \
-                                      ( uint32_t ) 0,                         \
-                                      eNoAction );                            \
-                ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                \
-            }                                                                 \
-        }                                                                     \
-        ( void ) xTaskResumeAll();                                            \
+    #define sbRECEIVE_COMPLETED( pxStreamBuffer )                                     \
+    do                                                                                \
+    {                                                                                 \
+        vTaskSuspendAll();                                                            \
+        {                                                                             \
+            if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                      \
+            {                                                                         \
+                ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToSend,  \
+                                             ( pxStreamBuffer )->uxNotificationIndex, \
+                                             ( uint32_t ) 0,                          \
+                                             eNoAction );                             \
+                ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                        \
+            }                                                                         \
+        }                                                                             \
+        ( void ) xTaskResumeAll();                                                    \
     } while( 0 )
 #endif /* sbRECEIVE_COMPLETED */
 
@@ -93,23 +94,24 @@
 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
 
 #ifndef sbRECEIVE_COMPLETED_FROM_ISR
-    #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                            \
-                                          pxHigherPriorityTaskWoken )                \
-    do {                                                                             \
-        UBaseType_t uxSavedInterruptStatus;                                          \
-                                                                                     \
-        uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                      \
-        {                                                                            \
-            if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                     \
-            {                                                                        \
-                ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \
-                                             ( uint32_t ) 0,                         \
-                                             eNoAction,                              \
-                                             ( pxHigherPriorityTaskWoken ) );        \
-                ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                       \
-            }                                                                        \
-        }                                                                            \
-        taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                        \
+    #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                                    \
+                                          pxHigherPriorityTaskWoken )                        \
+    do {                                                                                     \
+        UBaseType_t uxSavedInterruptStatus;                                                  \
+                                                                                             \
+        uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                              \
+        {                                                                                    \
+            if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                             \
+            {                                                                                \
+                ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,  \
+                                                    ( pxStreamBuffer )->uxNotificationIndex, \
+                                                    ( uint32_t ) 0,                          \
+                                                    eNoAction,                               \
+                                                    ( pxHigherPriorityTaskWoken ) );         \
+                ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                               \
+            }                                                                                \
+        }                                                                                    \
+        taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                \
     } while( 0 )
 #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
 
@@ -136,17 +138,18 @@
  * implementation that uses task notifications.
  */
 #ifndef sbSEND_COMPLETED
-    #define sbSEND_COMPLETED( pxStreamBuffer )                               \
-    vTaskSuspendAll();                                                       \
-    {                                                                        \
-        if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )              \
-        {                                                                    \
-            ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \
-                                  ( uint32_t ) 0,                            \
-                                  eNoAction );                               \
-            ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                \
-        }                                                                    \
-    }                                                                        \
+    #define sbSEND_COMPLETED( pxStreamBuffer )                                      \
+    vTaskSuspendAll();                                                              \
+    {                                                                               \
+        if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \
+        {                                                                           \
+            ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToReceive, \
+                                         ( pxStreamBuffer )->uxNotificationIndex,   \
+                                         ( uint32_t ) 0,                            \
+                                         eNoAction );                               \
+            ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \
+        }                                                                           \
+    }                                                                               \
     ( void ) xTaskResumeAll()
 #endif /* sbSEND_COMPLETED */
 
@@ -171,22 +174,23 @@
 
 
 #ifndef sbSEND_COMPLETE_FROM_ISR
-    #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )       \
-    do {                                                                                \
-        UBaseType_t uxSavedInterruptStatus;                                             \
-                                                                                        \
-        uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                         \
-        {                                                                               \
-            if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \
-            {                                                                           \
-                ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
-                                             ( uint32_t ) 0,                            \
-                                             eNoAction,                                 \
-                                             ( pxHigherPriorityTaskWoken ) );           \
-                ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \
-            }                                                                           \
-        }                                                                               \
-        taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                           \
+    #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )              \
+    do {                                                                                       \
+        UBaseType_t uxSavedInterruptStatus;                                                    \
+                                                                                               \
+        uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                                \
+        {                                                                                      \
+            if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                            \
+            {                                                                                  \
+                ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
+                                                    ( pxStreamBuffer )->uxNotificationIndex,   \
+                                                    ( uint32_t ) 0,                            \
+                                                    eNoAction,                                 \
+                                                    ( pxHigherPriorityTaskWoken ) );           \
+                ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                              \
+            }                                                                                  \
+        }                                                                                      \
+        taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                  \
     } while( 0 )
 #endif /* sbSEND_COMPLETE_FROM_ISR */
 
@@ -237,6 +241,7 @@
         StreamBufferCallbackFunction_t pxSendCompletedCallback;    /* Optional callback called on send complete. sbSEND_COMPLETED is called if this is NULL. */
         StreamBufferCallbackFunction_t pxReceiveCompletedCallback; /* Optional callback called on receive complete.  sbRECEIVE_COMPLETED is called if this is NULL. */
     #endif
+    UBaseType_t uxNotificationIndex;                               /* The index we are using for notification, by default tskDEFAULT_INDEX_TO_NOTIFY. */
 } StreamBuffer_t;
 
 /*
@@ -790,7 +795,7 @@
                 if( xSpace < xRequiredSpace )
                 {
                     /* Clear notification state as going to wait for space. */
-                    ( void ) xTaskNotifyStateClear( NULL );
+                    ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
 
                     /* Should only be one writer. */
                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
@@ -805,7 +810,7 @@
             taskEXIT_CRITICAL();
 
             traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
-            ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
+            ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
             pxStreamBuffer->xTaskWaitingToSend = NULL;
         } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
     }
@@ -1001,7 +1006,7 @@
             if( xBytesAvailable <= xBytesToStoreMessageLength )
             {
                 /* Clear notification state as going to wait for data. */
-                ( void ) xTaskNotifyStateClear( NULL );
+                ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
 
                 /* Should only be one reader. */
                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
@@ -1018,7 +1023,7 @@
         {
             /* Wait for data to be available. */
             traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
-            ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
+            ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
             pxStreamBuffer->xTaskWaitingToReceive = NULL;
 
             /* Recheck the data available after blocking. */
@@ -1307,10 +1312,11 @@
     {
         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
         {
-            ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
-                                         ( uint32_t ) 0,
-                                         eNoAction,
-                                         pxHigherPriorityTaskWoken );
+            ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
+                                                ( pxStreamBuffer )->uxNotificationIndex,
+                                                ( uint32_t ) 0,
+                                                eNoAction,
+                                                pxHigherPriorityTaskWoken );
             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
             xReturn = pdTRUE;
         }
@@ -1342,10 +1348,11 @@
     {
         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
         {
-            ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
-                                         ( uint32_t ) 0,
-                                         eNoAction,
-                                         pxHigherPriorityTaskWoken );
+            ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
+                                                ( pxStreamBuffer )->uxNotificationIndex,
+                                                ( uint32_t ) 0,
+                                                eNoAction,
+                                                pxHigherPriorityTaskWoken );
             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
             xReturn = pdTRUE;
         }
@@ -1499,6 +1506,7 @@
     pxStreamBuffer->xLength = xBufferSizeBytes;
     pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
     pxStreamBuffer->ucFlags = ucFlags;
+    pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY;
     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
     {
         pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;
@@ -1518,6 +1526,43 @@
     }
     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
 }
+/*-----------------------------------------------------------*/
+
+UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer )
+{
+    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
+
+    traceENTER_uxStreamBufferGetStreamBufferNotificationIndex( xStreamBuffer );
+
+    configASSERT( pxStreamBuffer );
+
+    traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex( pxStreamBuffer->uxNotificationIndex );
+
+    return pxStreamBuffer->uxNotificationIndex;
+}
+/*-----------------------------------------------------------*/
+
+void vStreamBufferSetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer,
+                                                    UBaseType_t uxNotificationIndex )
+{
+    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
+
+    traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex );
+
+    configASSERT( pxStreamBuffer );
+
+    /* There should be no task waiting otherwise we'd never resume them. */
+    configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
+    configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
+
+    /* Check that the task notification index is valid. */
+    configASSERT( uxNotificationIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES );
+
+    pxStreamBuffer->uxNotificationIndex = uxNotificationIndex;
+
+    traceRETURN_vStreamBufferSetStreamBufferNotificationIndex();
+}
+/*-----------------------------------------------------------*/
 
 #if ( configUSE_TRACE_FACILITY == 1 )