]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/MessageBufferDemo.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 / MessageBufferDemo.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 "message_buffer.h"\r
36 \r
37 /* Demo app includes. */\r
38 #include "MessageBufferDemo.h"\r
39 \r
40 /* The number of bytes of storage in the message buffers used in this test. */\r
41 #define mbMESSAGE_BUFFER_LENGTH_BYTES   ( ( size_t ) 50 )\r
42 \r
43 /* The number of additional bytes used to store the length of each message. */\r
44 #define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( size_t ) )\r
45 \r
46 /* Start and end ASCII characters used in messages sent to the buffers. */\r
47 #define mbASCII_SPACE                                   32\r
48 #define mbASCII_TILDA                                   126\r
49 \r
50 /* Defines the number of tasks to create in this test and demo. */\r
51 #define mbNUMBER_OF_ECHO_CLIENTS        ( 2 )\r
52 #define mbNUMBER_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 mbLOWER_PRIORITY                        ( tskIDLE_PRIORITY )\r
57 #define mbHIGHER_PRIORITY                       ( tskIDLE_PRIORITY + 1 )\r
58 \r
59 /* Block times used when sending and receiving from the message buffers. */\r
60 #define mbRX_TX_BLOCK_TIME                      pdMS_TO_TICKS( 125UL )\r
61 \r
62 /* A block time of 0 means "don't block". */\r
63 #define mbDONT_BLOCK                            ( 0 )\r
64 \r
65 /* The size of the stack allocated to the tasks that run as part of this demo/\r
66 test.  The stack size is over generous in most cases. */\r
67 #define mbSTACK_SIZE                            ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) )\r
68 /*-----------------------------------------------------------*/\r
69 \r
70 /*\r
71  * Performs various tests that do not require multiple tasks to interact.\r
72  */\r
73 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer );\r
74 \r
75 /*\r
76  * Tests sending and receiving various lengths of messages via a message buffer.\r
77  * The echo client sends the messages to the echo server, which then sends the\r
78  * message back to the echo client which, checks it receives exactly what it\r
79  * sent.\r
80  */\r
81 static void prvEchoClient( void *pvParameters );\r
82 static void prvEchoServer( void *pvParameters );\r
83 \r
84 /*\r
85  * Tasks that send and receive to a message buffer at a low priority and without\r
86  * blocking, so the send and receive functions interleave in time as the tasks\r
87  * are switched in and out.\r
88  */\r
89 static void prvNonBlockingReceiverTask( void *pvParameters );\r
90 static void prvNonBlockingSenderTask( void *pvParameters );\r
91 \r
92 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
93         /* This file tests both statically and dynamically allocated message buffers.\r
94         Allocate the structures and buffers to be used by the statically allocated\r
95         objects, which get used in the echo tests. */\r
96         static void prvReceiverTask( void *pvParameters );\r
97         static void prvSenderTask( void *pvParameters );\r
98 \r
99         static StaticMessageBuffer_t xStaticMessageBuffers[ mbNUMBER_OF_ECHO_CLIENTS ];\r
100         static uint8_t ucBufferStorage[ mbNUMBER_OF_SENDER_TASKS ][ mbMESSAGE_BUFFER_LENGTH_BYTES + 1 ];\r
101         static uint32_t ulSenderLoopCounters[ mbNUMBER_OF_SENDER_TASKS ] = { 0 };\r
102 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
103 \r
104 /*-----------------------------------------------------------*/\r
105 \r
106 /* The buffers used by the echo client and server tasks. */\r
107 typedef struct ECHO_MESSAGE_BUFFERS\r
108 {\r
109         /* Handles to the data structures that describe the message buffers. */\r
110         MessageBufferHandle_t xEchoClientBuffer;\r
111         MessageBufferHandle_t xEchoServerBuffer;\r
112 } EchoMessageBuffers_t;\r
113 static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
114 \r
115 /* The non-blocking tasks monitor their operation, and if no errors have been\r
116 found, increment ulNonBlockingRxCounter.  xAreMessageBufferTasksStillRunning()\r
117 then checks ulNonBlockingRxCounter and only returns pdPASS if\r
118 ulNonBlockingRxCounter is still incrementing. */\r
119 static uint32_t ulNonBlockingRxCounter = 0;\r
120 \r
121 /* A message that is longer than the buffer, parts of which are written to the\r
122 message buffer to test writing different lengths at different offsets. */\r
123 static const char *pc55ByteString = "One two three four five six seven eight nine ten eleve";\r
124 \r
125 \r
126 /*-----------------------------------------------------------*/\r
127 \r
128 void vStartMessageBufferTasks( void )\r
129 {\r
130 MessageBufferHandle_t xMessageBuffer;\r
131 \r
132         /* The echo servers sets up the message buffers before creating the echo\r
133         client tasks.  One set of tasks has the server as the higher priority, and\r
134         the other has the client as the higher priority. */\r
135         xTaskCreate( prvEchoServer, "1EchoServer", mbSTACK_SIZE, NULL, mbHIGHER_PRIORITY, NULL );\r
136         xTaskCreate( prvEchoServer, "2EchoServer", mbSTACK_SIZE, NULL, mbLOWER_PRIORITY, NULL );\r
137 \r
138         /* The non blocking tasks run continuously and will interleave with each\r
139         other, so must be created at the lowest priority.  The message buffer they\r
140         use is created and passed in using the task's parameter. */\r
141         xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
142         xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );\r
143         xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );\r
144 \r
145         #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
146         {\r
147                 /* The sender tasks set up the message buffers before creating the\r
148                 receiver tasks.  Priorities must be 0 and 1 as the priority is used to\r
149                 index into the xStaticMessageBuffers and ucBufferStorage arrays. */\r
150                 xTaskCreate( prvSenderTask, "1Sender", mbSTACK_SIZE, NULL, mbHIGHER_PRIORITY, NULL );\r
151                 xTaskCreate( prvSenderTask, "2Sender", mbSTACK_SIZE, NULL, mbLOWER_PRIORITY, NULL );\r
152         }\r
153         #endif /* configSUPPORT_STATIC_ALLOCATION */\r
154 }\r
155 /*-----------------------------------------------------------*/\r
156 \r
157 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer )\r
158 {\r
159 size_t xReturned, xItem, xExpectedSpace;\r
160 const size_t xMax6ByteMessages = mbMESSAGE_BUFFER_LENGTH_BYTES / ( 6 + mbBYTES_TO_STORE_MESSAGE_LENGTH );\r
161 const size_t x6ByteLength = 6, x17ByteLength = 17;\r
162 uint8_t *pucFullBuffer, *pucData, *pucReadData;\r
163 TickType_t xTimeBeforeCall, xTimeAfterCall;\r
164 const TickType_t xBlockTime = pdMS_TO_TICKS( 25 ), xAllowableMargin = pdMS_TO_TICKS( 3 );\r
165 UBaseType_t uxOriginalPriority;\r
166 \r
167         /* Remove warning in case configASSERT() is not defined. */\r
168         ( void ) xAllowableMargin;\r
169 \r
170         /* To minimise stack and heap usage a full size buffer is allocated from\r
171         the heap, then buffers which hold smaller amounts of data are overlayed\r
172         with the larger buffer - just make sure not to use both at once!. */\r
173         pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
174         configASSERT( pucFullBuffer );\r
175 \r
176         pucData = pucFullBuffer;\r
177         pucReadData = pucData + x17ByteLength;\r
178 \r
179         /* Nothing has been added or removed yet, so expect the free space to be\r
180         exactly as created. */\r
181         xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );\r
182         configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );\r
183         configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );\r
184 \r
185 \r
186         /* The buffer is 50 bytes long.  When an item is added to the buffer an\r
187         additional 4 bytes are added to hold the item's size.  That means adding\r
188         6 bytes to the buffer will actually add 10 bytes to the buffer.  Therefore,\r
189         with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the\r
190         buffer is completely full. */\r
191         for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
192         {\r
193                 configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );\r
194 \r
195                 /* Generate recognisable data to write to the buffer.  This is just\r
196                 ascii characters that shows which loop iteration the data was written\r
197                 in. The 'FromISR' version is used to give it some exercise as a block\r
198                 time is not used.  That requires the call to be in a critical section\r
199                 so this code can also run on FreeRTOS ports that do not support\r
200                 interrupt nesting (and so don't have interrupt safe critical\r
201                 sections).*/\r
202                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
203                 taskENTER_CRITICAL();\r
204                 {\r
205                         xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, x6ByteLength, NULL );\r
206                 }\r
207                 taskEXIT_CRITICAL();\r
208                 configASSERT( xReturned == x6ByteLength );\r
209                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
210 \r
211                 /* The space in the buffer will have reduced by the amount of user data\r
212                 written into the buffer and the amount of space used to store the length\r
213                 of the data written into the buffer. */\r
214                 xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );\r
215                 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );\r
216                 configASSERT( xReturned == xExpectedSpace );\r
217                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
218         }\r
219 \r
220         /* Now the buffer should be full, and attempting to add anything will should\r
221         fail. */\r
222         configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE );\r
223         xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK );\r
224         configASSERT( xReturned == 0 );\r
225         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
226 \r
227         /* Adding with a timeout should also fail after the appropriate time.  The\r
228         priority is temporarily boosted in this part of the test to keep the\r
229         allowable margin to a minimum. */\r
230         uxOriginalPriority = uxTaskPriorityGet( NULL );\r
231         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
232         xTimeBeforeCall = xTaskGetTickCount();\r
233         xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );\r
234         xTimeAfterCall = xTaskGetTickCount();\r
235         vTaskPrioritySet( NULL, uxOriginalPriority );\r
236         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
237         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
238         configASSERT( xReturned == 0 );\r
239         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
240         ( void ) xTimeBeforeCall;\r
241         ( void ) xTimeAfterCall;\r
242 \r
243 \r
244         /* The buffer is now full of data in the form "000000", "111111", etc.  Make\r
245         sure the data is read out as expected. */\r
246         for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )\r
247         {\r
248                 /* Generate the data that is expected to be read out for this loop\r
249                 iteration. */\r
250                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );\r
251 \r
252                 /* Try reading the message into a buffer that is too small.  The message\r
253                 should remain in the buffer. */\r
254                 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK );\r
255                 configASSERT( xReturned == 0 );\r
256                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
257 \r
258                 /* Read the next 6 bytes out.  The 'FromISR' version is used to give it\r
259                 some exercise as a block time is not used.  THa requires the code to be\r
260                 in a critical section so this test can be run with FreeRTOS ports that\r
261                 do not support interrupt nesting (and therefore don't have interrupt\r
262                 safe critical sections). */\r
263                 taskENTER_CRITICAL();\r
264                 {\r
265                         xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );\r
266                 }\r
267                 taskEXIT_CRITICAL();\r
268                 configASSERT( xReturned == x6ByteLength );\r
269                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
270 \r
271                 /* Does the data read out match that expected? */\r
272                 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );\r
273 \r
274                 /* The space in the buffer will have increased by the amount of user\r
275                 data read from into the buffer and the amount of space used to store the\r
276                 length of the data read into the buffer. */\r
277                 xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );\r
278                 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );\r
279                 configASSERT( xReturned == xExpectedSpace );\r
280                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
281         }\r
282 \r
283         /* The buffer should be empty again. */\r
284         configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );\r
285         xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );\r
286         configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );\r
287 \r
288         /* Reading with a timeout should also fail after the appropriate time.  The\r
289         priority is temporarily boosted in this part of the test to keep the\r
290         allowable margin to a minimum. */\r
291         vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );\r
292         xTimeBeforeCall = xTaskGetTickCount();\r
293         xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );\r
294         xTimeAfterCall = xTaskGetTickCount();\r
295         vTaskPrioritySet( NULL, uxOriginalPriority );\r
296         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );\r
297         configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );\r
298         configASSERT( xReturned == 0 );\r
299         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
300         ( void ) xTimeBeforeCall;\r
301         ( void ) xTimeAfterCall;\r
302 \r
303 \r
304         /* In the next loop 17 bytes are written to then read out on each iteration.\r
305         The expected length variable is always used after 17 bytes have been written\r
306         into the buffer - the length of the message is also written, making a total\r
307         of 21 bytes consumed for each 17 byte message. */\r
308         xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );\r
309 \r
310         /* Reading and writing 17 bytes at a time will result in 21 bytes being\r
311         written into the buffer, and as 50 is not divisible by 21, writing multiple\r
312         times will cause the data to wrap in the buffer.*/\r
313         for( xItem = 0; xItem < 100; xItem++ )\r
314         {\r
315                 /* Generate recognisable data to write to the queue.  This is just\r
316                 ascii characters that shows which loop iteration the data was written\r
317                 in. */\r
318                 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );\r
319                 xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK );\r
320                 configASSERT( xReturned == x17ByteLength );\r
321                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
322 \r
323                 /* The space in the buffer will have reduced by the amount of user data\r
324                 written into the buffer and the amount of space used to store the length\r
325                 of the data written into the buffer. */\r
326                 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );\r
327                 configASSERT( xReturned == xExpectedSpace );\r
328                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
329 \r
330                 /* Read the 17 bytes out again. */\r
331                 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x17ByteLength, mbDONT_BLOCK );\r
332                 configASSERT( xReturned == x17ByteLength );\r
333                 ( void ) xReturned; /* In case configASSERT() is not defined. */\r
334 \r
335                 /* Does the data read out match that expected? */\r
336                 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );\r
337         }\r
338 \r
339         /* The buffer should be empty again. */\r
340         configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );\r
341         xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );\r
342         configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );\r
343 \r
344         /* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test)\r
345         bytes of the full 50 bytes, as that would not leave space for the four bytes\r
346         taken by the data length. */\r
347         xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK );\r
348         configASSERT( xReturned == 0 );\r
349         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
350         xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK );\r
351         configASSERT( xReturned == 0 );\r
352         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
353         xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 2, mbDONT_BLOCK );\r
354         configASSERT( xReturned == 0 );\r
355         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
356         xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 3, mbDONT_BLOCK );\r
357         configASSERT( xReturned == 0 );\r
358         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
359 \r
360         /* Can write mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) bytes though. */\r
361         xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );\r
362         configASSERT( xReturned == mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) );\r
363         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
364         xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucFullBuffer, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );\r
365         configASSERT( xReturned == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );\r
366         ( void ) xReturned; /* In case configASSERT() is not defined. */\r
367         configASSERT( memcmp( ( const void * ) pucFullBuffer, pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) == 0 );\r
368 \r
369         /* Clean up. */\r
370         vPortFree( pucFullBuffer );\r
371         xMessageBufferReset( xMessageBuffer );\r
372 }\r
373 /*-----------------------------------------------------------*/\r
374 \r
375 static void prvNonBlockingSenderTask( void *pvParameters )\r
376 {\r
377 MessageBufferHandle_t xMessageBuffer;\r
378 int32_t iDataToSend = 0;\r
379 size_t xStringLength;\r
380 const int32_t iMaxValue = 1500;\r
381 char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */\r
382 \r
383         /* In this case the message buffer has already been created and is passed\r
384         into the task using the task's parameter. */\r
385         xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;\r
386 \r
387         /* Create a string from an incrementing number.  The length of the\r
388         string will increase and decrease as the value of the number increases\r
389         then overflows. */\r
390         memset( cTxString, 0x00, sizeof( cTxString ) );\r
391         sprintf( cTxString, "%d", ( int ) iDataToSend );\r
392         xStringLength = strlen( cTxString );\r
393 \r
394         for( ;; )\r
395         {\r
396                 /* Doesn't block so calls can interleave with the non-blocking\r
397                 receives performed by prvNonBlockingReceiverTask(). */\r
398                 if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength )\r
399                 {\r
400                         iDataToSend++;\r
401 \r
402                         if( iDataToSend > iMaxValue )\r
403                         {\r
404                                 /* The value sent is reset back to 0 to ensure the string being sent\r
405                                 does not remain at the same length for too long. */\r
406                                 iDataToSend = 0;\r
407                         }\r
408 \r
409                         /* Create the next string. */\r
410                         memset( cTxString, 0x00, sizeof( cTxString ) );\r
411                         sprintf( cTxString, "%d", ( int ) iDataToSend );\r
412                         xStringLength = strlen( cTxString );\r
413                 }\r
414         }\r
415 }\r
416 /*-----------------------------------------------------------*/\r
417 \r
418 static void prvNonBlockingReceiverTask( void *pvParameters )\r
419 {\r
420 MessageBufferHandle_t xMessageBuffer;\r
421 BaseType_t xNonBlockingReceiveError = pdFALSE;\r
422 int32_t iDataToSend = 0;\r
423 size_t xStringLength, xReceiveLength;\r
424 const int32_t iMaxValue = 1500;\r
425 char cExpectedString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */\r
426 char cRxString[ 12 ];\r
427 \r
428         /* In this case the message buffer has already been created and is passed\r
429         into the task using the task's parameter. */\r
430         xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;\r
431 \r
432         /* Create a string from an incrementing number.  The length of the\r
433         string will increase and decrease as the value of the number increases\r
434         then overflows.  This should always match the string sent to the buffer by\r
435         the non blocking sender task. */\r
436         memset( cExpectedString, 0x00, sizeof( cExpectedString ) );\r
437         memset( cRxString, 0x00, sizeof( cRxString ) );\r
438         sprintf( cExpectedString, "%d", ( int ) iDataToSend );\r
439         xStringLength = strlen( cExpectedString );\r
440 \r
441         for( ;; )\r
442         {\r
443                 /* Doesn't block so calls can interleave with the non-blocking\r
444                 receives performed by prvNonBlockingReceiverTask(). */\r
445                 xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK );\r
446 \r
447                 /* Should only ever receive no data is available, or the expected\r
448                 length of data is available. */\r
449                 if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) )\r
450                 {\r
451                         xNonBlockingReceiveError = pdTRUE;\r
452                 }\r
453 \r
454                 if( xReceiveLength == xStringLength )\r
455                 {\r
456                         /* Ensure the received data was that expected, then generate the\r
457                         next expected string. */\r
458                         if( strcmp( cRxString, cExpectedString ) != 0 )\r
459                         {\r
460                                 xNonBlockingReceiveError = pdTRUE;\r
461                         }\r
462 \r
463                         iDataToSend++;\r
464 \r
465                         if( iDataToSend > iMaxValue )\r
466                         {\r
467                                 /* The value sent is reset back to 0 to ensure the string being sent\r
468                                 does not remain at the same length for too long. */\r
469                                 iDataToSend = 0;\r
470                         }\r
471 \r
472                         memset( cExpectedString, 0x00, sizeof( cExpectedString ) );\r
473                         memset( cRxString, 0x00, sizeof( cRxString ) );\r
474                         sprintf( cExpectedString, "%d", ( int ) iDataToSend );\r
475                         xStringLength = strlen( cExpectedString );\r
476 \r
477                         if( xNonBlockingReceiveError == pdFALSE )\r
478                         {\r
479                                 /* No errors detected so increment the counter that lets the\r
480                                 check task know this test is still functioning correctly. */\r
481                                 ulNonBlockingRxCounter++;\r
482                         }\r
483                 }\r
484         }\r
485 }\r
486 /*-----------------------------------------------------------*/\r
487 \r
488 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
489 \r
490         static void prvSenderTask( void *pvParameters )\r
491         {\r
492         MessageBufferHandle_t xMessageBuffer, xTempMessageBuffer;\r
493         int32_t iDataToSend = 0;\r
494         const int32_t iSendsBetweenIncrements = 100;\r
495         char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */\r
496         const TickType_t xTicksToWait = mbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );\r
497         StaticMessageBuffer_t xStaticMessageBuffer;\r
498 \r
499 \r
500         /* The task's priority is used as an index into the loop counters used to\r
501         indicate this task is still running. */\r
502         UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
503 \r
504                 /* Make sure a change in priority does not inadvertently result in an\r
505                 invalid array index. */\r
506                 configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS );\r
507 \r
508                 /* Avoid compiler warnings about unused parameters. */\r
509                 ( void ) pvParameters;\r
510 \r
511                 xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ) / mbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */\r
512                                                                                                          &( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */\r
513                                                                                                          &( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */\r
514 \r
515                 /* Now the message buffer has been created the receiver task can be created.\r
516                 If this sender task has the higher priority then the receiver task is\r
517                 created at the lower priority - if this sender task has the lower priority\r
518                 then the receiver task is created at the higher priority. */\r
519                 if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )\r
520                 {\r
521                         /* Here prvSingleTaskTests() performs various tests on a message buffer\r
522                         that was created statically. */\r
523                         prvSingleTaskTests( xMessageBuffer );\r
524                         xTaskCreate( prvReceiverTask, "MsgReceiver", mbSTACK_SIZE,  ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL );\r
525                 }\r
526                 else\r
527                 {\r
528                         xTaskCreate( prvReceiverTask, "MsgReceiver", mbSTACK_SIZE,  ( void * ) xMessageBuffer, mbLOWER_PRIORITY, NULL );\r
529                 }\r
530 \r
531                 for( ;; )\r
532                 {\r
533                         /* Create a string from an incrementing number.  The length of the\r
534                         string will increase and decrease as the value of the number increases\r
535                         then overflows. */\r
536                         memset( cTxString, 0x00, sizeof( cTxString ) );\r
537                         sprintf( cTxString, "%d", ( int ) iDataToSend );\r
538                         xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), xTicksToWait );\r
539 \r
540                         iDataToSend++;\r
541 \r
542                         if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )\r
543                         {\r
544                                 /* Increment a loop counter so a check task can tell this task is\r
545                                 still running as expected. */\r
546                                 ulSenderLoopCounters[ uxIndex ]++;\r
547 \r
548                                 if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )\r
549                                 {\r
550                                         /* Allow other tasks to run. */\r
551                                         vTaskDelay( xShortDelay );\r
552                                 }\r
553 \r
554                                 /* This message buffer is just created and deleted to ensure no\r
555                                 issues when attempting to delete a message buffer that was\r
556                                 created using statically allocated memory.  To save stack space\r
557                                 the buffer is set to point to the cTxString array - this is\r
558                                 ok because nothing is actually written to the memory. */\r
559                                 xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer );\r
560                                 vMessageBufferDelete( xTempMessageBuffer );\r
561                         }\r
562                 }\r
563         }\r
564 \r
565 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
566 /*-----------------------------------------------------------*/\r
567 \r
568 #if( configSUPPORT_STATIC_ALLOCATION == 1  )\r
569 \r
570         static void prvReceiverTask( void *pvParameters )\r
571         {\r
572         MessageBufferHandle_t * const pxMessageBuffer = ( MessageBufferHandle_t * ) pvParameters;\r
573         char cExpectedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */\r
574         char cReceivedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */\r
575         int32_t iExpectedData = 0;\r
576         const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );\r
577         size_t xReceivedBytes;\r
578 \r
579                 for( ;; )\r
580                 {\r
581                         /* Generate the next expected string in the cExpectedString buffer. */\r
582                         memset( cExpectedString, 0x00, sizeof( cExpectedString ) );\r
583                         sprintf( cExpectedString, "%d", ( int ) iExpectedData );\r
584 \r
585                         /* Receive the next string from the message buffer. */\r
586                         memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
587 \r
588                         do\r
589                         {\r
590                                 xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );\r
591 \r
592                         } while( xReceivedBytes == 0 );\r
593 \r
594                         /* Ensure the received string matches the expected string. */\r
595                         configASSERT( strcmp( cExpectedString, cReceivedString ) == 0 );\r
596 \r
597                         iExpectedData++;\r
598                 }\r
599         }\r
600 \r
601 #endif /* configSUPPORT_STATIC_ALLOCATION */\r
602 /*-----------------------------------------------------------*/\r
603 \r
604 static void prvEchoClient( void *pvParameters )\r
605 {\r
606 size_t xSendLength = 0, ux;\r
607 char *pcStringToSend, *pcStringReceived, cNextChar = mbASCII_SPACE;\r
608 const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );\r
609 \r
610 /* The task's priority is used as an index into the loop counters used to\r
611 indicate this task is still running. */\r
612 UBaseType_t uxIndex = uxTaskPriorityGet( NULL );\r
613 \r
614 /* Pointers to the client and server message buffers are passed into this task\r
615 using the task's parameter. */\r
616 EchoMessageBuffers_t *pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters;\r
617 \r
618         /* Prevent compiler warnings. */\r
619         ( void ) pvParameters;\r
620 \r
621         /* Create the buffer into which strings to send to the server will be\r
622         created, and the buffer into which strings echoed back from the server will\r
623         be copied. */\r
624         pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
625         pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
626 \r
627         configASSERT( pcStringToSend );\r
628         configASSERT( pcStringReceived );\r
629 \r
630         for( ;; )\r
631         {\r
632                 /* Generate the length of the next string to send. */\r
633                 xSendLength++;\r
634 \r
635                 /* The message buffer is being used to hold variable length data, so\r
636                 each data item requires sizeof( size_t ) bytes to hold the data's\r
637                 length, hence the sizeof() in the if() condition below. */\r
638                 if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )\r
639                 {\r
640                         /* Back to a string length of 1. */\r
641                         xSendLength = sizeof( char );\r
642 \r
643                         /* Maintain a count of the number of times this code executes so a\r
644                         check task can determine if this task is still functioning as\r
645                         expected or not.  As there are two client tasks, and the priorities\r
646                         used are 0 and 1, the task's priority is used as an index into the\r
647                         loop count array. */\r
648                         ulEchoLoopCounters[ uxIndex ]++;\r
649                 }\r
650 \r
651                 memset( pcStringToSend, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );\r
652 \r
653                 for( ux = 0; ux < xSendLength; ux++ )\r
654                 {\r
655                         pcStringToSend[ ux ] = cNextChar;\r
656 \r
657                         cNextChar++;\r
658 \r
659                         if( cNextChar > mbASCII_TILDA )\r
660                         {\r
661                                 cNextChar = mbASCII_SPACE;\r
662                         }\r
663                 }\r
664 \r
665                 /* Send the generated string to the buffer. */\r
666                 do\r
667                 {\r
668                         ux = xMessageBufferSend( pxMessageBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );\r
669 \r
670                         if( ux == 0 )\r
671                         {\r
672                                 mtCOVERAGE_TEST_MARKER();\r
673                         }\r
674 \r
675                 } while( ux == 0 );\r
676 \r
677                 /* Wait for the string to be echoed back. */\r
678                 memset( pcStringReceived, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );\r
679                 xMessageBufferReceive( pxMessageBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );\r
680 \r
681                 configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );\r
682         }\r
683 }\r
684 /*-----------------------------------------------------------*/\r
685 \r
686 static void prvEchoServer( void *pvParameters )\r
687 {\r
688 MessageBufferHandle_t xTempMessageBuffer;\r
689 size_t xReceivedLength;\r
690 char *pcReceivedString;\r
691 EchoMessageBuffers_t xMessageBuffers;\r
692 TickType_t xTimeOnEntering;\r
693 const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );\r
694 \r
695         /* Prevent compiler warnings about unused parameters. */\r
696         ( void ) pvParameters;\r
697 \r
698         /* Create the message buffer used to send data from the client to the server,\r
699         and the message buffer used to echo the data from the server back to the\r
700         client. */\r
701         xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
702         xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
703         configASSERT( xMessageBuffers.xEchoClientBuffer );\r
704         configASSERT( xMessageBuffers.xEchoServerBuffer );\r
705 \r
706         /* Create the buffer into which received strings will be copied. */\r
707         pcReceivedString = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
708         configASSERT( pcReceivedString );\r
709 \r
710         /* Don't expect to receive anything yet! */\r
711         xTimeOnEntering = xTaskGetTickCount();\r
712         xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
713         configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToBlock );\r
714         configASSERT( xReceivedLength == 0 );\r
715         ( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */\r
716 \r
717         /* Now the message buffers have been created the echo client task can be\r
718         created.  If this server task has the higher priority then the client task\r
719         is created at the lower priority - if this server task has the lower\r
720         priority then the client task is created at the higher priority. */\r
721         if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )\r
722         {\r
723                 xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE,  ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );\r
724         }\r
725         else\r
726         {\r
727                 /* Here prvSingleTaskTests() performs various tests on a message buffer\r
728                 that was created dynamically. */\r
729                 prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer );\r
730                 xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL );\r
731         }\r
732 \r
733         for( ;; )\r
734         {\r
735                 memset( pcReceivedString, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );\r
736 \r
737                 /* Has any data been sent by the client? */\r
738                 xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );\r
739 \r
740                 /* Should always receive data as a delay was used. */\r
741                 configASSERT( xReceivedLength > 0 );\r
742 \r
743                 /* Echo the received data back to the client. */\r
744                 xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );\r
745 \r
746                 /* This message buffer is just created and deleted to ensure no memory\r
747                 leaks. */\r
748                 xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );\r
749                 vMessageBufferDelete( xTempMessageBuffer );\r
750         }\r
751 }\r
752 /*-----------------------------------------------------------*/\r
753 \r
754 BaseType_t xAreMessageBufferTasksStillRunning( void )\r
755 {\r
756 static uint32_t ulLastEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
757 static uint32_t ulLastNonBlockingRxCounter = 0;\r
758 BaseType_t xReturn = pdPASS, x;\r
759 \r
760         for( x = 0; x < mbNUMBER_OF_ECHO_CLIENTS; x++ )\r
761         {\r
762                 if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )\r
763                 {\r
764                         xReturn = pdFAIL;\r
765                 }\r
766                 else\r
767                 {\r
768                         ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];\r
769                 }\r
770         }\r
771 \r
772         if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )\r
773         {\r
774                 xReturn = pdFAIL;\r
775         }\r
776         else\r
777         {\r
778                 ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;\r
779         }\r
780 \r
781         #if( configSUPPORT_STATIC_ALLOCATION == 1 )\r
782         {\r
783                 static uint32_t ulLastSenderLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };\r
784 \r
785                 for( x = 0; x < mbNUMBER_OF_SENDER_TASKS; x++ )\r
786                 {\r
787                         if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )\r
788                         {\r
789                                 xReturn = pdFAIL;\r
790                         }\r
791                         else\r
792                         {\r
793                                 ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];\r
794                         }\r
795                 }\r
796         }\r
797         #endif /* configSUPPORT_STATIC_ALLOCATION */\r
798 \r
799         return xReturn;\r
800 }\r
801 /*-----------------------------------------------------------*/\r
802 \r
803 \r