From 2bca3b15eb0c3c4e07730012b0fb6574fb914cc7 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 13 Jun 2024 18:25:50 +0200 Subject: [PATCH 1/4] feat(aft_netif): Introduction of esp_netif with FreeRTOS+TCP stack --- .gitmodules | 3 + .pre-commit-config.yaml | 4 +- ci/check_copyright_config.yaml | 7 + components/freertos_tcp/CMakeLists.txt | 60 +++ components/freertos_tcp/FreeRTOS-Plus-TCP | 1 + .../examples/simple/CMakeLists.txt | 6 + .../examples/simple/main/CMakeLists.txt | 13 + .../examples/simple/main/hello_world_main.c | 420 ++++++++++++++++++ .../examples/simple/main/idf_component.yml | 7 + components/freertos_tcp/idf_component.yml | 6 + .../freertos_tcp/port/FreeRTOSIPConfig.c | 20 + .../freertos_tcp/port/NetworkInterface.c | 235 ++++++++++ .../port/include/FreeRTOSIPConfig.h | 359 +++++++++++++++ 13 files changed, 1139 insertions(+), 2 deletions(-) create mode 100644 components/freertos_tcp/CMakeLists.txt create mode 160000 components/freertos_tcp/FreeRTOS-Plus-TCP create mode 100644 components/freertos_tcp/examples/simple/CMakeLists.txt create mode 100644 components/freertos_tcp/examples/simple/main/CMakeLists.txt create mode 100644 components/freertos_tcp/examples/simple/main/hello_world_main.c create mode 100644 components/freertos_tcp/examples/simple/main/idf_component.yml create mode 100644 components/freertos_tcp/idf_component.yml create mode 100644 components/freertos_tcp/port/FreeRTOSIPConfig.c create mode 100644 components/freertos_tcp/port/NetworkInterface.c create mode 100644 components/freertos_tcp/port/include/FreeRTOSIPConfig.h diff --git a/.gitmodules b/.gitmodules index 6ecce627b4..960ca0f915 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "components/asio/asio"] path = components/asio/asio url = https://github.com/espressif/asio +[submodule "components/freertos_tcp/FreeRTOS-Plus-TCP"] + path = components/freertos_tcp/FreeRTOS-Plus-TCP + url = https://github.com/david-cermak/FreeRTOS-Plus-TCP.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a12312a52d..7235d24a28 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,8 +61,8 @@ repos: - repo: local hooks: - id: commit message scopes - name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, wifi_remote, tls_cxx" - entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|wifi_remote|tls_cxx)\)\:)' + name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, wifi_remote, tls_cxx, aft_netif" + entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|wifi_remote|tls_cxx|aft_netif)\)\:)' language: pygrep args: [--multiline] stages: [commit-msg] diff --git a/ci/check_copyright_config.yaml b/ci/check_copyright_config.yaml index 77f9f88028..54b8cc045e 100644 --- a/ci/check_copyright_config.yaml +++ b/ci/check_copyright_config.yaml @@ -40,6 +40,13 @@ examples_and_unit_tests: - CC0-1.0 license_for_new_files: Unlicense OR CC0-1.0 +freertos_tcp_component: + include: + - 'components/freertos_tcp/port/**' + allowed_licenses: + - Apache-2.0 + - MIT + asio_component: include: - 'components/asio/port/**' diff --git a/components/freertos_tcp/CMakeLists.txt b/components/freertos_tcp/CMakeLists.txt new file mode 100644 index 0000000000..1528f10d6a --- /dev/null +++ b/components/freertos_tcp/CMakeLists.txt @@ -0,0 +1,60 @@ +set(fdir /home/david/esp/idf/components/freertos/FreeRTOS-Kernel/include/freertos) +set(wdir /home/david/esp/idf/components/esp_wifi/include) +set(fcdir /home/david/esp/idf/components/freertos/config/include/freertos) + +set(fpt_dir FreeRTOS-Plus-TCP/source) +set(fpt_include_dir ${fpt_dir}/include ${fpt_dir}/portable/Compiler/GCC/) + +set(fpt_srcs ${fpt_dir}/FreeRTOS_ARP.c + ${fpt_dir}/FreeRTOS_BitConfig.c + ${fpt_dir}/FreeRTOS_DHCP.c + ${fpt_dir}/FreeRTOS_DHCPv6.c + ${fpt_dir}/FreeRTOS_DNS.c + ${fpt_dir}/FreeRTOS_DNS_Cache.c + ${fpt_dir}/FreeRTOS_DNS_Callback.c + ${fpt_dir}/FreeRTOS_DNS_Networking.c + ${fpt_dir}/FreeRTOS_DNS_Parser.c + ${fpt_dir}/FreeRTOS_ICMP.c + ${fpt_dir}/FreeRTOS_IP.c + ${fpt_dir}/FreeRTOS_IP_Timers.c + ${fpt_dir}/FreeRTOS_IP_Utils.c + ${fpt_dir}/FreeRTOS_IPv4.c + ${fpt_dir}/FreeRTOS_IPv4_Sockets.c + ${fpt_dir}/FreeRTOS_IPv4_Utils.c + ${fpt_dir}/FreeRTOS_IPv6.c + ${fpt_dir}/FreeRTOS_IPv6_Sockets.c + ${fpt_dir}/FreeRTOS_IPv6_Utils.c + ${fpt_dir}/FreeRTOS_ND.c + ${fpt_dir}/FreeRTOS_RA.c + ${fpt_dir}/FreeRTOS_Routing.c + ${fpt_dir}/FreeRTOS_Sockets.c + ${fpt_dir}/FreeRTOS_Stream_Buffer.c + ${fpt_dir}/FreeRTOS_TCP_IP.c + ${fpt_dir}/FreeRTOS_TCP_IP_IPv4.c + ${fpt_dir}/FreeRTOS_TCP_IP_IPv6.c + ${fpt_dir}/FreeRTOS_TCP_Reception.c + ${fpt_dir}/FreeRTOS_TCP_State_Handling.c + ${fpt_dir}/FreeRTOS_TCP_State_Handling_IPv4.c + ${fpt_dir}/FreeRTOS_TCP_State_Handling_IPv6.c + ${fpt_dir}/FreeRTOS_TCP_Transmission.c + ${fpt_dir}/FreeRTOS_TCP_Transmission_IPv4.c + ${fpt_dir}/FreeRTOS_TCP_Transmission_IPv6.c + ${fpt_dir}/FreeRTOS_TCP_Utils.c + ${fpt_dir}/FreeRTOS_TCP_Utils_IPv4.c + ${fpt_dir}/FreeRTOS_TCP_Utils_IPv6.c + ${fpt_dir}/FreeRTOS_TCP_WIN.c + ${fpt_dir}/FreeRTOS_Tiny_TCP.c + ${fpt_dir}/FreeRTOS_UDP_IP.c + ${fpt_dir}/FreeRTOS_UDP_IPv4.c + ${fpt_dir}/FreeRTOS_UDP_IPv6.c +# ${fpt_dir}/portable/NetworkInterface/esp32/NetworkInterface.c + ${fpt_dir}/portable/BufferManagement/BufferAllocation_1.c + ) + + +idf_component_register(SRCS ${fpt_srcs} port/FreeRTOSIPConfig.c port/NetworkInterface.c + INCLUDE_DIRS "port/include" + PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${fpt_include_dir} ${wdir} + PRIV_REQUIRES esp_wifi) + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/freertos_tcp/FreeRTOS-Plus-TCP b/components/freertos_tcp/FreeRTOS-Plus-TCP new file mode 160000 index 0000000000..a209cfcc74 --- /dev/null +++ b/components/freertos_tcp/FreeRTOS-Plus-TCP @@ -0,0 +1 @@ +Subproject commit a209cfcc74064ced9d199481b8aed3ba1668e62e diff --git a/components/freertos_tcp/examples/simple/CMakeLists.txt b/components/freertos_tcp/examples/simple/CMakeLists.txt new file mode 100644 index 0000000000..cba4bca926 --- /dev/null +++ b/components/freertos_tcp/examples/simple/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(simple_freertos_tcp_client) diff --git a/components/freertos_tcp/examples/simple/main/CMakeLists.txt b/components/freertos_tcp/examples/simple/main/CMakeLists.txt new file mode 100644 index 0000000000..7cd056ead5 --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/CMakeLists.txt @@ -0,0 +1,13 @@ +set(fdir /home/david/esp/idf/components/freertos/FreeRTOS-Kernel/include/freertos) +set(wdir /home/david/esp/idf/components/esp_wifi/include) +set(fcdir /home/david/esp/idf/components/freertos/config/include/freertos) +set(dir /home/david/temp/FreeRTOS-Plus-TCP/source) +set(idir ${dir}/include ${dir}/portable/Compiler/GCC/) + + +idf_component_register(SRCS "hello_world_main.c" ${srcs} + PRIV_REQUIRES spi_flash esp_wifi nvs_flash + PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${idir} ${wdir} . + INCLUDE_DIRS "") + +target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/freertos_tcp/examples/simple/main/hello_world_main.c b/components/freertos_tcp/examples/simple/main/hello_world_main.c new file mode 100644 index 0000000000..3a171c2a7f --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/hello_world_main.c @@ -0,0 +1,420 @@ +/* + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "esp_system.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "time.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#define TAG "wifi-connect" + +#if 1 + +#define mainHOST_NAME "RTOSDemo" +#define mainDEVICE_NICK_NAME "esp_demo" + + +/* The MAC address array is not declared const as the MAC address will + normally be read from an EEPROM and not hard coded (in real deployed + applications).*/ +static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; + +/* Define the network addressing. These parameters will be used if either + ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration + failed. */ +static const uint8_t ucIPAddress[ 4 ] = { 10, 10, 10, 200 }; +static const uint8_t ucNetMask[ 4 ] = { 255, 0, 0, 0 }; +static const uint8_t ucGatewayAddress[ 4 ] = { 10, 10, 10, 1 }; +static UBaseType_t ulNextRand; + +/* The following is the address of an OpenDNS server. */ +static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 }; +static NetworkInterface_t xInterfaces[ 1 ]; + +/* It will have several end-points. */ +static NetworkEndPoint_t xEndPoints[ 4 ]; +#endif + +static void wifi_init_sta(void); + +NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t *pxInterface ); + +void app_main(void) +{ + printf("Hello world!\n"); + pxESP32_Eth_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 ) */ + + FreeRTOS_IPInit_Multi(); + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); + wifi_init_sta(); + + return; + // extern NetworkInterface_t * pxLibslirp_FillInterfaceDescriptor( BaseType_t xEMACIndex, + // NetworkInterface_t * pxInterface ); + + /* Print chip information */ + esp_chip_info_t chip_info; + uint32_t flash_size; + esp_chip_info(&chip_info); + printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", + (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", + (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); + + unsigned major_rev = chip_info.revision / 100; + unsigned minor_rev = chip_info.revision % 100; + printf("silicon revision v%d.%d, ", major_rev, minor_rev); + if (esp_flash_get_size(NULL, &flash_size) != ESP_OK) { + printf("Get flash size failed"); + return; + } + + printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); + + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} + + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect + * events are only received if implemented in the MAC driver. */ +#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) +void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, + struct xNetworkEndPoint *pxEndPoint ) +#else +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ +{ + 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_TCP_ECHO_TASKS_SINGLE == 1 ) + { + vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); + } +#endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */ + + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + * server. */ +#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) + FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints ); +#else + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); +#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + printf( "\r\n\r\nIP Address: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + printf( "Subnet Mask: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + printf( "Gateway Address: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + printf( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ); + } else { + printf( "Application idle hook network down\n" ); + } +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ + const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return ( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +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 ]; + + /* Seed the random number generator. */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\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\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 ) + +#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) +BaseType_t xApplicationDNSQueryHook_Multi( struct xNetworkEndPoint *pxEndPoint, + const char *pcName ) +#else +BaseType_t xApplicationDNSQueryHook( const char *pcName ) +#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ +{ + 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 ( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) { + xReturn = pdPASS; + } else if ( strcasecmp( 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 ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 ) + +/* + * The stack will call this user hook for all Ethernet frames that it + * does not support, i.e. other than IPv4, IPv6 and ARP ( for the moment ) + * If this hook returns eReleaseBuffer or eProcessBuffer, the stack will + * release and reuse the network buffer. If this hook returns + * eReturnEthernetFrame, that means user code has reused the network buffer + * to generate a response and the stack will send that response out. + * If this hook returns eFrameConsumed, the user code has ownership of the + * network buffer and has to release it when it's done. + */ +eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t *const pxNetworkBuffer ) +{ + ( void ) ( pxNetworkBuffer ); + return eProcessBuffer; +} + +#endif +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, + uint16_t usIdentifier ) +{ + /* Provide a stub for this function. */ +} + +eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, + uint32_t ulIPAddress ) +{ + ( void ) eDHCPPhase; + ( void ) ulIPAddress; + + return eDHCPContinue; +} + + + +#define NETWORK_BUFFER_SIZE 1536 +static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ NETWORK_BUFFER_SIZE ]; + + +/* Next provide the vNetworkInterfaceAllocateRAMToBuffers() function, which + * simply fills in the pucEthernetBuffer member of each descriptor. */ +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + BaseType_t x; + + for ( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) { + /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the + * beginning of the allocated buffer. */ + pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] ); + + /* The following line is also required, but will not be required in + * future versions. */ + *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) & ( pxNetworkBuffers[ x ] ); + } +} + +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" +void vNetworkNotifyIFUp(); +static EventGroupHandle_t s_wifi_event_group; +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static void event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + vNetworkNotifyIFUp(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + esp_wifi_connect(); + ESP_LOGI(TAG, "connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +static void wifi_init_sta(void) +{ + s_wifi_event_group = xEventGroupCreate(); + + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_EXAMPLE_WIFI_SSID, + .password = CONFIG_EXAMPLE_WIFI_PASSWORD, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID password"); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect"); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } +} diff --git a/components/freertos_tcp/examples/simple/main/idf_component.yml b/components/freertos_tcp/examples/simple/main/idf_component.yml new file mode 100644 index 0000000000..91cda9be1a --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/idf_component.yml @@ -0,0 +1,7 @@ +## IDF Component Manager Manifest File +dependencies: + idf: + version: ">=5.3" + freertos_tcp: + version: "*" + override_path: '../../../' diff --git a/components/freertos_tcp/idf_component.yml b/components/freertos_tcp/idf_component.yml new file mode 100644 index 0000000000..fa4dd47ca1 --- /dev/null +++ b/components/freertos_tcp/idf_component.yml @@ -0,0 +1,6 @@ +version: 0.1.0 +url: https://github.com/espressif/esp-protocols/tree/master/components/freertos_tcp +description: The component provides FreeRTOS-plus-TCP port as a custom TCP/IP stack to esp-idf +dependencies: + idf: + version: '>=5.0' diff --git a/components/freertos_tcp/port/FreeRTOSIPConfig.c b/components/freertos_tcp/port/FreeRTOSIPConfig.c new file mode 100644 index 0000000000..389188f88a --- /dev/null +++ b/components/freertos_tcp/port/FreeRTOSIPConfig.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +portMUX_TYPE g_xBufferAllocLock = portMUX_INITIALIZER_UNLOCKED; +portMUX_TYPE g_xDHCPStaticLock = portMUX_INITIALIZER_UNLOCKED; diff --git a/components/freertos_tcp/port/NetworkInterface.c b/components/freertos_tcp/port/NetworkInterface.c new file mode 100644 index 0000000000..4e55dc6786 --- /dev/null +++ b/components/freertos_tcp/port/NetworkInterface.c @@ -0,0 +1,235 @@ +/* + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_private/wifi.h" +// #include "tcpip_adapter.h" + +enum if_state_t { + INTERFACE_DOWN = 0, + INTERFACE_UP, +}; + +static const char *TAG = "NetInterface"; +volatile static uint32_t xInterfaceState = INTERFACE_DOWN; + +static NetworkInterface_t *pxMyInterface; + +static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t *pxInterface ); + +static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t *pxInterface, + NetworkBufferDescriptor_t *const pxDescriptor, + BaseType_t xReleaseAfterSend ); + +static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t *pxInterface ); + +NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t *pxInterface ); + +/*-----------------------------------------------------------*/ + +#if ( ipconfigIPv4_BACKWARD_COMPATIBLE != 0 ) + +/* Do not call the following function directly. It is there for downward compatibility. + * The function FreeRTOS_IPInit() will call it to initialice the interface and end-point + * objects. See the description in FreeRTOS_Routing.h. */ +NetworkInterface_t *pxFillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t *pxInterface ) +{ + return pxESP32_Eth_FillInterfaceDescriptor( xEMACIndex, pxInterface ); +} + +#endif +/*-----------------------------------------------------------*/ + + +NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, + NetworkInterface_t *pxInterface ) +{ + static char pcName[ 8 ]; + + /* This function pxESP32_Eth_FillInterfaceDescriptor() adds a network-interface. + * Make sure that the object pointed to by 'pxInterface' + * is declared static or global, and that it will remain to exist. */ + + snprintf( pcName, sizeof( pcName ), "eth%ld", xEMACIndex ); + + memset( pxInterface, '\0', sizeof( *pxInterface ) ); + pxInterface->pcName = pcName; /* Just for logging, debugging. */ + pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */ + pxInterface->pfInitialise = xESP32_Eth_NetworkInterfaceInitialise; + pxInterface->pfOutput = xESP32_Eth_NetworkInterfaceOutput; + pxInterface->pfGetPhyLinkStatus = xESP32_Eth_GetPhyLinkStatus; + + FreeRTOS_AddNetworkInterface( pxInterface ); + pxMyInterface = pxInterface; + + return pxInterface; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t *pxInterface ) +{ + printf("xESP32_Eth_NetworkInterfaceInitialise\n"); +// xInterfaceState = INTERFACE_UP; + static BaseType_t xMACAdrInitialized = pdFALSE; + uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ]; + + if ( xInterfaceState == INTERFACE_UP ) { + if ( xMACAdrInitialized == pdFALSE ) { + ESP_LOGE(TAG, "Updaing MAC!"); + esp_wifi_get_mac( ESP_IF_WIFI_STA, ucMACAddress ); + FreeRTOS_UpdateMACAddress( ucMACAddress ); + xMACAdrInitialized = pdTRUE; + } + + return pdTRUE; + } + + return pdFALSE; +} + +static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t *pxInterface ) +{ + BaseType_t xResult = pdFALSE; + + if ( xInterfaceState == INTERFACE_UP ) { + xResult = pdTRUE; + } + + return xResult; +} + +static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t *pxInterface, + NetworkBufferDescriptor_t *const pxDescriptor, + BaseType_t xReleaseAfterSend ) +{ + ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); + if ( ( pxDescriptor == NULL ) || ( pxDescriptor->pucEthernetBuffer == NULL ) || ( pxDescriptor->xDataLength == 0 ) ) { + ESP_LOGE( TAG, "Invalid params" ); + return pdFALSE; + } + + esp_err_t ret; + + if ( xInterfaceState == INTERFACE_DOWN ) { + ESP_LOGD( TAG, "Interface down" ); + ret = ESP_FAIL; + } else { + ret = esp_wifi_internal_tx( ESP_IF_WIFI_STA, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ); + + if ( ret != ESP_OK ) { + ESP_LOGE( TAG, "Failed to tx buffer %p, len %d, err %d", pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, ret ); + } + ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); + ESP_LOG_BUFFER_HEXDUMP(TAG, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, ESP_LOG_INFO); + } + +#if ( ipconfigHAS_PRINTF != 0 ) + { + /* Call a function that monitors resources: the amount of free network + * buffers and the amount of free space on the heap. See FreeRTOS_IP.c + * for more detailed comments. */ + vPrintResourceStats(); + } +#endif /* ( ipconfigHAS_PRINTF != 0 ) */ + + if ( xReleaseAfterSend == pdTRUE ) { + // vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + + } + + return ret == ESP_OK ? pdTRUE : pdFALSE; +} + +void vNetworkNotifyIFDown() +{ + IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; + + if ( xInterfaceState != INTERFACE_DOWN ) { + xInterfaceState = INTERFACE_DOWN; + xSendEventStructToIPTask( &xRxEvent, 0 ); + } +} + + +static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) + +//esp_err_t wlanif_input( void * netif, +// void * buffer, +// uint16_t len, +// void * eb ) +{ + NetworkBufferDescriptor_t *pxNetworkBuffer; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); + +#if ( ipconfigHAS_PRINTF != 0 ) + { + vPrintResourceStats(); + } +#endif /* ( ipconfigHAS_PRINTF != 0 ) */ + + if ( eConsiderFrameForProcessing( buffer ) != eProcessBuffer ) { + ESP_LOGD( TAG, "Dropping packet" ); + esp_wifi_internal_free_rx_buffer( eb ); + return ESP_OK; + } + + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( len, xDescriptorWaitTime ); + + if ( pxNetworkBuffer != NULL ) { + /* Set the packet size, in case a larger buffer was returned. */ + pxNetworkBuffer->xDataLength = len; + pxNetworkBuffer->pxInterface = pxMyInterface; + pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxNetworkBuffer ); + + /* Copy the packet data. */ + memcpy( pxNetworkBuffer->pucEthernetBuffer, buffer, len ); + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + if ( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFAIL ) { + ESP_LOGE( TAG, "Failed to enqueue packet to network stack %p, len %d", buffer, len ); + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + return ESP_FAIL; + } + + esp_wifi_internal_free_rx_buffer( eb ); + return ESP_OK; + } else { + ESP_LOGE( TAG, "Failed to get buffer descriptor" ); + return ESP_FAIL; + } +} + +void vNetworkNotifyIFUp() +{ + xInterfaceState = INTERFACE_UP; + if (esp_wifi_internal_reg_rxcb(WIFI_IF_STA, wifi_rc_cb) != ESP_OK) { + ESP_LOGE( TAG, "Failed to register wifi callback" ); + } +} diff --git a/components/freertos_tcp/port/include/FreeRTOSIPConfig.h b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h new file mode 100644 index 0000000000..cb8c652444 --- /dev/null +++ b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h @@ -0,0 +1,359 @@ +/* + * FreeRTOS+TCP + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-FileCopyrightText: 2022 Amazon.com, Inc. or its affiliates + * + * SPDX-License-Identifier: MIT + * + * SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/***************************************************************************** +* +* See the following URL for configuration information. +* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html +* +*****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +#define ipconfigUSE_IPv4 ( 1 ) + +#define ipconfigUSE_IPv6 ( 0 ) + +#define ipconfigUSE_DHCPv6 0 +#define ipconfigIPv4_BACKWARD_COMPATIBLE 1 +#define ipconfigUSE_ARP_REVERSED_LOOKUP 1 +#define ipconfigUSE_ARP_REMOVE_ENTRY 1 +#define ipconfigARP_STORES_REMOTE_ADDRESSES 1 +#define ipconfigUSE_LINKED_RX_MESSAGES 1 +#define ipconfigFORCE_IP_DONT_FRAGMENT 1 +#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS 1 +#define ipconfigDHCP_FALL_BACK_AUTO_IP 1 +#define ipconfigARP_USE_CLASH_DETECTION 1 +#define ipconfigUSE_LLMNR 1 +#define ipconfigUSE_NBNS 1 +#define ipconfigUSE_MDNS 1 +#define ipconfigSUPPORT_OUTGOING_PINGS 1 +#define ipconfigETHERNET_DRIVER_FILTERS_PACKETS 1 +#define ipconfigZERO_COPY_TX_DRIVER 1 +#define ipconfigZERO_COPY_RX_DRIVER 1 +#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0 +#define ipconfigSOCKET_HAS_USER_SEMAPHORE 1 +#define ipconfigSELECT_USES_NOTIFY 1 +#define ipconfigSUPPORT_SIGNALS 1 +#define ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES 1 +#define ipconfigDNS_USE_CALLBACKS 1 +#define ipconfigIGNORE_UNKNOWN_PACKETS 1 +#define ipconfigCHECK_IP_QUEUE_SPACE 1 +#define ipconfigUDP_MAX_RX_PACKETS 1 +#define ipconfigETHERNET_MINIMUM_PACKET_BYTES 1 +#define ipconfigTCP_IP_SANITY 1 +#define ipconfigSUPPORT_NETWORK_DOWN_EVENT 1 + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to + * 1 then FreeRTOS_debug_printf should be defined to the function used to print + * out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 1 +#if ( ipconfigHAS_DEBUG_PRINTF == 1 ) +#define FreeRTOS_debug_printf( X ) printf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the + * FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 + * then FreeRTOS_printf should be set to the function used to print out the + * messages. */ +#define ipconfigHAS_PRINTF 1 +#if ( ipconfigHAS_PRINTF == 1 ) +#define FreeRTOS_printf( X ) printf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing + * on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading then set + * ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software + * stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 0 + +/* Several API's will block until the result is known, or the action has been + * performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be + * set per socket, using setsockopt(). If not set, the times below will be + * used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very + * useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low + * and also DNS may use small timeouts. If a DNS reply comes in after the DNS + * socket has been destroyed, the result will be stored into the cache. The next + * call to FreeRTOS_gethostbyname() will return immediately, without even creating + * a socket. + */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ( 6 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make + * use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY + * sets the priority of the task that executes the IP stack. The priority is a + * standard FreeRTOS task priority so can take any value from 0 (the lowest + * priority) to (configMAX_PRIORITIES - 1) (the highest priority). + * configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in + * FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to + * the priority assigned to the task executing the IP stack relative to the + * priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP + * task. This setting is less important when the FreeRTOS Win32 simulator is used + * as the Win32 simulator only stores a fixed amount of information on the task + * stack. FreeRTOS includes optional stack overflow detection, see: + * http://www.freertos.org/Stacks-and-stack-overflow-checking.html. */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the + * network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK + * is not set to 1 then the network event hook will never be called. See: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml. + */ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but + * a network buffer cannot be obtained then the calling task is held in the Blocked + * state (so other tasks can continue to executed) until either a network buffer + * becomes available or the send block time expires. If the send block time expires + * then the send operation is aborted. The maximum allowable send block time is + * capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the + * maximum allowable send block time prevents prevents a deadlock occurring when + * all the network buffers are in use and the tasks that process (and subsequently + * free) the network buffers are themselves blocked waiting for a network buffer. + * ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in + * milliseconds can be converted to a time in ticks by dividing the time in + * milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000U / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP + * address, netmask, DNS server address and gateway address from a DHCP server. If + * ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The + * stack will revert to using the static IP address even when ipconfigUSE_DHCP is + * set to 1 if a valid configuration cannot be obtained from a DHCP server for any + * reason. The static configuration used is that passed into the stack by the + * FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 +#define ipconfigDHCP_REGISTER_HOSTNAME 1 +#define ipconfigDHCP_USES_UNICAST 1 + +/* If ipconfigDHCP_USES_USER_HOOK is set to 1 then the application writer must + * provide an implementation of the DHCP callback function, + * xApplicationDHCPUserHook(). */ +#define ipconfigUSE_DHCP_HOOK 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at + * increasing time intervals until either a reply is received from a DHCP server + * and accepted, or the interval between transmissions reaches + * ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the + * static IP address passed as a parameter to FreeRTOS_IPInit() if the + * re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without + * a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD \ + ( 120000U / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP + * stack can only send a UDP message to a remove IP address if it knowns the MAC + * address associated with the IP address, or the MAC address of the router used to + * contact the remote IP address. When a UDP message is received from a remote IP + * address the MAC address and IP address are added to the ARP cache. When a UDP + * message is sent to a remote IP address that does not already appear in the ARP + * cache then the UDP message is replaced by a ARP message that solicits the + * required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum + * number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a + * maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is + * aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP + * table being created or refreshed and the entry being removed because it is stale. + * New ARP requests are sent for ARP cache entries that are nearing their maximum + * age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is + * equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling + * routines, which are relatively large. To save code space the full + * FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster + * alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() + * takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. + * FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets + * (for example, 192, 168, 0, 1) as its parameters. If + * ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and + * FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is + * not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that + * are available to the IP stack. The total number of network buffers is limited + * to ensure the total amount of RAM that can be consumed by the IP stack is capped + * to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP + * stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can + * be queued for processing at any one time. The event queue must be a minimum of + * 5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH \ + ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port + * number. FreeRTOS_bind() is used to manually allocate a port number to a socket + * (to 'bind' the socket to a port), but manual binding is not normally necessary + * for client sockets (those sockets that initiate outgoing connections rather than + * wait for incoming connections on a known port number). If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling + * FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP + * stack automatically binding the socket to a port number from the range + * socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If + * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() + * on a socket that has not yet been bound will result in the send operation being + * aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +/* Also defined in FreeRTOSIPConfigDefaults.h. */ +#define ipconfigTCP_TIME_TO_LIVE 128 + +/* USE_TCP: Use TCP and all its features. */ +#define ipconfigUSE_TCP ( 0 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can + * contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a + * lower value can save RAM, depending on the buffer management scheme used. If + * ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must + * be divisible by 8. */ +#define ipconfigNETWORK_MTU 1500U + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used + * through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will + * generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the + * FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 1 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() + * (and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames + * that are not in Ethernet II format will be dropped. This option is included for + * potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the + * responsibility of the Ethernet interface to filter out packets that are of no + * interest. If the Ethernet interface does not implement this functionality, then + * set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack + * perform the filtering instead (it is much less efficient for the stack to do it + * because the packet will already have been passed into the stack). If the + * Ethernet driver does all the necessary filtering in hardware then software + * filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to + * block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with + * 32-bit memory instructions, all packets will be stored 32-bit-aligned, + * plus 16-bits. This has to do with the contents of the IP-packets: all + * 32-bit fields are 32-bit-aligned, plus 16-bit. */ +#define ipconfigPACKET_FILLER_SIZE 2U + +/* Define the size of the pool of TCP window descriptors. On the average, each + * TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 + * outstanding packets (for Rx and Tx). When using up to 10 TP sockets + * simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed + * maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 10000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 10000 ) + +/* When using call-back handlers, the driver may check if the handler points to + * real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* Seconds. */ + +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK ( 1 ) +#define ipconfigUSE_CALLBACKS ( 1 ) + + +#define portINLINE __inline + +#define ipconfigISO_STRICTNESS_VIOLATION_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpedantic\"") + +#define ipconfigISO_STRICTNESS_VIOLATION_END _Pragma("GCC diagnostic pop") + +extern portMUX_TYPE g_xBufferAllocLock; +extern portMUX_TYPE g_xDHCPStaticLock; + +// For buffer allocation +#define ipconfigBUFFER_ALLOC_INIT() do {} while( ipFALSE_BOOL ) +#define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \ + UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { +#define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ +} + +#define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL(&g_xBufferAllocLock) +#define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL(&g_xBufferAllocLock) + +#define ipconfigSTATIC_IP_LOCK() taskENTER_CRITICAL(&g_xDHCPStaticLock); +#define ipconfigSTATIC_IP_UNLOCK() taskEXIT_CRITICAL(&g_xDHCPStaticLock); + + +#endif /* FREERTOS_IP_CONFIG_H */ From 408813f273d2c5b2d476a1142fceca8d2182db93 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 18 Jun 2024 17:08:36 +0200 Subject: [PATCH 2/4] fix(aft_netif): Implement support via esp_netif --- components/freertos_tcp/CMakeLists.txt | 7 +- components/freertos_tcp/Kconfig | 27 + components/freertos_tcp/esp_netif/defaults.c | 16 + .../freertos_tcp/esp_netif/esp_netif_impl.c | 545 ++++++++++++++++++ components/freertos_tcp/esp_netif/interface.c | 49 ++ components/freertos_tcp/esp_netif/interface.h | 18 + .../examples/simple/main/hello_world_main.c | 109 +--- .../examples/simple/main/idf_component.yml | 2 + .../freertos_tcp/port/NetworkInterface.c | 79 ++- .../port/include/FreeRTOSIPConfig.h | 12 +- 10 files changed, 732 insertions(+), 132 deletions(-) create mode 100644 components/freertos_tcp/Kconfig create mode 100644 components/freertos_tcp/esp_netif/defaults.c create mode 100644 components/freertos_tcp/esp_netif/esp_netif_impl.c create mode 100644 components/freertos_tcp/esp_netif/interface.c create mode 100644 components/freertos_tcp/esp_netif/interface.h diff --git a/components/freertos_tcp/CMakeLists.txt b/components/freertos_tcp/CMakeLists.txt index 1528f10d6a..b8d15e0b61 100644 --- a/components/freertos_tcp/CMakeLists.txt +++ b/components/freertos_tcp/CMakeLists.txt @@ -53,8 +53,13 @@ set(fpt_srcs ${fpt_dir}/FreeRTOS_ARP.c idf_component_register(SRCS ${fpt_srcs} port/FreeRTOSIPConfig.c port/NetworkInterface.c + esp_netif/defaults.c + esp_netif/interface.c + esp_netif/esp_netif_impl.c INCLUDE_DIRS "port/include" PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${fpt_include_dir} ${wdir} - PRIV_REQUIRES esp_wifi) + PRIV_REQUIRES esp_wifi esp_netif) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") +target_compile_definitions(${COMPONENT_LIB} PUBLIC "FREERTOS_CONFIG_H") +target_link_libraries(${COMPONENT_LIB} PRIVATE "-u _g_esp_netif_netstack_default_wifi_sta") diff --git a/components/freertos_tcp/Kconfig b/components/freertos_tcp/Kconfig new file mode 100644 index 0000000000..75def49a55 --- /dev/null +++ b/components/freertos_tcp/Kconfig @@ -0,0 +1,27 @@ +menu "Amazon FreeRTOS plus TCP (AFpT)" + + config AFPT_ENABLE + bool + default y + select ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION + + config AFPT_LOCAL_HOSTNAME + string "Local netif hostname" + default 'espressif' + help + The default name this device will report to other devices on the network. + Could be updated at runtime with esp_netif_set_hostname() + + config AFPT_IPV4 + bool "Enable IPv4" + default y + help + Enable IPv4 stack. If you want to use IPv6 only TCP/IP stack, disable this. + + config AFPT_IPV6 + bool "Enable IPv6" + default y + help + Enable IPv6 function. If you want to use IPv4 only TCP/IP stack, disable this. + +endmenu diff --git a/components/freertos_tcp/esp_netif/defaults.c b/components/freertos_tcp/esp_netif/defaults.c new file mode 100644 index 0000000000..0719a609fa --- /dev/null +++ b/components/freertos_tcp/esp_netif/defaults.c @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// +// Created by david on 6/17/24. +// +#include "esp_netif.h" + +struct netif; + + +esp_err_t wlanif_init_ap(struct netif *netif); +esp_err_t wlanif_init_sta(struct netif *netif); +esp_err_t wlanif_input(void *h, void *buffer, size_t len, void *l2_buff); diff --git a/components/freertos_tcp/esp_netif/esp_netif_impl.c b/components/freertos_tcp/esp_netif/esp_netif_impl.c new file mode 100644 index 0000000000..d0143191db --- /dev/null +++ b/components/freertos_tcp/esp_netif/esp_netif_impl.c @@ -0,0 +1,545 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// +// Created by david on 6/17/24. +// +#include "esp_netif.h" +#include "esp_netif_net_stack.h" +#include "interface.h" +#include "NetworkInterface.h" +#include "esp_log.h" +#include "esp_event.h" + +#define MAX_ENDPOINTS_PER_NETIF 4 + +static const char *TAG = "esp_netif_AFpT"; +static bool s_netif_initialized = false; + + +struct esp_netif_stack { + esp_netif_netstack_config_t config; + NetworkInterface_t aft_netif; + NetworkEndPoint_t xEndPoints[MAX_ENDPOINTS_PER_NETIF]; +}; + + +struct esp_netif_obj { + uint8_t mac[6]; + // io driver related + void *driver_handle; + esp_err_t (*driver_transmit)(void *h, void *buffer, size_t len); + void (*driver_free_rx_buffer)(void *h, void *buffer); + + // stack related + struct esp_netif_stack *net_stack; + + // misc flags, types, keys, priority + esp_netif_flags_t flags; + char *hostname; + char *if_key; + char *if_desc; + int route_prio; +}; + +static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; + +/* Define the network addressing. These parameters will be used if either + ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration + failed. */ +static const uint8_t ucIPAddress[ 4 ] = { 10, 10, 10, 200 }; +static const uint8_t ucNetMask[ 4 ] = { 255, 0, 0, 0 }; +static const uint8_t ucGatewayAddress[ 4 ] = { 10, 10, 10, 1 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 }; + +void *esp_netif_new_netstack_if(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *cfg) +{ + static int netif_count = 0; + struct esp_netif_stack *netif = calloc(1, sizeof(struct esp_netif_stack)); + if (!netif) { + return NULL; + } + netif->config.init_fn = cfg->init_fn; + if (!cfg->init_fn(netif_count++, &netif->aft_netif)) { + free(netif); + return NULL; + } +// ESP_LOGW(TAG, "%d %p", netif_count, netif->config.init_fn); +// FreeRTOS_IPInit_Multi(); + FreeRTOS_FillEndPoint( &( netif->aft_netif ), &( netif->xEndPoints[0]), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + netif->xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE; + netif->aft_netif.bits.bInterfaceUp = 0; + // netif->xEndPoints[ 0 ].bits.bEndPointUp = pdFALSE; + FreeRTOS_IPInit_Multi(); + + netif->aft_netif.pvArgument = esp_netif; + netif->config.input_fn = cfg->input_fn; + return netif; +} + + +esp_err_t esp_netif_receive(esp_netif_t *esp_netif, void *buffer, size_t len, void *eb) +{ + struct esp_netif_stack *netif = esp_netif->net_stack; +// ESP_LOGW(TAG, "esp_netif_receive() %d %p", len, netif->config.input_fn); + return netif->config.input_fn(&netif->aft_netif, buffer, len, eb); +} + +void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface); + +//esp_err_t esp_netif_update_netstack_if(void* netif, esp_netif_status_update_t status) +//{ +// if (status == ESP_NETIF_STATUS_CONNECTED) { +// vNetworkNotifyIFUp(); +// } +// return ESP_OK; +//} + +void esp_netif_set_ip4_addr(esp_ip4_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + memset(addr, 0, sizeof(esp_ip4_addr_t)); + addr->addr = esp_netif_htonl(esp_netif_ip4_makeu32(a, b, c, d)); +} + +char *esp_ip4addr_ntoa(const esp_ip4_addr_t *addr, char *buf, int buflen) +{ + return NULL; +} + +esp_netif_iodriver_handle esp_netif_get_io_driver(esp_netif_t *esp_netif) +{ + return esp_netif->driver_handle; +} + +esp_netif_t *esp_netif_get_handle_from_netif_impl(void *dev) +{ + return NULL; +} + +esp_err_t esp_netif_init(void) +{ + ESP_LOGI(TAG, "loopback initialization"); + if (s_netif_initialized) { + ESP_LOGE(TAG, "esp-netif has already been initialized"); + return ESP_ERR_INVALID_SIZE; + } + + s_netif_initialized = true; + ESP_LOGD(TAG, "esp-netif has been successfully initialized"); + return ESP_OK; +} + +esp_err_t esp_netif_deinit(void) +{ + ESP_LOGI(TAG, "loopback initialization"); + if (!s_netif_initialized) { + ESP_LOGE(TAG, "esp-netif has not been initialized yet"); + return ESP_ERR_INVALID_SIZE; + } + s_netif_initialized = false; + ESP_LOGD(TAG, "esp-netif has been successfully deinitialized"); + return ESP_OK; +} + +static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_netif_config_t *cfg) +{ + // Basic esp_netif and lwip is a mandatory configuration and cannot be updated after esp_netif_new() + if (cfg == NULL || cfg->base == NULL || cfg->stack == NULL) { + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + + // Setup main config parameters + esp_netif->flags = cfg->base->flags; + + if (cfg->base->if_key) { + esp_netif->if_key = strdup(cfg->base->if_key); + } + if (cfg->base->if_desc) { + esp_netif->if_desc = strdup(cfg->base->if_desc); + } + if (cfg->base->route_prio) { + esp_netif->route_prio = cfg->base->route_prio; + } + + // Network stack configs + esp_netif->net_stack = esp_netif_new_netstack_if(esp_netif, cfg->stack); + + // Install IO functions only if provided -- connects driver and netif + // this configuration could be updated after esp_netif_new(), typically in post_attach callback + if (cfg->driver) { + const esp_netif_driver_ifconfig_t *esp_netif_driver_config = cfg->driver; + if (esp_netif_driver_config->handle) { + esp_netif->driver_handle = esp_netif_driver_config->handle; + } + if (esp_netif_driver_config->transmit) { + esp_netif->driver_transmit = esp_netif_driver_config->transmit; + } + if (esp_netif_driver_config->driver_free_rx_buffer) { + esp_netif->driver_free_rx_buffer = esp_netif_driver_config->driver_free_rx_buffer; + } + } + return ESP_OK; +} + +esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) +{ + // mandatory configuration must be provided when creating esp_netif object + if (esp_netif_config == NULL) { + return NULL; + } + + // Create parent esp-netif object + esp_netif_t *esp_netif = calloc(1, sizeof(struct esp_netif_obj)); + if (!esp_netif) { + return NULL; + } + + // Create ip info + esp_netif_ip_info_t *ip_info = calloc(1, sizeof(esp_netif_ip_info_t)); + if (!ip_info) { + free(esp_netif); + return NULL; + } + + // creating another ip info (to store old ip) +// esp_netif_add_to_list_unsafe(esp_netif); + + // Configure the created object with provided configuration + esp_err_t ret = esp_netif_init_configuration(esp_netif, esp_netif_config); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Initial configuration of esp_netif failed with %d", ret); + esp_netif_destroy(esp_netif); + return NULL; + } + + return esp_netif; +} + +void esp_netif_destroy(esp_netif_t *esp_netif) +{ + if (esp_netif) { +// esp_netif_remove_from_list_unsafe(esp_netif); + free(esp_netif->if_key); + free(esp_netif->if_desc); + free(esp_netif); + } +} + +esp_err_t esp_netif_attach(esp_netif_t *esp_netif, esp_netif_iodriver_handle driver_handle) +{ + esp_netif_driver_base_t *base_driver = driver_handle; + + esp_netif->driver_handle = driver_handle; + if (base_driver->post_attach) { + esp_err_t ret = base_driver->post_attach(esp_netif, driver_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Post-attach callback of driver(%p) failed with %d", driver_handle, ret); + return ESP_ERR_ESP_NETIF_DRIVER_ATTACH_FAILED; + } + } + return ESP_OK; +} + +esp_err_t esp_netif_set_driver_config(esp_netif_t *esp_netif, + const esp_netif_driver_ifconfig_t *driver_config) +{ + if (esp_netif == NULL || driver_config == NULL) { + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + esp_netif->driver_handle = driver_config->handle; + esp_netif->driver_transmit = driver_config->transmit; + esp_netif->driver_free_rx_buffer = driver_config->driver_free_rx_buffer; + return ESP_OK; +} + +esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t ucMACAddress[]) +{ + ESP_LOGI(TAG, "esp_netif_set_mac()"); + memcpy(esp_netif->mac, ucMACAddress, 6); +// uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ]; + +// FreeRTOS_UpdateMACAddress( ucMACAddress ); + + return ESP_OK; +} + +esp_err_t esp_netif_start(esp_netif_t *esp_netif) +{ + ESP_LOGI(TAG, "Netif started"); + memcpy(&esp_netif->net_stack->xEndPoints->xMACAddress, esp_netif->mac, 6); +// FreeRTOS_UpdateMACAddress( esp_netif->mac ); + +// vNetworkNotifyIFUp(&esp_netif->net_stack->aft_netif); + return ESP_OK; +} + + +esp_err_t esp_netif_stop(esp_netif_t *esp_netif) +{ + ESP_LOGI(TAG, "Netif stopped"); + return ESP_OK; +} + +// +// IO translate functions +// +void esp_netif_free_rx_buffer(void *h, void *buffer) +{ + esp_netif_t *esp_netif = h; + esp_netif->driver_free_rx_buffer(esp_netif->driver_handle, buffer); +} + +esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void *data, size_t len) +{ + ESP_LOGW(TAG, "Transmitting data: ptr:%p, size:%lu", data, (long unsigned int) len); + return (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len); +} + +esp_err_t esp_netif_dhcpc_stop(esp_netif_t *esp_netif) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_dhcpc_start(esp_netif_t *esp_netif) +{ +// esp_netif->net_stack->xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE; + return ESP_OK; +} + +esp_err_t esp_netif_dhcps_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + *status = ESP_NETIF_DHCP_INIT; + return ESP_OK; +} + +esp_err_t esp_netif_dhcps_start(esp_netif_t *esp_netif) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_dhcps_stop(esp_netif_t *esp_netif) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_set_hostname(esp_netif_t *esp_netif, const char *hostname) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_get_hostname(esp_netif_t *esp_netif, const char **hostname) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_up(esp_netif_t *esp_netif) +{ + ESP_LOGI(TAG, "Netif going up"); + struct esp_netif_stack *netif = esp_netif->net_stack; + netif->aft_netif.bits.bInterfaceUp = 1; + vNetworkNotifyIFUp(&esp_netif->net_stack->aft_netif); + +// vNetworkNotifyIFUp(); + return ESP_OK; +} + +esp_err_t esp_netif_down(esp_netif_t *esp_netif) +{ + ESP_LOGI(TAG, "Netif going down"); + return ESP_OK; +} + +bool esp_netif_is_netif_up(esp_netif_t *esp_netif) +{ + return false; +} + +esp_err_t esp_netif_get_old_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif); + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif); + + return ESP_ERR_NOT_SUPPORTED; +} + +bool esp_netif_is_valid_static_ip(esp_netif_ip_info_t *ip_info) +{ + return true; +} + +esp_err_t esp_netif_set_old_ip_info(esp_netif_t *esp_netif, const esp_netif_ip_info_t *ip_info) +{ + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif); + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_set_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_get_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_create_ip6_linklocal(esp_netif_t *esp_netif) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_get_ip6_global(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_netif_flags_t esp_netif_get_flags(esp_netif_t *esp_netif) +{ + return esp_netif->flags; +} + +const char *esp_netif_get_ifkey(esp_netif_t *esp_netif) +{ + return esp_netif->if_key; +} + +const char *esp_netif_get_desc(esp_netif_t *esp_netif) +{ + return esp_netif->if_desc; +} + +int32_t esp_netif_get_event_id(esp_netif_t *esp_netif, esp_netif_ip_event_type_t event_type) +{ + return 0; +} + +esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, + uint32_t opt_len) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, + uint32_t opt_len) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) +{ + return 0; +} + +esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t addr, bool preferred) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_remove_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[]) +{ + return 0; +} + +esp_ip6_addr_type_t esp_netif_ip6_get_addr_type(esp_ip6_addr_t *ip6_addr) +{ + return ESP_IP6_ADDR_IS_UNKNOWN; +} + +esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void *ctx) +{ + return fn(ctx); +} + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect + * events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, + struct xNetworkEndPoint *pxEndPoint ) +{ + uint32_t ulIPAddress = 0, 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_TCP_ECHO_TASKS_SINGLE == 1 ) + { + vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); + } +#endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */ + + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + * server. */ +#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) + FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints ); +#else + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); +#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + printf( "\r\n\r\nIP Address: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + printf( "Subnet Mask: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + printf( "Gateway Address: %s\r\n", cBuffer ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + printf( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ); + ip_event_got_ip_t evt = { + .esp_netif = pxEndPoint->pxNetworkInterface->pvArgument, + .ip_changed = false, + }; + + evt.ip_info.ip.addr = ulIPAddress; + evt.ip_info.gw.addr = ulGatewayAddress; + evt.ip_info.netmask.addr = ulNetMask; + esp_err_t ret = esp_event_post(IP_EVENT, IP_EVENT_STA_GOT_IP, &evt, sizeof(evt), 0); + if (ESP_OK != ret) { + ESP_LOGE(TAG, "dhcpc cb: failed to post got ip event (%x)", ret); + } + } else { + printf( "Application idle hook network down\n" ); + } +} diff --git a/components/freertos_tcp/esp_netif/interface.c b/components/freertos_tcp/esp_netif/interface.c new file mode 100644 index 0000000000..ab8a11d0ba --- /dev/null +++ b/components/freertos_tcp/esp_netif/interface.c @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* Standard includes. */ +#include +#include +#include +//#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "FreeRTOS_IP.h" + +#include "esp_log.h" +#include "interface.h" +#include "esp_netif.h" + +//static const char *TAG = "freertos_tcp_netif"; + +NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface); +esp_err_t xESP32_Eth_NetworkInterfaceInput(NetworkInterface_t *pxInterface, void *buffer, size_t len, void *eb); + +static NetworkInterface_t *init(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface) +{ + return pxESP32_Eth_FillInterfaceDescriptor(xEMACIndex, pxInterface); +} + +static esp_err_t input(NetworkInterface_t *netif, void *buffer, size_t len, void *eb) +{ + return xESP32_Eth_NetworkInterfaceInput(netif, buffer, len, eb); +} + +void esp_netif_netstack_buf_ref(void *pbuf) +{ +} + +void esp_netif_netstack_buf_free(void *pbuf) +{ +} + +static const struct esp_netif_netstack_config s_netif_config = { + .init_fn = init, + .input_fn = input +}; + +const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta = &s_netif_config; +const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap = &s_netif_config; diff --git a/components/freertos_tcp/esp_netif/interface.h b/components/freertos_tcp/esp_netif/interface.h new file mode 100644 index 0000000000..8362790a5f --- /dev/null +++ b/components/freertos_tcp/esp_netif/interface.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "esp_netif.h" +#include "NetworkInterface.h" + +struct netif; + +typedef NetworkInterface_t *(*init_fn_t)(BaseType_t xEMACIndex, NetworkInterface_t *pxInterface); +typedef esp_err_t (*input_fn_t)(NetworkInterface_t *pxInterface, void *buffer, size_t len, void *eb); + +struct esp_netif_netstack_config { + init_fn_t init_fn; + input_fn_t input_fn; +}; diff --git a/components/freertos_tcp/examples/simple/main/hello_world_main.c b/components/freertos_tcp/examples/simple/main/hello_world_main.c index 3a171c2a7f..c54a1f2b5e 100644 --- a/components/freertos_tcp/examples/simple/main/hello_world_main.c +++ b/components/freertos_tcp/examples/simple/main/hello_world_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -17,6 +17,9 @@ #include "time.h" #include "esp_log.h" #include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "protocol_examples_common.h" #define TAG "wifi-connect" @@ -54,6 +57,18 @@ NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, void app_main(void) { + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + return; + + printf("Hello world!\n"); pxESP32_Eth_FillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) ); @@ -116,59 +131,7 @@ void app_main(void) } -/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect - * events are only received if implemented in the MAC driver. */ -#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) -void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, - struct xNetworkEndPoint *pxEndPoint ) -#else -void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) -#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ -{ - 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_TCP_ECHO_TASKS_SINGLE == 1 ) - { - vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); - } -#endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */ - - xTasksAlreadyCreated = pdTRUE; - } - - /* Print out the network configuration, which may have come from a DHCP - * server. */ -#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) - FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints ); -#else - FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); -#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ - FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); - printf( "\r\n\r\nIP Address: %s\r\n", cBuffer ); - - FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); - printf( "Subnet Mask: %s\r\n", cBuffer ); - - FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); - printf( "Gateway Address: %s\r\n", cBuffer ); - FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); - printf( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ); - } else { - printf( "Application idle hook network down\n" ); - } -} /*-----------------------------------------------------------*/ UBaseType_t uxRand( void ) @@ -182,34 +145,6 @@ UBaseType_t uxRand( void ) } /*-----------------------------------------------------------*/ -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 ]; - - /* Seed the random number generator. */ - time( &xTimeNow ); - FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\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\n", - ulRandomNumbers[ 0 ], - ulRandomNumbers[ 1 ], - ulRandomNumbers[ 2 ], - ulRandomNumbers[ 3 ] ) ); -} /*-----------------------------------------------------------*/ #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) @@ -307,11 +242,12 @@ void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, /* Provide a stub for this function. */ } -eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, - uint32_t ulIPAddress ) +eDHCPCallbackAnswer_t xApplicationDHCPHook_Multi( eDHCPCallbackPhase_t eDHCPPhase, + struct xNetworkEndPoint *pxEndPoint, + IP_Address_t *pxIPAddress ) { ( void ) eDHCPPhase; - ( void ) ulIPAddress; + ( void ) pxIPAddress; return eDHCPContinue; } @@ -344,7 +280,8 @@ void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkB #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" -void vNetworkNotifyIFUp(); +//void vNetworkNotifyIFUp(); +void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface); static EventGroupHandle_t s_wifi_event_group; #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 @@ -354,7 +291,7 @@ static void event_handler(void *arg, esp_event_base_t event_base, { if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); - vNetworkNotifyIFUp(); + vNetworkNotifyIFUp(&xInterfaces[0]); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { esp_wifi_connect(); ESP_LOGI(TAG, "connect to the AP fail"); diff --git a/components/freertos_tcp/examples/simple/main/idf_component.yml b/components/freertos_tcp/examples/simple/main/idf_component.yml index 91cda9be1a..b1ce04939f 100644 --- a/components/freertos_tcp/examples/simple/main/idf_component.yml +++ b/components/freertos_tcp/examples/simple/main/idf_component.yml @@ -5,3 +5,5 @@ dependencies: freertos_tcp: version: "*" override_path: '../../../' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/components/freertos_tcp/port/NetworkInterface.c b/components/freertos_tcp/port/NetworkInterface.c index 4e55dc6786..6f97de881f 100644 --- a/components/freertos_tcp/port/NetworkInterface.c +++ b/components/freertos_tcp/port/NetworkInterface.c @@ -26,7 +26,8 @@ #include "esp_log.h" #include "esp_wifi.h" #include "esp_private/wifi.h" -// #include "tcpip_adapter.h" +#include "esp_netif.h" +#include "esp_netif_net_stack.h" enum if_state_t { INTERFACE_DOWN = 0, @@ -34,9 +35,9 @@ enum if_state_t { }; static const char *TAG = "NetInterface"; -volatile static uint32_t xInterfaceState = INTERFACE_DOWN; +//volatile static uint32_t xInterfaceState = INTERFACE_DOWN; -static NetworkInterface_t *pxMyInterface; +//static NetworkInterface_t *pxMyInterface; static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t *pxInterface ); @@ -70,6 +71,7 @@ NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, NetworkInterface_t *pxInterface ) { static char pcName[ 8 ]; + printf("pxESP32_Eth_FillInterfaceDescriptor\n"); /* This function pxESP32_Eth_FillInterfaceDescriptor() adds a network-interface. * Make sure that the object pointed to by 'pxInterface' @@ -79,13 +81,12 @@ NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, memset( pxInterface, '\0', sizeof( *pxInterface ) ); pxInterface->pcName = pcName; /* Just for logging, debugging. */ - pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */ pxInterface->pfInitialise = xESP32_Eth_NetworkInterfaceInitialise; pxInterface->pfOutput = xESP32_Eth_NetworkInterfaceOutput; pxInterface->pfGetPhyLinkStatus = xESP32_Eth_GetPhyLinkStatus; FreeRTOS_AddNetworkInterface( pxInterface ); - pxMyInterface = pxInterface; +// pxMyInterface = pxInterface; return pxInterface; } @@ -94,29 +95,14 @@ NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, static BaseType_t xESP32_Eth_NetworkInterfaceInitialise( NetworkInterface_t *pxInterface ) { printf("xESP32_Eth_NetworkInterfaceInitialise\n"); -// xInterfaceState = INTERFACE_UP; - static BaseType_t xMACAdrInitialized = pdFALSE; - uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ]; - - if ( xInterfaceState == INTERFACE_UP ) { - if ( xMACAdrInitialized == pdFALSE ) { - ESP_LOGE(TAG, "Updaing MAC!"); - esp_wifi_get_mac( ESP_IF_WIFI_STA, ucMACAddress ); - FreeRTOS_UpdateMACAddress( ucMACAddress ); - xMACAdrInitialized = pdTRUE; - } - - return pdTRUE; - } - - return pdFALSE; + return pxInterface->bits.bInterfaceUp ? pdTRUE : pdFALSE; } static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t *pxInterface ) { BaseType_t xResult = pdFALSE; - if ( xInterfaceState == INTERFACE_UP ) { + if ( pxInterface->bits.bInterfaceUp) { xResult = pdTRUE; } @@ -127,7 +113,7 @@ static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t *pxInter NetworkBufferDescriptor_t *const pxDescriptor, BaseType_t xReleaseAfterSend ) { - ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); +// ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); if ( ( pxDescriptor == NULL ) || ( pxDescriptor->pucEthernetBuffer == NULL ) || ( pxDescriptor->xDataLength == 0 ) ) { ESP_LOGE( TAG, "Invalid params" ); return pdFALSE; @@ -135,17 +121,17 @@ static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t *pxInter esp_err_t ret; - if ( xInterfaceState == INTERFACE_DOWN ) { + if (!(pxInterface->bits.bInterfaceUp)) { ESP_LOGD( TAG, "Interface down" ); ret = ESP_FAIL; } else { - ret = esp_wifi_internal_tx( ESP_IF_WIFI_STA, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ); - + esp_netif_t *esp_netif = pxInterface->pvArgument; + ret = esp_netif_transmit(esp_netif, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength); if ( ret != ESP_OK ) { ESP_LOGE( TAG, "Failed to tx buffer %p, len %d, err %d", pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, ret ); } - ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); - ESP_LOG_BUFFER_HEXDUMP(TAG, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, ESP_LOG_INFO); +// ESP_LOGI(TAG, "xESP32_Eth_NetworkInterfaceOutput"); + ESP_LOG_BUFFER_HEXDUMP(TAG, pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, ESP_LOG_VERBOSE); } #if ( ipconfigHAS_PRINTF != 0 ) @@ -166,6 +152,7 @@ static BaseType_t xESP32_Eth_NetworkInterfaceOutput( NetworkInterface_t *pxInter return ret == ESP_OK ? pdTRUE : pdFALSE; } +/* void vNetworkNotifyIFDown() { IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; @@ -175,14 +162,9 @@ void vNetworkNotifyIFDown() xSendEventStructToIPTask( &xRxEvent, 0 ); } } +*/ - -static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) - -//esp_err_t wlanif_input( void * netif, -// void * buffer, -// uint16_t len, -// void * eb ) +esp_err_t xESP32_Eth_NetworkInterfaceInput(NetworkInterface_t *pxInterface, void *buffer, size_t len, void *eb) { NetworkBufferDescriptor_t *pxNetworkBuffer; IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; @@ -196,7 +178,7 @@ static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) if ( eConsiderFrameForProcessing( buffer ) != eProcessBuffer ) { ESP_LOGD( TAG, "Dropping packet" ); - esp_wifi_internal_free_rx_buffer( eb ); + esp_netif_free_rx_buffer(pxInterface->pvArgument, eb ); return ESP_OK; } @@ -205,8 +187,8 @@ static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) if ( pxNetworkBuffer != NULL ) { /* Set the packet size, in case a larger buffer was returned. */ pxNetworkBuffer->xDataLength = len; - pxNetworkBuffer->pxInterface = pxMyInterface; - pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxNetworkBuffer ); + pxNetworkBuffer->pxInterface = pxInterface; + pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxInterface, buffer ); /* Copy the packet data. */ memcpy( pxNetworkBuffer->pucEthernetBuffer, buffer, len ); @@ -218,7 +200,7 @@ static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) return ESP_FAIL; } - esp_wifi_internal_free_rx_buffer( eb ); + esp_netif_free_rx_buffer(pxInterface->pvArgument, eb ); return ESP_OK; } else { ESP_LOGE( TAG, "Failed to get buffer descriptor" ); @@ -226,10 +208,19 @@ static esp_err_t wifi_rc_cb(void *buffer, uint16_t len, void *eb) } } -void vNetworkNotifyIFUp() +void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface) { - xInterfaceState = INTERFACE_UP; - if (esp_wifi_internal_reg_rxcb(WIFI_IF_STA, wifi_rc_cb) != ESP_OK) { - ESP_LOGE( TAG, "Failed to register wifi callback" ); - } + pxInterface->bits.bInterfaceUp = 1; + IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; + xRxEvent.pvData = pxInterface; + xSendEventStructToIPTask( &xRxEvent, 0 ); + + +// pxInterface->bits.bInterfaceUp = 1; +// xInterfaceState = INTERFACE_UP; +// IPStackEvent_t xRxEvent = { eNetworkDownEvent, NULL }; +// xSendEventStructToIPTask( &xRxEvent, 0 ); +// if (esp_wifi_internal_reg_rxcb(WIFI_IF_STA, wifi_rc_cb) != ESP_OK) { +// ESP_LOGE( TAG, "Failed to register wifi callback" ); +// } } diff --git a/components/freertos_tcp/port/include/FreeRTOSIPConfig.h b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h index cb8c652444..cdcb654894 100644 --- a/components/freertos_tcp/port/include/FreeRTOSIPConfig.h +++ b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h @@ -40,12 +40,22 @@ #ifndef FREERTOS_IP_CONFIG_H #define FREERTOS_IP_CONFIG_H + +#ifdef CONFIG_AFPT_IPV4 #define ipconfigUSE_IPv4 ( 1 ) +#else +#define ipconfigUSE_IPv4 ( 0 ) +#endif +#ifdef CONFIG_AFPT_IPV6 +#define ipconfigUSE_IPv6 ( 1 ) +#else #define ipconfigUSE_IPv6 ( 0 ) +#endif #define ipconfigUSE_DHCPv6 0 -#define ipconfigIPv4_BACKWARD_COMPATIBLE 1 +#define ipconfigUSE_RA 1 +#define ipconfigIPv4_BACKWARD_COMPATIBLE 0 #define ipconfigUSE_ARP_REVERSED_LOOKUP 1 #define ipconfigUSE_ARP_REMOVE_ENTRY 1 #define ipconfigARP_STORES_REMOTE_ADDRESSES 1 From 35faf514245ea66b64e3e849787c8cdd3ef018db Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2024 12:00:35 +0200 Subject: [PATCH 3/4] fix(aft_netif): Working sample with static buffers --- components/freertos_tcp/CMakeLists.txt | 16 +- components/freertos_tcp/FreeRTOS-Plus-TCP | 2 +- .../freertos_tcp/esp_netif/esp_netif_impl.c | 149 ++++---- .../examples/simple/main/CMakeLists.txt | 18 +- .../examples/simple/main/Kconfig.projbuild | 16 + .../examples/simple/main/hello_world_main.c | 357 ------------------ .../examples/simple/main/tcp_client.c | 77 ++++ .../freertos_tcp/port/FreeRTOS_AppHooks.c | 91 +++++ .../freertos_tcp/port/NetworkInterface.c | 2 +- .../port/include/FreeRTOSIPConfig.h | 2 +- 10 files changed, 286 insertions(+), 444 deletions(-) create mode 100644 components/freertos_tcp/examples/simple/main/Kconfig.projbuild delete mode 100644 components/freertos_tcp/examples/simple/main/hello_world_main.c create mode 100644 components/freertos_tcp/examples/simple/main/tcp_client.c create mode 100644 components/freertos_tcp/port/FreeRTOS_AppHooks.c diff --git a/components/freertos_tcp/CMakeLists.txt b/components/freertos_tcp/CMakeLists.txt index b8d15e0b61..f4a8ea093b 100644 --- a/components/freertos_tcp/CMakeLists.txt +++ b/components/freertos_tcp/CMakeLists.txt @@ -1,6 +1,5 @@ -set(fdir /home/david/esp/idf/components/freertos/FreeRTOS-Kernel/include/freertos) -set(wdir /home/david/esp/idf/components/esp_wifi/include) -set(fcdir /home/david/esp/idf/components/freertos/config/include/freertos) +set(fdir $ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos) +set(fcdir $ENV{IDF_PATH}/components/freertos/config/include/freertos) set(fpt_dir FreeRTOS-Plus-TCP/source) set(fpt_include_dir ${fpt_dir}/include ${fpt_dir}/portable/Compiler/GCC/) @@ -47,17 +46,18 @@ set(fpt_srcs ${fpt_dir}/FreeRTOS_ARP.c ${fpt_dir}/FreeRTOS_UDP_IP.c ${fpt_dir}/FreeRTOS_UDP_IPv4.c ${fpt_dir}/FreeRTOS_UDP_IPv6.c -# ${fpt_dir}/portable/NetworkInterface/esp32/NetworkInterface.c ${fpt_dir}/portable/BufferManagement/BufferAllocation_1.c ) - -idf_component_register(SRCS ${fpt_srcs} port/FreeRTOSIPConfig.c port/NetworkInterface.c +idf_component_register(SRCS ${fpt_srcs} + port/FreeRTOSIPConfig.c + port/NetworkInterface.c + port/FreeRTOS_AppHooks.c esp_netif/defaults.c esp_netif/interface.c esp_netif/esp_netif_impl.c - INCLUDE_DIRS "port/include" - PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${fpt_include_dir} ${wdir} + INCLUDE_DIRS "port/include" ${fpt_include_dir} ${fdir} + PRIV_INCLUDE_DIRS ${fcdir} PRIV_REQUIRES esp_wifi esp_netif) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/freertos_tcp/FreeRTOS-Plus-TCP b/components/freertos_tcp/FreeRTOS-Plus-TCP index a209cfcc74..d12c0d5c2e 160000 --- a/components/freertos_tcp/FreeRTOS-Plus-TCP +++ b/components/freertos_tcp/FreeRTOS-Plus-TCP @@ -1 +1 @@ -Subproject commit a209cfcc74064ced9d199481b8aed3ba1668e62e +Subproject commit d12c0d5c2e3fcc851eb2099fa10cf44bcfe7257b diff --git a/components/freertos_tcp/esp_netif/esp_netif_impl.c b/components/freertos_tcp/esp_netif/esp_netif_impl.c index d0143191db..93e4a4f174 100644 --- a/components/freertos_tcp/esp_netif/esp_netif_impl.c +++ b/components/freertos_tcp/esp_netif/esp_netif_impl.c @@ -3,9 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -// -// Created by david on 6/17/24. -// #include "esp_netif.h" #include "esp_netif_net_stack.h" #include "interface.h" @@ -16,16 +13,16 @@ #define MAX_ENDPOINTS_PER_NETIF 4 static const char *TAG = "esp_netif_AFpT"; -static bool s_netif_initialized = false; +static bool s_netif_initialized = false; +static bool s_FreeRTOS_IP_started = false; struct esp_netif_stack { esp_netif_netstack_config_t config; NetworkInterface_t aft_netif; - NetworkEndPoint_t xEndPoints[MAX_ENDPOINTS_PER_NETIF]; + NetworkEndPoint_t endpoints[MAX_ENDPOINTS_PER_NETIF]; }; - struct esp_netif_obj { uint8_t mac[6]; // io driver related @@ -36,25 +33,26 @@ struct esp_netif_obj { // stack related struct esp_netif_stack *net_stack; + // misc flags, types, keys, priority esp_netif_flags_t flags; char *hostname; char *if_key; char *if_desc; int route_prio; + uint32_t got_ip_event; + uint32_t lost_ip_event; }; -static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - -/* Define the network addressing. These parameters will be used if either - ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration - failed. */ -static const uint8_t ucIPAddress[ 4 ] = { 10, 10, 10, 200 }; -static const uint8_t ucNetMask[ 4 ] = { 255, 0, 0, 0 }; -static const uint8_t ucGatewayAddress[ 4 ] = { 10, 10, 10, 1 }; -static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 }; +static inline void ip4_to_afpt_ip(const esp_ip4_addr_t *ip, uint8_t afpt_ip[4]) +{ + afpt_ip[0] = esp_ip4_addr1(ip); + afpt_ip[1] = esp_ip4_addr2(ip); + afpt_ip[2] = esp_ip4_addr3(ip); + afpt_ip[4] = esp_ip4_addr4(ip); +} -void *esp_netif_new_netstack_if(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *cfg) +struct esp_netif_stack *esp_netif_new_netstack_if(esp_netif_t *esp_netif, const esp_netif_inherent_config_t *base_cfg, const esp_netif_netstack_config_t *cfg) { static int netif_count = 0; struct esp_netif_stack *netif = calloc(1, sizeof(struct esp_netif_stack)); @@ -66,13 +64,22 @@ void *esp_netif_new_netstack_if(esp_netif_t *esp_netif, const esp_netif_netstack free(netif); return NULL; } -// ESP_LOGW(TAG, "%d %p", netif_count, netif->config.init_fn); -// FreeRTOS_IPInit_Multi(); - FreeRTOS_FillEndPoint( &( netif->aft_netif ), &( netif->xEndPoints[0]), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); - netif->xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE; + + uint8_t ip[4] = { 0 }, mask[4] = { 0 }, gw[4] = { 0 }, dns[4] = { 0 }; + if (base_cfg->ip_info) { + ip4_to_afpt_ip(&base_cfg->ip_info->ip, ip); + ip4_to_afpt_ip(&base_cfg->ip_info->netmask, mask); + ip4_to_afpt_ip(&base_cfg->ip_info->gw, gw); + } + FreeRTOS_FillEndPoint( &( netif->aft_netif ), &( netif->endpoints[0]), ip, mask, gw, dns, base_cfg->mac ); + if (base_cfg->flags & ESP_NETIF_DHCP_CLIENT) { + netif->endpoints[0].bits.bWantDHCP = pdTRUE; + } netif->aft_netif.bits.bInterfaceUp = 0; - // netif->xEndPoints[ 0 ].bits.bEndPointUp = pdFALSE; - FreeRTOS_IPInit_Multi(); + if (!s_FreeRTOS_IP_started) { + s_FreeRTOS_IP_started = true; + FreeRTOS_IPInit_Multi(); + } netif->aft_netif.pvArgument = esp_netif; netif->config.input_fn = cfg->input_fn; @@ -83,20 +90,11 @@ void *esp_netif_new_netstack_if(esp_netif_t *esp_netif, const esp_netif_netstack esp_err_t esp_netif_receive(esp_netif_t *esp_netif, void *buffer, size_t len, void *eb) { struct esp_netif_stack *netif = esp_netif->net_stack; -// ESP_LOGW(TAG, "esp_netif_receive() %d %p", len, netif->config.input_fn); return netif->config.input_fn(&netif->aft_netif, buffer, len, eb); } void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface); -//esp_err_t esp_netif_update_netstack_if(void* netif, esp_netif_status_update_t status) -//{ -// if (status == ESP_NETIF_STATUS_CONNECTED) { -// vNetworkNotifyIFUp(); -// } -// return ESP_OK; -//} - void esp_netif_set_ip4_addr(esp_ip4_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d) { memset(addr, 0, sizeof(esp_ip4_addr_t)); @@ -105,7 +103,8 @@ void esp_netif_set_ip4_addr(esp_ip4_addr_t *addr, uint8_t a, uint8_t b, uint8_t char *esp_ip4addr_ntoa(const esp_ip4_addr_t *addr, char *buf, int buflen) { - return NULL; + FreeRTOS_inet_ntoa(addr->addr, buf); + return buf; } esp_netif_iodriver_handle esp_netif_get_io_driver(esp_netif_t *esp_netif) @@ -115,17 +114,17 @@ esp_netif_iodriver_handle esp_netif_get_io_driver(esp_netif_t *esp_netif) esp_netif_t *esp_netif_get_handle_from_netif_impl(void *dev) { - return NULL; + NetworkInterface_t *netif = dev; + return (esp_netif_t *)netif->pvArgument; } esp_err_t esp_netif_init(void) { - ESP_LOGI(TAG, "loopback initialization"); + ESP_LOGI(TAG, "esp_netif AFpT initialization"); if (s_netif_initialized) { ESP_LOGE(TAG, "esp-netif has already been initialized"); - return ESP_ERR_INVALID_SIZE; + return ESP_ERR_INVALID_ARG; } - s_netif_initialized = true; ESP_LOGD(TAG, "esp-netif has been successfully initialized"); return ESP_OK; @@ -133,7 +132,7 @@ esp_err_t esp_netif_init(void) esp_err_t esp_netif_deinit(void) { - ESP_LOGI(TAG, "loopback initialization"); + ESP_LOGI(TAG, "esp_netif AFpT deinit"); if (!s_netif_initialized) { ESP_LOGE(TAG, "esp-netif has not been initialized yet"); return ESP_ERR_INVALID_SIZE; @@ -162,9 +161,11 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_ if (cfg->base->route_prio) { esp_netif->route_prio = cfg->base->route_prio; } + esp_netif->got_ip_event = cfg->base->get_ip_event; + esp_netif->lost_ip_event = cfg->base->lost_ip_event; // Network stack configs - esp_netif->net_stack = esp_netif_new_netstack_if(esp_netif, cfg->stack); + esp_netif->net_stack = esp_netif_new_netstack_if(esp_netif, cfg->base, cfg->stack); // Install IO functions only if provided -- connects driver and netif // this configuration could be updated after esp_netif_new(), typically in post_attach callback @@ -203,9 +204,6 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) return NULL; } - // creating another ip info (to store old ip) -// esp_netif_add_to_list_unsafe(esp_netif); - // Configure the created object with provided configuration esp_err_t ret = esp_netif_init_configuration(esp_netif, esp_netif_config); if (ret != ESP_OK) { @@ -220,7 +218,6 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) void esp_netif_destroy(esp_netif_t *esp_netif) { if (esp_netif) { -// esp_netif_remove_from_list_unsafe(esp_netif); free(esp_netif->if_key); free(esp_netif->if_desc); free(esp_netif); @@ -258,20 +255,13 @@ esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t ucMACAddress[]) { ESP_LOGI(TAG, "esp_netif_set_mac()"); memcpy(esp_netif->mac, ucMACAddress, 6); -// uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ]; - -// FreeRTOS_UpdateMACAddress( ucMACAddress ); - return ESP_OK; } esp_err_t esp_netif_start(esp_netif_t *esp_netif) { ESP_LOGI(TAG, "Netif started"); - memcpy(&esp_netif->net_stack->xEndPoints->xMACAddress, esp_netif->mac, 6); -// FreeRTOS_UpdateMACAddress( esp_netif->mac ); - -// vNetworkNotifyIFUp(&esp_netif->net_stack->aft_netif); + memcpy(&esp_netif->net_stack->endpoints[0].xMACAddress, esp_netif->mac, 6); return ESP_OK; } @@ -293,18 +283,19 @@ void esp_netif_free_rx_buffer(void *h, void *buffer) esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void *data, size_t len) { - ESP_LOGW(TAG, "Transmitting data: ptr:%p, size:%lu", data, (long unsigned int) len); + ESP_LOGD(TAG, "Transmitting data: ptr:%p, size:%lu", data, (long unsigned int) len); return (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len); } esp_err_t esp_netif_dhcpc_stop(esp_netif_t *esp_netif) { - return ESP_ERR_NOT_SUPPORTED; + esp_netif->net_stack->endpoints[0].bits.bWantDHCP = pdFALSE; + return ESP_OK; } esp_err_t esp_netif_dhcpc_start(esp_netif_t *esp_netif) { -// esp_netif->net_stack->xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE; + esp_netif->net_stack->endpoints[0].bits.bWantDHCP = pdTRUE; return ESP_OK; } @@ -331,12 +322,15 @@ esp_err_t esp_netif_dhcps_stop(esp_netif_t *esp_netif) esp_err_t esp_netif_set_hostname(esp_netif_t *esp_netif, const char *hostname) { - return ESP_ERR_NOT_SUPPORTED; + free(esp_netif->hostname); + esp_netif->hostname = strdup(hostname); + return ESP_OK; } esp_err_t esp_netif_get_hostname(esp_netif_t *esp_netif, const char **hostname) { - return ESP_ERR_NOT_SUPPORTED; + *hostname = esp_netif->hostname; + return ESP_OK; } esp_err_t esp_netif_up(esp_netif_t *esp_netif) @@ -345,20 +339,21 @@ esp_err_t esp_netif_up(esp_netif_t *esp_netif) struct esp_netif_stack *netif = esp_netif->net_stack; netif->aft_netif.bits.bInterfaceUp = 1; vNetworkNotifyIFUp(&esp_netif->net_stack->aft_netif); - -// vNetworkNotifyIFUp(); return ESP_OK; } esp_err_t esp_netif_down(esp_netif_t *esp_netif) { ESP_LOGI(TAG, "Netif going down"); + struct esp_netif_stack *netif = esp_netif->net_stack; + netif->aft_netif.bits.bInterfaceUp = 0; return ESP_OK; } bool esp_netif_is_netif_up(esp_netif_t *esp_netif) { - return false; + struct esp_netif_stack *netif = esp_netif->net_stack; + return (netif->aft_netif.bits.bInterfaceUp == pdTRUE_UNSIGNED) ? true : false; } esp_err_t esp_netif_get_old_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) @@ -370,8 +365,13 @@ esp_err_t esp_netif_get_old_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) { ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif); - - return ESP_ERR_NOT_SUPPORTED; + uint32_t ulIPAddress = 0, ulNetMask, ulGatewayAddress, ulDNSServerAddress; + struct esp_netif_stack *netif = esp_netif->net_stack; + FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, netif->aft_netif.pxEndPoint ); + ip_info->ip.addr = ulIPAddress; + ip_info->netmask.addr = ulNetMask; + ip_info->gw.addr = ulGatewayAddress; + return ESP_OK; } bool esp_netif_is_valid_static_ip(esp_netif_ip_info_t *ip_info) @@ -511,11 +511,7 @@ void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, /* Print out the network configuration, which may have come from a DHCP * server. */ -#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) - FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxNetworkEndPoints ); -#else - FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); -#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ + FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxEndPoint ); FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); printf( "\r\n\r\nIP Address: %s\r\n", cBuffer ); @@ -527,15 +523,16 @@ void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); printf( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ); + esp_netif_t *esp_netif = pxEndPoint->pxNetworkInterface->pvArgument; ip_event_got_ip_t evt = { - .esp_netif = pxEndPoint->pxNetworkInterface->pvArgument, + .esp_netif = esp_netif, .ip_changed = false, }; evt.ip_info.ip.addr = ulIPAddress; evt.ip_info.gw.addr = ulGatewayAddress; evt.ip_info.netmask.addr = ulNetMask; - esp_err_t ret = esp_event_post(IP_EVENT, IP_EVENT_STA_GOT_IP, &evt, sizeof(evt), 0); + esp_err_t ret = esp_event_post(IP_EVENT, esp_netif->got_ip_event, &evt, sizeof(evt), 0); if (ESP_OK != ret) { ESP_LOGE(TAG, "dhcpc cb: failed to post got ip event (%x)", ret); } @@ -543,3 +540,21 @@ void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, printf( "Application idle hook network down\n" ); } } + +BaseType_t xApplicationDNSQueryHook_Multi( struct xNetworkEndPoint *pxEndPoint, const char *pcName ) +{ + BaseType_t xReturn; + + esp_netif_t *esp_netif = pxEndPoint->pxNetworkInterface->pvArgument; + /* 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 ( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) { + xReturn = pdPASS; + } else if ( strcasecmp( pcName, esp_netif->hostname ) == 0 ) { + xReturn = pdPASS; + } else { + xReturn = pdFAIL; + } + return xReturn; +} diff --git a/components/freertos_tcp/examples/simple/main/CMakeLists.txt b/components/freertos_tcp/examples/simple/main/CMakeLists.txt index 7cd056ead5..b5dde314ec 100644 --- a/components/freertos_tcp/examples/simple/main/CMakeLists.txt +++ b/components/freertos_tcp/examples/simple/main/CMakeLists.txt @@ -1,13 +1,13 @@ -set(fdir /home/david/esp/idf/components/freertos/FreeRTOS-Kernel/include/freertos) -set(wdir /home/david/esp/idf/components/esp_wifi/include) -set(fcdir /home/david/esp/idf/components/freertos/config/include/freertos) -set(dir /home/david/temp/FreeRTOS-Plus-TCP/source) -set(idir ${dir}/include ${dir}/portable/Compiler/GCC/) +#set(fdir /home/david/esp/idf/components/freertos/FreeRTOS-Kernel/include/freertos) +#set(wdir /home/david/esp/idf/components/esp_wifi/include) +#set(fcdir /home/david/esp/idf/components/freertos/config/include/freertos) +#set(dir /home/david/temp/FreeRTOS-Plus-TCP/source) +#set(idir ${dir}/include ${dir}/portable/Compiler/GCC/) -idf_component_register(SRCS "hello_world_main.c" ${srcs} - PRIV_REQUIRES spi_flash esp_wifi nvs_flash - PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${idir} ${wdir} . +idf_component_register(SRCS "tcp_client.c" + PRIV_REQUIRES freertos_tcp +# PRIV_INCLUDE_DIRS ${fdir} ${fcdir} ${idir} ${wdir} . INCLUDE_DIRS "") -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") +#target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/freertos_tcp/examples/simple/main/Kconfig.projbuild b/components/freertos_tcp/examples/simple/main/Kconfig.projbuild new file mode 100644 index 0000000000..99010e8a6c --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/Kconfig.projbuild @@ -0,0 +1,16 @@ +menu "Example Configuration" + + config EXAMPLE_HOSTNAME + string "hostname to connect to" + default "httpbin.org" + help + The example will connect to this hostname. + + config EXAMPLE_PORT + int "Port" + range 0 65535 + default 80 + help + The remote port to which the client example will connect to. + +endmenu diff --git a/components/freertos_tcp/examples/simple/main/hello_world_main.c b/components/freertos_tcp/examples/simple/main/hello_world_main.c deleted file mode 100644 index c54a1f2b5e..0000000000 --- a/components/freertos_tcp/examples/simple/main/hello_world_main.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: CC0-1.0 - */ - -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_chip_info.h" -#include "esp_flash.h" -#include "esp_system.h" -#include "FreeRTOS_IP.h" -#include "FreeRTOS_Sockets.h" -#include "time.h" -#include "esp_log.h" -#include "nvs_flash.h" -#include "esp_event.h" -#include "esp_netif.h" -#include "protocol_examples_common.h" - -#define TAG "wifi-connect" - -#if 1 - -#define mainHOST_NAME "RTOSDemo" -#define mainDEVICE_NICK_NAME "esp_demo" - - -/* The MAC address array is not declared const as the MAC address will - normally be read from an EEPROM and not hard coded (in real deployed - applications).*/ -static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - -/* Define the network addressing. These parameters will be used if either - ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration - failed. */ -static const uint8_t ucIPAddress[ 4 ] = { 10, 10, 10, 200 }; -static const uint8_t ucNetMask[ 4 ] = { 255, 0, 0, 0 }; -static const uint8_t ucGatewayAddress[ 4 ] = { 10, 10, 10, 1 }; -static UBaseType_t ulNextRand; - -/* The following is the address of an OpenDNS server. */ -static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 }; -static NetworkInterface_t xInterfaces[ 1 ]; - -/* It will have several end-points. */ -static NetworkEndPoint_t xEndPoints[ 4 ]; -#endif - -static void wifi_init_sta(void); - -NetworkInterface_t *pxESP32_Eth_FillInterfaceDescriptor( BaseType_t xEMACIndex, - NetworkInterface_t *pxInterface ); - -void app_main(void) -{ - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. - * Read "Establishing Wi-Fi or Ethernet Connection" section in - * examples/protocols/README.md for more information about this function. - */ - ESP_ERROR_CHECK(example_connect()); - return; - - - printf("Hello world!\n"); - pxESP32_Eth_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 ) */ - - FreeRTOS_IPInit_Multi(); - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(); - - return; - // extern NetworkInterface_t * pxLibslirp_FillInterfaceDescriptor( BaseType_t xEMACIndex, - // NetworkInterface_t * pxInterface ); - - /* Print chip information */ - esp_chip_info_t chip_info; - uint32_t flash_size; - esp_chip_info(&chip_info); - printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", - CONFIG_IDF_TARGET, - chip_info.cores, - (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", - (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", - (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", - (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); - - unsigned major_rev = chip_info.revision / 100; - unsigned minor_rev = chip_info.revision % 100; - printf("silicon revision v%d.%d, ", major_rev, minor_rev); - if (esp_flash_get_size(NULL, &flash_size) != ESP_OK) { - printf("Get flash size failed"); - return; - } - - printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), - (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); - - printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); - - for (int i = 10; i >= 0; i--) { - printf("Restarting in %d seconds...\n", i); - vTaskDelay(1000 / portTICK_PERIOD_MS); - } - printf("Restarting now.\n"); - fflush(stdout); - esp_restart(); -} - - - -/*-----------------------------------------------------------*/ - -UBaseType_t uxRand( void ) -{ - const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; - - /* Utility function to generate a pseudo random number. */ - - ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; - return ( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); -} -/*-----------------------------------------------------------*/ - -/*-----------------------------------------------------------*/ - -#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 ) - -#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) -BaseType_t xApplicationDNSQueryHook_Multi( struct xNetworkEndPoint *pxEndPoint, - const char *pcName ) -#else -BaseType_t xApplicationDNSQueryHook( const char *pcName ) -#endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */ -{ - 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 ( strcasecmp( pcName, pcApplicationHostnameHook() ) == 0 ) { - xReturn = pdPASS; - } else if ( strcasecmp( 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 ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 ) - -/* - * The stack will call this user hook for all Ethernet frames that it - * does not support, i.e. other than IPv4, IPv6 and ARP ( for the moment ) - * If this hook returns eReleaseBuffer or eProcessBuffer, the stack will - * release and reuse the network buffer. If this hook returns - * eReturnEthernetFrame, that means user code has reused the network buffer - * to generate a response and the stack will send that response out. - * If this hook returns eFrameConsumed, the user code has ownership of the - * network buffer and has to release it when it's done. - */ -eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t *const pxNetworkBuffer ) -{ - ( void ) ( pxNetworkBuffer ); - return eProcessBuffer; -} - -#endif -void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, - uint16_t usIdentifier ) -{ - /* Provide a stub for this function. */ -} - -eDHCPCallbackAnswer_t xApplicationDHCPHook_Multi( eDHCPCallbackPhase_t eDHCPPhase, - struct xNetworkEndPoint *pxEndPoint, - IP_Address_t *pxIPAddress ) -{ - ( void ) eDHCPPhase; - ( void ) pxIPAddress; - - return eDHCPContinue; -} - - - -#define NETWORK_BUFFER_SIZE 1536 -static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ NETWORK_BUFFER_SIZE ]; - - -/* Next provide the vNetworkInterfaceAllocateRAMToBuffers() function, which - * simply fills in the pucEthernetBuffer member of each descriptor. */ -void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) -{ - BaseType_t x; - - for ( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) { - /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the - * beginning of the allocated buffer. */ - pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] ); - - /* The following line is also required, but will not be required in - * future versions. */ - *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) & ( pxNetworkBuffers[ x ] ); - } -} - -#include "esp_system.h" -#include "esp_wifi.h" -#include "esp_event.h" -#include "esp_log.h" -#include "nvs_flash.h" -//void vNetworkNotifyIFUp(); -void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface); -static EventGroupHandle_t s_wifi_event_group; -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_FAIL_BIT BIT1 - -static void event_handler(void *arg, esp_event_base_t event_base, - int32_t event_id, void *event_data) -{ - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - esp_wifi_connect(); - vNetworkNotifyIFUp(&xInterfaces[0]); - } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - esp_wifi_connect(); - ESP_LOGI(TAG, "connect to the AP fail"); - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; - ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); - xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - } -} - -static void wifi_init_sta(void) -{ - s_wifi_event_group = xEventGroupCreate(); - - - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - esp_event_handler_instance_t instance_any_id; - esp_event_handler_instance_t instance_got_ip; - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - ESP_EVENT_ANY_ID, - &event_handler, - NULL, - &instance_any_id)); - ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, - IP_EVENT_STA_GOT_IP, - &event_handler, - NULL, - &instance_got_ip)); - - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_EXAMPLE_WIFI_SSID, - .password = CONFIG_EXAMPLE_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); - ESP_ERROR_CHECK(esp_wifi_start() ); - - ESP_LOGI(TAG, "wifi_init_sta finished."); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) { - ESP_LOGI(TAG, "connected to ap SSID password"); - } else if (bits & WIFI_FAIL_BIT) { - ESP_LOGI(TAG, "Failed to connect"); - } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); - } -} diff --git a/components/freertos_tcp/examples/simple/main/tcp_client.c b/components/freertos_tcp/examples/simple/main/tcp_client.c new file mode 100644 index 0000000000..0a36b035ab --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/tcp_client.c @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "protocol_examples_common.h" + +static const char *TAG = "AFpT_tcp_client"; + +void app_main(void) +{ + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(example_connect()); + + Socket_t sock = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP); + if (sock == FREERTOS_INVALID_SOCKET) { + ESP_LOGE(TAG, "Unable to create socket"); + return; + } + struct freertos_sockaddr addr; + struct freertos_addrinfo *results = NULL; + struct freertos_addrinfo hints = { .ai_family = FREERTOS_AF_INET }; + NetworkEndPoint_t *pxEndPoint = FreeRTOS_FindGateWay( ipTYPE_IPv4 ); + + if ( ( pxEndPoint != NULL ) && ( pxEndPoint->ipv4_settings.ulGatewayAddress != 0U ) ) { + xARPWaitResolution( pxEndPoint->ipv4_settings.ulGatewayAddress, pdMS_TO_TICKS( 1000U ) ); + } + BaseType_t rc = FreeRTOS_getaddrinfo( + CONFIG_EXAMPLE_HOSTNAME, /* The node. */ + NULL, /* const char *pcService: ignored for now. */ + &hints, /* If not NULL: preferences. */ + &results ); /* An allocated struct, containing the results. */ + ESP_LOGI(TAG, "FreeRTOS_getaddrinfo() returned rc: %d", rc ); + if ( ( rc != 0 ) || ( results == NULL ) || results->ai_family != FREERTOS_AF_INET4 ) { + ESP_LOGI(TAG, "Failed to lookup IPv4"); + return; + } + addr.sin_len = sizeof( struct freertos_sockaddr ); + addr.sin_family = FREERTOS_AF_INET; + addr.sin_port = FreeRTOS_htons( CONFIG_EXAMPLE_PORT ); + addr.sin_address.ulIP_IPv4 = results->ai_addr->sin_address.ulIP_IPv4;; + rc = FreeRTOS_connect( sock, &addr, sizeof( addr ) ); + ESP_LOGI(TAG, "Connecting to %" PRIx32 " %d", addr.sin_address.ulIP_IPv4, rc); + const char *payload = "GET / HTTP/1.1\r\n\r\n"; + char rx_buffer[128] = {0}; + rc = FreeRTOS_send(sock, payload, strlen(payload), 0); + if (rc < 0) { + ESP_LOGE(TAG, "Error occurred during sending: rc: %d", rc); + return; + } + ESP_LOGI(TAG, "Sending finished with: rc %d", rc); + rc = FreeRTOS_recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (rc < 0) { + ESP_LOGE(TAG, "Error occurred during receiving: rc %d", rc); + return; + } else { + ESP_LOGI(TAG, "Receiving finished with: rc %d", rc); + if (rc > 0) { + rx_buffer[rc] = 0; // Null-terminate whatever we received and treat like a string + ESP_LOGI(TAG, "%s", rx_buffer); + } + } + FreeRTOS_closesocket(sock); +} diff --git a/components/freertos_tcp/port/FreeRTOS_AppHooks.c b/components/freertos_tcp/port/FreeRTOS_AppHooks.c new file mode 100644 index 0000000000..28ac25272f --- /dev/null +++ b/components/freertos_tcp/port/FreeRTOS_AppHooks.c @@ -0,0 +1,91 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_random.h" +#include "FreeRTOS.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" + +#define mainHOST_NAME "espressif" + + +UBaseType_t uxRand( void ) +{ + return esp_random(); +} + +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(); +} + +BaseType_t xApplicationGetRandomNumber( uint32_t *pulNumber ) +{ + *( pulNumber ) = uxRand(); + return pdTRUE; +} + +#if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 ) +eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t *const pxNetworkBuffer ) +{ + ( void ) ( pxNetworkBuffer ); + return eProcessBuffer; +} +#endif + +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, + uint16_t usIdentifier ) +{ +} + +eDHCPCallbackAnswer_t xApplicationDHCPHook_Multi( eDHCPCallbackPhase_t eDHCPPhase, + struct xNetworkEndPoint *pxEndPoint, + IP_Address_t *pxIPAddress ) +{ + ( void ) eDHCPPhase; + ( void ) pxIPAddress; + + return eDHCPContinue; +} + +// TODO: Make this netif specific once AFpT supports it +const char *pcApplicationHostnameHook( void ) +{ + return mainHOST_NAME; +} + +/*-----------------------------------------------------------*/ +// Network buffer management +// TODO: Make this based on Kconfig option (static-buffer) and support dynamic allocation +#define NETWORK_BUFFER_SIZE 1536 +static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ NETWORK_BUFFER_SIZE ]; +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + BaseType_t x; + + for ( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) { + /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the + * beginning of the allocated buffer. */ + pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] ); + + /* The following line is also required, but will not be required in + * future versions. */ + *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) & ( pxNetworkBuffers[ x ] ); + } +} diff --git a/components/freertos_tcp/port/NetworkInterface.c b/components/freertos_tcp/port/NetworkInterface.c index 6f97de881f..29f5fc395e 100644 --- a/components/freertos_tcp/port/NetworkInterface.c +++ b/components/freertos_tcp/port/NetworkInterface.c @@ -175,7 +175,7 @@ esp_err_t xESP32_Eth_NetworkInterfaceInput(NetworkInterface_t *pxInterface, void vPrintResourceStats(); } #endif /* ( ipconfigHAS_PRINTF != 0 ) */ - +// ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_INFO); if ( eConsiderFrameForProcessing( buffer ) != eProcessBuffer ) { ESP_LOGD( TAG, "Dropping packet" ); esp_netif_free_rx_buffer(pxInterface->pvArgument, eb ); diff --git a/components/freertos_tcp/port/include/FreeRTOSIPConfig.h b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h index cdcb654894..484df04fab 100644 --- a/components/freertos_tcp/port/include/FreeRTOSIPConfig.h +++ b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h @@ -261,7 +261,7 @@ #define ipconfigTCP_TIME_TO_LIVE 128 /* USE_TCP: Use TCP and all its features. */ -#define ipconfigUSE_TCP ( 0 ) +#define ipconfigUSE_TCP ( 1 ) /* USE_WIN: Let TCP use windowing mechanism. */ #define ipconfigUSE_TCP_WIN ( 1 ) From 97a4cf0b7af76f3e664a38418bf4b966564bbbee Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 20 Jun 2024 12:24:31 +0200 Subject: [PATCH 4/4] fix(aft_netif): Made Ethernet common connect working --- components/freertos_tcp/CMakeLists.txt | 1 - components/freertos_tcp/esp_netif/defaults.c | 16 ---------------- .../freertos_tcp/esp_netif/esp_netif_impl.c | 16 ++++++++++++++++ components/freertos_tcp/esp_netif/interface.c | 1 + 4 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 components/freertos_tcp/esp_netif/defaults.c diff --git a/components/freertos_tcp/CMakeLists.txt b/components/freertos_tcp/CMakeLists.txt index f4a8ea093b..08c3dd90a8 100644 --- a/components/freertos_tcp/CMakeLists.txt +++ b/components/freertos_tcp/CMakeLists.txt @@ -53,7 +53,6 @@ idf_component_register(SRCS ${fpt_srcs} port/FreeRTOSIPConfig.c port/NetworkInterface.c port/FreeRTOS_AppHooks.c - esp_netif/defaults.c esp_netif/interface.c esp_netif/esp_netif_impl.c INCLUDE_DIRS "port/include" ${fpt_include_dir} ${fdir} diff --git a/components/freertos_tcp/esp_netif/defaults.c b/components/freertos_tcp/esp_netif/defaults.c deleted file mode 100644 index 0719a609fa..0000000000 --- a/components/freertos_tcp/esp_netif/defaults.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -// -// Created by david on 6/17/24. -// -#include "esp_netif.h" - -struct netif; - - -esp_err_t wlanif_init_ap(struct netif *netif); -esp_err_t wlanif_init_sta(struct netif *netif); -esp_err_t wlanif_input(void *h, void *buffer, size_t len, void *l2_buff); diff --git a/components/freertos_tcp/esp_netif/esp_netif_impl.c b/components/freertos_tcp/esp_netif/esp_netif_impl.c index 93e4a4f174..c9c7e149d4 100644 --- a/components/freertos_tcp/esp_netif/esp_netif_impl.c +++ b/components/freertos_tcp/esp_netif/esp_netif_impl.c @@ -482,6 +482,22 @@ esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void *ctx) return fn(ctx); } +esp_netif_t *esp_netif_find_if(esp_netif_find_predicate_t fn, void *ctx) +{ + for (NetworkInterface_t *netif = FreeRTOS_FirstNetworkInterface(); netif != NULL; netif = FreeRTOS_NextNetworkInterface(netif) ) { + esp_netif_t *esp_netif = netif->pvArgument; + if (fn(esp_netif, ctx)) { + return esp_netif; + } + } + return NULL; +} + +esp_err_t esp_netif_set_link_speed(esp_netif_t *esp_netif, uint32_t speed) +{ + return ESP_OK; +} + /* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect * events are only received if implemented in the MAC driver. */ void vApplicationIPNetworkEventHook_Multi( eIPCallbackEvent_t eNetworkEvent, diff --git a/components/freertos_tcp/esp_netif/interface.c b/components/freertos_tcp/esp_netif/interface.c index ab8a11d0ba..162d70ed22 100644 --- a/components/freertos_tcp/esp_netif/interface.c +++ b/components/freertos_tcp/esp_netif/interface.c @@ -47,3 +47,4 @@ static const struct esp_netif_netstack_config s_netif_config = { const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta = &s_netif_config; const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap = &s_netif_config; +const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth = &s_netif_config;