diff options
Diffstat (limited to 'FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/TCPEchoClient_SingleTasks.c')
-rw-r--r-- | FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/TCPEchoClient_SingleTasks.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/TCPEchoClient_SingleTasks.c b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/TCPEchoClient_SingleTasks.c new file mode 100644 index 000000000..b8517e054 --- /dev/null +++ b/FreeRTOS-Plus/Demo/FreeRTOS_Plus_TCP_Echo_Qemu_mps2/TCPEchoClient_SingleTasks.c @@ -0,0 +1,376 @@ +/* + * FreeRTOS V202011.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 + * + */ + +/* + * A set of tasks are created that send TCP echo requests to the standard echo + * port (port 7) on the IP address set by the configECHO_SERVER_ADDR0 to + * configECHO_SERVER_ADDR3 constants, then wait for and verify the reply + * (another demo is avilable that demonstrates the reception being performed in + * a task other than that from with the request was made). + * + * 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> +#include <stdlib.h> + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */ +#if ( ipconfigUSE_TCP == 1 ) + +/* The echo tasks create a socket, send out a number of echo requests, listen +for the echo reply, then close the socket again before starting over. This +delay is used between each iteration to ensure the network does not get too +congested. */ + #define echoLOOP_DELAY ( ( TickType_t ) 150 / portTICK_PERIOD_MS ) + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ + #define echoECHO_PORT ( 7 ) + +/* The size of the buffers is a multiple of the MSS - the length of the data +sent is a pseudo random size between 20 and echoBUFFER_SIZES. */ + #define echoBUFFER_SIZE_MULTIPLIER ( 1 ) + #define echoBUFFER_SIZES ( ipconfigTCP_MSS * echoBUFFER_SIZE_MULTIPLIER ) + +/* The number of instances of the echo client task to create. */ + #define echoNUM_ECHO_CLIENTS ( 1 ) + +/*-----------------------------------------------------------*/ + +/* + * Uses a socket to send data to, then receive data from, the standard echo + * port number 7. + */ + static void prvEchoClientTask( void *pvParameters ); + +/* + * Creates a pseudo random sized buffer of data to send to the echo server. + */ + static BaseType_t prvCreateTxData( char *ucBuffer, + uint32_t ulBufferLength ); + +/*-----------------------------------------------------------*/ + +/* Rx and Tx time outs are used to ensure the sockets do not wait too long for +missing data. */ + static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 4000 ); + static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 ); + +/* Counters for each created task - for inspection only. */ + static uint32_t ulTxRxCycles[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulTxRxFailures[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; + +/* Rx and Tx buffers for each created task. */ + static char cTxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ], + cRxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ]; + +/*-----------------------------------------------------------*/ + + void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, + UBaseType_t uxTaskPriority ) + { + BaseType_t x; + + /* Create the echo client tasks. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + xTaskCreate( prvEchoClientTask, /* The function that implements the task. */ + "Echo0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + ( void * ) x, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + } + } +/*-----------------------------------------------------------*/ + + static void prvEchoClientTask( void *pvParameters ) + { + Socket_t xSocket; + struct freertos_sockaddr xEchoServerAddress; + int32_t lLoopCount = 0UL; + const int32_t lMaxLoopCount = 1; + volatile uint32_t ulTxCount = 0UL; + BaseType_t xReceivedBytes, xReturned, xInstance; + BaseType_t lTransmitted, lStringLength; + char *pcTransmittedString, *pcReceivedString; + WinProperties_t xWinProps; + TickType_t xTimeOnEntering; + BaseType_t ret; + + /* Fill in the buffer and window sizes that will be used by the socket. */ + xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lTxWinSize = 3; + xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lRxWinSize = 3; + + /* This task can be created a number of times. Each instance is numbered + to enable each instance to use a different Rx and Tx buffer. The number is + passed in as the task's parameter. */ + xInstance = ( BaseType_t ) pvParameters; + + /* Point to the buffers to be used by this instance of this task. */ + pcTransmittedString = &( cTxBuffers[ xInstance ][ 0 ] ); + pcReceivedString = &( cRxBuffers[ xInstance ][ 0 ] ); + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ; ; ) + { + /* Create a TCP socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + + /* Connect to the echo server. */ + printf( "connecting to echo server....\n" ); + + ret = FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ); + + if( ret == 0 ) + { + printf( "Connected to server.. \n" ); + ulConnections[ xInstance ]++; + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* Create the string that is sent to the echo server. */ + lStringLength = prvCreateTxData( pcTransmittedString, echoBUFFER_SIZES ); + + /* Add in some unique text at the front of the string. */ + sprintf( pcTransmittedString, "TxRx message number %u", ulTxCount ); + ulTxCount++; + + printf( "sending data to the echo server size %d original %d\n", + lStringLength, + echoBUFFER_SIZES); + /* Send the string to the socket. */ + lTransmitted = FreeRTOS_send( xSocket, /* The socket being sent to. */ + ( void * ) pcTransmittedString, /* The data being sent. */ + lStringLength, /* The length of the data being sent. */ + 0 ); /* No flags. */ + printf("FreeRTOS_send returned...transmitted %d\n", + lTransmitted); + + if( lTransmitted < 0 ) + { + /* Error? */ + break; + } + printf("data send receiving data... \n"); + + /* Clear the buffer into which the echoed string will be + placed. */ + memset( ( void * ) pcReceivedString, 0x00, echoBUFFER_SIZES ); + xReceivedBytes = 0; + + /* Receive data echoed back to the socket. */ + while( xReceivedBytes < lTransmitted ) + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ xReceivedBytes ] ), /* The buffer into which the received data will be written. */ + lStringLength - xReceivedBytes, /* The size of the buffer provided to receive the data. */ + 0 ); /* No flags. */ + + if( xReturned < 0 ) + { + /* Error occurred. Latch it so it can be detected + below. */ + xReceivedBytes = xReturned; + break; + } + else if( xReturned == 0 ) + { + /* Timed out. */ + break; + } + else + { + /* Keep a count of the bytes received so far. */ + xReceivedBytes += xReturned; + } + } + + /* If an error occurred it will be latched in xReceivedBytes, + otherwise xReceived bytes will be just that - the number of + bytes received from the echo server. */ + if( xReceivedBytes > 0 ) + { + /* Compare the transmitted string to the received string. */ + configASSERT( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ); + + if( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ) + { + /* The echo reply was received without error. */ + ulTxRxCycles[ xInstance ]++; + } + else + { + /* The received string did not match the transmitted + string. */ + ulTxRxFailures[ xInstance ]++; + break; + } + } + else if( xReceivedBytes < 0 ) + { + /* FreeRTOS_recv() returned an error. */ + break; + } + else + { + /* Timed out without receiving anything? */ + break; + } + } + + /* Finished using the connected socket, initiate a graceful close: + FIN, FIN+ACK, ACK. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Expect FreeRTOS_recv() to return an error once the shutdown is + complete. */ + xTimeOnEntering = xTaskGetTickCount(); + + do + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ 0 ] ), /* The buffer into which the received data will be written. */ + echoBUFFER_SIZES, /* The size of the buffer provided to receive the data. */ + 0 ); + + if( xReturned < 0 ) + { + break; + } + } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut ); + } + else + { + printf( "Could not connect to server %ld\n", ret ); + } + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + } + } +/*-----------------------------------------------------------*/ + + static BaseType_t prvCreateTxData( char *cBuffer, + uint32_t ulBufferLength ) + { + BaseType_t lCharactersToAdd, lCharacter; + char cChar = '0'; + const BaseType_t lMinimumLength = 60; + + /* Randomise the number of characters that will be sent in the echo + request. */ + do + { + lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL ); + } while( ( lCharactersToAdd == 0 ) || ( lCharactersToAdd < lMinimumLength ) ); /* Must be at least enough to add the unique text to the start of the string later. */ + + /* Fill the buffer. */ + for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ ) + { + cBuffer[ lCharacter ] = cChar; + cChar++; + + if( cChar > '~' ) + { + cChar = '0'; + } + } + + return lCharactersToAdd; + } +/*-----------------------------------------------------------*/ + + BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void ) + { + static uint32_t ulLastEchoSocketCount[ echoNUM_ECHO_CLIENTS ] = { 0 }, ulLastConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; + BaseType_t xReturn = pdPASS, x; + + /* Return fail is the number of cycles does not increment between + consecutive calls. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + if( ulTxRxCycles[ x ] == ulLastEchoSocketCount[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulLastEchoSocketCount[ x ] = ulTxRxCycles[ x ]; + } + + if( ulConnections[ x ] == ulLastConnections[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulConnections[ x ] = ulLastConnections[ x ]; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ |