--- /dev/null
+/*\r
+ * FreeRTOS Kernel V10.0.0\r
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software. If you wish to use our Amazon\r
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/* Standard includes. */\r
+#include "stdio.h"\r
+#include "string.h"\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "stream_buffer.h"\r
+\r
+/* Demo app includes. */\r
+#include "StreamBufferDemo.h"\r
+\r
+/* The number of bytes of storage in the stream buffers used in this test. */\r
+#define sbSTREAM_BUFFER_LENGTH_BYTES ( ( size_t ) 30 )\r
+\r
+/* Start and end ASCII characters used in data sent to the buffers. */\r
+#define sbASCII_SPACE 32\r
+#define sbASCII_TILDA 126\r
+\r
+/* Defines the number of tasks to create in this test and demo. */\r
+#define sbNUMBER_OF_ECHO_CLIENTS ( 2 )\r
+#define sbNUMBER_OF_SENDER_TASKS ( 2 )\r
+\r
+/* Priority of the test tasks. The send and receive go from low to high\r
+priority tasks, and from high to low priority tasks. */\r
+#define sbLOWER_PRIORITY ( tskIDLE_PRIORITY )\r
+#define sbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
+\r
+/* Block times used when sending and receiving from the stream buffers. */\r
+#define sbRX_TX_BLOCK_TIME pdMS_TO_TICKS( 125UL )\r
+\r
+/* A block time of 0 means "don't block". */\r
+#define sbDONT_BLOCK ( 0 )\r
+\r
+/* The trigger level sets the number of bytes that must be present in the\r
+stream buffer before a task that is blocked on the stream buffer is moved out of\r
+the Blocked state so it can read the bytes. */\r
+#define sbTRIGGER_LEVEL_1 ( 1 )\r
+\r
+/* The size of the stack allocated to the tasks that run as part of this demo/\r
+test. The stack size is over generous in most cases. */\r
+#define sbSTACK_SIZE ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Performs various tests that do not require multiple tasks to interact.\r
+ */\r
+static void prvSingleTaskTests( StreamBufferHandle_t xStreamBuffer );\r
+\r
+/*\r
+ * Tests sending and receiving various lengths of data via a stream buffer.\r
+ * The echo client sends the data to the echo server, which then sends the\r
+ * data back to the echo client, which checks it receives exactly what it\r
+ * sent.\r
+ */\r
+static void prvEchoClient( void *pvParameters );\r
+static void prvEchoServer( void *pvParameters );\r
+\r
+/*\r
+ * Tasks that send and receive to a stream buffer at a low priority and without\r
+ * blocking, so the send and receive functions interleave in time as the tasks\r
+ * are switched in and out.\r
+ */\r
+static void prvNonBlockingReceiverTask( void *pvParameters );\r
+static void prvNonBlockingSenderTask( void *pvParameters );\r
+\r
+/*\r
+ * A task that creates a stream buffer with a specific trigger level, then\r
+ * receives a string from an interrupt (the RTOS tick hook) byte by byte to\r
+ * check it is only unblocked when the specified trigger level is reached.\r
+ */\r
+static void prvInterruptTriggerLevelTest( void *pvParameters );\r
+\r
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+ /* This file tests both statically and dynamically allocated stream buffers.\r
+ Allocate the structures and buffers to be used by the statically allocated\r
+ objects, which get used in the echo tests. */\r
+ static void prvReceiverTask( void *pvParameters );\r
+ static void prvSenderTask( void *pvParameters );\r
+\r
+ static StaticStreamBuffer_t xStaticStreamBuffers[ sbNUMBER_OF_ECHO_CLIENTS ];\r
+ static uint8_t ucBufferStorage[ sbNUMBER_OF_SENDER_TASKS ][ sbSTREAM_BUFFER_LENGTH_BYTES + 1 ];\r
+ static uint32_t ulSenderLoopCounters[ sbNUMBER_OF_SENDER_TASKS ] = { 0 };\r
+#endif /* configSUPPORT_STATIC_ALLOCATION */\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The buffers used by the echo client and server tasks. */\r
+typedef struct ECHO_STREAM_BUFFERS\r
+{\r
+ /* Handles to the data structures that describe the stream buffers. */\r
+ StreamBufferHandle_t xEchoClientBuffer;\r
+ StreamBufferHandle_t xEchoServerBuffer;\r
+} EchoStreamBuffers_t;\r
+static volatile uint32_t ulEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
+\r
+/* The non-blocking tasks monitor their operation, and if no errors have been\r
+found, increment ulNonBlockingRxCounter. xAreStreamBufferTasksStillRunning()\r
+then checks ulNonBlockingRxCounter and only returns pdPASS if\r
+ulNonBlockingRxCounter is still incrementing. */\r
+static volatile uint32_t ulNonBlockingRxCounter = 0;\r
+\r
+/* The task that receives characters from the tick interrupt in order to test\r
+different trigger levels monitors its own behaviour. If it has not detected any\r
+error then it increments ulInterruptTriggerCounter to indicate to the check task\r
+that it is still operating correctly. */\r
+static volatile uint32_t ulInterruptTriggerCounter = 0UL;\r
+\r
+/* The stream buffer used from the tick interrupt. This sends one byte at a time\r
+to a test task to test the trigger level operation. The variable is set to NULL\r
+in between test runs. */\r
+static volatile StreamBufferHandle_t xInterruptStreamBuffer = NULL;\r
+\r
+/* The data sent from the tick interrupt to the task that tests the trigger\r
+level functionality. */\r
+static const char *pcDataSentFromInterrupt = "12345678";\r
+\r
+/* Data that is longer than the buffer that is sent to the buffers as a stream\r
+of bytes. Parts of which are written to the stream buffer to test writing\r
+different lengths at different offsets, to many bytes, part streams, streams\r
+that wrap, etc.. Two messages are defined to ensure left over data is not\r
+accidentally read out of the buffer. */\r
+static const char *pc55ByteString = "One two three four five six seven eight nine ten eleven";\r
+static const char *pc54ByteString = "01234567891abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ";\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartStreamBufferTasks( void )\r
+{\r
+StreamBufferHandle_t xStreamBuffer;\r
+\r
+ /* The echo servers sets up the stream buffers before creating the echo\r
+ client tasks. One set of tasks has the server as the higher priority, and\r
+ the other has the client as the higher priority. */\r
+ xTaskCreate( prvEchoServer, "1StrEchoServer", sbSTACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );\r
+ xTaskCreate( prvEchoServer, "2StrEchoServer", sbSTACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );\r
+\r
+ /* The non blocking tasks run continuously and will interleave with each\r
+ other, so must be created at the lowest priority. The stream buffer they\r
+ use is created and passed in using the task's parameter. */\r
+ xStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
+ xTaskCreate( prvNonBlockingReceiverTask, "StrNonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );\r
+ xTaskCreate( prvNonBlockingSenderTask, "StrNonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );\r
+\r
+ /* The task that receives bytes from an interrupt to test that it unblocks\r
+ at a specific trigger level must run at a high priority to minimise the risk\r
+ of it receiving more characters before it can execute again after being\r
+ unblocked. */\r
+ xTaskCreate( prvInterruptTriggerLevelTest, "StrTrig", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );\r
+\r
+ #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+ {\r
+ /* The sender tasks set up the stream buffers before creating the\r
+ receiver tasks. Priorities must be 0 and 1 as the priority is used to\r
+ index into the xStaticStreamBuffers and ucBufferStorage arrays. */\r
+ xTaskCreate( prvSenderTask, "Str1Sender", sbSTACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );\r
+ xTaskCreate( prvSenderTask, "Str2Sender", sbSTACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );\r
+ }\r
+ #endif /* configSUPPORT_STATIC_ALLOCATION */\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSingleTaskTests( StreamBufferHandle_t xStreamBuffer )\r
+{\r
+size_t xReturned, xItem, xExpectedSpace;\r
+const size_t xMax6ByteMessages = sbSTREAM_BUFFER_LENGTH_BYTES / 6;\r
+const size_t x6ByteLength = 6, x17ByteLength = 17, xFullBufferSize = sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2;\r
+uint8_t *pucFullBuffer, *pucData, *pucReadData;\r
+TickType_t xTimeBeforeCall, xTimeAfterCall;\r
+const TickType_t xBlockTime = pdMS_TO_TICKS( 15 ), xAllowableMargin = pdMS_TO_TICKS( 3 ), xMinimalBlockTime = 2;\r
+UBaseType_t uxOriginalPriority;\r
+\r
+ /* Remove warning in case configASSERT() is not defined. */\r
+ ( void ) xAllowableMargin;\r
+\r
+ /* To minimise stack and heap usage a full size buffer is allocated from the\r
+ heap, then buffers which hold smaller amounts of data are overlayed with the\r
+ larger buffer - just make sure not to use both at once! */\r
+ pucFullBuffer = pvPortMalloc( xFullBufferSize );\r
+ configASSERT( pucFullBuffer );\r
+\r
+ pucData = pucFullBuffer;\r
+ pucReadData = pucData + x17ByteLength;\r
+\r
+ /* Nothing has been added or removed yet, so expect the free space to be\r
+ exactly as created. */\r
+ xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
+\r
+\r
+ /* The buffer is 30 bytes long. 6 5 byte messages should fit before the\r
+ buffer is completely full. */\r
+ for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
+ {\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
+\r
+ /* Generate recognisable data to write to the buffer. This is just\r
+ ascii characters that shows which loop iteration the data was written\r
+ in. The 'FromISR' version is used to give it some exercise as a block\r
+ time is not used, so the call must be inside a critical section so it\r
+ runs with ports that don't support interrupt nesting (and therefore\r
+ don't have interrupt safe critical sections). */\r
+ memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
+ taskENTER_CRITICAL();\r
+ {\r
+ xReturned = xStreamBufferSendFromISR( xStreamBuffer, ( void * ) pucData, x6ByteLength, NULL );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+ configASSERT( xReturned == x6ByteLength );\r
+ ( void ) xReturned; /* In case configASSERT() is not defined. */\r
+\r
+ /* The space in the buffer will have reduced by the amount of user data\r
+ written into the buffer. */\r
+ xExpectedSpace -= x6ByteLength;\r
+ xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == xExpectedSpace );\r
+ ( void ) xReturned; /* In case configASSERT() is not defined. */\r
+ xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
+ /* +1 as it is zero indexed. */\r
+ configASSERT( xReturned == ( ( xItem + 1 ) * x6ByteLength ) );\r
+ ( void ) xReturned; /* In case configASSERT() is not defined. */\r
+ }\r
+\r
+ /* Now the buffer should be full, and attempting to add anything will should\r
+ fail. */\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), sbDONT_BLOCK );\r
+ configASSERT( xReturned == 0 );\r
+ ( void ) xReturned; /* In case configASSERT() is not defined. */\r
+\r
+ /* Adding with a timeout should also fail after the appropriate time. The\r
+ priority is temporarily boosted in this part of the test to keep the\r
+ allowable margin to a minimum. */\r
+ uxOriginalPriority = uxTaskPriorityGet( NULL );\r
+ vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
+ xTimeBeforeCall = xTaskGetTickCount();\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );\r
+ xTimeAfterCall = xTaskGetTickCount();\r
+ vTaskPrioritySet( NULL, uxOriginalPriority );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
+ configASSERT( xReturned == 0 ); /* In case configASSERT() is not defined. */\r
+ ( void ) xTimeAfterCall;\r
+ ( void ) xTimeBeforeCall;\r
+\r
+\r
+ /* The buffer is now full of data in the form "000000", "111111", etc. Make\r
+ sure the data is read out as expected. */\r
+ for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
+ {\r
+ /* Generate the data that is expected to be read out for this loop\r
+ iteration. */\r
+ memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
+\r
+ /* Read the next 6 bytes out. The 'FromISR' version is used to give it\r
+ some exercise as a block time is not used, so a it must be called from\r
+ a critical section so this will work on ports that don't support\r
+ interrupt nesting (so don't have interrupt safe critical sections). */\r
+ taskENTER_CRITICAL();\r
+ {\r
+ xReturned = xStreamBufferReceiveFromISR( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, NULL );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+ configASSERT( xReturned == x6ByteLength );\r
+\r
+ /* Does the data read out match that expected? */\r
+ configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );\r
+\r
+ /* The space in the buffer will have increased by the amount of user\r
+ data removed from the buffer. */\r
+ xExpectedSpace += x6ByteLength;\r
+ xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == xExpectedSpace );\r
+ xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == ( sbSTREAM_BUFFER_LENGTH_BYTES - xExpectedSpace ) );\r
+ }\r
+\r
+ /* The buffer should be empty again. */\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
+ xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+\r
+ /* Reading with a timeout should also fail after the appropriate time. The\r
+ priority is temporarily boosted in this part of the test to keep the\r
+ allowable margin to a minimum. */\r
+ vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
+ xTimeBeforeCall = xTaskGetTickCount();\r
+ xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );\r
+ xTimeAfterCall = xTaskGetTickCount();\r
+ vTaskPrioritySet( NULL, uxOriginalPriority );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
+ configASSERT( xReturned == 0 );\r
+\r
+\r
+ /* In the next loop 17 bytes are written to then read out on each\r
+ iteration. As 30 is not divisible by 17 the data will wrap around. */\r
+ xExpectedSpace = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength;\r
+\r
+ for( xItem = 0; xItem < 100; xItem++ )\r
+ {\r
+ /* Generate recognisable data to write to the queue. This is just\r
+ ascii characters that shows which loop iteration the data was written\r
+ in. */\r
+ memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, x17ByteLength, sbDONT_BLOCK );\r
+ configASSERT( xReturned == x17ByteLength );\r
+\r
+ /* The space in the buffer will have reduced by the amount of user data\r
+ written into the buffer. */\r
+ xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == xExpectedSpace );\r
+ xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == x17ByteLength );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
+\r
+ /* Read the 17 bytes out again. */\r
+ xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x17ByteLength, sbDONT_BLOCK );\r
+ configASSERT( xReturned == x17ByteLength );\r
+\r
+ /* Does the data read out match that expected? */\r
+ configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );\r
+\r
+ /* Full buffer space available again. */\r
+ xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
+ configASSERT( xReturned == 0 );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
+ }\r
+\r
+ /* Fill the buffer with one message, check it is full, then read it back\r
+ again and check the correct data is received. */\r
+ xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );\r
+ xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );\r
+ configASSERT( memcmp( pc55ByteString, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
+\r
+ /* Fill the buffer one bytes at a time. */\r
+ for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )\r
+ {\r
+ /* Block time is only for test coverage, the task should never actually\r
+ block here. */\r
+ xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xItem ] ), sizeof( char ), sbRX_TX_BLOCK_TIME );\r
+ }\r
+\r
+ /* The buffer should now be full. */\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
+\r
+ /* Read the message out in one go, even though it was written in individual\r
+ bytes. Try reading much more data than is actually available to ensure only\r
+ the available bytes are returned (otherwise this read will write outside of\r
+ the memory allocated anyway!). */\r
+ xReturned = xStreamBufferReceive( xStreamBuffer, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, sbRX_TX_BLOCK_TIME );\r
+ configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( memcmp( ( const void * ) pc54ByteString, ( const void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
+\r
+ /* Now do the opposite, write in one go and read out in single bytes. */\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbRX_TX_BLOCK_TIME );\r
+ configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
+ configASSERT( xStreamBufferBytesAvailable( xStreamBuffer ) == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( xStreamBufferSpacesAvailable( xStreamBuffer ) == 0 );\r
+\r
+ /* Read from the buffer one byte at a time. */\r
+ for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )\r
+ {\r
+ /* Block time is only for test coverage, the task should never actually\r
+ block here. */\r
+ xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sizeof( char ), sbRX_TX_BLOCK_TIME );\r
+ configASSERT( pc55ByteString[ xItem ] == pucFullBuffer[ 0 ] );\r
+ }\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
+\r
+ /* Try writing more bytes than there is space. */\r
+ vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
+ xTimeBeforeCall = xTaskGetTickCount();\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, xMinimalBlockTime );\r
+ xTimeAfterCall = xTaskGetTickCount();\r
+ vTaskPrioritySet( NULL, uxOriginalPriority );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xMinimalBlockTime );\r
+ configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xMinimalBlockTime + xAllowableMargin ) );\r
+ configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
+\r
+ /* No space now though. */\r
+ xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, xMinimalBlockTime );\r
+ configASSERT( xReturned == 0 );\r
+\r
+ /* Ensure data was written as expected even when there was an attempt to\r
+ write more than was available. This also tries to read more bytes than are\r
+ available. */\r
+ xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, xFullBufferSize, xMinimalBlockTime );\r
+ configASSERT( memcmp( ( const void * ) pucFullBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
+ configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
+ configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
+\r
+ /* Clean up with data in the buffer to ensure the tests that follow don't\r
+ see the data (the data should be discarded). */\r
+ ( void ) xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES / ( size_t ) 2, sbDONT_BLOCK );\r
+ vPortFree( pucFullBuffer );\r
+ xStreamBufferReset( xStreamBuffer );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvNonBlockingSenderTask( void *pvParameters )\r
+{\r
+StreamBufferHandle_t xStreamBuffer;\r
+size_t xNextChar = 0, xBytesToSend, xBytesActuallySent;\r
+const size_t xStringLength = strlen( pc54ByteString );\r
+\r
+ /* In this case the stream buffer has already been created and is passed\r
+ into the task using the task's parameter. */\r
+ xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;\r
+\r
+ /* Keep sending the string to the stream buffer as many bytes as possible in\r
+ each go. Doesn't block so calls can interleave with the non-blocking\r
+ receives performed by prvNonBlockingReceiverTask(). */\r
+ for( ;; )\r
+ {\r
+ /* The whole string cannot be sent at once, so xNextChar is an index to\r
+ the position within the string that has been sent so far. How many\r
+ bytes are there left to send before the end of the string? */\r
+ xBytesToSend = xStringLength - xNextChar;\r
+\r
+ /* Attempt to send right up to the end of the string. */\r
+ xBytesActuallySent = xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xNextChar ] ), xBytesToSend, sbDONT_BLOCK );\r
+ configASSERT( xBytesActuallySent <= xBytesToSend );\r
+\r
+ /* Move the index up the string to the next character to be sent,\r
+ wrapping if the end of the string has been reached. */\r
+ xNextChar += xBytesActuallySent;\r
+ configASSERT( xNextChar <= xStringLength );\r
+\r
+ if( xNextChar == xStringLength )\r
+ {\r
+ xNextChar = 0;\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvNonBlockingReceiverTask( void *pvParameters )\r
+{\r
+StreamBufferHandle_t xStreamBuffer;\r
+size_t xNextChar = 0, xReceiveLength, xBytesToTest, xStartIndex;\r
+const size_t xStringLength = strlen( pc54ByteString );\r
+char cRxString[ 12 ]; /* Holds received characters. */\r
+BaseType_t xNonBlockingReceiveError = pdFALSE;\r
+\r
+ /* In this case the stream buffer has already been created and is passed\r
+ into the task using the task's parameter. */\r
+ xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;\r
+\r
+ /* Expects to receive the pc54ByteString over and over again. Sends and\r
+ receives are not blocking so will interleave. */\r
+ for( ;; )\r
+ {\r
+ /* Attempt to receive as many bytes as possible, up to the limit of the\r
+ Rx buffer size. */\r
+ xReceiveLength = xStreamBufferReceive( xStreamBuffer, ( void * ) cRxString, sizeof( cRxString ), sbDONT_BLOCK );\r
+\r
+ if( xReceiveLength > 0 )\r
+ {\r
+ /* xNextChar is the index into pc54ByteString that has been received\r
+ already. If xReceiveLength bytes are added to that, will it go off\r
+ the end of the string? If so, then first test up to the end of the\r
+ string, then go back to the start of pc54ByteString to test the\r
+ remains of the received data. */\r
+ xBytesToTest = xReceiveLength;\r
+ if( ( xNextChar + xBytesToTest ) > xStringLength )\r
+ {\r
+ /* Cap to test the received data to the end of the string. */\r
+ xBytesToTest = xStringLength - xNextChar;\r
+\r
+ if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) cRxString, xBytesToTest ) != 0 )\r
+ {\r
+ xNonBlockingReceiveError = pdTRUE;\r
+ }\r
+\r
+ /* Then move back to the start of the string to test the\r
+ remaining received bytes. */\r
+ xNextChar = 0;\r
+ xStartIndex = xBytesToTest;\r
+ xBytesToTest = xReceiveLength - xBytesToTest;\r
+ }\r
+ else\r
+ {\r
+ /* The string didn't wrap in the buffer, so start comparing from\r
+ the start of the received data. */\r
+ xStartIndex = 0;\r
+ }\r
+\r
+ /* Test the received bytes are as expected, then move the index\r
+ along the string to the next expected char to receive. */\r
+ if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) &( cRxString[ xStartIndex ] ), xBytesToTest ) != 0 )\r
+ {\r
+ xNonBlockingReceiveError = pdTRUE;\r
+ }\r
+\r
+ if( xNonBlockingReceiveError == pdFALSE )\r
+ {\r
+ /* No errors detected so increment the counter that lets the\r
+ check task know this test is still functioning correctly. */\r
+ ulNonBlockingRxCounter++;\r
+ }\r
+\r
+ xNextChar += xBytesToTest;\r
+ if( xNextChar >= xStringLength )\r
+ {\r
+ xNextChar = 0;\r
+ }\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+\r
+ static void prvSenderTask( void *pvParameters )\r
+ {\r
+ StreamBufferHandle_t xStreamBuffer, xTempStreamBuffer;\r
+ static uint8_t ucTempBuffer[ 10 ]; /* Just used to exercise stream buffer creating and deletion. */\r
+ const TickType_t xTicksToWait = sbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );\r
+ StaticStreamBuffer_t xStaticStreamBuffer;\r
+ size_t xNextChar = 0, xBytesToSend, xBytesActuallySent;\r
+ const size_t xStringLength = strlen( pc55ByteString );\r
+\r
+ /* The task's priority is used as an index into the loop counters used to\r
+ indicate this task is still running. */\r
+ UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
+\r
+ /* Make sure a change in priority does not inadvertently result in an\r
+ invalid array index. */\r
+ configASSERT( uxIndex < sbNUMBER_OF_ECHO_CLIENTS );\r
+\r
+ /* Avoid compiler warnings about unused parameters. */\r
+ ( void ) pvParameters;\r
+\r
+ xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ) / sbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */\r
+ sbTRIGGER_LEVEL_1, /* The number of bytes to be in the buffer before a task blocked to wait for data is unblocked. */\r
+ &( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */\r
+ &( xStaticStreamBuffers[ uxIndex ] ) ); /* The static stream buffer structure to use within the array. */\r
+\r
+ /* Now the stream buffer has been created the receiver task can be\r
+ created. If this sender task has the higher priority then the receiver\r
+ task is created at the lower priority - if this sender task has the\r
+ lower priority then the receiver task is created at the higher\r
+ priority. */\r
+ if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )\r
+ {\r
+ /* Here prvSingleTaskTests() performs various tests on a stream buffer\r
+ that was created statically. */\r
+ prvSingleTaskTests( xStreamBuffer );\r
+ xTaskCreate( prvReceiverTask, "StrReceiver", sbSTACK_SIZE, ( void * ) xStreamBuffer, sbHIGHER_PRIORITY, NULL );\r
+ }\r
+ else\r
+ {\r
+ xTaskCreate( prvReceiverTask, "StrReceiver", sbSTACK_SIZE, ( void * ) xStreamBuffer, sbLOWER_PRIORITY, NULL );\r
+ }\r
+\r
+ for( ;; )\r
+ {\r
+ /* The whole string cannot be sent at once, so xNextChar is an index\r
+ to the position within the string that has been sent so far. How\r
+ many bytes are there left to send before the end of the string? */\r
+ xBytesToSend = xStringLength - xNextChar;\r
+\r
+ /* Attempt to send right up to the end of the string. */\r
+ xBytesActuallySent = xStreamBufferSend( xStreamBuffer, ( void * ) &( pc55ByteString[ xNextChar ] ), xBytesToSend, xTicksToWait );\r
+ configASSERT( xBytesActuallySent <= xBytesToSend );\r
+\r
+ /* Move the index up the string to the next character to be sent,\r
+ wrapping if the end of the string has been reached. */\r
+ xNextChar += xBytesActuallySent;\r
+ configASSERT( xNextChar <= xStringLength );\r
+\r
+ if( xNextChar == xStringLength )\r
+ {\r
+ xNextChar = 0;\r
+ }\r
+\r
+ /* Increment a loop counter so a check task can tell this task is\r
+ still running as expected. */\r
+ ulSenderLoopCounters[ uxIndex ]++;\r
+\r
+ if( uxTaskPriorityGet( NULL ) == sbHIGHER_PRIORITY )\r
+ {\r
+ /* Allow other tasks to run. */\r
+ vTaskDelay( xShortDelay );\r
+ }\r
+\r
+ /* This stream buffer is just created and deleted to ensure no\r
+ issues when attempting to delete a stream buffer that was\r
+ created using statically allocated memory. To save stack space\r
+ the buffer is set to point to the pc55ByteString, which is a const\r
+ string, but no data is written into the buffer so any valid address\r
+ will do. */\r
+ xTempStreamBuffer = xStreamBufferCreateStatic( sizeof( ucTempBuffer ), sbTRIGGER_LEVEL_1, ucTempBuffer, &xStaticStreamBuffer );\r
+ vStreamBufferDelete( xTempStreamBuffer );\r
+ }\r
+ }\r
+\r
+#endif /* configSUPPORT_STATIC_ALLOCATION */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+\r
+ static void prvReceiverTask( void *pvParameters )\r
+ {\r
+ StreamBufferHandle_t * const pxStreamBuffer = ( StreamBufferHandle_t * ) pvParameters;\r
+ char cRxString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */\r
+ const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );\r
+ const size_t xStringLength = strlen( pc55ByteString );\r
+ size_t xNextChar = 0, xReceivedLength, xBytesToReceive;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Attempt to receive the number of bytes to the end of the string,\r
+ or the number of byte that can be placed into the rx buffer,\r
+ whichever is smallest. */\r
+ xBytesToReceive = configMIN( ( xStringLength - xNextChar ), sizeof( cRxString ) );\r
+\r
+ do\r
+ {\r
+ xReceivedLength = xStreamBufferReceive( pxStreamBuffer, ( void * ) cRxString, xBytesToReceive, xTicksToWait );\r
+\r
+ } while( xReceivedLength == 0 );\r
+\r
+ /* Ensure the received string matches the expected string. */\r
+ configASSERT( memcmp( ( void * ) cRxString, ( void * ) &( pc55ByteString[ xNextChar ] ), xReceivedLength ) == 0 );\r
+\r
+ /* Move the index into the string up to the end of the bytes\r
+ received so far - wrapping if the end of the string has been\r
+ reached. */\r
+ xNextChar += xReceivedLength;\r
+ if( xNextChar >= xStringLength )\r
+ {\r
+ xNextChar = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+#endif /* configSUPPORT_STATIC_ALLOCATION */\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvEchoClient( void *pvParameters )\r
+{\r
+size_t xSendLength = 0, ux;\r
+char *pcStringToSend, *pcStringReceived, cNextChar = sbASCII_SPACE;\r
+const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );\r
+StreamBufferHandle_t xTempStreamBuffer;\r
+\r
+/* The task's priority is used as an index into the loop counters used to\r
+indicate this task is still running. */\r
+UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
+\r
+/* Pointers to the client and server stream buffers are passed into this task\r
+using the task's parameter. */\r
+EchoStreamBuffers_t *pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;\r
+\r
+ /* Prevent compiler warnings. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Create the buffer into which strings to send to the server will be\r
+ created, and the buffer into which strings echoed back from the server will\r
+ be copied. */\r
+ pcStringToSend = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ pcStringReceived = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
+\r
+ configASSERT( pcStringToSend );\r
+ configASSERT( pcStringReceived );\r
+\r
+ for( ;; )\r
+ {\r
+ /* Generate the length of the next string to send. */\r
+ xSendLength++;\r
+\r
+ /* The stream buffer is being used to hold variable length data, so\r
+ each data item requires sizeof( size_t ) bytes to hold the data's\r
+ length, hence the sizeof() in the if() condition below. */\r
+ if( xSendLength > ( sbSTREAM_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )\r
+ {\r
+ /* Back to a string length of 1. */\r
+ xSendLength = sizeof( char );\r
+ }\r
+\r
+ memset( pcStringToSend, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
+\r
+ for( ux = 0; ux < xSendLength; ux++ )\r
+ {\r
+ pcStringToSend[ ux ] = cNextChar;\r
+\r
+ cNextChar++;\r
+\r
+ if( cNextChar > sbASCII_TILDA )\r
+ {\r
+ cNextChar = sbASCII_SPACE;\r
+ }\r
+ }\r
+\r
+ /* Send the generated string to the buffer. */\r
+ do\r
+ {\r
+ ux = xStreamBufferSend( pxStreamBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );\r
+\r
+ } while( ux == 0 );\r
+\r
+ /* Wait for the string to be echoed back. */\r
+ memset( pcStringReceived, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ xStreamBufferReceive( pxStreamBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );\r
+\r
+ configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );\r
+\r
+ /* Maintain a count of the number of times this code executes so a\r
+ check task can determine if this task is still functioning as\r
+ expected or not. As there are two client tasks, and the priorities\r
+ used are 0 and 1, the task's priority is used as an index into the\r
+ loop count array. */\r
+ ulEchoLoopCounters[ uxIndex ]++;\r
+\r
+ /* This stream buffer is just created and deleted to ensure no memory\r
+ leaks. */\r
+ xTempStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
+ prvSingleTaskTests( xTempStreamBuffer );\r
+ vStreamBufferDelete( xTempStreamBuffer );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvEchoServer( void *pvParameters )\r
+{\r
+size_t xReceivedLength;\r
+char *pcReceivedString;\r
+EchoStreamBuffers_t xStreamBuffers;\r
+TickType_t xTimeOnEntering;\r
+const TickType_t xTicksToBlock = pdMS_TO_TICKS( 350UL );\r
+\r
+ /* Prevent compiler warnings about unused parameters. */\r
+ ( void ) pvParameters;\r
+\r
+ /* Create the stream buffer used to send data from the client to the server,\r
+ and the stream buffer used to echo the data from the server back to the\r
+ client. */\r
+ xStreamBuffers.xEchoClientBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
+ xStreamBuffers.xEchoServerBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
+ configASSERT( xStreamBuffers.xEchoClientBuffer );\r
+ configASSERT( xStreamBuffers.xEchoServerBuffer );\r
+\r
+ /* Create the buffer into which received strings will be copied. */\r
+ pcReceivedString = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
+ configASSERT( pcReceivedString );\r
+\r
+ /* Don't expect to receive anything yet! */\r
+ xTimeOnEntering = xTaskGetTickCount();\r
+ xReceivedLength = xStreamBufferReceive( xStreamBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, sbSTREAM_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
+ configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToBlock );\r
+ configASSERT( xReceivedLength == 0 );\r
+ ( void ) xTimeOnEntering;\r
+\r
+ /* Now the stream buffers have been created the echo client task can be\r
+ created. If this server task has the higher priority then the client task\r
+ is created at the lower priority - if this server task has the lower\r
+ priority then the client task is created at the higher priority. */\r
+ if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )\r
+ {\r
+ xTaskCreate( prvEchoClient, "EchoClient", sbSTACK_SIZE, ( void * ) &xStreamBuffers, sbHIGHER_PRIORITY, NULL );\r
+ }\r
+ else\r
+ {\r
+ /* Here prvSingleTaskTests() performs various tests on a stream buffer\r
+ that was created dynamically. */\r
+ prvSingleTaskTests( xStreamBuffers.xEchoClientBuffer );\r
+ xTaskCreate( prvEchoClient, "EchoClient", sbSTACK_SIZE, ( void * ) &xStreamBuffers, sbLOWER_PRIORITY, NULL );\r
+ }\r
+\r
+ for( ;; )\r
+ {\r
+ memset( pcReceivedString, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
+\r
+ /* Has any data been sent by the client? */\r
+ xReceivedLength = xStreamBufferReceive( xStreamBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, sbSTREAM_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
+\r
+ /* Should always receive data as a delay was used. */\r
+ configASSERT( xReceivedLength > 0 );\r
+\r
+ /* Echo the received data back to the client. */\r
+ xStreamBufferSend( xStreamBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPeriodicStreamBufferProcessing( void )\r
+{\r
+static size_t xNextChar = 0;\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+ /* Called from the tick interrupt hook. If the global stream buffer\r
+ variable is not NULL then the prvInterruptTriggerTest() task expects a byte\r
+ to be sent to the stream buffer on each tick interrupt. */\r
+ if( xInterruptStreamBuffer != NULL )\r
+ {\r
+ /* One character from the pcDataSentFromInterrupt string is sent on each\r
+ interrupt. The task blocked on the stream buffer should not be\r
+ unblocked until the defined trigger level is hit. */\r
+ xStreamBufferSendFromISR( xInterruptStreamBuffer, ( const void * ) &( pcDataSentFromInterrupt[ xNextChar ] ), sizeof( char ), &xHigherPriorityTaskWoken );\r
+\r
+ if( xNextChar < strlen( pcDataSentFromInterrupt ) )\r
+ {\r
+ xNextChar++;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Start at the beginning of the string being sent again. */\r
+ xNextChar = 0;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvInterruptTriggerLevelTest( void *pvParameters )\r
+{\r
+StreamBufferHandle_t xStreamBuffer;\r
+size_t xTriggerLevel = 1, xBytesReceived;\r
+const size_t xStreamBufferSizeBytes = ( size_t ) 8, xMaxTriggerLevel = ( size_t ) 6, xMinTriggerLevel = ( size_t ) 1;\r
+const TickType_t xReadBlockTime = 4, xCycleBlockTime = pdMS_TO_TICKS( 100 );\r
+uint8_t ucRxData[ 8 ];\r
+BaseType_t xErrorDetected = pdFALSE;\r
+#ifndef configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN\r
+ const size_t xAllowableMargin = ( size_t ) 0;\r
+#else\r
+ const size_t xAllowableMargin = ( size_t ) configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN;\r
+#endif\r
+\r
+ /* Remove compiler warning about unused parameter. */\r
+ ( void ) pvParameters;\r
+\r
+ for( ;; )\r
+ {\r
+ for( xTriggerLevel = xMinTriggerLevel; xTriggerLevel < xMaxTriggerLevel; xTriggerLevel++ )\r
+ {\r
+ /* Create the stream buffer that will be used from inside the tick\r
+ interrupt. */\r
+ xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );\r
+ configASSERT( xStreamBuffer );\r
+\r
+ /* Now the stream buffer has been created it can be assigned to the\r
+ file scope variable, which will allow the tick interrupt to start\r
+ using it. */\r
+ taskENTER_CRITICAL();\r
+ {\r
+ xInterruptStreamBuffer = xStreamBuffer;\r
+ }\r
+ taskEXIT_CRITICAL();\r
+\r
+ xBytesReceived = xStreamBufferReceive( xStreamBuffer, ( void * ) ucRxData, sizeof( ucRxData ), xReadBlockTime );\r
+\r
+ /* Set the file scope variable back to NULL so the interrupt doesn't\r
+ try to use it again. */\r
+ taskENTER_CRITICAL();\r
+ {\r
+ xInterruptStreamBuffer = NULL;\r
+ }\r
+ taskEXIT_CRITICAL();\r
+\r
+ /* Now check the number of bytes received equals the trigger level,\r
+ except in the case that the read timed out before the trigger level\r
+ was reached. */\r
+ if( xBytesReceived < xTriggerLevel )\r
+ {\r
+ /* This should only happen if the trigger level was greater than\r
+ the block time. */\r
+ if( xTriggerLevel < xReadBlockTime )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+ }\r
+ else if( ( xBytesReceived - xTriggerLevel ) > xAllowableMargin )\r
+ {\r
+ /* A margin may be required here if there are other high priority\r
+ tasks prevent the task that reads from the message buffer running\r
+ immediately. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( xBytesReceived > sizeof( ucRxData ) )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+ else if( memcmp( ( void * ) ucRxData, ( const void * ) pcDataSentFromInterrupt, xBytesReceived ) != 0 )\r
+ {\r
+ /* Received data didn't match that expected. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( xErrorDetected == pdFALSE )\r
+ {\r
+ /* Increment the cycle counter so the 'check' task knows this test\r
+ is still running without error. */\r
+ ulInterruptTriggerCounter++;\r
+ }\r
+\r
+ /* Tidy up ready for the next loop. */\r
+ vStreamBufferDelete( xStreamBuffer );\r
+ vTaskDelay( xCycleBlockTime );\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t xAreStreamBufferTasksStillRunning( void )\r
+{\r
+static uint32_t ulLastEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
+static uint32_t ulLastNonBlockingRxCounter = 0;\r
+static uint32_t ulLastInterruptTriggerCounter = 0;\r
+BaseType_t xReturn = pdPASS, x;\r
+\r
+ for( x = 0; x < sbNUMBER_OF_ECHO_CLIENTS; x++ )\r
+ {\r
+ if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )\r
+ {\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];\r
+ }\r
+ }\r
+\r
+ if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )\r
+ {\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;\r
+ }\r
+\r
+ if( ulLastInterruptTriggerCounter == ulInterruptTriggerCounter )\r
+ {\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ ulLastInterruptTriggerCounter = ulInterruptTriggerCounter;\r
+ }\r
+\r
+ #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
+ {\r
+ static uint32_t ulLastSenderLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
+\r
+ for( x = 0; x < sbNUMBER_OF_SENDER_TASKS; x++ )\r
+ {\r
+ if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )\r
+ {\r
+ xReturn = pdFAIL;\r
+ }\r
+ else\r
+ {\r
+ ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];\r
+ }\r
+ }\r
+ }\r
+ #endif /* configSUPPORT_STATIC_ALLOCATION */\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r