]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/Common/Minimal/StreamBufferDemo.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / Common / Minimal / StreamBufferDemo.c
diff --git a/FreeRTOS/Demo/Common/Minimal/StreamBufferDemo.c b/FreeRTOS/Demo/Common/Minimal/StreamBufferDemo.c
new file mode 100644 (file)
index 0000000..0ae9abc
--- /dev/null
@@ -0,0 +1,1003 @@
+/*\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