2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Standard includes. */
\r
33 /* FreeRTOS includes. */
\r
34 #include "FreeRTOS.h"
\r
36 #include "message_buffer.h"
\r
38 /* Demo app includes. */
\r
39 #include "MessageBufferDemo.h"
\r
41 /* The number of bytes of storage in the message buffers used in this test. */
\r
42 #define mbMESSAGE_BUFFER_LENGTH_BYTES ( ( size_t ) 50 )
\r
44 /* The number of additional bytes used to store the length of each message. */
\r
45 #define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( size_t ) )
\r
47 /* Start and end ASCII characters used in messages sent to the buffers. */
\r
48 #define mbASCII_SPACE 32
\r
49 #define mbASCII_TILDA 126
\r
51 /* Defines the number of tasks to create in this test and demo. */
\r
52 #define mbNUMBER_OF_ECHO_CLIENTS ( 2 )
\r
53 #define mbNUMBER_OF_SENDER_TASKS ( 2 )
\r
55 /* Priority of the test tasks. The send and receive go from low to high
\r
56 priority tasks, and from high to low priority tasks. */
\r
57 #define mbLOWER_PRIORITY ( tskIDLE_PRIORITY )
\r
58 #define mbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
60 /* Block times used when sending and receiving from the message buffers. */
\r
61 #define mbRX_TX_BLOCK_TIME pdMS_TO_TICKS( 125UL )
\r
63 /* A block time of 0 means "don't block". */
\r
64 #define mbDONT_BLOCK ( 0 )
\r
66 /* The size of the stack allocated to the tasks that run as part of this demo/
\r
67 test. The stack size is over generous in most cases. */
\r
68 #define mbSTACK_SIZE ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) )
\r
69 /*-----------------------------------------------------------*/
\r
72 * Performs various tests that do not require multiple tasks to interact.
\r
74 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer );
\r
77 * Tests sending and receiving various lengths of messages via a message buffer.
\r
78 * The echo client sends the messages to the echo server, which then sends the
\r
79 * message back to the echo client which, checks it receives exactly what it
\r
82 static void prvEchoClient( void *pvParameters );
\r
83 static void prvEchoServer( void *pvParameters );
\r
86 * Tasks that send and receive to a message buffer at a low priority and without
\r
87 * blocking, so the send and receive functions interleave in time as the tasks
\r
88 * are switched in and out.
\r
90 static void prvNonBlockingReceiverTask( void *pvParameters );
\r
91 static void prvNonBlockingSenderTask( void *pvParameters );
\r
93 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
94 /* This file tests both statically and dynamically allocated message buffers.
\r
95 Allocate the structures and buffers to be used by the statically allocated
\r
96 objects, which get used in the echo tests. */
\r
97 static void prvReceiverTask( void *pvParameters );
\r
98 static void prvSenderTask( void *pvParameters );
\r
100 static StaticMessageBuffer_t xStaticMessageBuffers[ mbNUMBER_OF_ECHO_CLIENTS ];
\r
101 static uint8_t ucBufferStorage[ mbNUMBER_OF_SENDER_TASKS ][ mbMESSAGE_BUFFER_LENGTH_BYTES + 1 ];
\r
102 static uint32_t ulSenderLoopCounters[ mbNUMBER_OF_SENDER_TASKS ] = { 0 };
\r
103 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
105 /*-----------------------------------------------------------*/
\r
107 /* The buffers used by the echo client and server tasks. */
\r
108 typedef struct ECHO_MESSAGE_BUFFERS
\r
110 /* Handles to the data structures that describe the message buffers. */
\r
111 MessageBufferHandle_t xEchoClientBuffer;
\r
112 MessageBufferHandle_t xEchoServerBuffer;
\r
113 } EchoMessageBuffers_t;
\r
114 static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
\r
116 /* The non-blocking tasks monitor their operation, and if no errors have been
\r
117 found, increment ulNonBlockingRxCounter. xAreMessageBufferTasksStillRunning()
\r
118 then checks ulNonBlockingRxCounter and only returns pdPASS if
\r
119 ulNonBlockingRxCounter is still incrementing. */
\r
120 static uint32_t ulNonBlockingRxCounter = 0;
\r
122 /* A message that is longer than the buffer, parts of which are written to the
\r
123 message buffer to test writing different lengths at different offsets. */
\r
124 static const char *pc55ByteString = "One two three four five six seven eight nine ten eleve";
\r
127 /*-----------------------------------------------------------*/
\r
129 void vStartMessageBufferTasks( void )
\r
131 MessageBufferHandle_t xMessageBuffer;
\r
133 /* The echo servers sets up the message buffers before creating the echo
\r
134 client tasks. One set of tasks has the server as the higher priority, and
\r
135 the other has the client as the higher priority. */
\r
136 xTaskCreate( prvEchoServer, "1EchoServer", mbSTACK_SIZE, NULL, mbHIGHER_PRIORITY, NULL );
\r
137 xTaskCreate( prvEchoServer, "2EchoServer", mbSTACK_SIZE, NULL, mbLOWER_PRIORITY, NULL );
\r
139 /* The non blocking tasks run continuously and will interleave with each
\r
140 other, so must be created at the lowest priority. The message buffer they
\r
141 use is created and passed in using the task's parameter. */
\r
142 xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
143 xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
\r
144 xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
\r
146 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
148 /* The sender tasks set up the message buffers before creating the
\r
149 receiver tasks. Priorities must be 0 and 1 as the priority is used to
\r
150 index into the xStaticMessageBuffers and ucBufferStorage arrays. */
\r
151 xTaskCreate( prvSenderTask, "1Sender", mbSTACK_SIZE, NULL, mbHIGHER_PRIORITY, NULL );
\r
152 xTaskCreate( prvSenderTask, "2Sender", mbSTACK_SIZE, NULL, mbLOWER_PRIORITY, NULL );
\r
154 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
156 /*-----------------------------------------------------------*/
\r
158 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer )
\r
160 size_t xReturned, xItem, xExpectedSpace;
\r
161 const size_t xMax6ByteMessages = mbMESSAGE_BUFFER_LENGTH_BYTES / ( 6 + mbBYTES_TO_STORE_MESSAGE_LENGTH );
\r
162 const size_t x6ByteLength = 6, x17ByteLength = 17;
\r
163 uint8_t *pucFullBuffer, *pucData, *pucReadData;
\r
164 TickType_t xTimeBeforeCall, xTimeAfterCall;
\r
165 const TickType_t xBlockTime = pdMS_TO_TICKS( 25 ), xAllowableMargin = pdMS_TO_TICKS( 3 );
\r
166 UBaseType_t uxOriginalPriority;
\r
168 /* Remove warning in case configASSERT() is not defined. */
\r
169 ( void ) xAllowableMargin;
\r
171 /* To minimise stack and heap usage a full size buffer is allocated from
\r
172 the heap, then buffers which hold smaller amounts of data are overlayed
\r
173 with the larger buffer - just make sure not to use both at once!. */
\r
174 pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
175 configASSERT( pucFullBuffer );
\r
177 pucData = pucFullBuffer;
\r
178 pucReadData = pucData + x17ByteLength;
\r
180 /* Nothing has been added or removed yet, so expect the free space to be
\r
181 exactly as created. */
\r
182 xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
183 configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
184 configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
\r
187 /* The buffer is 50 bytes long. When an item is added to the buffer an
\r
188 additional 4 bytes are added to hold the item's size. That means adding
\r
189 6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore,
\r
190 with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the
\r
191 buffer is completely full. */
\r
192 for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
\r
194 configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );
\r
196 /* Generate recognisable data to write to the buffer. This is just
\r
197 ascii characters that shows which loop iteration the data was written
\r
198 in. The 'FromISR' version is used to give it some exercise as a block
\r
199 time is not used. That requires the call to be in a critical section
\r
200 so this code can also run on FreeRTOS ports that do not support
\r
201 interrupt nesting (and so don't have interrupt safe critical
\r
203 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
\r
204 taskENTER_CRITICAL();
\r
206 xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, x6ByteLength, NULL );
\r
208 taskEXIT_CRITICAL();
\r
209 configASSERT( xReturned == x6ByteLength );
\r
210 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
212 /* The space in the buffer will have reduced by the amount of user data
\r
213 written into the buffer and the amount of space used to store the length
\r
214 of the data written into the buffer. */
\r
215 xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
\r
216 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
217 configASSERT( xReturned == xExpectedSpace );
\r
218 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
221 /* Now the buffer should be full, and attempting to add anything will should
\r
223 configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE );
\r
224 xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK );
\r
225 configASSERT( xReturned == 0 );
\r
226 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
228 /* Adding with a timeout should also fail after the appropriate time. The
\r
229 priority is temporarily boosted in this part of the test to keep the
\r
230 allowable margin to a minimum. */
\r
231 uxOriginalPriority = uxTaskPriorityGet( NULL );
\r
232 vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
\r
233 xTimeBeforeCall = xTaskGetTickCount();
\r
234 xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );
\r
235 xTimeAfterCall = xTaskGetTickCount();
\r
236 vTaskPrioritySet( NULL, uxOriginalPriority );
\r
237 configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );
\r
238 configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );
\r
239 configASSERT( xReturned == 0 );
\r
240 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
241 ( void ) xTimeBeforeCall;
\r
242 ( void ) xTimeAfterCall;
\r
245 /* The buffer is now full of data in the form "000000", "111111", etc. Make
\r
246 sure the data is read out as expected. */
\r
247 for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
\r
249 /* Generate the data that is expected to be read out for this loop
\r
251 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
\r
253 /* Try reading the message into a buffer that is too small. The message
\r
254 should remain in the buffer. */
\r
255 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK );
\r
256 configASSERT( xReturned == 0 );
\r
257 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
259 /* Read the next 6 bytes out. The 'FromISR' version is used to give it
\r
260 some exercise as a block time is not used. THa requires the code to be
\r
261 in a critical section so this test can be run with FreeRTOS ports that
\r
262 do not support interrupt nesting (and therefore don't have interrupt
\r
263 safe critical sections). */
\r
264 taskENTER_CRITICAL();
\r
266 xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
\r
268 taskEXIT_CRITICAL();
\r
269 configASSERT( xReturned == x6ByteLength );
\r
270 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
272 /* Does the data read out match that expected? */
\r
273 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
\r
275 /* The space in the buffer will have increased by the amount of user
\r
276 data read from into the buffer and the amount of space used to store the
\r
277 length of the data read into the buffer. */
\r
278 xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
\r
279 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
280 configASSERT( xReturned == xExpectedSpace );
\r
281 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
284 /* The buffer should be empty again. */
\r
285 configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
\r
286 xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
287 configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
289 /* Reading with a timeout should also fail after the appropriate time. The
\r
290 priority is temporarily boosted in this part of the test to keep the
\r
291 allowable margin to a minimum. */
\r
292 vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
\r
293 xTimeBeforeCall = xTaskGetTickCount();
\r
294 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );
\r
295 xTimeAfterCall = xTaskGetTickCount();
\r
296 vTaskPrioritySet( NULL, uxOriginalPriority );
\r
297 configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );
\r
298 configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );
\r
299 configASSERT( xReturned == 0 );
\r
300 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
301 ( void ) xTimeBeforeCall;
\r
302 ( void ) xTimeAfterCall;
\r
305 /* In the next loop 17 bytes are written to then read out on each iteration.
\r
306 The expected length variable is always used after 17 bytes have been written
\r
307 into the buffer - the length of the message is also written, making a total
\r
308 of 21 bytes consumed for each 17 byte message. */
\r
309 xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
\r
311 /* Reading and writing 17 bytes at a time will result in 21 bytes being
\r
312 written into the buffer, and as 50 is not divisible by 21, writing multiple
\r
313 times will cause the data to wrap in the buffer.*/
\r
314 for( xItem = 0; xItem < 100; xItem++ )
\r
316 /* Generate recognisable data to write to the queue. This is just
\r
317 ascii characters that shows which loop iteration the data was written
\r
319 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );
\r
320 xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK );
\r
321 configASSERT( xReturned == x17ByteLength );
\r
322 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
324 /* The space in the buffer will have reduced by the amount of user data
\r
325 written into the buffer and the amount of space used to store the length
\r
326 of the data written into the buffer. */
\r
327 xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
328 configASSERT( xReturned == xExpectedSpace );
\r
329 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
331 /* Read the 17 bytes out again. */
\r
332 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x17ByteLength, mbDONT_BLOCK );
\r
333 configASSERT( xReturned == x17ByteLength );
\r
334 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
336 /* Does the data read out match that expected? */
\r
337 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );
\r
340 /* The buffer should be empty again. */
\r
341 configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
\r
342 xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
\r
343 configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
345 /* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test)
\r
346 bytes of the full 50 bytes, as that would not leave space for the four bytes
\r
347 taken by the data length. */
\r
348 xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK );
\r
349 configASSERT( xReturned == 0 );
\r
350 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
351 xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK );
\r
352 configASSERT( xReturned == 0 );
\r
353 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
354 xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 2, mbDONT_BLOCK );
\r
355 configASSERT( xReturned == 0 );
\r
356 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
357 xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 3, mbDONT_BLOCK );
\r
358 configASSERT( xReturned == 0 );
\r
359 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
361 /* Can write mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) bytes though. */
\r
362 xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
\r
363 configASSERT( xReturned == mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) );
\r
364 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
365 xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucFullBuffer, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
\r
366 configASSERT( xReturned == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );
\r
367 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
368 configASSERT( memcmp( ( const void * ) pucFullBuffer, pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) == 0 );
\r
371 vPortFree( pucFullBuffer );
\r
372 xMessageBufferReset( xMessageBuffer );
\r
374 /*-----------------------------------------------------------*/
\r
376 static void prvNonBlockingSenderTask( void *pvParameters )
\r
378 MessageBufferHandle_t xMessageBuffer;
\r
379 int32_t iDataToSend = 0;
\r
380 size_t xStringLength;
\r
381 const int32_t iMaxValue = 1500;
\r
382 char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
\r
384 /* In this case the message buffer has already been created and is passed
\r
385 into the task using the task's parameter. */
\r
386 xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
\r
388 /* Create a string from an incrementing number. The length of the
\r
389 string will increase and decrease as the value of the number increases
\r
391 memset( cTxString, 0x00, sizeof( cTxString ) );
\r
392 sprintf( cTxString, "%d", ( int ) iDataToSend );
\r
393 xStringLength = strlen( cTxString );
\r
397 /* Doesn't block so calls can interleave with the non-blocking
\r
398 receives performed by prvNonBlockingReceiverTask(). */
\r
399 if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength )
\r
403 if( iDataToSend > iMaxValue )
\r
405 /* The value sent is reset back to 0 to ensure the string being sent
\r
406 does not remain at the same length for too long. */
\r
410 /* Create the next string. */
\r
411 memset( cTxString, 0x00, sizeof( cTxString ) );
\r
412 sprintf( cTxString, "%d", ( int ) iDataToSend );
\r
413 xStringLength = strlen( cTxString );
\r
417 /*-----------------------------------------------------------*/
\r
419 static void prvNonBlockingReceiverTask( void *pvParameters )
\r
421 MessageBufferHandle_t xMessageBuffer;
\r
422 BaseType_t xNonBlockingReceiveError = pdFALSE;
\r
423 int32_t iDataToSend = 0;
\r
424 size_t xStringLength, xReceiveLength;
\r
425 const int32_t iMaxValue = 1500;
\r
426 char cExpectedString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
\r
427 char cRxString[ 12 ];
\r
429 /* In this case the message buffer has already been created and is passed
\r
430 into the task using the task's parameter. */
\r
431 xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
\r
433 /* Create a string from an incrementing number. The length of the
\r
434 string will increase and decrease as the value of the number increases
\r
435 then overflows. This should always match the string sent to the buffer by
\r
436 the non blocking sender task. */
\r
437 memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
\r
438 memset( cRxString, 0x00, sizeof( cRxString ) );
\r
439 sprintf( cExpectedString, "%d", ( int ) iDataToSend );
\r
440 xStringLength = strlen( cExpectedString );
\r
444 /* Doesn't block so calls can interleave with the non-blocking
\r
445 receives performed by prvNonBlockingReceiverTask(). */
\r
446 xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK );
\r
448 /* Should only ever receive no data is available, or the expected
\r
449 length of data is available. */
\r
450 if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) )
\r
452 xNonBlockingReceiveError = pdTRUE;
\r
455 if( xReceiveLength == xStringLength )
\r
457 /* Ensure the received data was that expected, then generate the
\r
458 next expected string. */
\r
459 if( strcmp( cRxString, cExpectedString ) != 0 )
\r
461 xNonBlockingReceiveError = pdTRUE;
\r
466 if( iDataToSend > iMaxValue )
\r
468 /* The value sent is reset back to 0 to ensure the string being sent
\r
469 does not remain at the same length for too long. */
\r
473 memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
\r
474 memset( cRxString, 0x00, sizeof( cRxString ) );
\r
475 sprintf( cExpectedString, "%d", ( int ) iDataToSend );
\r
476 xStringLength = strlen( cExpectedString );
\r
478 if( xNonBlockingReceiveError == pdFALSE )
\r
480 /* No errors detected so increment the counter that lets the
\r
481 check task know this test is still functioning correctly. */
\r
482 ulNonBlockingRxCounter++;
\r
487 /*-----------------------------------------------------------*/
\r
489 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
491 static void prvSenderTask( void *pvParameters )
\r
493 MessageBufferHandle_t xMessageBuffer, xTempMessageBuffer;
\r
494 int32_t iDataToSend = 0;
\r
495 const int32_t iSendsBetweenIncrements = 100;
\r
496 char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
\r
497 const TickType_t xTicksToWait = mbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );
\r
498 StaticMessageBuffer_t xStaticMessageBuffer;
\r
501 /* The task's priority is used as an index into the loop counters used to
\r
502 indicate this task is still running. */
\r
503 UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
\r
505 /* Make sure a change in priority does not inadvertently result in an
\r
506 invalid array index. */
\r
507 configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS );
\r
509 /* Avoid compiler warnings about unused parameters. */
\r
510 ( void ) pvParameters;
\r
512 xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ) / mbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */
\r
513 &( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */
\r
514 &( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */
\r
516 /* Now the message buffer has been created the receiver task can be created.
\r
517 If this sender task has the higher priority then the receiver task is
\r
518 created at the lower priority - if this sender task has the lower priority
\r
519 then the receiver task is created at the higher priority. */
\r
520 if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
\r
522 /* Here prvSingleTaskTests() performs various tests on a message buffer
\r
523 that was created statically. */
\r
524 prvSingleTaskTests( xMessageBuffer );
\r
525 xTaskCreate( prvReceiverTask, "MsgReceiver", mbSTACK_SIZE, ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL );
\r
529 xTaskCreate( prvReceiverTask, "MsgReceiver", mbSTACK_SIZE, ( void * ) xMessageBuffer, mbLOWER_PRIORITY, NULL );
\r
534 /* Create a string from an incrementing number. The length of the
\r
535 string will increase and decrease as the value of the number increases
\r
537 memset( cTxString, 0x00, sizeof( cTxString ) );
\r
538 sprintf( cTxString, "%d", ( int ) iDataToSend );
\r
539 xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), xTicksToWait );
\r
543 if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )
\r
545 /* Increment a loop counter so a check task can tell this task is
\r
546 still running as expected. */
\r
547 ulSenderLoopCounters[ uxIndex ]++;
\r
549 if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )
\r
551 /* Allow other tasks to run. */
\r
552 vTaskDelay( xShortDelay );
\r
555 /* This message buffer is just created and deleted to ensure no
\r
556 issues when attempting to delete a message buffer that was
\r
557 created using statically allocated memory. To save stack space
\r
558 the buffer is set to point to the cTxString array - this is
\r
559 ok because nothing is actually written to the memory. */
\r
560 xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer );
\r
561 vMessageBufferDelete( xTempMessageBuffer );
\r
566 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
567 /*-----------------------------------------------------------*/
\r
569 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
571 static void prvReceiverTask( void *pvParameters )
\r
573 MessageBufferHandle_t * const pxMessageBuffer = ( MessageBufferHandle_t * ) pvParameters;
\r
574 char cExpectedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
\r
575 char cReceivedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
\r
576 int32_t iExpectedData = 0;
\r
577 const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );
\r
578 size_t xReceivedBytes;
\r
582 /* Generate the next expected string in the cExpectedString buffer. */
\r
583 memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
\r
584 sprintf( cExpectedString, "%d", ( int ) iExpectedData );
\r
586 /* Receive the next string from the message buffer. */
\r
587 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
\r
591 xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );
\r
593 } while( xReceivedBytes == 0 );
\r
595 /* Ensure the received string matches the expected string. */
\r
596 configASSERT( strcmp( cExpectedString, cReceivedString ) == 0 );
\r
602 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
603 /*-----------------------------------------------------------*/
\r
605 static void prvEchoClient( void *pvParameters )
\r
607 size_t xSendLength = 0, ux;
\r
608 char *pcStringToSend, *pcStringReceived, cNextChar = mbASCII_SPACE;
\r
609 const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );
\r
611 /* The task's priority is used as an index into the loop counters used to
\r
612 indicate this task is still running. */
\r
613 UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
\r
615 /* Pointers to the client and server message buffers are passed into this task
\r
616 using the task's parameter. */
\r
617 EchoMessageBuffers_t *pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters;
\r
619 /* Prevent compiler warnings. */
\r
620 ( void ) pvParameters;
\r
622 /* Create the buffer into which strings to send to the server will be
\r
623 created, and the buffer into which strings echoed back from the server will
\r
625 pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
626 pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
628 configASSERT( pcStringToSend );
\r
629 configASSERT( pcStringReceived );
\r
633 /* Generate the length of the next string to send. */
\r
636 /* The message buffer is being used to hold variable length data, so
\r
637 each data item requires sizeof( size_t ) bytes to hold the data's
\r
638 length, hence the sizeof() in the if() condition below. */
\r
639 if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )
\r
641 /* Back to a string length of 1. */
\r
642 xSendLength = sizeof( char );
\r
644 /* Maintain a count of the number of times this code executes so a
\r
645 check task can determine if this task is still functioning as
\r
646 expected or not. As there are two client tasks, and the priorities
\r
647 used are 0 and 1, the task's priority is used as an index into the
\r
648 loop count array. */
\r
649 ulEchoLoopCounters[ uxIndex ]++;
\r
652 memset( pcStringToSend, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
654 for( ux = 0; ux < xSendLength; ux++ )
\r
656 pcStringToSend[ ux ] = cNextChar;
\r
660 if( cNextChar > mbASCII_TILDA )
\r
662 cNextChar = mbASCII_SPACE;
\r
666 /* Send the generated string to the buffer. */
\r
669 ux = xMessageBufferSend( pxMessageBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );
\r
673 mtCOVERAGE_TEST_MARKER();
\r
676 } while( ux == 0 );
\r
678 /* Wait for the string to be echoed back. */
\r
679 memset( pcStringReceived, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
680 xMessageBufferReceive( pxMessageBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );
\r
682 configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );
\r
685 /*-----------------------------------------------------------*/
\r
687 static void prvEchoServer( void *pvParameters )
\r
689 MessageBufferHandle_t xTempMessageBuffer;
\r
690 size_t xReceivedLength;
\r
691 char *pcReceivedString;
\r
692 EchoMessageBuffers_t xMessageBuffers;
\r
693 TickType_t xTimeOnEntering;
\r
694 const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
\r
696 /* Prevent compiler warnings about unused parameters. */
\r
697 ( void ) pvParameters;
\r
699 /* Create the message buffer used to send data from the client to the server,
\r
700 and the message buffer used to echo the data from the server back to the
\r
702 xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
703 xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
704 configASSERT( xMessageBuffers.xEchoClientBuffer );
\r
705 configASSERT( xMessageBuffers.xEchoServerBuffer );
\r
707 /* Create the buffer into which received strings will be copied. */
\r
708 pcReceivedString = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
709 configASSERT( pcReceivedString );
\r
711 /* Don't expect to receive anything yet! */
\r
712 xTimeOnEntering = xTaskGetTickCount();
\r
713 xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );
\r
714 configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToBlock );
\r
715 configASSERT( xReceivedLength == 0 );
\r
716 ( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */
\r
718 /* Now the message buffers have been created the echo client task can be
\r
719 created. If this server task has the higher priority then the client task
\r
720 is created at the lower priority - if this server task has the lower
\r
721 priority then the client task is created at the higher priority. */
\r
722 if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
\r
724 xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );
\r
728 /* Here prvSingleTaskTests() performs various tests on a message buffer
\r
729 that was created dynamically. */
\r
730 prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer );
\r
731 xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL );
\r
736 memset( pcReceivedString, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
738 /* Has any data been sent by the client? */
\r
739 xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );
\r
741 /* Should always receive data as a delay was used. */
\r
742 configASSERT( xReceivedLength > 0 );
\r
744 /* Echo the received data back to the client. */
\r
745 xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );
\r
747 /* This message buffer is just created and deleted to ensure no memory
\r
749 xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
750 vMessageBufferDelete( xTempMessageBuffer );
\r
753 /*-----------------------------------------------------------*/
\r
755 BaseType_t xAreMessageBufferTasksStillRunning( void )
\r
757 static uint32_t ulLastEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
\r
758 static uint32_t ulLastNonBlockingRxCounter = 0;
\r
759 BaseType_t xReturn = pdPASS, x;
\r
761 for( x = 0; x < mbNUMBER_OF_ECHO_CLIENTS; x++ )
\r
763 if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )
\r
769 ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];
\r
773 if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )
\r
779 ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;
\r
782 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
784 static uint32_t ulLastSenderLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
\r
786 for( x = 0; x < mbNUMBER_OF_SENDER_TASKS; x++ )
\r
788 if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )
\r
794 ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];
\r
798 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
802 /*-----------------------------------------------------------*/
\r