/* * 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 * */ /* * This project is a cut down version of the project described on the following * link. Only the simple UDP client and server and the TCP echo clients are * included in the build: * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html */ /* Standard includes. */ #include #include /* FreeRTOS includes. */ #include #include "task.h" #include "FreeRTOSIPConfig.h" /* Demo application includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "SimpleUDPClientAndServer.h" #include "SimpleTCPEchoServer.h" #include "TCPEchoClient_SingleTasks.h" #include "logging.h" /* Simple UDP client and server task parameters. */ #define mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define mainSIMPLE_UDP_CLIENT_SERVER_PORT ( 5005UL ) /* Echo client task parameters - used for both TCP and UDP echo clients. */ #define mainECHO_CLIENT_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) /* Not used in the Windows port. */ #define mainECHO_CLIENT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) /* Echo server task parameters. */ #define mainECHO_SERVER_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) /* Not used in the Windows port. */ #define mainECHO_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) /* Define a name that will be used for LLMNR and NBNS searches. */ #define mainHOST_NAME "RTOSDemo" #define mainDEVICE_NICK_NAME "windows_demo" /* Set the following constants to 1 or 0 to define which tasks to include and * exclude: * * mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS: When set to 1 two UDP client tasks * and two UDP server tasks are created. The clients talk to the servers. One set * of tasks use the standard sockets interface, and the other the zero copy sockets * interface. These tasks are self checking and will trigger a configASSERT() if * they detect a difference in the data that is received from that which was sent. * As these tasks use UDP, and can therefore loose packets, they will cause * configASSERT() to be called when they are run in a less than perfect networking * environment. * * mainCREATE_TCP_ECHO_TASKS_SINGLE: When set to 1 a set of tasks are created that * send TCP echo requests to the standard echo port (port 7), then wait for and * verify the echo reply, from within the same task (Tx and Rx are performed in the * same RTOS task). The IP address of the echo server must be configured using the * configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants in * FreeRTOSConfig.h. * * mainCREATE_TCP_ECHO_SERVER_TASK: When set to 1 a task is created that accepts * connections on the standard echo port (port 7), then echos back any data * received on that connection. */ #define mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS 1 #define mainCREATE_TCP_ECHO_TASKS_SINGLE 0 #define mainCREATE_TCP_ECHO_SERVER_TASK 0 /*-----------------------------------------------------------*/ /* * Just seeds the simple pseudo random number generator. */ static void prvSRand( UBaseType_t ulSeed ); /* * Miscellaneous initialisation including preparing the logging and seeding the * random number generator. */ static void prvMiscInitialisation( void ); /* The default IP and MAC address used by the demo. The address configuration * defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is * 1 but a DHCP server could not be contacted. See the online documentation for * more information. */ static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; /* Set the following constant to pdTRUE to log using the method indicated by the * name of the constant, or pdFALSE to not log using the method indicated by the * name of the constant. Options include to standard out (xLogToStdout) and to a * file on disk (xLogToFile). */ const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE; /* Default MAC address configuration. The demo creates a virtual network * connection that uses this MAC address by accessing the raw Ethernet data * to and from a real network connection on the host PC. See the * configNETWORK_INTERFACE_TO_USE definition for information on how to configure * the real network connection to use. */ const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; /* Use by the pseudo random number generator. */ static UBaseType_t ulNextRand; /*-----------------------------------------------------------*/ #if defined( FREERTOS_PLUS_TCP_VERSION ) && ( FREERTOS_PLUS_TCP_VERSION >= 10 ) /* In case multiple interfaces are used, define them statically. */ /* With WinPCap there is only 1 physical interface. */ static NetworkInterface_t xInterfaces[ 1 ]; /* It will have several end-points. */ static NetworkEndPoint_t xEndPoints[ 4 ]; #endif /* if defined( FREERTOS_PLUS_TCP_VERSION ) && ( FREERTOS_PLUS_TCP_VERSION >= 10 ) */ /*-----------------------------------------------------------*/ int main( void ) { const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL ); /* * Instructions for using this project are provided on: * https://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html */ /* Miscellaneous initialisation including preparing the logging and seeding * the random number generator. */ prvMiscInitialisation(); /* Initialise the network interface. * ***NOTE*** Tasks that use the network are created in the network event hook * when the network is connected and ready for use (see the definition of * vApplicationIPNetworkEventHook() below). The address values passed in here * are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 * but a DHCP server cannot be contacted. */ /* Initialise the network interface.*/ FreeRTOS_debug_printf( ( "FreeRTOS_IPInit\r\n" ) ); #if defined( FREERTOS_PLUS_TCP_VERSION ) && ( FREERTOS_PLUS_TCP_VERSION >= 10 ) /* Initialise the interface descriptor for WinPCap. */ pxWinPcap_FillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) ); /* === End-point 0 === */ FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); #if ( ipconfigUSE_DHCP != 0 ) { /* End-point 0 wants to use DHCPv4. */ xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE; } #endif /* ( ipconfigUSE_DHCP != 0 ) */ memcpy( ipLOCAL_MAC_ADDRESS, ucMACAddress, sizeof( ucMACAddress ) ); FreeRTOS_IPStart(); #else /* Using the old /single /IPv4 library, or using backward compatible mode of the new /multi library. */ FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); #endif /* if defined( FREERTOS_PLUS_TCP_VERSION ) && ( FREERTOS_PLUS_TCP_VERSION >= 10 ) */ /* Start the RTOS scheduler. */ FreeRTOS_debug_printf( ( "vTaskStartScheduler\r\n" ) ); vTaskStartScheduler(); /* If all is well, the scheduler will now be running, and the following * line will never be reached. If the following line does execute, then * there was insufficient FreeRTOS heap memory available for the idle and/or * timer tasks to be created. See the memory management section on the * FreeRTOS web site for more details (this is standard text that is not not * really applicable to the Win32 simulator port). */ for( ; ; ) { Sleep( ulLongTime_ms ); } } /*-----------------------------------------------------------*/ void vApplicationIdleHook( void ) { const uint32_t ulMSToSleep = 1; /* This is just a trivial example of an idle hook. It is called on each * cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in * FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the * idle task just sleeps to lower the CPU usage. */ Sleep( ulMSToSleep ); } /*-----------------------------------------------------------*/ /* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect * events are only received if implemented in the MAC driver. */ void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) { uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; char cBuffer[ 16 ]; static BaseType_t xTasksAlreadyCreated = pdFALSE; /* If the network has just come up...*/ if( eNetworkEvent == eNetworkUp ) { /* Create the tasks that use the IP stack if they have not already been * created. */ if( xTasksAlreadyCreated == pdFALSE ) { /* See the comments above the definitions of these pre-processor * macros at the top of this file for a description of the individual * demo tasks. */ #if ( mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS == 1 ) { vStartSimpleUDPClientServerTasks( configMINIMAL_STACK_SIZE, mainSIMPLE_UDP_CLIENT_SERVER_PORT, mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ); } #endif /* mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS */ #if ( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 ) { vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); } #endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */ #if ( mainCREATE_TCP_ECHO_SERVER_TASK == 1 ) { vStartSimpleTCPServerTasks( mainECHO_SERVER_TASK_STACK_SIZE, mainECHO_SERVER_TASK_PRIORITY ); } #endif xTasksAlreadyCreated = pdTRUE; } /* Print out the network configuration, which may have come from a DHCP * server. */ /* Using FREERTOS_PLUS_TCP_VERSION as the substitute of the * downward compatibility*/ #if defined( FREERTOS_PLUS_TCP_VERSION ) && ( FREERTOS_PLUS_TCP_VERSION >= 10 ) FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints ); #else FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); #endif FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) ); FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); } } /*-----------------------------------------------------------*/ void vApplicationMallocFailedHook( void ) { /* Called if a call to pvPortMalloc() fails because there is insufficient * free memory available in the FreeRTOS heap. pvPortMalloc() is called * internally by FreeRTOS API functions that create tasks, queues, software * timers, and semaphores. The size of the FreeRTOS heap is set by the * configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ vAssertCalled( __FILE__, __LINE__ ); } /*-----------------------------------------------------------*/ static void prvSRand( UBaseType_t ulSeed ) { /* Utility function to seed the pseudo random number generator. */ ulNextRand = ulSeed; } /*-----------------------------------------------------------*/ static void prvMiscInitialisation( void ) { time_t xTimeNow; uint32_t ulRandomNumbers[ 4 ]; vLoggingInit( xLogToStdout, xLogToFile, pdFALSE, 0, 0 ); /* Seed the random number generator. */ time( &xTimeNow ); FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\r\n", xTimeNow ) ); prvSRand( ( uint32_t ) xTimeNow ); ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 0 ] ); ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 1 ] ); ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 2 ] ); ( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 3 ] ); FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\r\n", ulRandomNumbers[ 0 ], ulRandomNumbers[ 1 ], ulRandomNumbers[ 2 ], ulRandomNumbers[ 3 ] ) ); } /*-----------------------------------------------------------*/ #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) const char * pcApplicationHostnameHook( void ) { /* Assign the name "FreeRTOS" to this network node. This function will * be called during the DHCP: the machine will be registered with an IP * address plus this name. */ return mainHOST_NAME; } #endif /*-----------------------------------------------------------*/ #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) BaseType_t xApplicationDNSQueryHook( const char * pcName ) { BaseType_t xReturn; /* Determine if a name lookup is for this node. Two names are given * to this node: that returned by pcApplicationHostnameHook() and that set * by mainDEVICE_NICK_NAME. */ if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) { xReturn = pdPASS; } else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) { xReturn = pdPASS; } else { xReturn = pdFAIL; } return xReturn; } #endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */ /*-----------------------------------------------------------*/ /* * Callback that provides the inputs necessary to generate a randomized TCP * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION * SYSTEMS. */ extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, uint16_t usSourcePort, uint32_t ulDestinationAddress, uint16_t usDestinationPort ) { ( void ) ulSourceAddress; ( void ) usSourcePort; ( void ) ulDestinationAddress; ( void ) usDestinationPort; return uxRand(); } /*-----------------------------------------------------------*/ /* * Supply a random number to FreeRTOS+TCP stack. * THIS IS ONLY A DUMMY IMPLEMENTATION THAT RETURNS A PSEUDO RANDOM NUMBER * SO IS NOT INTENDED FOR USE IN PRODUCTION SYSTEMS. */ BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber ) { *( pulNumber ) = uxRand(); return pdTRUE; } /*-----------------------------------------------------------*/ #if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_DHCP_HOOK != 0 ) ) eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress ) { /* Provide a stub for this function. */ return eDHCPContinue; } #endif /*-----------------------------------------------------------*/