2 * FreeRTOS Kernel V10.0.1
\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.
\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
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Standard includes. */
\r
32 /* FreeRTOS includes. */
\r
33 #include "FreeRTOS.h"
\r
35 #include "message_buffer.h"
\r
37 /* Demo app includes. */
\r
38 #include "MessageBufferDemo.h"
\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
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
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
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
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
59 /* Block times used when sending and receiving from the message buffers. */
\r
60 #define mbRX_TX_BLOCK_TIME pdMS_TO_TICKS( 125UL )
\r
62 /* A block time of 0 means "don't block". */
\r
63 #define mbDONT_BLOCK ( 0 )
\r
65 /*-----------------------------------------------------------*/
\r
68 * Performs various tests that do not require multiple tasks to interact.
\r
70 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer );
\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
78 static void prvEchoClient( void *pvParameters );
\r
79 static void prvEchoServer( void *pvParameters );
\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
86 static void prvNonBlockingReceiverTask( void *pvParameters );
\r
87 static void prvNonBlockingSenderTask( void *pvParameters );
\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
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
101 /*-----------------------------------------------------------*/
\r
103 /* The buffers used by the echo client and server tasks. */
\r
104 typedef struct ECHO_MESSAGE_BUFFERS
\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
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
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
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
126 /*-----------------------------------------------------------*/
\r
128 void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize )
\r
130 MessageBufferHandle_t xMessageBuffer;
\r
132 xBlockingStackSize = ( xStackSize + ( xStackSize >> 1U ) );
\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
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
147 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\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
155 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
157 /*-----------------------------------------------------------*/
\r
159 static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer )
\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
169 /* Remove warning in case configASSERT() is not defined. */
\r
170 ( void ) xAllowableMargin;
\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
178 pucData = pucFullBuffer;
\r
179 pucReadData = pucData + x17ByteLength;
\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
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
200 configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );
\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
209 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
\r
210 taskENTER_CRITICAL();
\r
212 xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, x6ByteLength, NULL );
\r
214 taskEXIT_CRITICAL();
\r
215 configASSERT( xReturned == x6ByteLength );
\r
216 ( void ) xReturned; /* In case configASSERT() is not defined. */
\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
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
232 /* Now the buffer should be full, and attempting to add anything will should
\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
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
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
260 /* Generate the data that is expected to be read out for this loop
\r
262 memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
\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
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
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
282 xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
\r
284 taskEXIT_CRITICAL();
\r
285 configASSERT( xReturned == x6ByteLength );
\r
286 ( void ) xReturned; /* In case configASSERT() is not defined. */
\r
288 /* Does the data read out match that expected? */
\r
289 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
\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
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
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
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
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
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
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
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
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
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
362 /* Does the data read out match that expected? */
\r
363 configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );
\r
365 /* Don't expect any messages to be available as the data was read out
\r
367 xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
\r
368 configASSERT( xNextLength == 0 );
\r
369 ( void ) xNextLength; /* In case configASSERT() is not defined. */
\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
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
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
399 /* Don't expect any messages to be available as the above were too large to
\r
401 xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
\r
402 configASSERT( xNextLength == 0 );
\r
403 ( void ) xNextLength; /* In case configASSERT() is not defined. */
\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
418 vPortFree( pucFullBuffer );
\r
419 xMessageBufferReset( xMessageBuffer );
\r
421 /*-----------------------------------------------------------*/
\r
423 static void prvNonBlockingSenderTask( void *pvParameters )
\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
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
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
438 memset( cTxString, 0x00, sizeof( cTxString ) );
\r
439 sprintf( cTxString, "%d", ( int ) iDataToSend );
\r
440 xStringLength = strlen( cTxString );
\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
450 if( iDataToSend > iMaxValue )
\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
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
464 /*-----------------------------------------------------------*/
\r
466 static void prvNonBlockingReceiverTask( void *pvParameters )
\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
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
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
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
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
499 xNonBlockingReceiveError = pdTRUE;
\r
502 if( xReceiveLength == xStringLength )
\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
508 xNonBlockingReceiveError = pdTRUE;
\r
513 if( iDataToSend > iMaxValue )
\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
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
525 if( xNonBlockingReceiveError == pdFALSE )
\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
534 /*-----------------------------------------------------------*/
\r
536 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
538 static void prvSenderTask( void *pvParameters )
\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
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
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
556 /* Avoid compiler warnings about unused parameters. */
\r
557 ( void ) pvParameters;
\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
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
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
576 xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbLOWER_PRIORITY, NULL );
\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
584 memset( cTxString, 0x00, sizeof( cTxString ) );
\r
585 sprintf( cTxString, "%d", ( int ) iDataToSend );
\r
586 xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), xTicksToWait );
\r
590 if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )
\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
596 if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )
\r
598 /* Allow other tasks to run. */
\r
599 vTaskDelay( xShortDelay );
\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
613 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
614 /*-----------------------------------------------------------*/
\r
616 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
618 static void prvReceiverTask( void *pvParameters )
\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
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
633 /* Receive the next string from the message buffer. */
\r
634 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
\r
638 xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );
\r
640 } while( xReceivedBytes == 0 );
\r
642 /* Ensure the received string matches the expected string. */
\r
643 configASSERT( strcmp( cExpectedString, cReceivedString ) == 0 );
\r
649 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
650 /*-----------------------------------------------------------*/
\r
652 static void prvEchoClient( void *pvParameters )
\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
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
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
666 /* Prevent compiler warnings. */
\r
667 ( void ) pvParameters;
\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
672 pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
673 pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
675 configASSERT( pcStringToSend );
\r
676 configASSERT( pcStringReceived );
\r
680 /* Generate the length of the next string to send. */
\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
688 /* Back to a string length of 1. */
\r
689 xSendLength = sizeof( char );
\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
699 memset( pcStringToSend, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
701 for( ux = 0; ux < xSendLength; ux++ )
\r
703 pcStringToSend[ ux ] = cNextChar;
\r
707 if( cNextChar > mbASCII_TILDA )
\r
709 cNextChar = mbASCII_SPACE;
\r
713 /* Send the generated string to the buffer. */
\r
716 ux = xMessageBufferSend( pxMessageBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );
\r
720 mtCOVERAGE_TEST_MARKER();
\r
723 } while( ux == 0 );
\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
729 configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );
\r
732 /*-----------------------------------------------------------*/
\r
734 static void prvEchoServer( void *pvParameters )
\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
743 /* Prevent compiler warnings about unused parameters. */
\r
744 ( void ) pvParameters;
\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
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
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
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
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
771 xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );
\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
783 memset( pcReceivedString, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
785 /* Has any data been sent by the client? */
\r
786 xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );
\r
788 /* Should always receive data as a delay was used. */
\r
789 configASSERT( xReceivedLength > 0 );
\r
791 /* Echo the received data back to the client. */
\r
792 xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );
\r
794 /* This message buffer is just created and deleted to ensure no memory
\r
796 xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
\r
797 vMessageBufferDelete( xTempMessageBuffer );
\r
800 /*-----------------------------------------------------------*/
\r
802 BaseType_t xAreMessageBufferTasksStillRunning( void )
\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
808 for( x = 0; x < mbNUMBER_OF_ECHO_CLIENTS; x++ )
\r
810 if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )
\r
816 ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];
\r
820 if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )
\r
826 ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;
\r
829 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
\r
831 static uint32_t ulLastSenderLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
\r
833 for( x = 0; x < mbNUMBER_OF_SENDER_TASKS; x++ )
\r
835 if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )
\r
841 ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];
\r
845 #endif /* configSUPPORT_STATIC_ALLOCATION */
\r
849 /*-----------------------------------------------------------*/
\r