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