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