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