From 6bec0e94692620cf5219d2f0d083c3691d35fa6f Mon Sep 17 00:00:00 2001 From: Karl Osterseher Date: Sun, 26 Jan 2025 23:35:11 +0100 Subject: [PATCH] try to auto choose STA vs ETH and also choose IPv4 or IPv6 depending on config change printf to ESP_LOGI in net_functions add missing components to network interface Signed-off-by: Karl Osterseher --- .clangd | 1 + .../net_functions/include/net_functions.h | 2 +- components/net_functions/net_functions.c | 21 +- components/network_interface/CMakeLists.txt | 2 +- components/network_interface/eth_interface.c | 27 ++- .../include/network_interface.h | 9 +- .../network_interface/network_interface.c | 20 ++ main/Kconfig.projbuild | 6 + main/main.c | 192 ++++++++++++++++-- 9 files changed, 245 insertions(+), 35 deletions(-) diff --git a/.clangd b/.clangd index 22e5ea0..d8031c4 100644 --- a/.clangd +++ b/.clangd @@ -1,3 +1,4 @@ CompileFlags: CompilationDatabase: build Remove: [-m*, -f*] +InlayHints: {Enabled: false} diff --git a/components/net_functions/include/net_functions.h b/components/net_functions/include/net_functions.h index 017d7fa..2d17bb9 100644 --- a/components/net_functions/include/net_functions.h +++ b/components/net_functions/include/net_functions.h @@ -10,7 +10,7 @@ extern "C" { #define SNTP_TIMEZONE CONFIG_SNTP_TIMEZONE void net_mdns_register(const char* clientname); -void mdns_print_results(mdns_result_t* results); +void mdns_print_results(const mdns_result_t* results); // Return port number uint32_t find_mdns_service(const char* service_name, const char* proto); diff --git a/components/net_functions/net_functions.c b/components/net_functions/net_functions.c index 8741d4f..98f6680 100644 --- a/components/net_functions/net_functions.c +++ b/components/net_functions/net_functions.c @@ -33,33 +33,32 @@ void net_mdns_register(const char *clientname) { ESP_ERROR_CHECK(mdns_service_add(NULL, "_http", "_tcp", 8032, NULL, 0)); } -void mdns_print_results(mdns_result_t *results) { +void mdns_print_results(const mdns_result_t *results) { mdns_result_t *r = results; mdns_ip_addr_t *a = NULL; int i = 1, t; + while (r) { - // printf ("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], - // ip_protocol_str[r->ip_protocol]); - printf("%d: Type: %s\n", i++, ip_protocol_str[r->ip_protocol]); + ESP_LOGI(TAG, "Interface: %s", esp_netif_get_desc(r->esp_netif)); + ESP_LOGI(TAG, "Type: %s", ip_protocol_str[r->ip_protocol]); if (r->instance_name) { - printf(" PTR : %s\n", r->instance_name); + ESP_LOGI(TAG, " PTR : %s", r->instance_name); } if (r->hostname) { - printf(" SRV : %s.local:%u\n", r->hostname, r->port); + ESP_LOGI(TAG, " SRV : %s.local:%u", r->hostname, r->port); } if (r->txt_count) { - printf(" TXT : [%u] ", r->txt_count); + ESP_LOGI(TAG, " TXT : [%u] ", r->txt_count); for (t = 0; t < r->txt_count; t++) { - printf("%s=%s; ", r->txt[t].key, r->txt[t].value); + ESP_LOGI(TAG, "%s=%s; ", r->txt[t].key, r->txt[t].value); } - printf("\n"); } a = r->addr; while (a) { if (a->addr.type == IPADDR_TYPE_V6) { - printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + ESP_LOGI(TAG, " AAAA: " IPV6STR, IPV62STR(a->addr.u_addr.ip6)); } else { - printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + ESP_LOGI(TAG, " A : " IPSTR, IP2STR(&(a->addr.u_addr.ip4))); } a = a->next; } diff --git a/components/network_interface/CMakeLists.txt b/components/network_interface/CMakeLists.txt index d369f27..1d51b81 100644 --- a/components/network_interface/CMakeLists.txt +++ b/components/network_interface/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "network_interface.c" "eth_interface.c" "wifi_interface.c" INCLUDE_DIRS "include" - PRIV_REQUIRES driver esp_eth esp_netif esp_timer nvs_flash + PRIV_REQUIRES driver esp_eth esp_netif esp_timer nvs_flash improv_wifi REQUIRES esp_wifi) diff --git a/components/network_interface/eth_interface.c b/components/network_interface/eth_interface.c index fcf8e03..1f41a45 100644 --- a/components/network_interface/eth_interface.c +++ b/components/network_interface/eth_interface.c @@ -347,6 +347,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, uint8_t mac_addr[6] = {0}; /* we can get the ethernet driver handle from event data */ esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + esp_netif_t *netif = (esp_netif_t *)arg; switch (event_id) { case ETHERNET_EVENT_CONNECTED: @@ -355,6 +356,9 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + ESP_ERROR_CHECK(esp_netif_create_ip6_linklocal(netif)); + break; case ETHERNET_EVENT_DISCONNECTED: ESP_LOGI(TAG, "Ethernet Link Down"); @@ -397,10 +401,25 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, } } +static void eth_on_got_ipv6(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { + ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; + if (!network_is_our_netif(NETWORK_INTERFACE_DESC_ETH, event->esp_netif)) { + return; + } + esp_ip6_addr_type_t ipv6_type = + esp_netif_ip6_get_addr_type(&event->ip6_info.ip); + ESP_LOGI(TAG, + "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", + esp_netif_get_desc(event->esp_netif), IPV62STR(event->ip6_info.ip), + ipv6_addr_types_to_str[ipv6_type]); +} + /** Init function that exposes to the main application */ void eth_start(void) { // Initialize Ethernet driver esp_eth_handle_t *eth_handles; + esp_netif_t *eth_netif; ESP_ERROR_CHECK(eth_init(ð_handles, ð_port_cnt)); @@ -409,7 +428,7 @@ void eth_start(void) { // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and // you don't need to modify default esp-netif configuration parameters. esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); - esp_netif_t *eth_netif = esp_netif_new(&cfg); + eth_netif = esp_netif_new(&cfg); // Attach Ethernet driver to TCP/IP stack ESP_ERROR_CHECK( esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0]))); @@ -431,7 +450,7 @@ void eth_start(void) { esp_netif_config.if_key = if_key_str; esp_netif_config.if_desc = if_desc_str; esp_netif_config.route_prio -= i * 5; - esp_netif_t *eth_netif = esp_netif_new(&cfg_spi); + eth_netif = esp_netif_new(&cfg_spi); // Attach Ethernet driver to TCP/IP stack ESP_ERROR_CHECK( @@ -441,9 +460,11 @@ void eth_start(void) { // Register user defined event handers ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, - ð_event_handler, NULL)); + ð_event_handler, eth_netif)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, + ð_on_got_ipv6, NULL)); // Start Ethernet driver state machine for (int i = 0; i < eth_port_cnt; i++) { diff --git a/components/network_interface/include/network_interface.h b/components/network_interface/include/network_interface.h index 7190f03..f04b59d 100644 --- a/components/network_interface/include/network_interface.h +++ b/components/network_interface/include/network_interface.h @@ -13,8 +13,15 @@ #include "esp_netif.h" #define NETWORK_INTERFACE_DESC_STA "sta" -#define NETWORK_INTERFACE_DESC_ETH "eth" +#define NETWORK_INTERFACE_DESC_ETH \ + "eth" // this is the default value created by ESP_NETIF_DEFAULT_ETH(); + // if more than 1 Ethernet interface is configured, they are appended + // with numbers starting from 0, e.g.: eth0, eth1, ... +extern char *ipv6_addr_types_to_str[6]; + +esp_netif_t *network_get_netif_from_desc(const char *desc); +bool network_is_netif_up(esp_netif_t *esp_netif); bool network_is_our_netif(const char *prefix, esp_netif_t *netif); void network_init(void); diff --git a/components/network_interface/network_interface.c b/components/network_interface/network_interface.c index 078bad6..7ce5888 100644 --- a/components/network_interface/network_interface.c +++ b/components/network_interface/network_interface.c @@ -34,6 +34,16 @@ static const char *TAG = "NET_IF"; +/* types of ipv6 addresses to be displayed on ipv6 events */ +const char *ipv6_addr_types_to_str[6] = { + "ESP_IP6_ADDR_IS_UNKNOWN", "ESP_IP6_ADDR_IS_GLOBAL", + "ESP_IP6_ADDR_IS_LINK_LOCAL", "ESP_IP6_ADDR_IS_SITE_LOCAL", + "ESP_IP6_ADDR_IS_UNIQUE_LOCAL", "ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6"}; + +static bool netif_desc_matches_with(esp_netif_t *netif, void *ctx) { + return strcmp(ctx, esp_netif_get_desc(netif)) == 0; +} + /** * @brief Checks the netif description if it contains specified prefix. * All netifs created withing common connect component are prefixed with the @@ -43,6 +53,16 @@ bool network_is_our_netif(const char *prefix, esp_netif_t *netif) { return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix) - 1) == 0; } +/** + */ +esp_netif_t *network_get_netif_from_desc(const char *desc) { + return esp_netif_find_if(netif_desc_matches_with, (void *)desc); +} + +bool network_is_netif_up(esp_netif_t *esp_netif) { + return esp_netif_is_netif_up(esp_netif); +} + void network_init(void) { esp_netif_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 24cab05..09012cf 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -5,6 +5,12 @@ menu "Snapclient Configuration" help Use mDNS to look for the snapserver to connect to on the local network. + config SNAPCLIENT_CONNECT_IPV6 + bool "use IPv6" + default false + help + Use IPv6 to connect to snapserver + config SNAPSERVER_HOST string "Snapserver host" default "192.168.1.158" diff --git a/main/main.c b/main/main.c index ab62973..1ac886b 100644 --- a/main/main.c +++ b/main/main.c @@ -11,13 +11,16 @@ #include "esp_event.h" #include "esp_log.h" #include "esp_mac.h" +#include "esp_netif_ip_addr.h" #include "esp_system.h" #include "esp_timer.h" #include "esp_wifi.h" #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" +#include "freertos/projdefs.h" #include "freertos/task.h" #include "hal/gpio_types.h" +#include "lwip/ip_addr.h" #if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ CONFIG_SNAPCLIENT_USE_SPI_ETHERNET #include "eth_interface.h" @@ -451,7 +454,6 @@ static void http_get_task(void *pvParameters) { codec_type_t codec = NONE; snapcastSetting_t scSet; pcm_chunk_message_t *pcmData = NULL; - ip_addr_t remote_ip; uint16_t remotePort = 0; int rc1 = ERR_OK, rc2 = ERR_OK; struct netbuf *firstNetBuf = NULL; @@ -514,8 +516,33 @@ static void http_get_task(void *pvParameters) { free(serverSettingsString); serverSettingsString = NULL; } + + if (lwipNetconn != NULL) { + netconn_delete(lwipNetconn); + lwipNetconn = NULL; + } } +#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ + CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + esp_netif_t *eth_netif = + network_get_netif_from_desc(NETWORK_INTERFACE_DESC_ETH); + esp_netif_t *sta_netif = + network_get_netif_from_desc(NETWORK_INTERFACE_DESC_STA); + while (1) { + bool ethUp = network_is_netif_up(eth_netif); + bool staUp = network_is_netif_up(sta_netif); + + if (ethUp && staUp) { + break; + } + + ESP_LOGI(TAG, "Wait for WiFi and Eth"); + + vTaskDelay(pdMS_TO_TICKS(1000)); + } +#endif + #if SNAPCAST_SERVER_USE_MDNS // Find snapcast server // Connect to first snapcast server found @@ -535,21 +562,42 @@ static void http_get_task(void *pvParameters) { } } - mdns_ip_addr_t *a = r->addr; - if (a) { - ip_addr_copy(remote_ip, (a->addr)); - remote_ip.type = a->addr.type; - remotePort = r->port; - ESP_LOGI(TAG, "Found %s:%d", ipaddr_ntoa(&remote_ip), remotePort); + ESP_LOGI(TAG, "\n~~~~~~~~~~ MDNS Query success ~~~~~~~~~~"); + mdns_print_results(r); + ESP_LOGI(TAG, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); - mdns_query_results_free(r); - } else { + ip_addr_t remote_ip; + mdns_result_t *re = r; + while (re) { + mdns_ip_addr_t *a = re->addr; +#if CONFIG_SNAPCLIENT_CONNECT_IPV6 + if (a->addr.type == IPADDR_TYPE_V6) { + break; + } +#else + if (a->addr.type == IPADDR_TYPE_V4) { + break; + } +#endif + + re = re->next; + } + + if (!re) { mdns_query_results_free(r); - ESP_LOGW(TAG, "No IP found in MDNS query"); + ESP_LOGW(TAG, "didn't find any valid IP in MDNS query"); continue; } + + ip_addr_copy(remote_ip, re->addr->addr); + // remote_ip.type = a->addr.type; + remotePort = r->port; + + mdns_query_results_free(r); + + ESP_LOGI(TAG, "Found %s:%d", ipaddr_ntoa(&remote_ip), remotePort); #else // configure a failsafe snapserver according to CONFIG values struct sockaddr_in servaddr; @@ -566,19 +614,122 @@ static void http_get_task(void *pvParameters) { ipaddr_ntoa(&remote_ip), remotePort); #endif - if (lwipNetconn != NULL) { - netconn_delete(lwipNetconn); - lwipNetconn = NULL; + ip_addr_t ipAddr; + if (remote_ip.type == IPADDR_TYPE_V4) { +#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ + CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + esp_netif_ip_info_t eth_ip_info; + esp_netif_get_ip_info(eth_netif, ð_ip_info); +#endif + esp_netif_ip_info_t sta_ip_info; + esp_netif_get_ip_info(sta_netif, &sta_ip_info); + +#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ + CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + esp_netif_ip_info_t *ip_info = ð_ip_info; +#else + esp_netif_ip_info_t *ip_info = &sta_ip_info; +#endif + + ip_addr_t _ipAddr = IPADDR4_INIT(ip_info->ip.addr); + + ipAddr = _ipAddr; + + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ipAddr.u_addr.ip4.addr), str, INET_ADDRSTRLEN); + + ESP_LOGI(TAG, "IP4 %s", str); + } else if (remote_ip.type == IPADDR_TYPE_V6) { +#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ + CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + esp_netif_ip6_info_t eth_ip_info; + esp_netif_get_ip6_linklocal(eth_netif, ð_ip_info.ip); +#endif + esp_netif_ip6_info_t sta_ip_info; + esp_netif_get_ip6_linklocal(eth_netif, &sta_ip_info.ip); + +#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ + CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + esp_netif_ip6_info_t *ip_info = ð_ip_info; +#else + esp_netif_ip6_info_t *ip_info = &sta_ip_info; +#endif + ip_addr_t _ipAddr = + IPADDR6_INIT(ip_info->ip.addr[0], ip_info->ip.addr[1], + ip_info->ip.addr[2], ip_info->ip.addr[3]); + ipAddr = _ipAddr; + + char str[INET6_ADDRSTRLEN]; + // inet_ntop(AF_INET6, &(ipAddr.u_addr.ip6.addr), str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &(ip_info->ip.addr), str, INET6_ADDRSTRLEN); + + // ESP_LOGI(TAG, "Got IPv6 event: address: " IPV6STR, + // IPV62STR(ip_info->ip)); + + // ESP_LOGI(TAG, "IP6 %s", str); + } else { + ESP_LOGI(TAG, "wrong remote IP address type %u", remote_ip.type); + + continue; + } + + // /* Create a socket */ + // int sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6); + // if (sock < 0) { + // ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + // } + // ESP_LOGI(TAG, "Socket created"); + // + // esp_netif_ip6_info_t ip; + // memset(&ip, 0, sizeof(esp_netif_ip6_info_t)); + // esp_netif_get_ip6_linklocal(eth_netif, &ip.ip); + // + // struct sockaddr_in6 addr; + // memset(&addr, 0, sizeof(addr)); + // addr.sin6_family = AF_INET6; + // addr.sin6_port = htons(0); + // memcpy(&addr.sin6_addr.un.u32_addr, &ip.ip.addr, sizeof(ip.ip.addr)); + // + // int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + // if (ret < 0) { + // ESP_LOGE(TAG, "Unable to bind socket: errno %d", errno); + // } + // + // /* Connect to the host by the network interface */ + // struct sockaddr_in6 destAddr; + // memcpy(&destAddr.sin6_addr.un.u32_addr, &remote_ip.u_addr.ip6.addr, + // sizeof(remote_ip.u_addr.ip6.addr)); destAddr.sin6_family = AF_INET6; + // destAddr.sin6_port = htons(remotePort); + // ret = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); + // if (ret != 0) { + // ESP_LOGE(TAG, "Socket unable to connect: errno %d",errno); + // } + // ESP_LOGI(TAG, "Successfully connected"); + // + // + + if (remote_ip.type == IPADDR_TYPE_V4) { + lwipNetconn = netconn_new(NETCONN_TCP); + + ESP_LOGI(TAG, "netconn using IPv4"); + } else if (remote_ip.type == IPADDR_TYPE_V6) { + lwipNetconn = netconn_new(NETCONN_TCP_IPV6); + + ESP_LOGI(TAG, "netconn using IPv6"); + } else { + ESP_LOGW(TAG, "remote IP has unsupported IP type"); + + continue; } - lwipNetconn = netconn_new(NETCONN_TCP); if (lwipNetconn == NULL) { ESP_LOGE(TAG, "can't create netconn"); continue; } - rc1 = netconn_bind(lwipNetconn, IPADDR_ANY, 0); + // rc1 = netconn_bind(lwipNetconn, IP6_ADDR_ANY, 0); + rc1 = netconn_bind(lwipNetconn, &ipAddr, 0); if (rc1 != ERR_OK) { ESP_LOGE(TAG, "can't bind local IP"); } @@ -605,17 +756,22 @@ static void http_get_task(void *pvParameters) { return; } - char mac_address[18]; uint8_t base_mac[6]; // Get MAC address for WiFi station #if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \ CONFIG_SNAPCLIENT_USE_SPI_ETHERNET + char eth_mac_address[18]; + esp_read_mac(base_mac, ESP_MAC_ETH); -#else - esp_read_mac(base_mac, ESP_MAC_WIFI_STA); + sprintf(eth_mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", base_mac[0], + base_mac[1], base_mac[2], base_mac[3], base_mac[4], base_mac[5]); + ESP_LOGI(TAG, "eth mac: %s", eth_mac_address); #endif + char mac_address[18]; + esp_read_mac(base_mac, ESP_MAC_WIFI_STA); sprintf(mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", base_mac[0], base_mac[1], base_mac[2], base_mac[3], base_mac[4], base_mac[5]); + ESP_LOGI(TAG, "sta mac: %s", mac_address); now = esp_timer_get_time();