/* | |
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. | |
All rights reserved | |
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
This file is part of the FreeRTOS distribution. | |
FreeRTOS is free software; you can redistribute it and/or modify it under | |
the terms of the GNU General Public License (version 2) as published by the | |
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. | |
*************************************************************************** | |
>>! NOTE: The modification to the GPL is included to allow you to !<< | |
>>! distribute a combined work that includes FreeRTOS without being !<< | |
>>! obliged to provide the source code for proprietary components !<< | |
>>! outside of the FreeRTOS kernel. !<< | |
*************************************************************************** | |
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY | |
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
FOR A PARTICULAR PURPOSE. Full license text is available on the following | |
link: http://www.freertos.org/a00114.html | |
*************************************************************************** | |
* * | |
* FreeRTOS provides completely free yet professionally developed, * | |
* robust, strictly quality controlled, supported, and cross * | |
* platform software that is more than just the market leader, it * | |
* is the industry's de facto standard. * | |
* * | |
* Help yourself get started quickly while simultaneously helping * | |
* to support the FreeRTOS project by purchasing a FreeRTOS * | |
* tutorial book, reference manual, or both: * | |
* http://www.FreeRTOS.org/Documentation * | |
* * | |
*************************************************************************** | |
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading | |
the FAQ page "My application does not run, what could be wrong?". Have you | |
defined configASSERT()? | |
http://www.FreeRTOS.org/support - In return for receiving this top quality | |
embedded software for free we request you assist our global community by | |
participating in the support forum. | |
http://www.FreeRTOS.org/training - Investing in training allows your team to | |
be as productive as possible as early as possible. Now you can receive | |
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers | |
Ltd, and the world's leading authority on the world's leading RTOS. | |
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
including FreeRTOS+Trace - an indispensable productivity tool, a DOS | |
compatible FAT file system, and our tiny thread aware UDP/IP stack. | |
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. | |
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. | |
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High | |
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS | |
licenses offer ticketed support, indemnification and commercial middleware. | |
http://www.SafeRTOS.com - High Integrity Systems also provide a safety | |
engineered and independently SIL3 certified version for use in safety and | |
mission critical applications that require provable dependability. | |
1 tab == 4 spaces! | |
*/ | |
/* | |
* A number of sockets are created and added to a set. One task then blocks on | |
* the set while the other task sends data to a (pseudo) random member of the | |
* set. The value sent increments from 0 to selMAX_TX_VALUE, and when all the | |
* values have been sent a check is made that each expected value has indeed | |
* been received before the cycle re-starts. | |
* | |
* See the following web page for essential demo usage and configuration | |
* details: | |
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html | |
*/ | |
/* Standard includes. */ | |
#include <stdint.h> | |
#include <stdio.h> | |
/* FreeRTOS includes. */ | |
#include "FreeRTOS.h" | |
#include "task.h" | |
#include "semphr.h" | |
/* FreeRTOS+TCP includes. */ | |
#include "FreeRTOS_IP.h" | |
#include "FreeRTOS_Sockets.h" | |
/* Demo project includes. */ | |
#include "UDPSelectServer.h" | |
/* Exclude the whole file if select() is not being supported. */ | |
#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) | |
/* The numbers of sockets added to the set. */ | |
#define selNUMBER_OF_SOCKETS ( 3 ) | |
/* Each cycle of the demo sends the value 0 to selMAX_TX_VALUE to a socket in | |
the set. */ | |
#define selMAX_TX_VALUE ( 100 ) | |
/*-----------------------------------------------------------*/ | |
/* | |
* The Tx task that sends the data to the sockets created by the Rx task and | |
* added to the select set. | |
*/ | |
static void prvMultipleSocketTxTask( void *pvParameters ); | |
/* | |
* Uses the FreeRTOS_select() API function to receive from multiple sockets. | |
* This task expects to receive every value from 0 to selMAX_TX_VALUE during | |
* each cycle of the demo. An array with an index for each value it expects to | |
* receive is used to record which values were and were not received. | |
*/ | |
static void prvMultipleSocketRxTask( void *pvParameters ); | |
/*-----------------------------------------------------------*/ | |
/* The sockets used in FreeRTOS_select(). */ | |
static Socket_t xRxSockets[ selNUMBER_OF_SOCKETS ] = { 0 }; | |
/* Used to monitor the status of the task. */ | |
static volatile uint32_t ulTxCycles = 0, ulRxCycles = 0, ulFailedRxCycles = 0, ulErrorOccurred = pdFALSE; | |
/* The block time used by the Tx task when sending - other delays are derived | |
from this value. */ | |
const TickType_t xSendBlockTime = pdMS_TO_TICKS( 400 ); | |
const TickType_t xReceiveBlockTime = pdMS_TO_TICKS( 600 ); | |
/* The Tx task needs to know the handle of the Rx task. */ | |
static TaskHandle_t xRxTaskHandle; | |
/*-----------------------------------------------------------*/ | |
void vStartUDPSelectServerTasks( uint16_t usStackSize, uint32_t ulFirstPortNumber, UBaseType_t uxPriority ) | |
{ | |
/* Create a task that sends to multiple sockets, and the task that uses the | |
FreeRTOS_select() function to receive from multiple sockets. The first port | |
number to use is passed into both tasks using the task's parameter. Other | |
port numbers are consecutive from the first. */ | |
xTaskCreate( prvMultipleSocketTxTask, "MultiTx", usStackSize, ( void * ) ulFirstPortNumber, uxPriority, NULL ); | |
xTaskCreate( prvMultipleSocketRxTask, "MultiRx", usStackSize, ( void * ) ulFirstPortNumber, uxPriority, &xRxTaskHandle ); | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvMultipleSocketRxTask( void *pvParameters ) | |
{ | |
SocketSet_t xFD_Set; | |
Socket_t xSocket; | |
struct freertos_sockaddr xAddress; | |
uint32_t xClientLength = sizeof( struct freertos_sockaddr ), ulFirstRxPortNumber, x; | |
uint32_t ulReceivedValue = 0, ulCount; | |
uint8_t ucReceivedValues[ selMAX_TX_VALUE ]; /* If the array position is pdTRUE then the corresponding value has been received. */ | |
int32_t lBytes; | |
const TickType_t xRxBlockTime = 0; | |
BaseType_t xResult; | |
/* The number of the port the first Rx socket will be bound to is passed in | |
as the task parameter. Other port numbers used are consecutive from this. */ | |
ulFirstRxPortNumber = ( uint32_t ) pvParameters; | |
/* Create the set for sockets that will be passed into FreeRTOS_select(). */ | |
xFD_Set = FreeRTOS_CreateSocketSet(); | |
/* Create the sockets and add them to the set. */ | |
for( x = 0; x < selNUMBER_OF_SOCKETS; x++ ) | |
{ | |
/* Create the next Rx socket. */ | |
xRxSockets[ x ] = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); | |
configASSERT( xRxSockets[ x ] != FREERTOS_INVALID_SOCKET ); | |
/* Bind to the next port number. */ | |
xAddress.sin_port = FreeRTOS_htons( ( uint16_t ) ( ulFirstRxPortNumber + x ) ); | |
FreeRTOS_bind( xRxSockets[ x ], &xAddress, sizeof( struct freertos_sockaddr ) ); | |
/* There should always be data available after FreeRTOS_select() so | |
blocking on a read should not be necessary. */ | |
FreeRTOS_setsockopt( xRxSockets[ x ], 0, FREERTOS_SO_RCVTIMEO, &xRxBlockTime, sizeof( xRxBlockTime ) ); | |
/* Add the created socket to the set. */ | |
FreeRTOS_FD_SET( xRxSockets[ x ], xFD_Set, eSELECT_ALL ); | |
} | |
for( ;; ) | |
{ | |
/* No values have yet been received so set each array position to | |
pdFALSE. Each expected Rx value has a corresponding array position. */ | |
memset( ( void * ) ucReceivedValues, pdFALSE, sizeof( ucReceivedValues ) ); | |
/* Wait for the other task to resume this task - indicating that it is | |
about to start sending. */ | |
vTaskSuspend( NULL ); | |
/* Expect to receive selMAX_TX_VALUE values. */ | |
ulCount = 0; | |
while( ulCount < selMAX_TX_VALUE ) | |
{ | |
/* Wait for a socket from the set to become available for | |
reading. */ | |
xResult = FreeRTOS_select( xFD_Set, xReceiveBlockTime ); | |
if( xResult != 0 ) | |
{ | |
/* See which sockets have data waiting to be read. */ | |
for( x = 0; x < selNUMBER_OF_SOCKETS; x++ ) | |
{ | |
xSocket = xRxSockets[ x ]; | |
/* Find the expected value for this socket */ | |
if( FreeRTOS_FD_ISSET( xSocket, xFD_Set ) != 0 ) | |
{ | |
while( ( lBytes = FreeRTOS_recvfrom( xSocket, &( ulReceivedValue ), sizeof( uint32_t ), 0, &xAddress, &xClientLength ) ) > 0 ) | |
{ | |
/* Received another message. */ | |
ulCount++; | |
/* It is always expected that the read will pass. */ | |
configASSERT( ( size_t ) lBytes == ( sizeof( uint32_t ) ) ); | |
/* Don't expect to receive anything greater than | |
selMAX_TX_VALUE - 1. */ | |
configASSERT( ulReceivedValue < selMAX_TX_VALUE ); | |
/* Don't expect to receive any value twice. */ | |
configASSERT( ucReceivedValues[ ulReceivedValue ] != pdTRUE ); | |
if( ucReceivedValues[ ulReceivedValue ] != pdTRUE ) | |
{ | |
/* Mark the value as received by setting its | |
index in the received array to pdTRUE. */ | |
ucReceivedValues[ ulReceivedValue ] = pdTRUE; | |
} | |
else | |
{ | |
ulErrorOccurred = pdTRUE; | |
} | |
} | |
} | |
} | |
} | |
else | |
{ | |
/* No value was received in time. */ | |
break; | |
} | |
} | |
/* Were all values received? */ | |
if( ulCount == selMAX_TX_VALUE ) | |
{ | |
/* Check all selMAX_TX_VALUE values are present and correct | |
before starting a new cycle. It is valid for a few values at | |
the beginning of the array to be missing as they may have been | |
dropped for ARP messages, so start a few indexes in. */ | |
for( ulCount = 4; ulCount < selMAX_TX_VALUE; ulCount++ ) | |
{ | |
configASSERT( ucReceivedValues[ ulCount ] == pdTRUE ); | |
if( ucReceivedValues[ ulCount ] != pdTRUE ) | |
{ | |
/* The value corresponding to this array position was | |
never received. In a real application UDP is not | |
reliable, but in this tightly controlled test it is | |
unusual for a packet to be dropped. */ | |
ulErrorOccurred = pdTRUE; | |
} | |
} | |
ulRxCycles++; | |
} | |
else | |
{ | |
/* Just for viewing in the debugger. */ | |
ulFailedRxCycles++; | |
} | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvMultipleSocketTxTask( void *pvParameters ) | |
{ | |
uint32_t ulTxValue = 0; | |
struct freertos_sockaddr xDestinationAddress; | |
uint32_t ulIPAddress, ulFirstDestinationPortNumber, xPortNumber; | |
Socket_t xTxSocket; | |
uint32_t ulSendCount[ selNUMBER_OF_SOCKETS ]; | |
memset( ulSendCount, '\0', sizeof( ulSendCount ) ); | |
/* The first destination port number is passed in as the task parameter. | |
Other destination port numbers used are consecutive from this. */ | |
ulFirstDestinationPortNumber = ( uint32_t ) pvParameters; | |
/* Create the socket used to send to the sockets created by the Rx task. | |
Let the IP stack select a port to bind to. */ | |
xTxSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); | |
FreeRTOS_bind( xTxSocket, NULL, sizeof( struct freertos_sockaddr ) ); | |
/* The Rx and Tx tasks execute at the same priority so it is possible that | |
the Tx task will fill up the send queue - set a Tx block time to ensure | |
flow control is managed if this happens. */ | |
FreeRTOS_setsockopt( xTxSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendBlockTime, sizeof( xSendBlockTime ) ); | |
/* It is assumed that this task is not created until the network is up, | |
so the IP address can be obtained immediately. Store the IP address being | |
used in ulIPAddress. This is done so the socket can send to a different | |
port on the same IP address. */ | |
FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); | |
/* This test sends to itself, so data sent from here is received by a server | |
socket on the same IP address. Setup the freertos_sockaddr structure with | |
this nodes IP address. */ | |
xDestinationAddress.sin_addr = ulIPAddress; | |
/* Block for a short time to ensure the task implemented by the | |
prvMultipleSocketRxTask() function has finished creating the Rx sockets. */ | |
while( eTaskGetState( xRxTaskHandle ) != eSuspended ) | |
{ | |
vTaskDelay( xSendBlockTime ); | |
} | |
vTaskResume( xRxTaskHandle ); | |
for( ;; ) | |
{ | |
/* Pseudo randomly select the destination port number from the range of | |
valid destination port numbers. */ | |
xPortNumber = ipconfigRAND32() % selNUMBER_OF_SOCKETS; | |
ulSendCount[ xPortNumber ]++; | |
xDestinationAddress.sin_port = ( uint16_t ) ( ulFirstDestinationPortNumber + xPortNumber ); | |
xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port ); | |
/* Send an incrementing value to the pseudo randomly selected port. */ | |
FreeRTOS_sendto( xTxSocket, &ulTxValue, sizeof( ulTxValue ), 0, &xDestinationAddress, sizeof( xDestinationAddress ) ); | |
ulTxValue++; | |
if( ulTxValue >= selMAX_TX_VALUE ) | |
{ | |
/* Start over. */ | |
ulTxValue = 0; | |
/* As a sanity check that this demo is valid, ensure each socket has | |
been used at least once. */ | |
for( xPortNumber = 0; xPortNumber < selNUMBER_OF_SOCKETS; xPortNumber++ ) | |
{ | |
if( ulSendCount[ xPortNumber ] == 0 ) | |
{ | |
ulErrorOccurred = pdTRUE; | |
} | |
ulSendCount[ xPortNumber ] = 0; | |
} | |
/* Allow the Rx task to check it has received all the values. */ | |
while( eTaskGetState( xRxTaskHandle ) != eSuspended ) | |
{ | |
vTaskDelay( xSendBlockTime ); | |
} | |
vTaskResume( xRxTaskHandle ); | |
/* Increment to show this task is still executing. */ | |
ulTxCycles++; | |
} | |
/* Delay here because in the Windows simulator the MAC interrupt | |
simulator delays, so network traffic cannot be received any faster than | |
this. */ | |
vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY << 2 ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
BaseType_t xAreUDPSelectTasksStillRunning( void ) | |
{ | |
static uint32_t ulLastRxCycles = 0, ulLastTxCycles = 0; | |
BaseType_t ulError; | |
ulError = ulErrorOccurred; | |
if( ulRxCycles == ulLastRxCycles ) | |
{ | |
ulError |= pdTRUE; | |
} | |
if( ulTxCycles == ulLastTxCycles ) | |
{ | |
ulError |= pdTRUE; | |
} | |
ulLastRxCycles = ulRxCycles; | |
ulLastTxCycles = ulTxCycles; | |
return !ulError; | |
} | |
/* The whole file is excluded if select() is not being supported. */ | |
#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ | |