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