]> git.sur5r.net Git - freertos/blob - 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
1 /*\r
2  * FreeRTOS Kernel V10.0.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* Standard includes. */\r
30 #include "stdio.h"\r
31 #include "string.h"\r
32 \r
33 /* FreeRTOS includes. */\r
34 #include "FreeRTOS.h"\r
35 #include "task.h"\r
36 #include "stream_buffer.h"\r
37 \r
38 /* Demo app includes. */\r
39 #include "StreamBufferDemo.h"\r
40 \r
41 /* The number of bytes of storage in the stream buffers used in this test. */\r
42 #define sbSTREAM_BUFFER_LENGTH_BYTES    ( ( size_t ) 30 )\r
43 \r
44 /* Start and end ASCII characters used in data sent to the buffers. */\r
45 #define sbASCII_SPACE                                   32\r
46 #define sbASCII_TILDA                                   126\r
47 \r
48 /* Defines the number of tasks to create in this test and demo. */\r
49 #define sbNUMBER_OF_ECHO_CLIENTS        ( 2 )\r
50 #define sbNUMBER_OF_SENDER_TASKS        ( 2 )\r
51 \r
52 /* Priority of the test tasks.  The send and receive go from low to high\r
53 priority tasks, and from high to low priority tasks. */\r
54 #define sbLOWER_PRIORITY                        ( tskIDLE_PRIORITY )\r
55 #define sbHIGHER_PRIORITY                       ( tskIDLE_PRIORITY + 1 )\r
56 \r
57 /* Block times used when sending and receiving from the stream buffers. */\r
58 #define sbRX_TX_BLOCK_TIME                      pdMS_TO_TICKS( 125UL )\r
59 \r
60 /* A block time of 0 means "don't block". */\r
61 #define sbDONT_BLOCK                            ( 0 )\r
62 \r
63 /* The trigger level sets the number of bytes that must be present in the\r
64 stream buffer before a task that is blocked on the stream buffer is moved out of\r
65 the Blocked state so it can read the bytes. */\r
66 #define sbTRIGGER_LEVEL_1                       ( 1 )\r
67 \r
68 /* The size of the stack allocated to the tasks that run as part of this demo/\r
69 test.  The stack size is over generous in most cases. */\r
70 #define sbSTACK_SIZE                            ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) )\r
71 \r
72 /*-----------------------------------------------------------*/\r
73 \r
74 /*\r
75  * Performs various tests that do not require multiple tasks to interact.\r
76  */\r
77 static void prvSingleTaskTests( StreamBufferHandle_t xStreamBuffer );\r
78 \r
79 /*\r
80  * Tests sending and receiving various lengths of data via a stream buffer.\r
81  * The echo client sends the data to the echo server, which then sends the\r
82  * data back to the echo client, which checks it receives exactly what it\r
83  * sent.\r
84  */\r
85 static void prvEchoClient( void *pvParameters );\r
86 static void prvEchoServer( void *pvParameters );\r
87 \r
88 /*\r
89  * Tasks that send and receive to a stream buffer at a low priority and without\r
90  * blocking, so the send and receive functions interleave in time as the tasks\r
91  * are switched in and out.\r
92  */\r
93 static void prvNonBlockingReceiverTask( void *pvParameters );\r
94 static void prvNonBlockingSenderTask( void *pvParameters );\r
95 \r
96 /*\r
97  * A task that creates a stream buffer with a specific trigger level, then\r
98  * receives a string from an interrupt (the RTOS tick hook) byte by byte to\r
99  * check it is only unblocked when the specified trigger level is reached.\r
100  */\r
101 static void prvInterruptTriggerLevelTest( void *pvParameters );\r
102 \r
103 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
104         /* This file tests both statically and dynamically allocated stream buffers.\r
105         Allocate the structures and buffers to be used by the statically allocated\r
106         objects, which get used in the echo tests. */\r
107         static void prvReceiverTask( void *pvParameters );\r
108         static void prvSenderTask( void *pvParameters );\r
109 \r
110         static StaticStreamBuffer_t xStaticStreamBuffers[ sbNUMBER_OF_ECHO_CLIENTS ];\r
111         static uint8_t ucBufferStorage[ sbNUMBER_OF_SENDER_TASKS ][ sbSTREAM_BUFFER_LENGTH_BYTES + 1 ];\r
112         static uint32_t ulSenderLoopCounters[ sbNUMBER_OF_SENDER_TASKS ] = { 0 };\r
113 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
114 \r
115 /*-----------------------------------------------------------*/\r
116 \r
117 /* The buffers used by the echo client and server tasks. */\r
118 typedef struct ECHO_STREAM_BUFFERS\r
119 {\r
120         /* Handles to the data structures that describe the stream buffers. */\r
121         StreamBufferHandle_t xEchoClientBuffer;\r
122         StreamBufferHandle_t xEchoServerBuffer;\r
123 } EchoStreamBuffers_t;\r
124 static volatile uint32_t ulEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
125 \r
126 /* The non-blocking tasks monitor their operation, and if no errors have been\r
127 found, increment ulNonBlockingRxCounter.  xAreStreamBufferTasksStillRunning()\r
128 then checks ulNonBlockingRxCounter and only returns pdPASS if\r
129 ulNonBlockingRxCounter is still incrementing. */\r
130 static volatile uint32_t ulNonBlockingRxCounter = 0;\r
131 \r
132 /* The task that receives characters from the tick interrupt in order to test\r
133 different trigger levels monitors its own behaviour.  If it has not detected any\r
134 error then it increments ulInterruptTriggerCounter to indicate to the check task\r
135 that it is still operating correctly. */\r
136 static volatile uint32_t ulInterruptTriggerCounter = 0UL;\r
137 \r
138 /* The stream buffer used from the tick interrupt.  This sends one byte at a time\r
139 to a test task to test the trigger level operation.  The variable is set to NULL\r
140 in between test runs. */\r
141 static volatile StreamBufferHandle_t xInterruptStreamBuffer = NULL;\r
142 \r
143 /* The data sent from the tick interrupt to the task that tests the trigger\r
144 level functionality. */\r
145 static const char *pcDataSentFromInterrupt = "12345678";\r
146 \r
147 /* Data that is longer than the buffer that is sent to the buffers as a stream\r
148 of bytes.  Parts of which are written to the stream buffer to test writing\r
149 different lengths at different offsets, to many bytes, part streams, streams\r
150 that wrap, etc..  Two messages are defined to ensure left over data is not\r
151 accidentally read out of the buffer. */\r
152 static const char *pc55ByteString = "One two three four five six seven eight nine ten eleven";\r
153 static const char *pc54ByteString = "01234567891abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ";\r
154 \r
155 /*-----------------------------------------------------------*/\r
156 \r
157 void vStartStreamBufferTasks( void )\r
158 {\r
159 StreamBufferHandle_t xStreamBuffer;\r
160 \r
161         /* The echo servers sets up the stream buffers before creating the echo\r
162         client tasks.  One set of tasks has the server as the higher priority, and\r
163         the other has the client as the higher priority. */\r
164         xTaskCreate( prvEchoServer, "1StrEchoServer", sbSTACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );\r
165         xTaskCreate( prvEchoServer, "2StrEchoServer", sbSTACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );\r
166 \r
167         /* The non blocking tasks run continuously and will interleave with each\r
168         other, so must be created at the lowest priority.  The stream buffer they\r
169         use is created and passed in using the task's parameter. */\r
170         xStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
171         xTaskCreate( prvNonBlockingReceiverTask, "StrNonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );\r
172         xTaskCreate( prvNonBlockingSenderTask, "StrNonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );\r
173 \r
174         /* The task that receives bytes from an interrupt to test that it unblocks\r
175         at a specific trigger level must run at a high priority to minimise the risk\r
176         of it receiving more characters before it can execute again after being\r
177         unblocked. */\r
178         xTaskCreate( prvInterruptTriggerLevelTest, "StrTrig", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );\r
179 \r
180         #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
181         {\r
182                 /* The sender tasks set up the stream buffers before creating the\r
183                 receiver tasks.  Priorities must be 0 and 1 as the priority is used to\r
184                 index into the xStaticStreamBuffers and ucBufferStorage arrays. */\r
185                 xTaskCreate( prvSenderTask, "Str1Sender", sbSTACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );\r
186                 xTaskCreate( prvSenderTask, "Str2Sender", sbSTACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );\r
187         }\r
188         #endif /* configSUPPORT_STATIC_ALLOCATION */\r
189 }\r
190 /*-----------------------------------------------------------*/\r
191 \r
192 static void prvSingleTaskTests( StreamBufferHandle_t xStreamBuffer )\r
193 {\r
194 size_t xReturned, xItem, xExpectedSpace;\r
195 const size_t xMax6ByteMessages = sbSTREAM_BUFFER_LENGTH_BYTES / 6;\r
196 const size_t x6ByteLength = 6, x17ByteLength = 17, xFullBufferSize = sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2;\r
197 uint8_t *pucFullBuffer, *pucData, *pucReadData;\r
198 TickType_t xTimeBeforeCall, xTimeAfterCall;\r
199 const TickType_t xBlockTime = pdMS_TO_TICKS( 15 ), xAllowableMargin = pdMS_TO_TICKS( 3 ), xMinimalBlockTime = 2;\r
200 UBaseType_t uxOriginalPriority;\r
201 \r
202         /* Remove warning in case configASSERT() is not defined. */\r
203         ( void ) xAllowableMargin;\r
204 \r
205         /* To minimise stack and heap usage a full size buffer is allocated from the\r
206         heap, then buffers which hold smaller amounts of data are overlayed with the\r
207         larger buffer - just make sure not to use both at once! */\r
208         pucFullBuffer = pvPortMalloc( xFullBufferSize );\r
209         configASSERT( pucFullBuffer );\r
210 \r
211         pucData = pucFullBuffer;\r
212         pucReadData = pucData + x17ByteLength;\r
213 \r
214         /* Nothing has been added or removed yet, so expect the free space to be\r
215         exactly as created. */\r
216         xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );\r
217         configASSERT( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );\r
218         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
219 \r
220 \r
221         /* The buffer is 30 bytes long.  6 5 byte messages should fit before the\r
222         buffer is completely full. */\r
223         for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
224         {\r
225                 configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
226 \r
227                 /* Generate recognisable data to write to the buffer.  This is just\r
228                 ascii characters that shows which loop iteration the data was written\r
229                 in. The 'FromISR' version is used to give it some exercise as a block\r
230                 time is not used, so the call must be inside a critical section so it\r
231                 runs with ports that don't support interrupt nesting (and therefore\r
232                 don't have interrupt safe critical sections). */\r
233                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
234                 taskENTER_CRITICAL();\r
235                 {\r
236                         xReturned = xStreamBufferSendFromISR( xStreamBuffer, ( void * ) pucData, x6ByteLength, NULL );\r
237                 }\r
238                 taskEXIT_CRITICAL();\r
239                 configASSERT( xReturned == x6ByteLength );\r
240                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
241 \r
242                 /* The space in the buffer will have reduced by the amount of user data\r
243                 written into the buffer. */\r
244                 xExpectedSpace -= x6ByteLength;\r
245                 xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
246                 configASSERT( xReturned == xExpectedSpace );\r
247                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
248                 xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
249                 /* +1 as it is zero indexed. */\r
250                 configASSERT( xReturned == ( ( xItem + 1 ) * x6ByteLength ) );\r
251                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
252         }\r
253 \r
254         /* Now the buffer should be full, and attempting to add anything will should\r
255         fail. */\r
256         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
257         xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), sbDONT_BLOCK );\r
258         configASSERT( xReturned == 0 );\r
259         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
260 \r
261         /* Adding with a timeout should also fail after the appropriate time.  The\r
262         priority is temporarily boosted in this part of the test to keep the\r
263         allowable margin to a minimum. */\r
264         uxOriginalPriority = uxTaskPriorityGet( NULL );\r
265         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
266         xTimeBeforeCall = xTaskGetTickCount();\r
267         xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );\r
268         xTimeAfterCall = xTaskGetTickCount();\r
269         vTaskPrioritySet( NULL, uxOriginalPriority );\r
270         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
271         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
272         configASSERT( xReturned == 0 ); /* In case configASSERT() is not defined. */\r
273         ( void ) xTimeAfterCall;\r
274         ( void ) xTimeBeforeCall;\r
275 \r
276 \r
277         /* The buffer is now full of data in the form "000000", "111111", etc.  Make\r
278         sure the data is read out as expected. */\r
279         for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
280         {\r
281                 /* Generate the data that is expected to be read out for this loop\r
282                 iteration. */\r
283                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
284 \r
285                 /* Read the next 6 bytes out.  The 'FromISR' version is used to give it\r
286                 some exercise as a block time is not used, so a it must be called from\r
287                 a critical section so this will work on ports that don't support\r
288                 interrupt nesting (so don't have interrupt safe critical sections). */\r
289                 taskENTER_CRITICAL();\r
290                 {\r
291                         xReturned = xStreamBufferReceiveFromISR( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, NULL );\r
292                 }\r
293                 taskEXIT_CRITICAL();\r
294                 configASSERT( xReturned == x6ByteLength );\r
295 \r
296                 /* Does the data read out match that expected? */\r
297                 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );\r
298 \r
299                 /* The space in the buffer will have increased by the amount of user\r
300                 data removed from the buffer. */\r
301                 xExpectedSpace += x6ByteLength;\r
302                 xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
303                 configASSERT( xReturned == xExpectedSpace );\r
304                 xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
305                 configASSERT( xReturned == ( sbSTREAM_BUFFER_LENGTH_BYTES - xExpectedSpace ) );\r
306         }\r
307 \r
308         /* The buffer should be empty again. */\r
309         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
310         xExpectedSpace = xStreamBufferSpacesAvailable( xStreamBuffer );\r
311         configASSERT( xExpectedSpace == sbSTREAM_BUFFER_LENGTH_BYTES );\r
312 \r
313         /* Reading with a timeout should also fail after the appropriate time.  The\r
314         priority is temporarily boosted in this part of the test to keep the\r
315         allowable margin to a minimum. */\r
316         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
317         xTimeBeforeCall = xTaskGetTickCount();\r
318         xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );\r
319         xTimeAfterCall = xTaskGetTickCount();\r
320         vTaskPrioritySet( NULL, uxOriginalPriority );\r
321         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
322         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
323         configASSERT( xReturned == 0 );\r
324 \r
325 \r
326         /* In the next loop 17 bytes are written to then read out on each\r
327         iteration.  As 30 is not divisible by 17 the data will wrap around. */\r
328         xExpectedSpace = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength;\r
329 \r
330         for( xItem = 0; xItem < 100; xItem++ )\r
331         {\r
332                 /* Generate recognisable data to write to the queue.  This is just\r
333                 ascii characters that shows which loop iteration the data was written\r
334                 in. */\r
335                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );\r
336                 xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, x17ByteLength, sbDONT_BLOCK );\r
337                 configASSERT( xReturned == x17ByteLength );\r
338 \r
339                 /* The space in the buffer will have reduced by the amount of user data\r
340                 written into the buffer. */\r
341                 xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
342                 configASSERT( xReturned == xExpectedSpace );\r
343                 xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
344                 configASSERT( xReturned == x17ByteLength );\r
345                 configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
346                 configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
347 \r
348                 /* Read the 17 bytes out again. */\r
349                 xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x17ByteLength, sbDONT_BLOCK );\r
350                 configASSERT( xReturned == x17ByteLength );\r
351 \r
352                 /* Does the data read out match that expected? */\r
353                 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );\r
354 \r
355                 /* Full buffer space available again. */\r
356                 xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );\r
357                 configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
358                 xReturned = xStreamBufferBytesAvailable( xStreamBuffer );\r
359                 configASSERT( xReturned == 0 );\r
360                 configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
361                 configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
362         }\r
363 \r
364         /* Fill the buffer with one message, check it is full, then read it back\r
365         again and check the correct data is received. */\r
366         xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );\r
367         xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );\r
368         configASSERT( memcmp( pc55ByteString, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
369 \r
370         /* Fill the buffer one bytes at a time. */\r
371         for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )\r
372         {\r
373                 /* Block time is only for test coverage, the task should never actually\r
374                 block here. */\r
375                 xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xItem ] ), sizeof( char ), sbRX_TX_BLOCK_TIME );\r
376         }\r
377 \r
378         /* The buffer should now be full. */\r
379         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
380 \r
381         /* Read the message out in one go, even though it was written in individual\r
382         bytes.  Try reading much more data than is actually available to ensure only\r
383         the available bytes are returned (otherwise this read will write outside of\r
384         the memory allocated anyway!). */\r
385         xReturned = xStreamBufferReceive( xStreamBuffer, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, sbRX_TX_BLOCK_TIME );\r
386         configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
387         configASSERT( memcmp( ( const void * ) pc54ByteString, ( const void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
388 \r
389         /* Now do the opposite, write in one go and read out in single bytes. */\r
390         xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbRX_TX_BLOCK_TIME );\r
391         configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
392         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
393         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
394         configASSERT( xStreamBufferBytesAvailable( xStreamBuffer ) == sbSTREAM_BUFFER_LENGTH_BYTES );\r
395         configASSERT( xStreamBufferSpacesAvailable( xStreamBuffer ) == 0 );\r
396 \r
397         /* Read from the buffer one byte at a time. */\r
398         for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )\r
399         {\r
400                 /* Block time is only for test coverage, the task should never actually\r
401                 block here. */\r
402                 xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sizeof( char ), sbRX_TX_BLOCK_TIME );\r
403                 configASSERT( pc55ByteString[ xItem ] == pucFullBuffer[ 0 ] );\r
404         }\r
405         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
406         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
407 \r
408         /* Try writing more bytes than there is space. */\r
409         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
410         xTimeBeforeCall = xTaskGetTickCount();\r
411         xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, xMinimalBlockTime );\r
412         xTimeAfterCall = xTaskGetTickCount();\r
413         vTaskPrioritySet( NULL, uxOriginalPriority );\r
414         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xMinimalBlockTime );\r
415         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xMinimalBlockTime + xAllowableMargin ) );\r
416         configASSERT( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );\r
417         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );\r
418         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdFALSE );\r
419 \r
420         /* No space now though. */\r
421         xReturned = xStreamBufferSend( xStreamBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, xMinimalBlockTime );\r
422         configASSERT( xReturned == 0 );\r
423 \r
424         /* Ensure data was written as expected even when there was an attempt to\r
425         write more than was available.  This also tries to read more bytes than are\r
426         available. */\r
427         xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, xFullBufferSize, xMinimalBlockTime );\r
428         configASSERT( memcmp( ( const void * ) pucFullBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );\r
429         configASSERT( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );\r
430         configASSERT( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );\r
431 \r
432         /* Clean up with data in the buffer to ensure the tests that follow don't\r
433         see the data (the data should be discarded). */\r
434         ( void ) xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES / ( size_t ) 2, sbDONT_BLOCK );\r
435         vPortFree( pucFullBuffer );\r
436         xStreamBufferReset( xStreamBuffer );\r
437 }\r
438 /*-----------------------------------------------------------*/\r
439 \r
440 static void prvNonBlockingSenderTask( void *pvParameters )\r
441 {\r
442 StreamBufferHandle_t xStreamBuffer;\r
443 size_t xNextChar = 0, xBytesToSend, xBytesActuallySent;\r
444 const size_t xStringLength = strlen( pc54ByteString );\r
445 \r
446         /* In this case the stream buffer has already been created and is passed\r
447         into the task using the task's parameter. */\r
448         xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;\r
449 \r
450         /* Keep sending the string to the stream buffer as many bytes as possible in\r
451         each go.  Doesn't block so calls can interleave with the non-blocking\r
452         receives performed by prvNonBlockingReceiverTask(). */\r
453         for( ;; )\r
454         {\r
455                 /* The whole string cannot be sent at once, so xNextChar is an index to\r
456                 the position within the string that has been sent so far.  How many\r
457                 bytes are there left to send before the end of the string? */\r
458                 xBytesToSend = xStringLength - xNextChar;\r
459 \r
460                 /* Attempt to send right up to the end of the string. */\r
461                 xBytesActuallySent = xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xNextChar ] ), xBytesToSend, sbDONT_BLOCK );\r
462                 configASSERT( xBytesActuallySent <= xBytesToSend );\r
463 \r
464                 /* Move the index up the string to the next character to be sent,\r
465                 wrapping if the end of the string has been reached. */\r
466                 xNextChar += xBytesActuallySent;\r
467                 configASSERT( xNextChar <= xStringLength );\r
468 \r
469                 if( xNextChar == xStringLength )\r
470                 {\r
471                         xNextChar = 0;\r
472                 }\r
473         }\r
474 }\r
475 /*-----------------------------------------------------------*/\r
476 \r
477 static void prvNonBlockingReceiverTask( void *pvParameters )\r
478 {\r
479 StreamBufferHandle_t xStreamBuffer;\r
480 size_t xNextChar = 0, xReceiveLength, xBytesToTest, xStartIndex;\r
481 const size_t xStringLength = strlen( pc54ByteString );\r
482 char cRxString[ 12 ]; /* Holds received characters. */\r
483 BaseType_t xNonBlockingReceiveError = pdFALSE;\r
484 \r
485         /* In this case the stream buffer has already been created and is passed\r
486         into the task using the task's parameter. */\r
487         xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;\r
488 \r
489         /* Expects to receive the pc54ByteString over and over again.  Sends and\r
490         receives are not blocking so will interleave. */\r
491         for( ;; )\r
492         {\r
493                 /* Attempt to receive as many bytes as possible, up to the limit of the\r
494                 Rx buffer size. */\r
495                 xReceiveLength = xStreamBufferReceive( xStreamBuffer, ( void * ) cRxString, sizeof( cRxString ), sbDONT_BLOCK );\r
496 \r
497                 if( xReceiveLength > 0 )\r
498                 {\r
499                         /* xNextChar is the index into pc54ByteString that has been received\r
500                         already.  If xReceiveLength bytes are added to that, will it go off\r
501                         the end of the string?  If so, then first test up to the end of the\r
502                         string, then go back to the start of pc54ByteString to test the\r
503                         remains of the received data. */\r
504                         xBytesToTest = xReceiveLength;\r
505                         if( ( xNextChar + xBytesToTest ) > xStringLength )\r
506                         {\r
507                                 /* Cap to test the received data to the end of the string. */\r
508                                 xBytesToTest = xStringLength - xNextChar;\r
509 \r
510                                 if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) cRxString, xBytesToTest ) != 0 )\r
511                                 {\r
512                                         xNonBlockingReceiveError = pdTRUE;\r
513                                 }\r
514 \r
515                                 /* Then move back to the start of the string to test the\r
516                                 remaining received bytes. */\r
517                                 xNextChar = 0;\r
518                                 xStartIndex = xBytesToTest;\r
519                                 xBytesToTest = xReceiveLength - xBytesToTest;\r
520                         }\r
521                         else\r
522                         {\r
523                                 /* The string didn't wrap in the buffer, so start comparing from\r
524                                 the start of the received data. */\r
525                                 xStartIndex = 0;\r
526                         }\r
527 \r
528                         /* Test the received bytes are as expected, then move the index\r
529                         along the string to the next expected char to receive. */\r
530                         if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) &( cRxString[ xStartIndex ] ), xBytesToTest ) != 0 )\r
531                         {\r
532                                 xNonBlockingReceiveError = pdTRUE;\r
533                         }\r
534 \r
535                         if( xNonBlockingReceiveError == pdFALSE )\r
536                         {\r
537                                 /* No errors detected so increment the counter that lets the\r
538                                 check task know this test is still functioning correctly. */\r
539                                 ulNonBlockingRxCounter++;\r
540                         }\r
541 \r
542                         xNextChar += xBytesToTest;\r
543                         if( xNextChar >= xStringLength )\r
544                         {\r
545                                 xNextChar = 0;\r
546                         }\r
547                 }\r
548         }\r
549 }\r
550 /*-----------------------------------------------------------*/\r
551 \r
552 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
553 \r
554         static void prvSenderTask( void *pvParameters )\r
555         {\r
556         StreamBufferHandle_t xStreamBuffer, xTempStreamBuffer;\r
557         static uint8_t ucTempBuffer[ 10 ]; /* Just used to exercise stream buffer creating and deletion. */\r
558         const TickType_t xTicksToWait = sbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );\r
559         StaticStreamBuffer_t xStaticStreamBuffer;\r
560         size_t xNextChar = 0, xBytesToSend, xBytesActuallySent;\r
561         const size_t xStringLength = strlen( pc55ByteString );\r
562 \r
563         /* The task's priority is used as an index into the loop counters used to\r
564         indicate this task is still running. */\r
565         UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
566 \r
567                 /* Make sure a change in priority does not inadvertently result in an\r
568                 invalid array index. */\r
569                 configASSERT( uxIndex < sbNUMBER_OF_ECHO_CLIENTS );\r
570 \r
571                 /* Avoid compiler warnings about unused parameters. */\r
572                 ( void ) pvParameters;\r
573 \r
574                 xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ) / sbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */\r
575                                                                                                    sbTRIGGER_LEVEL_1, /* The number of bytes to be in the buffer before a task blocked to wait for data is unblocked. */\r
576                                                                                                    &( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */\r
577                                                                                                    &( xStaticStreamBuffers[ uxIndex ] ) ); /* The static stream buffer structure to use within the array. */\r
578 \r
579                 /* Now the stream buffer has been created the receiver task can be\r
580                 created.  If this sender task has the higher priority then the receiver\r
581                 task is created at the lower priority - if this sender task has the\r
582                 lower priority then the receiver task is created at the higher\r
583                 priority. */\r
584                 if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )\r
585                 {\r
586                         /* Here prvSingleTaskTests() performs various tests on a stream buffer\r
587                         that was created statically. */\r
588                         prvSingleTaskTests( xStreamBuffer );\r
589                         xTaskCreate( prvReceiverTask, "StrReceiver", sbSTACK_SIZE,  ( void * ) xStreamBuffer, sbHIGHER_PRIORITY, NULL );\r
590                 }\r
591                 else\r
592                 {\r
593                         xTaskCreate( prvReceiverTask, "StrReceiver", sbSTACK_SIZE,  ( void * ) xStreamBuffer, sbLOWER_PRIORITY, NULL );\r
594                 }\r
595 \r
596                 for( ;; )\r
597                 {\r
598                         /* The whole string cannot be sent at once, so xNextChar is an index\r
599                         to the position within the string that has been sent so far.  How\r
600                         many bytes are there left to send before the end of the string? */\r
601                         xBytesToSend = xStringLength - xNextChar;\r
602 \r
603                         /* Attempt to send right up to the end of the string. */\r
604                         xBytesActuallySent = xStreamBufferSend( xStreamBuffer, ( void * ) &( pc55ByteString[ xNextChar ] ), xBytesToSend, xTicksToWait );\r
605                         configASSERT( xBytesActuallySent <= xBytesToSend );\r
606 \r
607                         /* Move the index up the string to the next character to be sent,\r
608                         wrapping if the end of the string has been reached. */\r
609                         xNextChar += xBytesActuallySent;\r
610                         configASSERT( xNextChar <= xStringLength );\r
611 \r
612                         if( xNextChar == xStringLength )\r
613                         {\r
614                                 xNextChar = 0;\r
615                         }\r
616 \r
617                         /* Increment a loop counter so a check task can tell this task is\r
618                         still running as expected. */\r
619                         ulSenderLoopCounters[ uxIndex ]++;\r
620 \r
621                         if( uxTaskPriorityGet( NULL ) == sbHIGHER_PRIORITY )\r
622                         {\r
623                                 /* Allow other tasks to run. */\r
624                                 vTaskDelay( xShortDelay );\r
625                         }\r
626 \r
627                         /* This stream buffer is just created and deleted to ensure no\r
628                         issues when attempting to delete a stream buffer that was\r
629                         created using statically allocated memory.  To save stack space\r
630                         the buffer is set to point to the pc55ByteString, which is a const\r
631                         string, but no data is written into the buffer so any valid address\r
632                         will do. */\r
633                         xTempStreamBuffer = xStreamBufferCreateStatic( sizeof( ucTempBuffer ), sbTRIGGER_LEVEL_1, ucTempBuffer, &xStaticStreamBuffer );\r
634                         vStreamBufferDelete( xTempStreamBuffer );\r
635                 }\r
636         }\r
637 \r
638 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
639 /*-----------------------------------------------------------*/\r
640 \r
641 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
642 \r
643         static void prvReceiverTask( void *pvParameters )\r
644         {\r
645         StreamBufferHandle_t * const pxStreamBuffer = ( StreamBufferHandle_t * ) pvParameters;\r
646         char cRxString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */\r
647         const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );\r
648         const size_t xStringLength = strlen( pc55ByteString );\r
649         size_t xNextChar = 0, xReceivedLength, xBytesToReceive;\r
650 \r
651                 for( ;; )\r
652                 {\r
653                         /* Attempt to receive the number of bytes to the end of the string,\r
654                         or the number of byte that can be placed into the rx buffer,\r
655                         whichever is smallest. */\r
656                         xBytesToReceive = configMIN( ( xStringLength - xNextChar ), sizeof( cRxString ) );\r
657 \r
658                         do\r
659                         {\r
660                                 xReceivedLength = xStreamBufferReceive( pxStreamBuffer, ( void * ) cRxString, xBytesToReceive, xTicksToWait );\r
661 \r
662                         } while( xReceivedLength == 0 );\r
663 \r
664                         /* Ensure the received string matches the expected string. */\r
665                         configASSERT( memcmp( ( void * ) cRxString, ( void * ) &( pc55ByteString[ xNextChar ] ), xReceivedLength ) == 0 );\r
666 \r
667                         /* Move the index into the string up to the end of the bytes\r
668                         received so far - wrapping if the end of the string has been\r
669                         reached. */\r
670                         xNextChar += xReceivedLength;\r
671                         if( xNextChar >= xStringLength )\r
672                         {\r
673                                 xNextChar = 0;\r
674                         }\r
675                 }\r
676         }\r
677 \r
678 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
679 /*-----------------------------------------------------------*/\r
680 \r
681 static void prvEchoClient( void *pvParameters )\r
682 {\r
683 size_t xSendLength = 0, ux;\r
684 char *pcStringToSend, *pcStringReceived, cNextChar = sbASCII_SPACE;\r
685 const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );\r
686 StreamBufferHandle_t xTempStreamBuffer;\r
687 \r
688 /* The task's priority is used as an index into the loop counters used to\r
689 indicate this task is still running. */\r
690 UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
691 \r
692 /* Pointers to the client and server stream buffers are passed into this task\r
693 using the task's parameter. */\r
694 EchoStreamBuffers_t *pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;\r
695 \r
696         /* Prevent compiler warnings. */\r
697         ( void ) pvParameters;\r
698 \r
699         /* Create the buffer into which strings to send to the server will be\r
700         created, and the buffer into which strings echoed back from the server will\r
701         be copied. */\r
702         pcStringToSend = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
703         pcStringReceived = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
704 \r
705         configASSERT( pcStringToSend );\r
706         configASSERT( pcStringReceived );\r
707 \r
708         for( ;; )\r
709         {\r
710                 /* Generate the length of the next string to send. */\r
711                 xSendLength++;\r
712 \r
713                 /* The stream buffer is being used to hold variable length data, so\r
714                 each data item requires sizeof( size_t ) bytes to hold the data's\r
715                 length, hence the sizeof() in the if() condition below. */\r
716                 if( xSendLength > ( sbSTREAM_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )\r
717                 {\r
718                         /* Back to a string length of 1. */\r
719                         xSendLength = sizeof( char );\r
720                 }\r
721 \r
722                 memset( pcStringToSend, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
723 \r
724                 for( ux = 0; ux < xSendLength; ux++ )\r
725                 {\r
726                         pcStringToSend[ ux ] = cNextChar;\r
727 \r
728                         cNextChar++;\r
729 \r
730                         if( cNextChar > sbASCII_TILDA )\r
731                         {\r
732                                 cNextChar = sbASCII_SPACE;\r
733                         }\r
734                 }\r
735 \r
736                 /* Send the generated string to the buffer. */\r
737                 do\r
738                 {\r
739                         ux = xStreamBufferSend( pxStreamBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );\r
740 \r
741                 } while( ux == 0 );\r
742 \r
743                 /* Wait for the string to be echoed back. */\r
744                 memset( pcStringReceived, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
745                 xStreamBufferReceive( pxStreamBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );\r
746 \r
747                 configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );\r
748 \r
749                 /* Maintain a count of the number of times this code executes so a\r
750                 check task can determine if this task is still functioning as\r
751                 expected or not.  As there are two client tasks, and the priorities\r
752                 used are 0 and 1, the task's priority is used as an index into the\r
753                 loop count array. */\r
754                 ulEchoLoopCounters[ uxIndex ]++;\r
755 \r
756                 /* This stream buffer is just created and deleted to ensure no memory\r
757                 leaks. */\r
758                 xTempStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
759                 prvSingleTaskTests( xTempStreamBuffer );\r
760                 vStreamBufferDelete( xTempStreamBuffer );\r
761         }\r
762 }\r
763 /*-----------------------------------------------------------*/\r
764 \r
765 static void prvEchoServer( void *pvParameters )\r
766 {\r
767 size_t xReceivedLength;\r
768 char *pcReceivedString;\r
769 EchoStreamBuffers_t xStreamBuffers;\r
770 TickType_t xTimeOnEntering;\r
771 const TickType_t xTicksToBlock = pdMS_TO_TICKS( 350UL );\r
772 \r
773         /* Prevent compiler warnings about unused parameters. */\r
774         ( void ) pvParameters;\r
775 \r
776         /* Create the stream buffer used to send data from the client to the server,\r
777         and the stream buffer used to echo the data from the server back to the\r
778         client. */\r
779         xStreamBuffers.xEchoClientBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
780         xStreamBuffers.xEchoServerBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );\r
781         configASSERT( xStreamBuffers.xEchoClientBuffer );\r
782         configASSERT( xStreamBuffers.xEchoServerBuffer );\r
783 \r
784         /* Create the buffer into which received strings will be copied. */\r
785         pcReceivedString = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );\r
786         configASSERT( pcReceivedString );\r
787 \r
788         /* Don't expect to receive anything yet! */\r
789         xTimeOnEntering = xTaskGetTickCount();\r
790         xReceivedLength = xStreamBufferReceive( xStreamBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, sbSTREAM_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
791         configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToBlock );\r
792         configASSERT( xReceivedLength == 0 );\r
793         ( void ) xTimeOnEntering;\r
794 \r
795         /* Now the stream buffers have been created the echo client task can be\r
796         created.  If this server task has the higher priority then the client task\r
797         is created at the lower priority - if this server task has the lower\r
798         priority then the client task is created at the higher priority. */\r
799         if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )\r
800         {\r
801                 xTaskCreate( prvEchoClient, "EchoClient", sbSTACK_SIZE,  ( void * ) &xStreamBuffers, sbHIGHER_PRIORITY, NULL );\r
802         }\r
803         else\r
804         {\r
805                 /* Here prvSingleTaskTests() performs various tests on a stream buffer\r
806                 that was created dynamically. */\r
807                 prvSingleTaskTests( xStreamBuffers.xEchoClientBuffer );\r
808                 xTaskCreate( prvEchoClient, "EchoClient", sbSTACK_SIZE, ( void * ) &xStreamBuffers, sbLOWER_PRIORITY, NULL );\r
809         }\r
810 \r
811         for( ;; )\r
812         {\r
813                 memset( pcReceivedString, 0x00, sbSTREAM_BUFFER_LENGTH_BYTES );\r
814 \r
815                 /* Has any data been sent by the client? */\r
816                 xReceivedLength = xStreamBufferReceive( xStreamBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, sbSTREAM_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
817 \r
818                 /* Should always receive data as a delay was used. */\r
819                 configASSERT( xReceivedLength > 0 );\r
820 \r
821                 /* Echo the received data back to the client. */\r
822                 xStreamBufferSend( xStreamBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );\r
823         }\r
824 }\r
825 /*-----------------------------------------------------------*/\r
826 \r
827 void vPeriodicStreamBufferProcessing( void )\r
828 {\r
829 static size_t xNextChar = 0;\r
830 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
831 \r
832         /* Called from the tick interrupt hook.  If the global stream buffer\r
833         variable is not NULL then the prvInterruptTriggerTest() task expects a byte\r
834         to be sent to the stream buffer on each tick interrupt. */\r
835         if( xInterruptStreamBuffer != NULL )\r
836         {\r
837                 /* One character from the pcDataSentFromInterrupt string is sent on each\r
838                 interrupt.  The task blocked on the stream buffer should not be\r
839                 unblocked until the defined trigger level is hit. */\r
840                 xStreamBufferSendFromISR( xInterruptStreamBuffer, ( const void * ) &( pcDataSentFromInterrupt[ xNextChar ] ), sizeof( char ), &xHigherPriorityTaskWoken );\r
841 \r
842                 if( xNextChar < strlen( pcDataSentFromInterrupt ) )\r
843                 {\r
844                         xNextChar++;\r
845                 }\r
846         }\r
847         else\r
848         {\r
849                 /* Start at the beginning of the string being sent again. */\r
850                 xNextChar = 0;\r
851         }\r
852 }\r
853 /*-----------------------------------------------------------*/\r
854 \r
855 static void prvInterruptTriggerLevelTest( void *pvParameters )\r
856 {\r
857 StreamBufferHandle_t xStreamBuffer;\r
858 size_t xTriggerLevel = 1, xBytesReceived;\r
859 const size_t xStreamBufferSizeBytes = ( size_t ) 8, xMaxTriggerLevel = ( size_t ) 6, xMinTriggerLevel = ( size_t ) 1;\r
860 const TickType_t xReadBlockTime = 4, xCycleBlockTime = pdMS_TO_TICKS( 100 );\r
861 uint8_t ucRxData[ 8 ];\r
862 BaseType_t xErrorDetected = pdFALSE;\r
863 #ifndef configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN\r
864     const size_t xAllowableMargin = ( size_t ) 0;\r
865 #else\r
866     const size_t xAllowableMargin = ( size_t ) configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN;\r
867 #endif\r
868 \r
869         /* Remove compiler warning about unused parameter. */\r
870         ( void ) pvParameters;\r
871 \r
872         for( ;; )\r
873         {\r
874                 for( xTriggerLevel = xMinTriggerLevel; xTriggerLevel < xMaxTriggerLevel; xTriggerLevel++ )\r
875                 {\r
876                         /* Create the stream buffer that will be used from inside the tick\r
877                         interrupt. */\r
878                         xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );\r
879                         configASSERT( xStreamBuffer );\r
880 \r
881                         /* Now the stream buffer has been created it can be assigned to the\r
882                         file scope variable, which will allow the tick interrupt to start\r
883                         using it. */\r
884                         taskENTER_CRITICAL();\r
885                         {\r
886                                 xInterruptStreamBuffer = xStreamBuffer;\r
887                         }\r
888                         taskEXIT_CRITICAL();\r
889 \r
890                         xBytesReceived = xStreamBufferReceive( xStreamBuffer, ( void * ) ucRxData, sizeof( ucRxData ), xReadBlockTime );\r
891 \r
892                         /* Set the file scope variable back to NULL so the interrupt doesn't\r
893                         try to use it again. */\r
894                         taskENTER_CRITICAL();\r
895                         {\r
896                                 xInterruptStreamBuffer = NULL;\r
897                         }\r
898                         taskEXIT_CRITICAL();\r
899 \r
900                         /* Now check the number of bytes received equals the trigger level,\r
901                         except in the case that the read timed out before the trigger level\r
902                         was reached. */\r
903                         if( xBytesReceived < xTriggerLevel )\r
904                         {\r
905                                 /* This should only happen if the trigger level was greater than\r
906                                 the block time. */\r
907                                 if( xTriggerLevel < xReadBlockTime )\r
908                                 {\r
909                                         xErrorDetected = pdTRUE;\r
910                                 }\r
911                         }\r
912                         else if( ( xBytesReceived - xTriggerLevel ) > xAllowableMargin )\r
913                         {\r
914                                 /* A margin may be required here if there are other high priority\r
915                                 tasks prevent the task that reads from the message buffer running\r
916                                 immediately. */\r
917                                 xErrorDetected = pdTRUE;\r
918                         }\r
919 \r
920                         if( xBytesReceived > sizeof( ucRxData ) )\r
921                         {\r
922                                 xErrorDetected = pdTRUE;\r
923                         }\r
924                         else if( memcmp( ( void * ) ucRxData, ( const void * ) pcDataSentFromInterrupt, xBytesReceived ) != 0 )\r
925                         {\r
926                                 /* Received data didn't match that expected. */\r
927                                 xErrorDetected = pdTRUE;\r
928                         }\r
929 \r
930                         if( xErrorDetected == pdFALSE )\r
931                         {\r
932                                 /* Increment the cycle counter so the 'check' task knows this test\r
933                                 is still running without error. */\r
934                                 ulInterruptTriggerCounter++;\r
935                         }\r
936 \r
937                         /* Tidy up ready for the next loop. */\r
938                         vStreamBufferDelete( xStreamBuffer );\r
939                         vTaskDelay( xCycleBlockTime );\r
940                 }\r
941         }\r
942 }\r
943 /*-----------------------------------------------------------*/\r
944 \r
945 BaseType_t xAreStreamBufferTasksStillRunning( void )\r
946 {\r
947 static uint32_t ulLastEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
948 static uint32_t ulLastNonBlockingRxCounter = 0;\r
949 static uint32_t ulLastInterruptTriggerCounter = 0;\r
950 BaseType_t xReturn = pdPASS, x;\r
951 \r
952         for( x = 0; x < sbNUMBER_OF_ECHO_CLIENTS; x++ )\r
953         {\r
954                 if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )\r
955                 {\r
956                         xReturn = pdFAIL;\r
957                 }\r
958                 else\r
959                 {\r
960                         ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];\r
961                 }\r
962         }\r
963 \r
964         if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )\r
965         {\r
966                 xReturn = pdFAIL;\r
967         }\r
968         else\r
969         {\r
970                 ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;\r
971         }\r
972 \r
973         if( ulLastInterruptTriggerCounter == ulInterruptTriggerCounter )\r
974         {\r
975                 xReturn = pdFAIL;\r
976         }\r
977         else\r
978         {\r
979                 ulLastInterruptTriggerCounter = ulInterruptTriggerCounter;\r
980         }\r
981 \r
982         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
983         {\r
984                 static uint32_t ulLastSenderLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
985 \r
986                 for( x = 0; x < sbNUMBER_OF_SENDER_TASKS; x++ )\r
987                 {\r
988                         if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )\r
989                         {\r
990                                 xReturn = pdFAIL;\r
991                         }\r
992                         else\r
993                         {\r
994                                 ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];\r
995                         }\r
996                 }\r
997         }\r
998         #endif /* configSUPPORT_STATIC_ALLOCATION */\r
999 \r
1000         return xReturn;\r
1001 }\r
1002 /*-----------------------------------------------------------*/\r
1003 \r