From a2673db45290ff331cfdeb77d612028d3d7d3071 Mon Sep 17 00:00:00 2001 From: Phillip Stevens Date: Mon, 8 Jan 2024 16:30:51 +1100 Subject: [PATCH] add streambuffer updates --- library.properties | 2 +- src/Arduino_FreeRTOS.h | 45 +++++++++- src/atomic.h | 12 ++- src/port.c | 161 ++++++++++++++++++----------------- src/portmacro.h | 24 +++--- src/queue.h | 4 +- src/stream_buffer.c | 185 +++++++++++++++++++++++++---------------- src/stream_buffer.h | 51 ++++++++++++ src/tasks.c | 10 +-- 9 files changed, 323 insertions(+), 171 deletions(-) diff --git a/library.properties b/library.properties index 53654aa..162c44b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=FreeRTOS -version=11.0.1-1 +version=11.0.1-2 author=Richard Barry maintainer=Phillip Stevens sentence=FreeRTOS Real Time Operating System implemented for AVR (Uno, Nano, Leonardo, Mega). diff --git a/src/Arduino_FreeRTOS.h b/src/Arduino_FreeRTOS.h index 953d0a2..2a4099b 100644 --- a/src/Arduino_FreeRTOS.h +++ b/src/Arduino_FreeRTOS.h @@ -499,12 +499,36 @@ #endif /* configUSE_TIMERS */ +#ifndef portHAS_NESTED_INTERRUPTS + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) && defined( portCLEAR_INTERRUPT_MASK_FROM_ISR ) + #define portHAS_NESTED_INTERRUPTS 1 + #else + #define portHAS_NESTED_INTERRUPTS 0 + #endif +#endif + #ifndef portSET_INTERRUPT_MASK_FROM_ISR - #define portSET_INTERRUPT_MASK_FROM_ISR() 0 + #if ( portHAS_NESTED_INTERRUPTS == 1 ) + #error portSET_INTERRUPT_MASK_FROM_ISR must be defined for ports that support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 1) + #else + #define portSET_INTERRUPT_MASK_FROM_ISR() 0 + #endif +#else + #if ( portHAS_NESTED_INTERRUPTS == 0 ) + #error portSET_INTERRUPT_MASK_FROM_ISR must not be defined for ports that do not support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 0) + #endif #endif #ifndef portCLEAR_INTERRUPT_MASK_FROM_ISR - #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) ( uxSavedStatusValue ) + #if ( portHAS_NESTED_INTERRUPTS == 1 ) + #error portCLEAR_INTERRUPT_MASK_FROM_ISR must be defined for ports that support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 1) + #else + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) ( void ) ( uxSavedStatusValue ) + #endif +#else + #if ( portHAS_NESTED_INTERRUPTS == 0 ) + #error portCLEAR_INTERRUPT_MASK_FROM_ISR must not be defined for ports that do not support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 0) + #endif #endif #ifndef portCLEAN_UP_TCB @@ -2475,6 +2499,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 @@ -3236,6 +3276,7 @@ typedef struct xSTATIC_STREAM_BUFFER #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/src/atomic.h b/src/atomic.h index 4679e6f..e97664c 100644 --- a/src/atomic.h +++ b/src/atomic.h @@ -33,6 +33,14 @@ * This file implements atomic functions by disabling interrupts globally. * Implementations with architecture specific atomic instructions can be * provided under each compiler directory. + * + * The atomic interface can be used in FreeRTOS tasks on all FreeRTOS ports. It + * can also be used in Interrupt Service Routines (ISRs) on FreeRTOS ports that + * support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 1). The + * atomic interface must not be used in ISRs on FreeRTOS ports that do not + * support nested interrupts (i.e. portHAS_NESTED_INTERRUPTS is set to 0) + * because ISRs on these ports cannot be interrupted and therefore, do not need + * atomics in ISRs. */ #ifndef ATOMIC_H @@ -59,7 +67,7 @@ * ATOMIC_ENTER_CRITICAL(). * */ -#if defined( portSET_INTERRUPT_MASK_FROM_ISR ) +#if ( portHAS_NESTED_INTERRUPTS == 1 ) /* Nested interrupt scheme is supported in this port. */ #define ATOMIC_ENTER_CRITICAL() \ @@ -74,7 +82,7 @@ #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() -#endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ +#endif /* portHAS_NESTED_INTERRUPTS */ /* * Port specific definition -- "always inline". diff --git a/src/port.c b/src/port.c index ff2a158..ad5b166 100644 --- a/src/port.c +++ b/src/port.c @@ -42,10 +42,10 @@ *----------------------------------------------------------*/ /* Start tasks with interrupts enabled. */ -#define portFLAGS_INT_ENABLED ( (StackType_t) 0x80 ) +#define portFLAGS_INT_ENABLED ( ( StackType_t ) 0x80 ) #if defined( portUSE_WDTO ) - #define portSCHEDULER_ISR WDT_vect + #define portSCHEDULER_ISR WDT_vect #else #warning "The user must define a Timer to be used for the Scheduler." @@ -54,27 +54,27 @@ /*-----------------------------------------------------------*/ /* We require the address of the pxCurrentTCB variable, but don't want to know -any details of its type. */ + * any details of its type. */ typedef void TCB_t; extern volatile TCB_t * volatile pxCurrentTCB; /*-----------------------------------------------------------*/ /** - Enable the watchdog timer, configuring it for expire after - (value) timeout (which is a combination of the WDP0 - through WDP3 bits). - - This function is derived from but enables only - the interrupt bit (WDIE), rather than the reset bit (WDE). - - Can't find it documented but the WDT, once enabled, - rolls over and fires a new interrupt each time. - - See also the symbolic constants WDTO_15MS et al. - - Updated to match avr-libc 2.0.0 -*/ + * Enable the watchdog timer, configuring it for expire after + * (value) timeout (which is a combination of the WDP0 + * through WDP3 bits). + * + * This function is derived from but enables only + * the interrupt bit (WDIE), rather than the reset bit (WDE). + * + * Can't find it documented but the WDT, once enabled, + * rolls over and fires a new interrupt each time. + * + * See also the symbolic constants WDTO_15MS et al. + * + * Updated to match avr-libc 2.0.0 + */ #if defined( portUSE_WDTO ) @@ -121,26 +121,26 @@ void wdt_interrupt_enable (const uint8_t value) /*-----------------------------------------------------------*/ /** - Enable the watchdog timer, configuring it for expire after - (value) timeout (which is a combination of the WDP0 - through WDP3 bits). - - This function is derived from but enables both - the reset bit (WDE), and the interrupt bit (WDIE). - - This will ensure that if the interrupt is not serviced - before the second timeout, the AVR will reset. - - Servicing the interrupt automatically clears it, - and ensures the AVR does not reset. - - Can't find it documented but the WDT, once enabled, - rolls over and fires a new interrupt each time. - - See also the symbolic constants WDTO_15MS et al. - - Updated to match avr-libc 2.0.0 -*/ + * Enable the watchdog timer, configuring it for expire after + * (value) timeout (which is a combination of the WDP0 + * through WDP3 bits). + * + * This function is derived from but enables both + * the reset bit (WDE), and the interrupt bit (WDIE). + * + * This will ensure that if the interrupt is not serviced + * before the second timeout, the AVR will reset. + * + * Servicing the interrupt automatically clears it, + * and ensures the AVR does not reset. + * + * Can't find it documented but the WDT, once enabled, + * rolls over and fires a new interrupt each time. + * + * See also the symbolic constants WDTO_15MS et al. + * + * Updated to match avr-libc 2.0.0 + */ #if defined( portUSE_WDTO ) @@ -551,10 +551,11 @@ uint16_t usAddress; #endif /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). - portSAVE_CONTEXT places the flags on the stack immediately after r0 - to ensure the interrupts get disabled as soon as possible, and so ensuring - the stack use is minimal should a context switch interrupt occur. */ - *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */ + * portSAVE_CONTEXT places the flags on the stack immediately after r0 + * to ensure the interrupts get disabled as soon as possible, and so ensuring + * the stack use is minimal should a context switch interrupt occur. + */ + *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */ pxTopOfStack--; *pxTopOfStack = portFLAGS_INT_ENABLED; pxTopOfStack--; @@ -605,7 +606,7 @@ BaseType_t xPortStartScheduler( void ) portRESTORE_CONTEXT(); /* Simulate a function call end as generated by the compiler. We will now - jump to the start of the task the context of which we have just restored. */ + * jump to the start of the task the context of which we have just restored. */ __asm__ __volatile__ ( "ret" ); /* Should not get here. */ @@ -622,15 +623,15 @@ void vPortEndScheduler( void ) } /*-----------------------------------------------------------*/ - /* - * Choose which delay function to use. - * Arduino delay() is a millisecond granularity busy wait, that - * that breaks FreeRTOS. So its use is limited to less than one - * System Tick (portTICK_PERIOD_MS milliseconds). - * FreeRTOS vTaskDelay() is relies on the System Tick which here - * has a granularity of portTICK_PERIOD_MS milliseconds (15ms), - * with the remainder implemented as an Arduino delay(). - */ +/* + * Choose which delay function to use. + * Arduino delay() is a millisecond granularity busy wait, that + * that breaks FreeRTOS. So its use is limited to less than one + * System Tick (portTICK_PERIOD_MS milliseconds). + * FreeRTOS vTaskDelay() is relies on the System Tick which here + * has a granularity of portTICK_PERIOD_MS milliseconds (15ms), + * with the remainder implemented as an Arduino delay(). + */ #ifdef delay #undef delay @@ -639,7 +640,7 @@ void vPortEndScheduler( void ) extern void delay ( unsigned long ms ); #if defined( portUSE_WDTO ) -void vPortDelay( const uint32_t ms ) __attribute__ ((hot, flatten)); +void vPortDelay( const uint32_t ms ) __attribute__ ( ( hot, flatten ) ); void vPortDelay( const uint32_t ms ) { if ( ms < portTICK_PERIOD_MS ) @@ -655,7 +656,7 @@ void vPortDelay( const uint32_t ms ) #else #warning "The user is responsible to provide function `vPortDelay()`" #warning "Arduino uses all AVR MCU Timers, so breakage may occur" -extern void vPortDelay( const uint32_t ms ) __attribute__ ((hot, flatten)); +extern void vPortDelay( const uint32_t ms ) __attribute__ ( ( hot, flatten ) ); #endif /*-----------------------------------------------------------*/ @@ -663,7 +664,7 @@ extern void vPortDelay( const uint32_t ms ) __attribute__ ((hot, flatten)); * Manual context switch. The first thing we do is save the registers so we * can use a naked attribute. */ -void vPortYield( void ) __attribute__ ((hot, flatten, naked)); +void vPortYield( void ) __attribute__( ( hot, flatten, naked ) ); void vPortYield( void ) { portSAVE_CONTEXT(); @@ -678,7 +679,7 @@ void vPortYield( void ) * Manual context switch callable from ISRs. The first thing we do is save * the registers so we can use a naked attribute. */ -void vPortYieldFromISR( void ) __attribute__ ((hot, flatten, naked)); +void vPortYieldFromISR( void ) __attribute__( ( hot, flatten, naked ) ); void vPortYieldFromISR( void ) { portSAVE_CONTEXT(); @@ -695,7 +696,7 @@ void vPortYieldFromISR( void ) * difference from vPortYield() is the tick count is incremented as the * call comes from the tick ISR. */ -void vPortYieldFromTick( void ) __attribute__ ((hot, flatten, naked)); +void vPortYieldFromTick( void ) __attribute__( ( hot, flatten, naked ) ); void vPortYieldFromTick( void ) { portSAVE_CONTEXT(); @@ -704,6 +705,7 @@ void vPortYieldFromTick( void ) { vTaskSwitchContext(); } + portRESTORE_CONTEXT(); __asm__ __volatile__ ( "ret" ); @@ -711,21 +713,22 @@ void vPortYieldFromTick( void ) /*-----------------------------------------------------------*/ #if defined( portUSE_WDTO ) -/* - * Setup WDT to generate a tick interrupt. - */ -void prvSetupTimerInterrupt( void ) -{ - /* reset watchdog */ - wdt_reset(); - /* set up WDT Interrupt (rather than the WDT Reset). */ - wdt_interrupt_enable( portUSE_WDTO ); -} + /* + * Setup WDT to generate a tick interrupt. + */ + void prvSetupTimerInterrupt( void ) + { + /* reset watchdog */ + wdt_reset(); + + /* set up WDT Interrupt (rather than the WDT Reset). */ + wdt_interrupt_enable( portUSE_WDTO ); + } #else -#warning "The user is responsible to provide function `prvSetupTimerInterrupt()`" -extern void prvSetupTimerInterrupt( void ); + #warning "The user is responsible to provide function `prvSetupTimerInterrupt()`" + extern void prvSetupTimerInterrupt( void ); #endif /*-----------------------------------------------------------*/ @@ -740,15 +743,16 @@ extern void prvSetupTimerInterrupt( void ); * use ISR_NOBLOCK where there is an important timer running, that should preempt the scheduler. * */ - ISR(portSCHEDULER_ISR, ISR_NAKED) __attribute__ ((hot, flatten)); -/* ISR(portSCHEDULER_ISR, ISR_NAKED ISR_NOBLOCK) __attribute__ ((hot, flatten)); - */ - ISR(portSCHEDULER_ISR) + ISR( portSCHEDULER_ISR, ISR_NAKED ) __attribute__( ( hot, flatten ) ); + + /* ISR(portSCHEDULER_ISR, ISR_NAKED ISR_NOBLOCK) __attribute__ ((hot, flatten)); + */ + ISR( portSCHEDULER_ISR ) { vPortYieldFromTick(); __asm__ __volatile__ ( "reti" ); } -#else +#else /* if configUSE_PREEMPTION == 1 */ /* * Tick ISR for the cooperative scheduler. All this does is increment the @@ -757,11 +761,12 @@ extern void prvSetupTimerInterrupt( void ); * * use ISR_NOBLOCK where there is an important timer running, that should preempt the scheduler. */ - ISR(portSCHEDULER_ISR) __attribute__ ((hot, flatten)); -/* ISR(portSCHEDULER_ISR, ISR_NOBLOCK) __attribute__ ((hot, flatten)); - */ - ISR(portSCHEDULER_ISR) + ISR( portSCHEDULER_ISR ) __attribute__( ( hot, flatten ) ); + + /* ISR(portSCHEDULER_ISR, ISR_NOBLOCK) __attribute__ ((hot, flatten)); + */ + ISR( portSCHEDULER_ISR ) { xTaskIncrementTick(); } -#endif +#endif /* if configUSE_PREEMPTION == 1 */ diff --git a/src/portmacro.h b/src/portmacro.h index b8c923d..8497baa 100644 --- a/src/portmacro.h +++ b/src/portmacro.h @@ -24,7 +24,7 @@ * https://www.FreeRTOS.org * https://github.com/FreeRTOS * -*/ + */ #ifndef PORTMACRO_H #define PORTMACRO_H @@ -47,6 +47,8 @@ /* Type definitions. */ +#define portPOINTER_SIZE_TYPE uint16_t + typedef uint8_t StackType_t; typedef int8_t BaseType_t; typedef uint8_t UBaseType_t; @@ -79,8 +81,8 @@ typedef uint8_t UBaseType_t; ) -#define portDISABLE_INTERRUPTS() __asm__ __volatile__ ( "cli" ::: "memory") -#define portENABLE_INTERRUPTS() __asm__ __volatile__ ( "sei" ::: "memory") +#define portDISABLE_INTERRUPTS() __asm__ __volatile__ ( "cli" ::: "memory" ) +#define portENABLE_INTERRUPTS() __asm__ __volatile__ ( "sei" ::: "memory" ) /*-----------------------------------------------------------*/ /* Architecture specifics. */ @@ -97,25 +99,25 @@ typedef uint8_t UBaseType_t; extern void vPortDelay( const uint32_t ms ); #define portDELAY( ms ) vPortDelay( ms ) -extern void vPortYield( void ) __attribute__ ((naked)); -#define portYIELD() vPortYield() +extern void vPortYield( void ) __attribute__( ( naked ) ); +#define portYIELD() vPortYield() -extern void vPortYieldFromISR( void ) __attribute__ ((naked)); -#define portYIELD_FROM_ISR() vPortYieldFromISR() +extern void vPortYieldFromISR( void ) __attribute__( ( naked ) ); +#define portYIELD_FROM_ISR() vPortYieldFromISR() /*-----------------------------------------------------------*/ -#if defined(__AVR_3_BYTE_PC__) +#if defined( __AVR_3_BYTE_PC__ ) /* Task function macros as described on the FreeRTOS.org WEB site. */ /* Add .lowtext tag from the avr linker script avr6.x for ATmega2560 and ATmega2561 * to make sure functions are loaded in low memory. */ -#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) __attribute__ ((section (".lowtext"))) + #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) __attribute__( ( section( ".lowtext" ) ) ) #else -#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) + #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #endif -#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) /* *INDENT-OFF* */ #ifdef __cplusplus diff --git a/src/queue.h b/src/queue.h index 49870ab..f80a3b2 100644 --- a/src/queue.h +++ b/src/queue.h @@ -1496,8 +1496,8 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, #endif /* - * For internal use only. Use xSemaphoreTakeMutexRecursive() or - * xSemaphoreGiveMutexRecursive() instead of calling these functions directly. + * For internal use only. Use xSemaphoreTakeRecursive() or + * xSemaphoreGiveRecursive() instead of calling these functions directly. */ BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; diff --git a/src/stream_buffer.c b/src/stream_buffer.c index 40fa295..421304a 100644 --- a/src/stream_buffer.c +++ b/src/stream_buffer.c @@ -57,20 +57,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 */ @@ -94,23 +95,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 */ @@ -137,17 +139,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 */ @@ -172,22 +175,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 */ @@ -238,6 +242,7 @@ typedef struct StreamBufferDef_t 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; /* @@ -791,7 +796,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, 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 ); @@ -806,7 +811,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, 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 ); } @@ -1002,7 +1007,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, 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 ); @@ -1019,7 +1024,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, { /* 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. */ @@ -1308,10 +1313,11 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer { 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; } @@ -1343,10 +1349,11 @@ BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuf { 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; } @@ -1500,6 +1507,7 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, pxStreamBuffer->xLength = xBufferSizeBytes; pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; pxStreamBuffer->ucFlags = ucFlags; + pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY; #if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) { pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback; @@ -1519,6 +1527,43 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, } #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 ) diff --git a/src/stream_buffer.h b/src/stream_buffer.h index 4eb7287..b5a2a8d 100644 --- a/src/stream_buffer.h +++ b/src/stream_buffer.h @@ -911,6 +911,57 @@ BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer 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/src/tasks.c b/src/tasks.c index 6faadfe..69a44b3 100644 --- a/src/tasks.c +++ b/src/tasks.c @@ -6340,17 +6340,17 @@ static void prvCheckTasksWaitingTermination( void ) static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte ) { - configSTACK_DEPTH_TYPE ulCount = 0U; + configSTACK_DEPTH_TYPE uxCount = 0U; while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE ) { pucStackByte -= portSTACK_GROWTH; - ulCount++; + uxCount++; } - ulCount /= ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ); + uxCount /= ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ); - return ( configSTACK_DEPTH_TYPE ) ulCount; + return ( configSTACK_DEPTH_TYPE ) uxCount; } #endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ @@ -6421,7 +6421,7 @@ static void prvCheckTasksWaitingTermination( void ) } #endif - uxReturn = ( configSTACK_DEPTH_TYPE) prvTaskCheckFreeStackSpace( pucEndOfStack ); + uxReturn = prvTaskCheckFreeStackSpace( pucEndOfStack ); traceRETURN_uxTaskGetStackHighWaterMark( uxReturn );