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..08c3dd90a8 --- /dev/null +++ b/components/freertos_tcp/CMakeLists.txt @@ -0,0 +1,64 @@ +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/) + +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/BufferManagement/BufferAllocation_1.c + ) + +idf_component_register(SRCS ${fpt_srcs} + port/FreeRTOSIPConfig.c + port/NetworkInterface.c + port/FreeRTOS_AppHooks.c + esp_netif/interface.c + esp_netif/esp_netif_impl.c + 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") +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/FreeRTOS-Plus-TCP b/components/freertos_tcp/FreeRTOS-Plus-TCP new file mode 160000 index 0000000000..d12c0d5c2e --- /dev/null +++ b/components/freertos_tcp/FreeRTOS-Plus-TCP @@ -0,0 +1 @@ +Subproject commit d12c0d5c2e3fcc851eb2099fa10cf44bcfe7257b 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/esp_netif_impl.c b/components/freertos_tcp/esp_netif/esp_netif_impl.c new file mode 100644 index 0000000000..c9c7e149d4 --- /dev/null +++ b/components/freertos_tcp/esp_netif/esp_netif_impl.c @@ -0,0 +1,576 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#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; +static bool s_FreeRTOS_IP_started = false; + +struct esp_netif_stack { + esp_netif_netstack_config_t config; + NetworkInterface_t aft_netif; + NetworkEndPoint_t endpoints[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; + uint32_t got_ip_event; + uint32_t lost_ip_event; +}; + +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); +} + +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)); + if (!netif) { + return NULL; + } + netif->config.init_fn = cfg->init_fn; + if (!cfg->init_fn(netif_count++, &netif->aft_netif)) { + free(netif); + return NULL; + } + + 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; + 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; + 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; + return netif->config.input_fn(&netif->aft_netif, buffer, len, eb); +} + +void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface); + +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) +{ + FreeRTOS_inet_ntoa(addr->addr, buf); + return buf; +} + +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) +{ + NetworkInterface_t *netif = dev; + return (esp_netif_t *)netif->pvArgument; +} + +esp_err_t esp_netif_init(void) +{ + ESP_LOGI(TAG, "esp_netif AFpT initialization"); + if (s_netif_initialized) { + ESP_LOGE(TAG, "esp-netif has already been initialized"); + return ESP_ERR_INVALID_ARG; + } + 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, "esp_netif AFpT deinit"); + 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; + } + 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->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 + 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; + } + + // 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) { + 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); + return ESP_OK; +} + +esp_err_t esp_netif_start(esp_netif_t *esp_netif) +{ + ESP_LOGI(TAG, "Netif started"); + memcpy(&esp_netif->net_stack->endpoints[0].xMACAddress, esp_netif->mac, 6); + 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_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) +{ + 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->endpoints[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) +{ + 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) +{ + *hostname = esp_netif->hostname; + return ESP_OK; +} + +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); + 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) +{ + 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) +{ + 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); + 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) +{ + 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); +} + +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, + 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. */ + FreeRTOS_GetEndPointConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress, pxEndPoint ); + 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 ); + esp_netif_t *esp_netif = pxEndPoint->pxNetworkInterface->pvArgument; + ip_event_got_ip_t evt = { + .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, 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); + } + } else { + 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/esp_netif/interface.c b/components/freertos_tcp/esp_netif/interface.c new file mode 100644 index 0000000000..162d70ed22 --- /dev/null +++ b/components/freertos_tcp/esp_netif/interface.c @@ -0,0 +1,50 @@ +/* + * 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; +const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth = &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/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..b5dde314ec --- /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 "tcp_client.c" + PRIV_REQUIRES freertos_tcp +# 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/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/idf_component.yml b/components/freertos_tcp/examples/simple/main/idf_component.yml new file mode 100644 index 0000000000..b1ce04939f --- /dev/null +++ b/components/freertos_tcp/examples/simple/main/idf_component.yml @@ -0,0 +1,9 @@ +## IDF Component Manager Manifest File +dependencies: + idf: + version: ">=5.3" + freertos_tcp: + version: "*" + override_path: '../../../' + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common 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/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/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 new file mode 100644 index 0000000000..29f5fc395e --- /dev/null +++ b/components/freertos_tcp/port/NetworkInterface.c @@ -0,0 +1,226 @@ +/* + * 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 "esp_netif.h" +#include "esp_netif_net_stack.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 ]; + printf("pxESP32_Eth_FillInterfaceDescriptor\n"); + + /* 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->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"); + return pxInterface->bits.bInterfaceUp ? pdTRUE : pdFALSE; +} + +static BaseType_t xESP32_Eth_GetPhyLinkStatus( NetworkInterface_t *pxInterface ) +{ + BaseType_t xResult = pdFALSE; + + if ( pxInterface->bits.bInterfaceUp) { + 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 (!(pxInterface->bits.bInterfaceUp)) { + ESP_LOGD( TAG, "Interface down" ); + ret = ESP_FAIL; + } else { + 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_VERBOSE); + } + +#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 ); + } +} +*/ + +esp_err_t xESP32_Eth_NetworkInterfaceInput(NetworkInterface_t *pxInterface, void *buffer, size_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 ) */ +// 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 ); + 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 = pxInterface; + pxNetworkBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxInterface, buffer ); + + /* 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_netif_free_rx_buffer(pxInterface->pvArgument, eb ); + return ESP_OK; + } else { + ESP_LOGE( TAG, "Failed to get buffer descriptor" ); + return ESP_FAIL; + } +} + +void vNetworkNotifyIFUp(NetworkInterface_t *pxInterface) +{ + 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 new file mode 100644 index 0000000000..484df04fab --- /dev/null +++ b/components/freertos_tcp/port/include/FreeRTOSIPConfig.h @@ -0,0 +1,369 @@ +/* + * 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 + + +#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 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 +#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 ( 1 ) + +/* 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 */