972 lines
44 KiB
C
972 lines
44 KiB
C
|
/*
|
||
|
* FreeRTOS V202212.00
|
||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
|
* this software and associated documentation files (the "Software"), to deal in
|
||
|
* the Software without restriction, including without limitation the rights to
|
||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||
|
* subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in all
|
||
|
* copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* https://www.FreeRTOS.org
|
||
|
* https://github.com/FreeRTOS
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* Standard includes. */
|
||
|
#include "stdio.h"
|
||
|
#include "string.h"
|
||
|
|
||
|
/* FreeRTOS includes. */
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "task.h"
|
||
|
#include "message_buffer.h"
|
||
|
|
||
|
/* Demo app includes. */
|
||
|
#include "MessageBufferDemo.h"
|
||
|
|
||
|
/* The number of bytes of storage in the message buffers used in this test. */
|
||
|
#define mbMESSAGE_BUFFER_LENGTH_BYTES ( ( size_t ) 50 )
|
||
|
|
||
|
/* The number of additional bytes used to store the length of each message. */
|
||
|
#define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
|
||
|
|
||
|
/* Start and end ASCII characters used in messages sent to the buffers. */
|
||
|
#define mbASCII_SPACE 32
|
||
|
#define mbASCII_TILDA 126
|
||
|
|
||
|
/* Defines the number of tasks to create in this test and demo. */
|
||
|
#define mbNUMBER_OF_ECHO_CLIENTS ( 2 )
|
||
|
#define mbNUMBER_OF_SENDER_TASKS ( 2 )
|
||
|
|
||
|
/* Priority of the test tasks. The send and receive go from low to high
|
||
|
* priority tasks, and from high to low priority tasks. */
|
||
|
#define mbLOWER_PRIORITY ( tskIDLE_PRIORITY )
|
||
|
#define mbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||
|
|
||
|
/* Block times used when sending and receiving from the message buffers. */
|
||
|
#define mbRX_TX_BLOCK_TIME pdMS_TO_TICKS( 175UL )
|
||
|
|
||
|
/* A block time of 0 means "don't block". */
|
||
|
#define mbDONT_BLOCK ( 0 )
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
* Performs various tests that do not require multiple tasks to interact.
|
||
|
*/
|
||
|
static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer );
|
||
|
|
||
|
/*
|
||
|
* Tests sending and receiving various lengths of messages via a message buffer.
|
||
|
* The echo client sends the messages to the echo server, which then sends the
|
||
|
* message back to the echo client which, checks it receives exactly what it
|
||
|
* sent.
|
||
|
*/
|
||
|
static void prvEchoClient( void * pvParameters );
|
||
|
static void prvEchoServer( void * pvParameters );
|
||
|
|
||
|
/*
|
||
|
* Tasks that send and receive to a message buffer at a low priority and without
|
||
|
* blocking, so the send and receive functions interleave in time as the tasks
|
||
|
* are switched in and out.
|
||
|
*/
|
||
|
static void prvNonBlockingReceiverTask( void * pvParameters );
|
||
|
static void prvNonBlockingSenderTask( void * pvParameters );
|
||
|
|
||
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||
|
|
||
|
/* This file tests both statically and dynamically allocated message buffers.
|
||
|
* Allocate the structures and buffers to be used by the statically allocated
|
||
|
* objects, which get used in the echo tests. */
|
||
|
static void prvReceiverTask( void * pvParameters );
|
||
|
static void prvSenderTask( void * pvParameters );
|
||
|
|
||
|
static StaticMessageBuffer_t xStaticMessageBuffers[ mbNUMBER_OF_ECHO_CLIENTS ];
|
||
|
static uint8_t ucBufferStorage[ mbNUMBER_OF_SENDER_TASKS ][ mbMESSAGE_BUFFER_LENGTH_BYTES + 1 ];
|
||
|
static uint32_t ulSenderLoopCounters[ mbNUMBER_OF_SENDER_TASKS ] = { 0 };
|
||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||
|
|
||
|
|
||
|
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||
|
#define mbCOHERENCE_TEST_BUFFER_SIZE 20
|
||
|
#define mbCOHERENCE_TEST_BYTES_WRITTEN 5
|
||
|
#define mbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
|
||
|
#define mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ( mbCOHERENCE_TEST_BUFFER_SIZE - ( mbCOHERENCE_TEST_BYTES_WRITTEN + mbBYTES_TO_STORE_MESSAGE_LENGTH ) )
|
||
|
|
||
|
static void prvSpaceAvailableCoherenceActor( void * pvParameters );
|
||
|
static void prvSpaceAvailableCoherenceTester( void * pvParameters );
|
||
|
static MessageBufferHandle_t xCoherenceTestMessageBuffer = NULL;
|
||
|
|
||
|
static uint32_t ulSizeCoherencyTestCycles = 0UL;
|
||
|
#endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/* The buffers used by the echo client and server tasks. */
|
||
|
typedef struct ECHO_MESSAGE_BUFFERS
|
||
|
{
|
||
|
/* Handles to the data structures that describe the message buffers. */
|
||
|
MessageBufferHandle_t xEchoClientBuffer;
|
||
|
MessageBufferHandle_t xEchoServerBuffer;
|
||
|
} EchoMessageBuffers_t;
|
||
|
static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||
|
|
||
|
/* The non-blocking tasks monitor their operation, and if no errors have been
|
||
|
* found, increment ulNonBlockingRxCounter. xAreMessageBufferTasksStillRunning()
|
||
|
* then checks ulNonBlockingRxCounter and only returns pdPASS if
|
||
|
* ulNonBlockingRxCounter is still incrementing. */
|
||
|
static uint32_t ulNonBlockingRxCounter = 0;
|
||
|
|
||
|
/* A message that is longer than the buffer, parts of which are written to the
|
||
|
* message buffer to test writing different lengths at different offsets. */
|
||
|
static const char * pc55ByteString = "One two three four five six seven eight nine ten eleven";
|
||
|
|
||
|
/* Remember the required stack size so tasks can be created at run time (after
|
||
|
* initialisation time. */
|
||
|
static configSTACK_DEPTH_TYPE xBlockingStackSize = 0;
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize )
|
||
|
{
|
||
|
MessageBufferHandle_t xMessageBuffer;
|
||
|
|
||
|
#ifndef configMESSAGE_BUFFER_BLOCK_TASK_STACK_SIZE
|
||
|
xBlockingStackSize = ( xStackSize + ( xStackSize >> 1U ) );
|
||
|
#else
|
||
|
xBlockingStackSize = configMESSAGE_BUFFER_BLOCK_TASK_STACK_SIZE;
|
||
|
#endif
|
||
|
|
||
|
/* The echo servers sets up the message buffers before creating the echo
|
||
|
* client tasks. One set of tasks has the server as the higher priority, and
|
||
|
* the other has the client as the higher priority. */
|
||
|
xTaskCreate( prvEchoServer, "1EchoServer", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
|
||
|
xTaskCreate( prvEchoServer, "2EchoServer", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
|
||
|
|
||
|
/* The non blocking tasks run continuously and will interleave with each
|
||
|
* other, so must be created at the lowest priority. The message buffer they
|
||
|
* use is created and passed in using the task's parameter. */
|
||
|
xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
|
||
|
xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
|
||
|
|
||
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||
|
{
|
||
|
/* The sender tasks set up the message buffers before creating the
|
||
|
* receiver tasks. Priorities must be 0 and 1 as the priority is used to
|
||
|
* index into the xStaticMessageBuffers and ucBufferStorage arrays. */
|
||
|
xTaskCreate( prvSenderTask, "1Sender", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
|
||
|
xTaskCreate( prvSenderTask, "2Sender", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
|
||
|
}
|
||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||
|
|
||
|
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||
|
{
|
||
|
xCoherenceTestMessageBuffer = xMessageBufferCreate( mbCOHERENCE_TEST_BUFFER_SIZE );
|
||
|
configASSERT( xCoherenceTestMessageBuffer );
|
||
|
|
||
|
xTaskCreate( prvSpaceAvailableCoherenceActor, "mbsanity1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||
|
xTaskCreate( prvSpaceAvailableCoherenceTester, "mbsanity2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvSingleTaskTests( MessageBufferHandle_t xMessageBuffer )
|
||
|
{
|
||
|
size_t xReturned, xItem, xExpectedSpace, xNextLength;
|
||
|
const size_t xMax6ByteMessages = mbMESSAGE_BUFFER_LENGTH_BYTES / ( 6 + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||
|
const size_t x6ByteLength = 6, x17ByteLength = 17;
|
||
|
uint8_t * pucFullBuffer, * pucData, * pucReadData;
|
||
|
TickType_t xTimeBeforeCall, xTimeAfterCall;
|
||
|
const TickType_t xBlockTime = pdMS_TO_TICKS( 25 ), xAllowableMargin = pdMS_TO_TICKS( 3 );
|
||
|
UBaseType_t uxOriginalPriority;
|
||
|
|
||
|
/* Remove warning in case configASSERT() is not defined. */
|
||
|
( void ) xAllowableMargin;
|
||
|
|
||
|
/* To minimise stack and heap usage a full size buffer is allocated from
|
||
|
* the heap, then buffers which hold smaller amounts of data are overlayed
|
||
|
* with the larger buffer - just make sure not to use both at once!. */
|
||
|
pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
configASSERT( pucFullBuffer );
|
||
|
|
||
|
pucData = pucFullBuffer;
|
||
|
pucReadData = pucData + x17ByteLength;
|
||
|
|
||
|
/* Nothing has been added or removed yet, so expect the free space to be
|
||
|
* exactly as created and the length of the next message to be 0. */
|
||
|
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == 0 );
|
||
|
/* In case configASSERT() is not define. */
|
||
|
( void ) xExpectedSpace;
|
||
|
( void ) xNextLength;
|
||
|
|
||
|
/* Try sending more bytes than possible, first using the FromISR version, then
|
||
|
* with an infinite block time to ensure this task does not lock up. */
|
||
|
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), NULL );
|
||
|
configASSERT( xReturned == ( size_t ) 0 );
|
||
|
/* In case configASSERT() is not defined. */
|
||
|
( void ) xReturned;
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), portMAX_DELAY );
|
||
|
configASSERT( xReturned == ( size_t ) 0 );
|
||
|
/* In case configASSERT() is not defined. */
|
||
|
( void ) xReturned;
|
||
|
|
||
|
/* The buffer is 50 bytes long. When an item is added to the buffer an
|
||
|
* additional 4 bytes are added to hold the item's size. That means adding
|
||
|
* 6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore,
|
||
|
* with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the
|
||
|
* buffer is completely full. NOTE: The numbers in this paragraph assume
|
||
|
* sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) == 4. */
|
||
|
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
|
||
|
{
|
||
|
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );
|
||
|
|
||
|
/* Generate recognizable data to write to the buffer. This is just
|
||
|
* ascii characters that shows which loop iteration the data was written
|
||
|
* in. The 'FromISR' version is used to give it some exercise as a block
|
||
|
* time is not used. That requires the call to be in a critical section
|
||
|
* so this code can also run on FreeRTOS ports that do not support
|
||
|
* interrupt nesting (and so don't have interrupt safe critical
|
||
|
* sections).*/
|
||
|
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
|
||
|
taskENTER_CRITICAL();
|
||
|
{
|
||
|
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, x6ByteLength, NULL );
|
||
|
}
|
||
|
taskEXIT_CRITICAL();
|
||
|
configASSERT( xReturned == x6ByteLength );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* The space in the buffer will have reduced by the amount of user data
|
||
|
* written into the buffer and the amount of space used to store the length
|
||
|
* of the data written into the buffer. */
|
||
|
xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||
|
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xReturned == xExpectedSpace );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Only 6 byte messages are written. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == x6ByteLength );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* Now the buffer should be full, and attempting to add anything will should
|
||
|
* fail. */
|
||
|
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE );
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Adding with a timeout should also fail after the appropriate time. The
|
||
|
* priority is temporarily boosted in this part of the test to keep the
|
||
|
* allowable margin to a minimum. */
|
||
|
uxOriginalPriority = uxTaskPriorityGet( NULL );
|
||
|
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||
|
xTimeBeforeCall = xTaskGetTickCount();
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), xBlockTime );
|
||
|
xTimeAfterCall = xTaskGetTickCount();
|
||
|
vTaskPrioritySet( NULL, uxOriginalPriority );
|
||
|
configASSERT( ( ( TickType_t ) ( xTimeAfterCall - xTimeBeforeCall ) ) >= xBlockTime );
|
||
|
configASSERT( ( ( TickType_t ) ( xTimeAfterCall - xTimeBeforeCall ) ) < ( xBlockTime + xAllowableMargin ) );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
( void ) xTimeBeforeCall;
|
||
|
( void ) xTimeAfterCall;
|
||
|
|
||
|
/* The buffer is now full of data in the form "000000", "111111", etc. Make
|
||
|
* sure the data is read out as expected. */
|
||
|
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
|
||
|
{
|
||
|
/* Generate the data that is expected to be read out for this loop
|
||
|
* iteration. */
|
||
|
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
|
||
|
|
||
|
/* Try reading the message into a buffer that is too small. The message
|
||
|
* should remain in the buffer. */
|
||
|
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Should still be at least one 6 byte message still available. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == x6ByteLength );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Read the next 6 bytes out. The 'FromISR' version is used to give it
|
||
|
* some exercise as a block time is not used. THa requires the code to be
|
||
|
* in a critical section so this test can be run with FreeRTOS ports that
|
||
|
* do not support interrupt nesting (and therefore don't have interrupt
|
||
|
* safe critical sections). */
|
||
|
taskENTER_CRITICAL();
|
||
|
{
|
||
|
xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
|
||
|
}
|
||
|
taskEXIT_CRITICAL();
|
||
|
configASSERT( xReturned == x6ByteLength );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Does the data read out match that expected? */
|
||
|
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
|
||
|
|
||
|
/* The space in the buffer will have increased by the amount of user
|
||
|
* data read from into the buffer and the amount of space used to store the
|
||
|
* length of the data read into the buffer. */
|
||
|
xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||
|
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xReturned == xExpectedSpace );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* The buffer should be empty again. */
|
||
|
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||
|
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
( void ) xExpectedSpace; /* In case configASSERT() is not defined. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == 0 );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
|
||
|
/* Reading with a timeout should also fail after the appropriate time. The
|
||
|
* priority is temporarily boosted in this part of the test to keep the
|
||
|
* allowable margin to a minimum. */
|
||
|
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||
|
xTimeBeforeCall = xTaskGetTickCount();
|
||
|
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );
|
||
|
xTimeAfterCall = xTaskGetTickCount();
|
||
|
vTaskPrioritySet( NULL, uxOriginalPriority );
|
||
|
configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) >= xBlockTime );
|
||
|
configASSERT( ( xTimeAfterCall - xTimeBeforeCall ) < ( xBlockTime + xAllowableMargin ) );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
( void ) xTimeBeforeCall;
|
||
|
( void ) xTimeAfterCall;
|
||
|
|
||
|
|
||
|
/* In the next loop 17 bytes are written to then read out on each iteration.
|
||
|
* The expected length variable is always used after 17 bytes have been written
|
||
|
* into the buffer - the length of the message is also written, making a total
|
||
|
* of 21 bytes consumed for each 17 byte message. */
|
||
|
xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
|
||
|
|
||
|
/* Reading and writing 17 bytes at a time will result in 21 bytes being
|
||
|
* written into the buffer, and as 50 is not divisible by 21, writing multiple
|
||
|
* times will cause the data to wrap in the buffer.*/
|
||
|
for( xItem = 0; xItem < 100; xItem++ )
|
||
|
{
|
||
|
/* Generate recognizable data to write to the queue. This is just
|
||
|
* ascii characters that shows which loop iteration the data was written
|
||
|
* in. */
|
||
|
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == x17ByteLength );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Only 17 byte messages are written. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == x17ByteLength );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* The space in the buffer will have reduced by the amount of user data
|
||
|
* written into the buffer and the amount of space used to store the length
|
||
|
* of the data written into the buffer. */
|
||
|
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xReturned == xExpectedSpace );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Read the 17 bytes out again. */
|
||
|
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x17ByteLength, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == x17ByteLength );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Does the data read out match that expected? */
|
||
|
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );
|
||
|
|
||
|
/* Don't expect any messages to be available as the data was read out
|
||
|
* again. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == 0 );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* The buffer should be empty again. */
|
||
|
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
|
||
|
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
|
||
|
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
|
||
|
/* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test)
|
||
|
* bytes of the full 50 bytes, as that would not leave space for the four bytes
|
||
|
* taken by the data length. */
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
#ifndef configMESSAGE_BUFFER_LENGTH_TYPE
|
||
|
{
|
||
|
/* The following will fail if configMESSAGE_BUFFER_LENGTH_TYPE is set
|
||
|
* to a non 32-bit type. */
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 2, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 3, mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == 0 );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
}
|
||
|
#endif /* ifndef configMESSAGE_BUFFER_LENGTH_TYPE */
|
||
|
|
||
|
/* Don't expect any messages to be available as the above were too large to
|
||
|
* get written. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == 0 );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Can write mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) bytes though. */
|
||
|
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
|
||
|
configASSERT( xNextLength == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );
|
||
|
( void ) xNextLength; /* In case configASSERT() is not defined. */
|
||
|
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucFullBuffer, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ), mbDONT_BLOCK );
|
||
|
configASSERT( xReturned == ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) );
|
||
|
( void ) xReturned; /* In case configASSERT() is not defined. */
|
||
|
configASSERT( memcmp( ( const void * ) pucFullBuffer, pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) == 0 );
|
||
|
|
||
|
/* Clean up. */
|
||
|
vPortFree( pucFullBuffer );
|
||
|
xMessageBufferReset( xMessageBuffer );
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvNonBlockingSenderTask( void * pvParameters )
|
||
|
{
|
||
|
MessageBufferHandle_t xMessageBuffer;
|
||
|
int32_t iDataToSend = 0;
|
||
|
size_t xStringLength;
|
||
|
const int32_t iMaxValue = 1500;
|
||
|
char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||
|
|
||
|
/* In this case the message buffer has already been created and is passed
|
||
|
* into the task using the task's parameter. */
|
||
|
|
||
|
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||
|
|
||
|
/* Create a string from an incrementing number. The length of the
|
||
|
* string will increase and decrease as the value of the number increases
|
||
|
* then overflows. */
|
||
|
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||
|
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||
|
xStringLength = strlen( cTxString );
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Doesn't block so calls can interleave with the non-blocking
|
||
|
* receives performed by prvNonBlockingReceiverTask(). */
|
||
|
if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength )
|
||
|
{
|
||
|
iDataToSend++;
|
||
|
|
||
|
if( iDataToSend > iMaxValue )
|
||
|
{
|
||
|
/* The value sent is reset back to 0 to ensure the string being sent
|
||
|
* does not remain at the same length for too long. */
|
||
|
iDataToSend = 0;
|
||
|
}
|
||
|
|
||
|
/* Create the next string. */
|
||
|
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||
|
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||
|
xStringLength = strlen( cTxString );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvNonBlockingReceiverTask( void * pvParameters )
|
||
|
{
|
||
|
MessageBufferHandle_t xMessageBuffer;
|
||
|
BaseType_t xNonBlockingReceiveError = pdFALSE;
|
||
|
int32_t iDataToSend = 0;
|
||
|
size_t xStringLength, xReceiveLength;
|
||
|
const int32_t iMaxValue = 1500;
|
||
|
char cExpectedString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||
|
char cRxString[ 12 ];
|
||
|
|
||
|
/* In this case the message buffer has already been created and is passed
|
||
|
* into the task using the task's parameter. */
|
||
|
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||
|
|
||
|
/* Create a string from an incrementing number. The length of the
|
||
|
* string will increase and decrease as the value of the number increases
|
||
|
* then overflows. This should always match the string sent to the buffer by
|
||
|
* the non blocking sender task. */
|
||
|
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||
|
memset( cRxString, 0x00, sizeof( cRxString ) );
|
||
|
sprintf( cExpectedString, "%d", ( int ) iDataToSend );
|
||
|
xStringLength = strlen( cExpectedString );
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Doesn't block so calls can interleave with the non-blocking
|
||
|
* receives performed by prvNonBlockingReceiverTask(). */
|
||
|
xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK );
|
||
|
|
||
|
/* Should only ever receive no data is available, or the expected
|
||
|
* length of data is available. */
|
||
|
if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) )
|
||
|
{
|
||
|
xNonBlockingReceiveError = pdTRUE;
|
||
|
}
|
||
|
|
||
|
if( xReceiveLength == xStringLength )
|
||
|
{
|
||
|
/* Ensure the received data was that expected, then generate the
|
||
|
* next expected string. */
|
||
|
if( strcmp( cRxString, cExpectedString ) != 0 )
|
||
|
{
|
||
|
xNonBlockingReceiveError = pdTRUE;
|
||
|
}
|
||
|
|
||
|
iDataToSend++;
|
||
|
|
||
|
if( iDataToSend > iMaxValue )
|
||
|
{
|
||
|
/* The value sent is reset back to 0 to ensure the string being sent
|
||
|
* does not remain at the same length for too long. */
|
||
|
iDataToSend = 0;
|
||
|
}
|
||
|
|
||
|
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||
|
memset( cRxString, 0x00, sizeof( cRxString ) );
|
||
|
sprintf( cExpectedString, "%d", ( int ) iDataToSend );
|
||
|
xStringLength = strlen( cExpectedString );
|
||
|
|
||
|
if( xNonBlockingReceiveError == pdFALSE )
|
||
|
{
|
||
|
/* No errors detected so increment the counter that lets the
|
||
|
* check task know this test is still functioning correctly. */
|
||
|
ulNonBlockingRxCounter++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||
|
|
||
|
static void prvSenderTask( void * pvParameters )
|
||
|
{
|
||
|
MessageBufferHandle_t xMessageBuffer, xTempMessageBuffer;
|
||
|
int32_t iDataToSend = 0;
|
||
|
const int32_t iSendsBetweenIncrements = 100;
|
||
|
char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
|
||
|
const TickType_t xTicksToWait = mbRX_TX_BLOCK_TIME, xShortDelay = pdMS_TO_TICKS( 50 );
|
||
|
StaticMessageBuffer_t xStaticMessageBuffer;
|
||
|
size_t xBytesSent;
|
||
|
|
||
|
|
||
|
/* The task's priority is used as an index into the loop counters used to
|
||
|
* indicate this task is still running. */
|
||
|
UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
|
||
|
|
||
|
/* Make sure a change in priority does not inadvertently result in an
|
||
|
* invalid array index. */
|
||
|
configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS );
|
||
|
|
||
|
/* Avoid compiler warnings about unused parameters. */
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ) / mbNUMBER_OF_SENDER_TASKS, /* The number of bytes in each buffer in the array. */
|
||
|
&( ucBufferStorage[ uxIndex ][ 0 ] ), /* The address of the buffer to use within the array. */
|
||
|
&( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */
|
||
|
|
||
|
/* Now the message buffer has been created the receiver task can be created.
|
||
|
* If this sender task has the higher priority then the receiver task is
|
||
|
* created at the lower priority - if this sender task has the lower priority
|
||
|
* then the receiver task is created at the higher priority. */
|
||
|
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
|
||
|
{
|
||
|
/* Here prvSingleTaskTests() performs various tests on a message buffer
|
||
|
* that was created statically. */
|
||
|
prvSingleTaskTests( xMessageBuffer );
|
||
|
xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbLOWER_PRIORITY, NULL );
|
||
|
}
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Create a string from an incrementing number. The length of the
|
||
|
* string will increase and decrease as the value of the number increases
|
||
|
* then overflows. */
|
||
|
memset( cTxString, 0x00, sizeof( cTxString ) );
|
||
|
sprintf( cTxString, "%d", ( int ) iDataToSend );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), xTicksToWait );
|
||
|
} while( xBytesSent == 0 ); /* Buffer may become full when receiver is running at the idle priority. */
|
||
|
|
||
|
iDataToSend++;
|
||
|
|
||
|
if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )
|
||
|
{
|
||
|
/* Increment a loop counter so a check task can tell this task is
|
||
|
* still running as expected. */
|
||
|
ulSenderLoopCounters[ uxIndex ]++;
|
||
|
|
||
|
if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )
|
||
|
{
|
||
|
/* Allow other tasks to run. */
|
||
|
vTaskDelay( xShortDelay );
|
||
|
}
|
||
|
|
||
|
/* This message buffer is just created and deleted to ensure no
|
||
|
* issues when attempting to delete a message buffer that was
|
||
|
* created using statically allocated memory. To save stack space
|
||
|
* the buffer is set to point to the cTxString array - this is
|
||
|
* ok because nothing is actually written to the memory. */
|
||
|
xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer );
|
||
|
vMessageBufferDelete( xTempMessageBuffer );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||
|
|
||
|
static void prvReceiverTask( void * pvParameters )
|
||
|
{
|
||
|
MessageBufferHandle_t const pxMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
|
||
|
char cExpectedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
|
||
|
char cReceivedString[ 12 ]; /* Large enough to hold a 32-bit number in ASCII. */
|
||
|
int32_t iExpectedData = 0;
|
||
|
const TickType_t xTicksToWait = pdMS_TO_TICKS( 5UL );
|
||
|
size_t xReceivedBytes;
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Generate the next expected string in the cExpectedString buffer. */
|
||
|
memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
|
||
|
sprintf( cExpectedString, "%d", ( int ) iExpectedData );
|
||
|
|
||
|
/* Receive the next string from the message buffer. */
|
||
|
memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );
|
||
|
} while( xReceivedBytes == 0 );
|
||
|
|
||
|
/* Ensure the received string matches the expected string. */
|
||
|
configASSERT( strcmp( cExpectedString, cReceivedString ) == 0 );
|
||
|
|
||
|
iExpectedData++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvEchoClient( void * pvParameters )
|
||
|
{
|
||
|
size_t xSendLength = 0, ux;
|
||
|
char * pcStringToSend, * pcStringReceived, cNextChar = mbASCII_SPACE;
|
||
|
const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );
|
||
|
|
||
|
/* The task's priority is used as an index into the loop counters used to
|
||
|
* indicate this task is still running. */
|
||
|
UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
|
||
|
|
||
|
/* Pointers to the client and server message buffers are passed into this task
|
||
|
* using the task's parameter. */
|
||
|
EchoMessageBuffers_t * pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters;
|
||
|
|
||
|
/* Prevent compiler warnings. */
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
/* Create the buffer into which strings to send to the server will be
|
||
|
* created, and the buffer into which strings echoed back from the server will
|
||
|
* be copied. */
|
||
|
pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
|
||
|
configASSERT( pcStringToSend );
|
||
|
configASSERT( pcStringReceived );
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Generate the length of the next string to send. */
|
||
|
xSendLength++;
|
||
|
|
||
|
/* The message buffer is being used to hold variable length data, so
|
||
|
* each data item requires sizeof( size_t ) bytes to hold the data's
|
||
|
* length, hence the sizeof() in the if() condition below. */
|
||
|
if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )
|
||
|
{
|
||
|
/* Back to a string length of 1. */
|
||
|
xSendLength = sizeof( char );
|
||
|
|
||
|
/* Maintain a count of the number of times this code executes so a
|
||
|
* check task can determine if this task is still functioning as
|
||
|
* expected or not. As there are two client tasks, and the priorities
|
||
|
* used are 0 and 1, the task's priority is used as an index into the
|
||
|
* loop count array. */
|
||
|
ulEchoLoopCounters[ uxIndex ]++;
|
||
|
}
|
||
|
|
||
|
memset( pcStringToSend, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
|
||
|
for( ux = 0; ux < xSendLength; ux++ )
|
||
|
{
|
||
|
pcStringToSend[ ux ] = cNextChar;
|
||
|
|
||
|
cNextChar++;
|
||
|
|
||
|
if( cNextChar > mbASCII_TILDA )
|
||
|
{
|
||
|
cNextChar = mbASCII_SPACE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Send the generated string to the buffer. */
|
||
|
do
|
||
|
{
|
||
|
ux = xMessageBufferSend( pxMessageBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );
|
||
|
|
||
|
if( ux == 0 )
|
||
|
{
|
||
|
mtCOVERAGE_TEST_MARKER();
|
||
|
}
|
||
|
} while( ux == 0 );
|
||
|
|
||
|
/* Wait for the string to be echoed back. */
|
||
|
memset( pcStringReceived, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
xMessageBufferReceive( pxMessageBuffers->xEchoServerBuffer, ( void * ) pcStringReceived, xSendLength, portMAX_DELAY );
|
||
|
|
||
|
configASSERT( strcmp( pcStringToSend, pcStringReceived ) == 0 );
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvEchoServer( void * pvParameters )
|
||
|
{
|
||
|
MessageBufferHandle_t xTempMessageBuffer;
|
||
|
size_t xReceivedLength;
|
||
|
char * pcReceivedString;
|
||
|
EchoMessageBuffers_t xMessageBuffers;
|
||
|
TickType_t xTimeOnEntering;
|
||
|
const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
|
||
|
|
||
|
/* Prevent compiler warnings about unused parameters. */
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
/* Create the message buffer used to send data from the client to the server,
|
||
|
* and the message buffer used to echo the data from the server back to the
|
||
|
* client. */
|
||
|
xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
configASSERT( xMessageBuffers.xEchoClientBuffer );
|
||
|
configASSERT( xMessageBuffers.xEchoServerBuffer );
|
||
|
|
||
|
/* Create the buffer into which received strings will be copied. */
|
||
|
pcReceivedString = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
configASSERT( pcReceivedString );
|
||
|
|
||
|
/* Don't expect to receive anything yet! */
|
||
|
xTimeOnEntering = xTaskGetTickCount();
|
||
|
xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, xTicksToBlock );
|
||
|
configASSERT( ( ( TickType_t ) ( xTaskGetTickCount() - xTimeOnEntering ) ) >= xTicksToBlock );
|
||
|
configASSERT( xReceivedLength == 0 );
|
||
|
( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */
|
||
|
|
||
|
/* Now the message buffers have been created the echo client task can be
|
||
|
* created. If this server task has the higher priority then the client task
|
||
|
* is created at the lower priority - if this server task has the lower
|
||
|
* priority then the client task is created at the higher priority. */
|
||
|
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
|
||
|
{
|
||
|
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Here prvSingleTaskTests() performs various tests on a message buffer
|
||
|
* that was created dynamically. */
|
||
|
prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer );
|
||
|
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL );
|
||
|
}
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
memset( pcReceivedString, 0x00, mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
|
||
|
/* Has any data been sent by the client? */
|
||
|
xReceivedLength = xMessageBufferReceive( xMessageBuffers.xEchoClientBuffer, ( void * ) pcReceivedString, mbMESSAGE_BUFFER_LENGTH_BYTES, portMAX_DELAY );
|
||
|
|
||
|
/* Should always receive data as max delay was used. */
|
||
|
configASSERT( xReceivedLength > 0 );
|
||
|
|
||
|
/* Echo the received data back to the client. */
|
||
|
xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );
|
||
|
|
||
|
/* This message buffer is just created and deleted to ensure no memory
|
||
|
* leaks. */
|
||
|
xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
|
||
|
vMessageBufferDelete( xTempMessageBuffer );
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/* Tests within configRUN_ADDITIONAL_TESTS blocks only execute on larger
|
||
|
* platforms or have been added to pre-existing files that are already in use
|
||
|
* by other test projects without ensuring they don't cause those pre-existing
|
||
|
* projects to run out of program or data memory. */
|
||
|
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||
|
|
||
|
static void prvSpaceAvailableCoherenceActor( void * pvParameters )
|
||
|
{
|
||
|
static char * cTxString = "12345";
|
||
|
char cRxString[ mbCOHERENCE_TEST_BYTES_WRITTEN + 1 ]; /* +1 for NULL terminator. */
|
||
|
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* Add bytes to the buffer so the other task should see
|
||
|
* mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING bytes free. */
|
||
|
xMessageBufferSend( xCoherenceTestMessageBuffer, ( void * ) cTxString, strlen( cTxString ), 0 );
|
||
|
configASSERT( xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer ) == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING );
|
||
|
|
||
|
/* Read out message again so the other task should read the full
|
||
|
* mbCOHERENCE_TEST_BUFFER_SIZE bytes free again. */
|
||
|
memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) );
|
||
|
xMessageBufferReceive( xCoherenceTestMessageBuffer, ( void * ) cRxString, mbCOHERENCE_TEST_BYTES_WRITTEN, 0 );
|
||
|
configASSERT( strcmp( cTxString, cRxString ) == 0 );
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvSpaceAvailableCoherenceTester( void * pvParameters )
|
||
|
{
|
||
|
size_t xSpaceAvailable;
|
||
|
BaseType_t xErrorFound = pdFALSE;
|
||
|
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
for( ; ; )
|
||
|
{
|
||
|
/* This message buffer is only ever empty or contains 5 bytes. So all
|
||
|
* queries of its free space should result in one of the two values tested
|
||
|
* below. */
|
||
|
xSpaceAvailable = xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer );
|
||
|
|
||
|
if( ( xSpaceAvailable == mbCOHERENCE_TEST_BUFFER_SIZE ) ||
|
||
|
( xSpaceAvailable == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ) )
|
||
|
{
|
||
|
/* Only continue to increment the variable that shows this task
|
||
|
* is still executing if no errors have been found. */
|
||
|
if( xErrorFound == pdFALSE )
|
||
|
{
|
||
|
ulSizeCoherencyTestCycles++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xErrorFound = pdTRUE;
|
||
|
}
|
||
|
|
||
|
configASSERT( xErrorFound == pdFALSE );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* configRUN_ADDITIONAL_TESTS == 1 */
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
BaseType_t xAreMessageBufferTasksStillRunning( void )
|
||
|
{
|
||
|
static uint32_t ulLastEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||
|
static uint32_t ulLastNonBlockingRxCounter = 0;
|
||
|
BaseType_t xReturn = pdPASS, x;
|
||
|
|
||
|
for( x = 0; x < mbNUMBER_OF_ECHO_CLIENTS; x++ )
|
||
|
{
|
||
|
if( ulLastEchoLoopCounters[ x ] == ulEchoLoopCounters[ x ] )
|
||
|
{
|
||
|
xReturn = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulLastEchoLoopCounters[ x ] = ulEchoLoopCounters[ x ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( ulNonBlockingRxCounter == ulLastNonBlockingRxCounter )
|
||
|
{
|
||
|
xReturn = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulLastNonBlockingRxCounter = ulNonBlockingRxCounter;
|
||
|
}
|
||
|
|
||
|
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||
|
{
|
||
|
static uint32_t ulLastSenderLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
|
||
|
|
||
|
for( x = 0; x < mbNUMBER_OF_SENDER_TASKS; x++ )
|
||
|
{
|
||
|
if( ulLastSenderLoopCounters[ x ] == ulSenderLoopCounters[ x ] )
|
||
|
{
|
||
|
xReturn = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulLastSenderLoopCounters[ x ] = ulSenderLoopCounters[ x ];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||
|
|
||
|
#if ( configRUN_ADDITIONAL_TESTS == 1 )
|
||
|
{
|
||
|
static uint32_t ullastSizeCoherencyTestCycles = 0UL;
|
||
|
|
||
|
if( ullastSizeCoherencyTestCycles == ulSizeCoherencyTestCycles )
|
||
|
{
|
||
|
xReturn = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ullastSizeCoherencyTestCycles = ulSizeCoherencyTestCycles;
|
||
|
}
|
||
|
}
|
||
|
#endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
|
||
|
|
||
|
return xReturn;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|