From 81756a76494c7eeb88f5452a217f7022d49ec7e4 Mon Sep 17 00:00:00 2001 From: Sebastien L Date: Tue, 16 Nov 2021 10:11:38 -0500 Subject: [PATCH] cpp state machine for ethernet --- CMakeLists.txt | 97 +- components/cpp-stateless | 1 + components/platform_console/cmd_wifi.c | 6 +- .../platform_console/platform_console.c | 11 +- components/raop/raop_sink.c | 3 +- components/raop/util.c | 2 +- components/services/accessors.c | 109 +- components/services/accessors.h | 5 +- components/services/buttons.c | 2 +- components/services/{i2s.c => i2s.c.0} | 63 +- components/services/messaging.c | 11 +- components/services/messaging.h | 7 + .../protocol_examples_common.h | 2 +- components/squeezelite-ota/squeezelite-ota.c | 3 +- components/telnet/telnet.c | 2 - components/tools/trace.h | 5 +- components/wifi-manager/CMakeLists.txt | 2 +- components/wifi-manager/Kconfig.projbuild | 180 +- components/wifi-manager/dns_server.c | 2 +- .../wifi-manager/http_server_handlers.c | 20 +- .../wifi-manager/http_server_handlers.h | 2 +- .../wifi-manager/network_driver_DM9051.c | 38 + .../wifi-manager/network_driver_LAN8720.c | 47 + .../wifi-manager/network_driver_W5500.c | 43 + components/wifi-manager/network_ethernet.c | 283 +++ components/wifi-manager/network_ethernet.h | 30 + components/wifi-manager/network_manager.c | 120 ++ .../{wifi_manager.h => network_manager.h} | 175 +- components/wifi-manager/network_status.c | 381 ++++ components/wifi-manager/network_status.h | 59 + components/wifi-manager/network_wifi.c | 990 +++++++++ components/wifi-manager/network_wifi.h | 61 + components/wifi-manager/state_machine.cpp | 793 ++++++++ components/wifi-manager/state_machine.h | 108 + components/wifi-manager/wifi_manager.c | 1803 ----------------- file-size.txt | Bin 0 -> 332410 bytes file_size.txt | Bin 0 -> 323232 bytes main/Kconfig.projbuild | 84 +- main/esp_app_main.c | 239 +-- sdkconfig | 1426 ++++++++----- sdkconfig.defaults | 6 +- squeezelite.cmake | 14 +- test/main/unit_tests.c | 2 +- 43 files changed, 4463 insertions(+), 2774 deletions(-) create mode 160000 components/cpp-stateless rename components/services/{i2s.c => i2s.c.0} (97%) create mode 100644 components/wifi-manager/network_driver_DM9051.c create mode 100644 components/wifi-manager/network_driver_LAN8720.c create mode 100644 components/wifi-manager/network_driver_W5500.c create mode 100644 components/wifi-manager/network_ethernet.c create mode 100644 components/wifi-manager/network_ethernet.h create mode 100644 components/wifi-manager/network_manager.c rename components/wifi-manager/{wifi_manager.h => network_manager.h} (73%) create mode 100644 components/wifi-manager/network_status.c create mode 100644 components/wifi-manager/network_status.h create mode 100644 components/wifi-manager/network_wifi.c create mode 100644 components/wifi-manager/network_wifi.h create mode 100644 components/wifi-manager/state_machine.cpp create mode 100644 components/wifi-manager/state_machine.h delete mode 100644 components/wifi-manager/wifi_manager.c create mode 100644 file-size.txt create mode 100644 file_size.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 6216195c..3c0046d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,5 +10,98 @@ project(recovery) set_property(TARGET recovery.elf PROPERTY RECOVERY_PREFIX app_recovery ) include(squeezelite.cmake) set(PROJECT_VER $ENV{PROJECT_VER}) -#target_compile_definitions(__idf_squeezelite-ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_VERBOSE) -#target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) + +#target_compile_definitions(__idf_wifi-manager PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) +target_compile_definitions(__idf_esp_wifi PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) + +target_compile_definitions(__idf_app_recovery PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) +# target_compile_definitions(__idf_esp_eth PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) +# target_compile_definitions(__idf_esp_event PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO) +# target_compile_definitions(__idf_esp_netif PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) + +# target_compile_definitions(__idf_freertos PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_mdns PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_tcpip_adapter PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_tcp_transport PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) + +#target_compile_definitions(__idf_app_squeezelite PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_app_trace PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_app_update PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_asio PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_audio PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_bootloader_support PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) + +# target_compile_definitions(__idf_cbor PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_cmock PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_coap PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_cxx PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_display PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_driver PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_driver_bt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_efuse PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp-dsp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp-tls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp32 PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_espcoredump PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_adc_cal PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_common PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_gdbstub PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_hid PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_https_ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_http_client PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_http_server PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_hw_support PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_ipc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_local_ctrl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_pm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_ringbuf PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_rom PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_serial_slave_link PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_system PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_timer PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_esp_websocket_client PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_expat PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_fatfs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_freemodbus PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_hal PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_heap PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_jsmn PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_json PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_libsodium PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_log PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_lwip PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_main PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_mbedtls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(mbedcrypto PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(mbedtls PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(mbedx509 PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_mqtt PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_newlib PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_nghttp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_nvs_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_openssl PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_perfmon PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_platform_config PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_platform_console PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_protobuf-c PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_protocomm PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_pthread PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_raop PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_sdmmc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_services PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_soc PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_spiffs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_spi_flash PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_squeezelite PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_squeezelite-ota PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_telnet PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_tools PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_ulp PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_unity PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_vfs PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_wear_levelling PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_wifi_provisioning PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_wpa_supplicant PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) +# target_compile_definitions(__idf_xtensa PRIVATE -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG) \ No newline at end of file diff --git a/components/cpp-stateless b/components/cpp-stateless new file mode 160000 index 00000000..9e7138f8 --- /dev/null +++ b/components/cpp-stateless @@ -0,0 +1 @@ +Subproject commit 9e7138f8fe164d64deb73b2b23994eeb9abe3e0b diff --git a/components/platform_console/cmd_wifi.c b/components/platform_console/cmd_wifi.c index 558c3c9f..9e165ddf 100644 --- a/components/platform_console/cmd_wifi.c +++ b/components/platform_console/cmd_wifi.c @@ -8,7 +8,7 @@ */ // cmd_wifi has been replaced by wifi-manager -/* Console example — WiFi commands +/* Console example � WiFi commands This example code is in the Public Domain (or CC0 licensed, at your option.) @@ -29,7 +29,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" #include "esp_wifi.h" -#include "tcpip_adapter.h" +#include "esp_netif.h" #include "esp_event.h" #include "led.h" extern bool bypass_wifi_manager; @@ -98,7 +98,7 @@ static void initialise_wifi(void) if (initialized) { return; } - tcpip_adapter_init(); + esp_netif_init(); // Now moved to esp_app_main: wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); diff --git a/components/platform_console/platform_console.c b/components/platform_console/platform_console.c index 80e2f22a..0d491d05 100644 --- a/components/platform_console/platform_console.c +++ b/components/platform_console/platform_console.c @@ -236,16 +236,17 @@ void initialize_console() { /* Disable buffering on stdin */ setvbuf(stdin, NULL, _IONBF, 0); - /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ - esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); - /* Move the caret to the beginning of the next line on '\n' */ - esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); +/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); + /* Configure UART. Note that REF_TICK is used so that the baud rate remains * correct while APB frequency is changing in light sleep mode. */ const uart_config_t uart_config = { .baud_rate = - CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS, + CONFIG_ESP_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .use_ref_tick = true }; ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); diff --git a/components/raop/raop_sink.c b/components/raop/raop_sink.c index 51356d12..d14f27d9 100644 --- a/components/raop/raop_sink.c +++ b/components/raop/raop_sink.c @@ -5,8 +5,7 @@ #include "mdns.h" #include "nvs.h" -#include "tcpip_adapter.h" -// IDF-V4++ #include "esp_netif.h" +#include "esp_netif.h" #include "esp_log.h" #include "esp_console.h" #include "esp_pthread.h" diff --git a/components/raop/util.c b/components/raop/util.c index eb6ae76c..7c637473 100644 --- a/components/raop/util.c +++ b/components/raop/util.c @@ -13,7 +13,7 @@ #ifdef WIN32 #include #else -#include "tcpip_adapter.h" +#include "esp_netif.h" // IDF-V4++ #include "esp_netif.h" #include #endif diff --git a/components/services/accessors.c b/components/services/accessors.c index 0601312b..871c31d0 100644 --- a/components/services/accessors.c +++ b/components/services/accessors.c @@ -15,7 +15,6 @@ #include "accessors.h" #include "globdefs.h" #include "display.h" -#include "display.h" #include "cJSON.h" #include "driver/gpio.h" #include "stdbool.h" @@ -118,13 +117,8 @@ static void set_i2s_pin(char *config, i2s_pin_config_t *pin_config) { * Get i2s config structure from config string */ const i2s_platform_config_t * config_get_i2s_from_str(char * dac_config ){ - static EXT_RAM_ATTR i2s_platform_config_t i2s_dac_pin = { - .i2c_addr = -1, - .sda= -1, - .scl = -1, - .mute_gpio = -1, - .mute_level = -1 - }; + static EXT_RAM_ATTR i2s_platform_config_t i2s_dac_pin; + memset(&i2s_dac_pin, 0xFF, sizeof(i2s_dac_pin)); set_i2s_pin(dac_config, &i2s_dac_pin.pin); strcpy(i2s_dac_pin.model, "i2s"); char * p=NULL; @@ -146,11 +140,12 @@ const i2s_platform_config_t * config_get_i2s_from_str(char * dac_config ){ * Get eth config structure from config string */ const eth_config_t * config_get_eth_from_str(char * eth_config ){ - static EXT_RAM_ATTR eth_config_t eth_pin = { - .rmii = false, - .model = "", - }; char * p=NULL; + static EXT_RAM_ATTR eth_config_t eth_pin; + memset(ð_pin, 0xFF, sizeof(eth_pin)); + memset(ð_pin.model, 0xFF, sizeof(eth_pin.model)); + eth_pin.spi = false; + eth_pin.rmii = false; if ((p = strcasestr(eth_config, "model")) != NULL) sscanf(p, "%*[^=]=%15[^,]", eth_pin.model); if ((p = strcasestr(eth_config, "mdc")) != NULL) eth_pin.mdc = atoi(strchr(p, '=') + 1); @@ -163,9 +158,16 @@ const eth_config_t * config_get_eth_from_str(char * eth_config ){ if ((p = strcasestr(eth_config, "speed")) != NULL) eth_pin.speed = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "clk")) != NULL) eth_pin.clk = atoi(strchr(p, '=') + 1); if ((p = strcasestr(eth_config, "host")) != NULL) eth_pin.host = atoi(strchr(p, '=') + 1); + eth_pin.valid = eth_pin.model && strlen(eth_pin.model)>0 && GPIO_IS_VALID_GPIO(eth_pin.mdio) && GPIO_IS_VALID_GPIO(eth_pin.mdc); - if (strcasestr(eth_pin.model, "lan8720")) eth_pin.rmii = true; - + if(strcasestr(eth_pin.model, "LAN8720")){ + eth_pin.rmii = true; + } + else { + eth_pin.spi = true; + /* here we must also check that we have at least a CS gpio */ + eth_pin.valid = eth_pin.valid && GPIO_IS_VALID_GPIO(eth_pin.cs); + } return ð_pin; } @@ -196,22 +198,37 @@ const i2s_platform_config_t * config_dac_get(){ */ const eth_config_t * config_eth_get( ){ char * config = config_alloc_get_str("eth_config", CONFIG_ETH_CONFIG, "rst=" STR(CONFIG_ETH_PHY_RST_IO) -#if defined(CONFIG_ETH_LAN8720) - ",model=lan8720" -#elif defined(CONFIG_ETH_DM9051) + #if defined(ETH_LAN8720) + #else +#if defined(CONFIG_ETH_USE_SPI_ETHERNET) +#if defined(CONFIG_ETH_DM9051) ",model=dm9051" -#endif - ",mdc=" STR(CONFIG_ETH_MDC_IO) ",mdio=" STR(CONFIG_ETH_MDIO_IO) +#elif defined(CONFIG_ETH_W5500) + ",model=w5500" +#endif ",host=" STR(CONFIG_ETH_SPI_HOST) ",cs=" STR(CONFIG_ETH_SPI_CS_IO) ",mosi=" STR(CONFIG_ETH_SPI_MOSI_IO) ",miso=" STR(CONFIG_ETH_SPI_MISO_IO) ",intr=" STR(CONFIG_ETH_SPI_INTR_IO) - ",clk=" STR(CONFIG_ETH_SPI_CLK_IO) ",speed=" STR(CONFIG_ETH_SPI_SPEED) ); + ",clk=" STR(CONFIG_ETH_SPI_CLK_IO) ",speed=" STR(CONFIG_ETH_SPI_SPEED) + +#elif defined(CONFIG_ETH_PHY_INTERFACE_RMII) + ",model=lan8720, tx_en=21, tx0=19, tx1=22, rx0=25, rx1=26, crs_dv=27" +#endif +#endif + ",mdc=" STR(CONFIG_ETH_MDC_IO) ",mdio=" STR(CONFIG_ETH_MDIO_IO)) ; static EXT_RAM_ATTR eth_config_t eth_config; ESP_LOGD(TAG, "Ethernet config string %s", config); memcpy(ð_config, config_get_eth_from_str(config), sizeof(eth_config)); free(config); return ð_config; } +/**************************************************************************************** + * Get ethernet config structure and assign to eth config structure + */ +void config_eth_init( eth_config_t * target ){ + const eth_config_t * source = config_eth_get(); + memcpy(target,source,sizeof(eth_config_t)); +} /**************************************************************************************** * @@ -561,14 +578,9 @@ const set_GPIO_struct_t * get_gpio_struct(){ */ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) { char *nvs_item, *p; - static EXT_RAM_ATTR spi_bus_config_t spi = { - .mosi_io_num = -1, - .sclk_io_num = -1, - .miso_io_num = -1, - .quadwp_io_num = -1, - .quadhd_io_num = -1 - }; - + static EXT_RAM_ATTR spi_bus_config_t spi; + memset(&spi, 0xFF, sizeof(spi)); + nvs_item = config_alloc_get_str("spi_config", CONFIG_SPI_CONFIG, NULL); if (nvs_item) { if ((p = strcasestr(nvs_item, "data")) != NULL) spi.mosi_io_num = atoi(strchr(p, '=') + 1); @@ -770,6 +782,46 @@ cJSON * get_SPI_GPIO(cJSON * list){ return llist; } +/**************************************************************************************** + * + */ +cJSON * get_eth_GPIO(cJSON * list){ + cJSON * llist = list; + if(!llist){ + llist = cJSON_CreateArray(); + } + spi_host_device_t spi_host; + const eth_config_t * eth_config = config_eth_get(&spi_host); + #if defined(CONFIG_ETH_CONFIG) + bool fixed = strlen(CONFIG_ETH_CONFIG)>0; + #else + bool fixed =false; + #endif + if(eth_config->valid ){ + add_gpio_for_value(llist,"mdc",eth_config->mdc,"ethernet",fixed); + add_gpio_for_value(llist,"rst",eth_config->rst,"ethernet",fixed); + add_gpio_for_value(llist,"mdio",eth_config->mdio,"ethernet",fixed); + if(eth_config->rmii){ + add_gpio_for_value(llist,"tx_en", 21,"ethernet",true); + add_gpio_for_value(llist,"tx0", 19 ,"ethernet",true); + add_gpio_for_value(llist,"tx1", 22 ,"ethernet",true); + add_gpio_for_value(llist,"rx0", 25 ,"ethernet",true); + add_gpio_for_value(llist,"rx1", 26 ,"ethernet",true); + add_gpio_for_value(llist,"crs_dv",27 ,"ethernet",true); + } + else if(eth_config->spi) { + /* SPI ethernet */ + add_gpio_for_value(llist,"cs",eth_config->cs,"ethernet",fixed); + add_gpio_for_value(llist,"mosi",eth_config->mosi,"ethernet",fixed); + add_gpio_for_value(llist,"miso",eth_config->miso,"ethernet",fixed); + add_gpio_for_value(llist,"intr",eth_config->intr,"ethernet",fixed); + add_gpio_for_value(llist,"clk",eth_config->clk,"ethernet",fixed); + } + } + return llist; +} + + /**************************************************************************************** * */ @@ -1013,5 +1065,6 @@ cJSON * get_gpio_list(bool refresh) { gpio_list=get_I2C_GPIO(gpio_list); gpio_list=get_DAC_GPIO(gpio_list); gpio_list=get_psram_gpio_list(gpio_list); + gpio_list=get_eth_GPIO(gpio_list); return gpio_list; } diff --git a/components/services/accessors.h b/components/services/accessors.h index 614d39cf..8f720b8a 100644 --- a/components/services/accessors.h +++ b/components/services/accessors.h @@ -31,8 +31,10 @@ typedef struct { } display_config_t; typedef struct { - bool rmii; char model[16]; + bool valid; + bool rmii; + bool spi; int rst; int mdc, mdio; int host; @@ -86,6 +88,7 @@ typedef struct { const display_config_t * config_display_get(); const eth_config_t * config_eth_get( ); +void config_eth_init( eth_config_t * target ); esp_err_t config_display_set(const display_config_t * config); esp_err_t config_i2c_set(const i2c_config_t * config, int port); esp_err_t config_i2s_set(const i2s_platform_config_t * config, const char * nvs_name); diff --git a/components/services/buttons.c b/components/services/buttons.c index d734dec7..7b23788b 100644 --- a/components/services/buttons.c +++ b/components/services/buttons.c @@ -47,7 +47,7 @@ static EXT_RAM_ATTR struct button_s { TimerHandle_t timer; } buttons[MAX_BUTTONS]; -static EXT_RAM_ATTR struct { +static struct { int gpio, level; struct button_s *button; } polled_gpio[] = { {36, -1, NULL}, {39, -1, NULL}, {-1, -1, NULL} }; diff --git a/components/services/i2s.c b/components/services/i2s.c.0 similarity index 97% rename from components/services/i2s.c rename to components/services/i2s.c.0 index d908f389..e6b3a860 100644 --- a/components/services/i2s.c +++ b/components/services/i2s.c.0 @@ -28,7 +28,7 @@ #include "driver/i2s.h" #include "driver/rtc_io.h" #include "driver/dac.h" -#include +#include "adc1_private.h" #include "esp_intr_alloc.h" #include "esp_err.h" @@ -880,7 +880,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co //initialize the specific ADC channel. //in the current stage, we only support ADC1 and single channel mode. //In default data mode, the ADC data is in 12-bit resolution mode. - adc_power_always_on(); + // todo: fix this - adc_power_always_on(); } // configure I2S data port interface. i2s_reset_fifo(i2s_num); @@ -974,35 +974,36 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co I2S[i2s_num]->pdm_conf.rx_pdm_en = 0; I2S[i2s_num]->pdm_conf.tx_pdm_en = 0; } - if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) { - I2S[i2s_num]->conf.tx_short_sync = 0; - I2S[i2s_num]->conf.rx_short_sync = 0; - I2S[i2s_num]->conf.tx_msb_shift = 1; - I2S[i2s_num]->conf.rx_msb_shift = 1; - if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) { - if (i2s_config->mode & I2S_MODE_TX) { - I2S[i2s_num]->conf.tx_msb_shift = 0; - } - if (i2s_config->mode & I2S_MODE_RX) { - I2S[i2s_num]->conf.rx_msb_shift = 0; - } - } - } + // todo: fix this below!! + // if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) { + // I2S[i2s_num]->conf.tx_short_sync = 0; + // I2S[i2s_num]->conf.rx_short_sync = 0; + // I2S[i2s_num]->conf.tx_msb_shift = 1; + // I2S[i2s_num]->conf.rx_msb_shift = 1; + // if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) { + // if (i2s_config->mode & I2S_MODE_TX) { + // I2S[i2s_num]->conf.tx_msb_shift = 0; + // } + // if (i2s_config->mode & I2S_MODE_RX) { + // I2S[i2s_num]->conf.rx_msb_shift = 0; + // } + // } + // } - if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) { - I2S[i2s_num]->conf.tx_msb_shift = 0; - I2S[i2s_num]->conf.rx_msb_shift = 0; - I2S[i2s_num]->conf.tx_short_sync = 0; - I2S[i2s_num]->conf.rx_short_sync = 0; - if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) { - if (i2s_config->mode & I2S_MODE_TX) { - I2S[i2s_num]->conf.tx_short_sync = 1; - } - if (i2s_config->mode & I2S_MODE_RX) { - I2S[i2s_num]->conf.rx_short_sync = 1; - } - } - } + // if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) { + // I2S[i2s_num]->conf.tx_msb_shift = 0; + // I2S[i2s_num]->conf.rx_msb_shift = 0; + // I2S[i2s_num]->conf.tx_short_sync = 0; + // I2S[i2s_num]->conf.rx_short_sync = 0; + // if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) { + // if (i2s_config->mode & I2S_MODE_TX) { + // I2S[i2s_num]->conf.tx_short_sync = 1; + // } + // if (i2s_config->mode & I2S_MODE_RX) { + // I2S[i2s_num]->conf.rx_short_sync = 1; + // } + // } + // } if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) { I2S[i2s_num]->conf.sig_loopback = 1; if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { @@ -1217,7 +1218,7 @@ esp_err_t i2s_adc_enable(i2s_port_t i2s_num) I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); - adc1_i2s_mode_acquire(); + // todo: fix this adc1_i2s_mode_acquire(); _i2s_adc_mode_recover(); return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); } diff --git a/components/services/messaging.c b/components/services/messaging.c index 3a708f54..968d9c46 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -238,7 +238,16 @@ void messaging_post_message(messaging_types type,messaging_classes msg_class, co message->type = type; message->msg_class = msg_class; message->sent_time = esp_timer_get_time() / 1000; - ESP_LOGD(tag,"Post: %s",message->message); + if(type==MESSAGING_WARNING) { + ESP_LOGW(tag,"%s",message->message); + } + else if(type==MESSAGING_ERROR) { + ESP_LOGE(tag,"%s",message->message); + } + else { + ESP_LOGD(tag,"Post: %s",message->message); + } + while(cur){ messaging_post_to_queue(get_handle_ptr(cur), message, msg_size); cur = get_struct_ptr(cur->next); diff --git a/components/services/messaging.h b/components/services/messaging.h index d715d6fc..baa5a193 100644 --- a/components/services/messaging.h +++ b/components/services/messaging.h @@ -3,6 +3,10 @@ #include "freertos/ringbuf.h" #include "cJSON.h" #pragma once +#ifdef __cplusplus +extern "C" { + +#endif typedef enum { MESSAGING_INFO, MESSAGING_WARNING, @@ -48,3 +52,6 @@ messaging_post_message(y, MESSAGING_CLASS_SYSTEM, ##__VA_ARGS__); } #define LOG_SEND_WARN( ...) LOG_SEND(MESSAGING_WARNING,##__VA_ARGS__) +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/squeezelite-ota/protocol_examples_common.h b/components/squeezelite-ota/protocol_examples_common.h index 0d1bc2cb..0abf097d 100644 --- a/components/squeezelite-ota/protocol_examples_common.h +++ b/components/squeezelite-ota/protocol_examples_common.h @@ -14,7 +14,7 @@ extern "C" { #endif #include "esp_err.h" -#include "tcpip_adapter.h" +#include "esp_netif.h" // IDF-V4++ #include "esp_netif.h" #ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index b31777fe..c5e20000 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -20,8 +20,7 @@ #include "cmd_system.h" #include "esp_err.h" #include "squeezelite-ota.h" -#include "tcpip_adapter.h" -// IDF-V4++ #include "esp_netif.h" +#include "esp_netif.h" #include "platform_config.h" #include #include diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 5e23617b..42b3c064 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -117,9 +117,7 @@ void init_telnet(){ uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ); buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { - ESP_LOGE(TAG,"Failed to create ring buffer for telnet!"); messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Failed to allocate memory for telnet buffer"); - return; } diff --git a/components/tools/trace.h b/components/tools/trace.h index b2fe74ce..5550c427 100644 --- a/components/tools/trace.h +++ b/components/tools/trace.h @@ -21,7 +21,10 @@ #ifndef STR_OR_ALT #define STR_OR_ALT(str,alt) (str?str:alt) #endif - +#define ENUM_TO_STRING(g) \ + case g: \ + return STR(g); \ + break; extern const char unknown_string_placeholder[]; extern const char * str_or_unknown(const char * str); extern const char * str_or_null(const char * str); diff --git a/components/wifi-manager/CMakeLists.txt b/components/wifi-manager/CMakeLists.txt index 8ce2910e..c15fc2cd 100644 --- a/components/wifi-manager/CMakeLists.txt +++ b/components/wifi-manager/CMakeLists.txt @@ -3,7 +3,7 @@ set( WEBPACK_DIR webapp/webpack/dist ) idf_component_register( SRC_DIRS . webapp INCLUDE_DIRS . webapp ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/ REQUIRES squeezelite-ota json mdns - PRIV_REQUIRES tools services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt + PRIV_REQUIRES tools cpp-stateless services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt ) diff --git a/components/wifi-manager/Kconfig.projbuild b/components/wifi-manager/Kconfig.projbuild index 2679940e..a8f0bad4 100644 --- a/components/wifi-manager/Kconfig.projbuild +++ b/components/wifi-manager/Kconfig.projbuild @@ -1,67 +1,121 @@ -menu "Wifi Manager Configuration" +menu "Network Manager Configuration" + + menu "WiFi Options" + config WIFI_MANAGER_TASK_PRIORITY + int "RTOS Task Priority for the wifi_manager" + default 1 + help + Tasks spawn by the manager will have a priority of WIFI_MANAGER_TASK_PRIORITY-1. For this particular reason, minimum recommended task priority is 2. -config WIFI_MANAGER_TASK_PRIORITY - int "RTOS Task Priority for the wifi_manager" - default 1 - help - Tasks spawn by the manager will have a priority of WIFI_MANAGER_TASK_PRIORITY-1. For this particular reason, minimum recommended task priority is 2. + config WIFI_MANAGER_MAX_RETRY + int "Max Retry on failed connection" + default 2 + help + Defines when a connection is lost/attempt to connect is made, how many retries should be made before giving up. + + config DEFAULT_AP_SSID + string "Access Point SSID" + default "esp32" + help + SSID (network name) the the esp32 will broadcast. -config WIFI_MANAGER_MAX_RETRY - int "Max Retry on failed connection" - default 2 - help - Defines when a connection is lost/attempt to connect is made, how many retries should be made before giving up. - -config DEFAULT_AP_SSID - string "Access Point SSID" - default "esp32" - help - SSID (network name) the the esp32 will broadcast. + config DEFAULT_AP_PASSWORD + string "Access Point Password" + default "esp32pwd" + help + Password used for the Access Point. Leave empty and set AUTH MODE to WIFI_AUTH_OPEN for no password. -config DEFAULT_AP_PASSWORD - string "Access Point Password" - default "esp32pwd" - help - Password used for the Access Point. Leave empty and set AUTH MODE to WIFI_AUTH_OPEN for no password. - -config DEFAULT_AP_CHANNEL - int "Access Point WiFi Channel" - default 1 - help - Be careful you might not see the access point if you use a channel not allowed in your country. - -config DEFAULT_AP_IP - string "Access Point IP Address" - default "10.10.0.1" - help - This is used for the redirection to the captive portal. It is recommended to leave unchanged. - -config DEFAULT_AP_GATEWAY - string "Access Point IP Gateway" - default "10.10.0.1" - help - This is used for the redirection to the captive portal. It is recommended to leave unchanged. - -config DEFAULT_AP_NETMASK - string "Access Point Netmask" - default "255.255.255.0" - help - This is used for the redirection to the captive portal. It is recommended to leave unchanged. - -config DEFAULT_AP_MAX_CONNECTIONS - int "Access Point Max Connections" - default 4 - help - Max is 4. - -config DEFAULT_AP_BEACON_INTERVAL - int "Access Point Beacon Interval (ms)" - default 100 - help - 100ms is the recommended default. -config DEFAULT_COMMAND_LINE - string "Default command line to execute" - default "squeezelite -o I2S -b 500:2000 -d all=info -C 30" - help - This is the command to run when starting the device + config DEFAULT_AP_CHANNEL + int "Access Point WiFi Channel" + default 1 + help + Be careful you might not see the access point if you use a channel not allowed in your country. + + config DEFAULT_AP_IP + string "Access Point IP Address" + default "10.10.0.1" + help + This is used for the redirection to the captive portal. It is recommended to leave unchanged. + + config DEFAULT_AP_GATEWAY + string "Access Point IP Gateway" + default "10.10.0.1" + help + This is used for the redirection to the captive portal. It is recommended to leave unchanged. + + config DEFAULT_AP_NETMASK + string "Access Point Netmask" + default "255.255.255.0" + help + This is used for the redirection to the captive portal. It is recommended to leave unchanged. + + config DEFAULT_AP_MAX_CONNECTIONS + int "Access Point Max Connections" + default 4 + help + Max is 4. + + config DEFAULT_AP_BEACON_INTERVAL + int "Access Point Beacon Interval (ms)" + default 100 + help + 100ms is the recommended default. + endmenu + menu "Ethernet Options" + visible if BASIC_I2C_BT && (ETH_USE_ESP32_EMAC || ETH_USE_SPI_ETHERNET) + choice + prompt "Ethernet Chipset" + default ETH_NODRIVER + config ETH_NODRIVER + bool "Defined in NVS" + config ETH_LAN8720 + bool "Microchip LAN8720 (RMII)" + config ETH_DM9051 + bool "Davicom 9051 (SPI)" + config ETH_W5500 + bool "WIZnet 5500 (SPI)" + endchoice + comment "LAN8720 is an RMII interface and most of the required GPIOs aren't user selectable. They are defined as follow tx_en=21, tx0=19, tx1=22, rx0=25, rx1=26, crs_dv=27" + depends on ETH_LAN8720 + config ETH_PHY_RST_IO + int "PHY Reset GPIO number" if !ETH_NODRIVER + default -1 + help + Set the GPIO number used to reset PHY chip. + Set to -1 to disable PHY chip hardware reset. + config ETH_MDC_IO + int "SMI MDC GPIO number" if ETH_LAN8720 + default -1 + help + Set the GPIO number used by SMI MDC. + config ETH_MDIO_IO + int "SMI MDIO GPIO number" if ETH_LAN8720 + default -1 + help + Set the GPIO number used by SMI MDIO. + config ETH_SPI_HOST + int "SPI host number (-1,1 or 2)" if ETH_DM9051 || ETH_W5500 + default -1 + help + Set to -1 to use system's SPI config (see Various I/O) + Set to 2 or 3 to use a dedicated bus + config ETH_SPI_INTR_IO + int "interrupt" if ETH_DM9051 || ETH_W5500 + default -1 + config ETH_SPI_CS_IO + int "Chip Select" if ETH_DM9051 || ETH_W5500 + default -1 + config ETH_SPI_CLK_IO + int "SPI clock" if ETH_SPI_HOST != -1 && (ETH_DM9051 || ETH_W5500) + default -1 + config ETH_SPI_MOSI_IO + int "Data Out" if ETH_SPI_HOST != -1 && (ETH_DM9051 || ETH_W5500) + default -1 + config ETH_SPI_MISO_IO + int "Data In" if ETH_SPI_HOST != -1 && (ETH_DM9051 || ETH_W5500) + default -1 + config ETH_SPI_SPEED + int "SPI speed (Hz)" if ETH_SPI_HOST != -1 && (ETH_DM9051 || ETH_W5500) + default 20000000 + endmenu endmenu diff --git a/components/wifi-manager/dns_server.c b/components/wifi-manager/dns_server.c index 3ccafca1..f5ce722b 100644 --- a/components/wifi-manager/dns_server.c +++ b/components/wifi-manager/dns_server.c @@ -53,7 +53,7 @@ Contains the freeRTOS task for the DNS server that processes the requests. #include #include "squeezelite-ota.h" -#include "wifi_manager.h" +#include "network_manager.h" static const char TAG[] = "dns_server"; static TaskHandle_t task_dns_server = NULL; diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 9f932c6b..212b23e6 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -55,6 +55,8 @@ function to process requests, decode URLs, serve files, etc. etc. #include "platform_console.h" #include "accessors.h" #include "webapp/webpack.h" +#include "network_wifi.h" +#include "network_status.h" #define HTTP_STACK_SIZE (5*1024) const char str_na[]="N/A"; @@ -437,7 +439,7 @@ esp_err_t ap_scan_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - wifi_manager_scan_async(); + network_manager_async_scan(); esp_err_t err = set_content_type_from_req(req); if(err == ESP_OK){ httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN); @@ -728,7 +730,7 @@ esp_err_t config_post_handler(httpd_req_t *req){ ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL); } - wifi_manager_reboot_ota(otaURL); + network_manager_reboot_ota(otaURL); free(otaURL); } return err; @@ -789,8 +791,8 @@ esp_err_t connect_post_handler(httpd_req_t *req){ if(password){ strlcpy((char *)config->sta.password, password, sizeof(config->sta.password)+1); } - ESP_LOGD_LOC(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); + ESP_LOGD_LOC(TAG, "http_server_netconn_serve: network_manager_async_scan() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); + network_manager_async_scan(); httpd_resp_send(req, (const char *)success, strlen(success)); } else { @@ -814,7 +816,7 @@ esp_err_t connect_delete_handler(httpd_req_t *req){ return err; } httpd_resp_send(req, (const char *)success, strlen(success)); - wifi_manager_disconnect_async(); + network_manager_async_disconnect(); return ESP_OK; } @@ -831,7 +833,7 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){ } httpd_resp_send(req, (const char *)success, strlen(success)); - wifi_manager_reboot(OTA); + network_manager_async_reboot(OTA); return ESP_OK; } esp_err_t reboot_post_handler(httpd_req_t *req){ @@ -846,7 +848,7 @@ esp_err_t reboot_post_handler(httpd_req_t *req){ return err; } httpd_resp_send(req, (const char *)success, strlen(success)); - wifi_manager_reboot(RESTART); + network_manager_async_reboot(RESTART); return ESP_OK; } esp_err_t recovery_post_handler(httpd_req_t *req){ @@ -861,7 +863,7 @@ esp_err_t recovery_post_handler(httpd_req_t *req){ return err; } httpd_resp_send(req, (const char *)success, strlen(success)); - wifi_manager_reboot(RECOVERY); + network_manager_async_reboot(RECOVERY); return ESP_OK; } @@ -1162,7 +1164,7 @@ esp_err_t status_get_handler(httpd_req_t *req){ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object"); } // update status for next status call - wifi_manager_update_status(); + network_manager_async_update_status(); return ESP_OK; } diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index f040dd74..53797b4c 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -38,7 +38,7 @@ function to process requests, decode URLs, serve files, etc. etc. #include #include #include "esp_http_server.h" -#include "wifi_manager.h" +#include "network_manager.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" diff --git a/components/wifi-manager/network_driver_DM9051.c b/components/wifi-manager/network_driver_DM9051.c new file mode 100644 index 00000000..74088c33 --- /dev/null +++ b/components/wifi-manager/network_driver_DM9051.c @@ -0,0 +1,38 @@ +#include "esp_eth.h" +#include "network_ethernet.h" + +static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051 + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + eth_dm9051_config_t eth_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); + // we assume that isr has been installed already + eth_config.int_gpio_num = ethernet_config->intr; + return esp_eth_mac_new_dm9051(ð_config, &mac_config); +#else + return NULL; +#endif +} +static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051 + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = 1; + phy_config.reset_gpio_num = ethernet_config->rst; + return esp_eth_phy_new_dm9051(&phy_config); +#else + return NULL; +#endif +} +static void init_config(eth_config_t* ethernet_config) { +} + +static network_ethernet_driver_t DM9051 = { + .mac_new = mac_new, + .phy_new = phy_new, + .init_config = init_config, + .valid = true, +}; +network_ethernet_driver_t* DM9051_Detect(char* Driver) { + if (!strcasestr(Driver, "DM9051")) + return NULL; + return &DM9051; +} diff --git a/components/wifi-manager/network_driver_LAN8720.c b/components/wifi-manager/network_driver_LAN8720.c new file mode 100644 index 00000000..f77c29e2 --- /dev/null +++ b/components/wifi-manager/network_driver_LAN8720.c @@ -0,0 +1,47 @@ +#include "esp_eth.h" +#include "network_ethernet.h" + +static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_PHY_INTERFACE_RMII + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.smi_mdc_gpio_num = ethernet_config->mdc; + mac_config.smi_mdio_gpio_num = ethernet_config->mdio; + mac_config.sw_reset_timeout_ms = 400; + return esp_eth_mac_new_esp32(&mac_config); +#else + return NULL; +#endif +} +static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_PHY_INTERFACE_RMII + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = 1; + phy_config.reset_gpio_num = ethernet_config->rst; + return esp_eth_phy_new_lan8720(&phy_config); +#else + return NULL; +#endif +} +static void init_config(eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_PHY_INTERFACE_RMII +#else + return NULL; +#endif +} + +static network_ethernet_driver_t LAN8720 = { + + .mac_new = mac_new, + .phy_new = phy_new, + .init_config = init_config, +#ifdef CONFIG_ETH_PHY_INTERFACE_RMII + .valid = true, +#else + .valid = false, +#endif +}; +network_ethernet_driver_t* LAN8720_Detect(char* Driver) { + if (!strcasestr(Driver, "LAN8720")) + return NULL; + return &LAN8720; +} diff --git a/components/wifi-manager/network_driver_W5500.c b/components/wifi-manager/network_driver_W5500.c new file mode 100644 index 00000000..39ae65dd --- /dev/null +++ b/components/wifi-manager/network_driver_W5500.c @@ -0,0 +1,43 @@ +#include "esp_eth.h" +#include "network_ethernet.h" + +static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_SPI_ETHERNET_W5500 + eth_w5500_config_t eth_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + // we assume that isr has been installed already + eth_config.int_gpio_num = ethernet_config->intr; + return esp_eth_mac_new_w5500(ð_config, &mac_config); +#else + return NULL; +#endif +} +static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) { +#ifdef CONFIG_ETH_SPI_ETHERNET_W5500 + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = 1; + phy_config.reset_gpio_num = ethernet_config->rst; + return esp_eth_phy_new_w5500(&phy_config); +#else + return NULL; +#endif +} + +static void init_config(eth_config_t* ethernet_config) { +} + +static network_ethernet_driver_t W5500 = { + .mac_new = mac_new, + .phy_new = phy_new, + .init_config = init_config, +#ifdef CONFIG_ETH_SPI_ETHERNET_W5500 + .valid = true, +#else + .valid = false, +#endif +}; +network_ethernet_driver_t* W5500_Detect(char* Driver, network_ethernet_driver_t* Device) { + if (!strcasestr(Driver, "W5500")) + return NULL; + return &W5500; +} diff --git a/components/wifi-manager/network_ethernet.c b/components/wifi-manager/network_ethernet.c new file mode 100644 index 00000000..07cfcbfa --- /dev/null +++ b/components/wifi-manager/network_ethernet.c @@ -0,0 +1,283 @@ +#include "network_ethernet.h" +#include "freertos/timers.h" +#include "globdefs.h" +#include "messaging.h" +#include "network_status.h" +#include "platform_config.h" +#include "trace.h" +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "esp_log.h" + +//#include "dnserver.h" + +static char TAG[] = "network_ethernet"; +TimerHandle_t ETH_timer; +esp_eth_handle_t eth_handle = NULL; +esp_netif_t* eth_netif = NULL; +EventGroupHandle_t ethernet_event_group; +const int LINK_UP_BIT = BIT0; + +static const char* known_drivers[] = {"DM9051", "W5500", "LAN8720", NULL}; +static network_ethernet_driver_t* network_driver = NULL; +extern network_ethernet_detect_func_t DM9051_Detect, W5500_Detect, LAN8720_Detect; +static network_ethernet_detect_func_t* drivers[] = {DM9051_Detect, W5500_Detect, LAN8720_Detect, NULL}; +#define ETH_TIMEOUT_MS (30 * 1000) +static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); + +/**************************************************************************************** + * + */ +const char* network_ethernet_conf_get_driver_name(const char* driver) { + for (uint8_t i = 0; known_drivers[i] != NULL && strlen(known_drivers[i]) > 0; i++) { + if (strcasestr(driver, known_drivers[i])) { + return known_drivers[i]; + } + } + return NULL; +} +/**************************************************************************************** + * + */ +bool network_ethernet_is_valid_driver(const char* driver) { + return network_ethernet_conf_get_driver_name(driver) != NULL; +} + +network_ethernet_driver_t* network_ethernet_driver_autodetect(const char* Driver) { + if (!Driver) + return NULL; + + for (int i = 0; drivers[i]; i++) { + network_ethernet_driver_t* found_driver = drivers[i](Driver); + if (found_driver) { + ESP_LOGD(TAG, "Detected driver %s ", Driver); + + network_driver = found_driver; + return found_driver; + } + } + return NULL; +} + +static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); +esp_netif_t *network_ethernet_get_interface(){ + return eth_netif; +} + +bool network_ethernet_is_up() { + return (xEventGroupGetBits(ethernet_event_group) & LINK_UP_BIT)!=0; +} +bool network_ethernet_enabled() { + return eth_handle != NULL; +} +bool network_ethernet_wait_for_link(uint16_t max_wait_ms){ + if(!network_ethernet_enabled()) return false; + bool link_up=(xEventGroupGetBits(ethernet_event_group) & LINK_UP_BIT)!=0; + if(!link_up){ + ESP_LOGD(TAG,"Waiting for Ethernet link to be established..."); + link_up = (xEventGroupWaitBits(ethernet_event_group, LINK_UP_BIT,pdFALSE, pdTRUE, max_wait_ms / portTICK_PERIOD_MS)& LINK_UP_BIT)!=0; + if(!link_up){ + ESP_LOGW(TAG,"Ethernet Link timeout."); + } + else + { + ESP_LOGI(TAG,"Ethernet Link Up!"); + } + } + return link_up; +} + +static void ETH_Timeout(void* timer_id); +void destroy_network_ethernet() { +} +static void set_host_name() { + ESP_LOGE(TAG, "TODO: Find a way to set the host name here!"); + // esp_err_t err; + // ESP_LOGD(TAG, "Retrieving host name from nvs"); + // char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name"); + // if (host_name == NULL) { + // ESP_LOGE(TAG, "Could not retrieve host name from nvs"); + // } else { + // if (!network_ethernet_enabled()) { + // ESP_LOGE(TAG, "Cannot set name on a disabled interface"); + // } else { + // ESP_LOGD(TAG, "Setting host name to : %s", host_name); + // if ((err = esp_netif_set_hostname(eth_handle, host_name)) != ESP_OK) { + // ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err)); + // } + // ESP_LOGD(TAG, "Done setting host name to : %s", host_name); + // } + + // FREE_AND_NULL(host_name); + // } +} +static void network_ethernet_print_config(const eth_config_t* eth_config) { + // #if defined(CONFIG_ETH_PHY_INTERFACE_RMII) + // if(eth_config->) + // ESP_LOGI(TAG, + // "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d, tx_en=%d, tx0=%d, tx1=%d, rx0=%d, rx1=%d, crs_dv=%d", + // eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs, + // eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed, + // eth_config->tx_en, eth_config->tx0, eth_config->tx1, eth_config->rx0, eth_config->rx1, eth_config->crs_dv); + // #else + // ESP_LOGI(TAG, "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d ", + // eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs, + // eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed); + // : + // #endif +} + +void init_network_ethernet() { + esp_err_t err = ESP_OK; + esp_eth_mac_t* mac; + esp_eth_phy_t* phy; + eth_config_t eth; + config_eth_init(ð); + ESP_LOGD(TAG, "Attempting to initialize Ethernet"); + // quick check if we have a valid ethernet configuration + if (!eth.valid) { + ESP_LOGI(TAG, "No ethernet"); + return; + } + network_driver = network_ethernet_driver_autodetect(eth.model); + if (!network_driver) { + messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Invalid ethernet Ethernet chip %s", eth.model); + return; + } + if (!network_driver->valid) { + messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Code not compiled for Ethernet chip %s", eth.model); + return; + } + network_driver->init_config(ð); + network_ethernet_print_config(ð); + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + eth_netif = esp_netif_new(&cfg); + esp_eth_set_default_handlers(eth_netif); + esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); + esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); + ethernet_event_group = xEventGroupCreate(); + xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT); + spi_device_handle_t spi_handle = NULL; + if (network_driver->eth_config.spi) { + spi_host_device_t host = SPI3_HOST; + + if (eth.host != -1) { + // don't use system's shared SPI + spi_bus_config_t buscfg = { + .miso_io_num = eth.miso, + .mosi_io_num = eth.mosi, + .sclk_io_num = eth.clk, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + + // can't use SPI0 + if (eth.host == 1) + host = SPI2_HOST; + ESP_LOGI(TAG, "Initializing SPI bus on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso); + err = spi_bus_initialize(host, &buscfg, 1); + if (err != ESP_OK) { + ESP_LOGE(TAG, "SPI bus init failed : %s", esp_err_to_name(err)); + } + + } else { + // when we use shared SPI, we assume it has been initialized + host = spi_system_host; + } + if (err == ESP_OK) { + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = eth.speed, + .spics_io_num = eth.cs, + .queue_size = 20}; + ESP_LOGI(TAG, "Adding ethernet SPI on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso); + err = spi_bus_add_device(host, &devcfg, &spi_handle); + } + if (err != ESP_OK) { + ESP_LOGE(TAG, "SPI host failed : %s", esp_err_to_name(err)); + } + } + if (err == ESP_OK) { + ESP_LOGD(TAG, "Setting up ethernet driver"); + mac = network_driver->mac_new(spi_handle, ð); + phy = network_driver->phy_new(ð); + esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); + err = esp_eth_driver_install(&config, ð_handle); + } + if (err == ESP_OK) { + ESP_LOGD(TAG, "Attaching ethernet to network interface"); + err = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)); + } + if (err == ESP_OK) { + ESP_LOGI(TAG, "Starting ethernet network"); + err = esp_eth_start(eth_handle); + } + if (err != ESP_OK) { + messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Configuring Ethernet failed: %s", esp_err_to_name(err)); + eth_handle = NULL; + } +} + +void network_ethernet_start_timer() { + ETH_timer = xTimerCreate("ETH check", pdMS_TO_TICKS(ETH_TIMEOUT_MS), pdFALSE, NULL, ETH_Timeout); +} + +/** Event handler for Ethernet events */ +static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + uint8_t mac_addr[6] = {0}; + /* we can get the ethernet driver handle from event data */ + if (event_base == ETH_EVENT) { + esp_eth_handle_t eth_handle = *(esp_eth_handle_t*)event_data; + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + xEventGroupSetBits(ethernet_event_group, LINK_UP_BIT); + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); + ESP_LOGI(TAG, ""); + ESP_LOGI(TAG, "Ethernet Link Up, 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_LOGD(TAG, "Sending EVENT_ETH_LINK_UP message to network manager"); + network_manager_async_link_up(); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet Link Down"); + xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT); + ESP_LOGD(TAG, "Sending EVENT_ETH_LINK_DOWN message to network manager"); + network_manager_async_link_down(); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "Ethernet Started. Setting host name"); + set_host_name(); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGI(TAG, "Ethernet Stopped"); + break; + default: + break; + } + } else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) { + network_manager_ethernet_ip_event_handler(arg, event_base, event_id, event_data); + } +} + +static void ETH_Timeout(void* timer_id) { + network_manager_async_fail(); +} + +static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + if (event_base != IP_EVENT) + return; + ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; + ip_event_got_ip_t* s = event_data; + tcpip_adapter_if_t index = s->if_index; + esp_netif_ip_info_t* ip_info = &s->ip_info; + + ESP_LOGI(TAG, "Got an IP address from Ethernet interface #%i. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s", + index, + IP2STR(&ip_info->ip), + IP2STR(&ip_info->gw), + IP2STR(&ip_info->netmask), + s->ip_changed ? "Address was changed" : "Address unchanged"); + ip_event_got_ip_t* parm = malloc(sizeof(ip_event_got_ip_t)); + memcpy(parm, event_data, sizeof(ip_event_got_ip_t)); + network_manager_async_got_ip(parm); +} \ No newline at end of file diff --git a/components/wifi-manager/network_ethernet.h b/components/wifi-manager/network_ethernet.h new file mode 100644 index 00000000..e4513a51 --- /dev/null +++ b/components/wifi-manager/network_ethernet.h @@ -0,0 +1,30 @@ +#pragma once + +#include "network_manager.h" +#include "accessors.h" +#include +#ifdef __cplusplus +extern "C" { + +#endif +typedef struct { + bool valid; + eth_config_t eth_config; + esp_eth_mac_t* (*mac_new)(spi_device_handle_t spi_handle, eth_config_t * eth_config); + esp_eth_phy_t *(*phy_new)( eth_config_t* eth_config); + void (*init_config)(eth_config_t * eth_config); +} network_ethernet_driver_t; +typedef network_ethernet_driver_t* network_ethernet_detect_func_t(const char* Driver); + +void destroy_network_ethernet(); +void init_network_ethernet(); +bool network_ethernet_wait_for_link(uint16_t max_wait_ms); + +void network_ethernet_start_timer(); +bool network_ethernet_is_up(); +bool network_ethernet_enabled(); +esp_netif_t *network_ethernet_get_interface(); +#ifdef __cplusplus +} + +#endif \ No newline at end of file diff --git a/components/wifi-manager/network_manager.c b/components/wifi-manager/network_manager.c new file mode 100644 index 00000000..d8681547 --- /dev/null +++ b/components/wifi-manager/network_manager.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2017-2019 Tony Pottier + +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. + +@file wifi_manager.c +@author Tony Pottier +@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis + +Contains the freeRTOS task and all necessary support + +@see https://idyl.io +@see https://github.com/tonyp7/esp32-wifi-manager +*/ + +#include "network_manager.h" +#include +#include +#include +#include +#include "network_ethernet.h" +#include "network_status.h" +#include "network_wifi.h" +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "esp_log.h" +#include "platform_esp32.h" + + +#include "esp_system.h" +#include "freertos/FreeRTOS.h" + +#include "freertos/task.h" +#include "esp_netif.h" + +#include "cJSON.h" +#include "cmd_system.h" +#include "esp_app_format.h" + +#include "esp_event.h" +#include "esp_ota_ops.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "lwip/api.h" +#include "lwip/err.h" +#include "lwip/ip4_addr.h" +#include "lwip/netdb.h" +#include "mdns.h" +#include "messaging.h" +#include "state_machine.h" + +#include "platform_config.h" +#include "trace.h" + +#include "accessors.h" +#include "globdefs.h" +#include "http_server_handlers.h" + + + +#ifndef STR_OR_BLANK +#define STR_OR_BLANK(p) p == NULL ? "" : p +#endif + +//EventGroupHandle_t wifi_manager_event_group; +void (**cb_ptr_arr)(void*) = NULL; + +/* @brief tag used for ESP serial console messages */ +//static const char TAG[] = "network_manager"; + +/* @brief indicate that the ESP32 is currently connected. */ +const int WIFI_MANAGER_WIFI_CONNECTED_BIT = BIT0; +const int WIFI_MANAGER_AP_STA_CONNECTED_BIT = BIT1; +/* @brief Set automatically once the SoftAP is started */ +const int WIFI_MANAGER_AP_STARTED_BIT = BIT2; +/* @brief When set, means a client requested to connect to an access point.*/ +const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT = BIT3; +/* @brief This bit is set automatically as soon as a connection was lost */ +const int WIFI_MANAGER_STA_DISCONNECT_BIT = BIT4; +/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */ +const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT = BIT5; +/* @brief When set, means a client requested to disconnect from currently connected AP. */ +const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT = BIT6; +/* @brief When set, means a scan is in progress */ +const int WIFI_MANAGER_SCAN_BIT = BIT7; +/* @brief When set, means user requested for a disconnect */ +const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT = BIT8; +/* @brief When set, means user requested connecting to a new network and it failed */ +const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT = BIT9; + +/* @brief task handle for the main wifi_manager task */ + + + + + + + + +void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*)) { + if (cb_ptr_arr && message_code < MESSAGE_CODE_COUNT) { + cb_ptr_arr[message_code] = func_ptr; + } +} + diff --git a/components/wifi-manager/wifi_manager.h b/components/wifi-manager/network_manager.h similarity index 73% rename from components/wifi-manager/wifi_manager.h rename to components/wifi-manager/network_manager.h index b43ce072..b2b0e96a 100644 --- a/components/wifi-manager/wifi_manager.h +++ b/components/wifi-manager/network_manager.h @@ -19,7 +19,7 @@ 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. -@file wifi_manager.h +@file network_manager.h @author Tony Pottier @brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis @@ -41,8 +41,10 @@ extern "C" { #include "esp_wifi_types.h" #include "squeezelite-ota.h" #include "cJSON.h" - - +#include "esp_eth.h" +#include "freertos/event_groups.h" +#include "state_machine.h" +#include "state_machine.h" /** * @brief Defines the maximum size of a SSID name. 32 is IEEE standard. * @warning limit is also hard coded in wifi_config_t. Never extend this value. @@ -158,9 +160,6 @@ extern "C" { */ #define JSON_ONE_APP_SIZE 99 - - - /** * @brief Defines the complete list of all messages that the wifi_manager can process. * @@ -186,25 +185,51 @@ typedef enum message_code_t { ORDER_START_DNS_HIJACK = 11, EVENT_STA_DISCONNECTED = 12, EVENT_SCAN_DONE = 13, - EVENT_STA_GOT_IP = 14, + EVENT_GOT_IP = 14, ORDER_RESTART_OTA = 15, ORDER_RESTART_RECOVERY = 16, ORDER_RESTART_OTA_URL = 17, ORDER_RESTART = 18, ORDER_UPDATE_STATUS = 19, EVENT_ETH_GOT_IP = 20, - MESSAGE_CODE_COUNT = 21 /* important for the callback array */ - + EVENT_ETH_TIMEOUT = 21, + EVENT_ETH_LINK_UP = 22, + EVENT_ETH_LINK_DOWN = 23, + MESSAGE_CODE_COUNT = 24 /* important for the callback array */ }message_code_t; -typedef enum reboot_type_t{ - OTA, - RECOVERY, - RESTART, -} reboot_type_t; -void wifi_manager_reboot(reboot_type_t rtype); -void wifi_manager_reboot_ota(char * url); -void wifi_manager_update_status(); + + +/* @brief indicate that the ESP32 is currently connected. */ +extern const int WIFI_MANAGER_WIFI_CONNECTED_BIT; + +extern const int WIFI_MANAGER_AP_STA_CONNECTED_BIT; + +/* @brief Set automatically once the SoftAP is started */ +extern const int WIFI_MANAGER_AP_STARTED_BIT; + +/* @brief When set, means a client requested to connect to an access point.*/ +extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT; + +/* @brief This bit is set automatically as soon as a connection was lost */ +extern const int WIFI_MANAGER_STA_DISCONNECT_BIT ; + +/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */ +extern const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT ; + +/* @brief When set, means a client requested to disconnect from currently connected AP. */ +extern const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT ; + +/* @brief When set, means a scan is in progress */ +extern const int WIFI_MANAGER_SCAN_BIT ; + +/* @brief When set, means user requested for a disconnect */ +extern const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT ; + +/* @brief When set, means user requested connecting to a new network and it failed */ +extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT ; + +void network_manager_reboot_ota(char * url); /** @@ -218,6 +243,7 @@ typedef enum update_reason_code_t { UPDATE_USER_DISCONNECT = 2, UPDATE_LOST_CONNECTION = 3, UPDATE_FAILED_ATTEMPT_AND_RESTORE = 4, + UPDATE_ETHERNET_CONNECTED = 5 }update_reason_code_t; @@ -226,6 +252,7 @@ typedef enum connection_request_made_by_code_t{ CONNECTION_REQUEST_USER = 1, CONNECTION_REQUEST_AUTO_RECONNECT = 2, CONNECTION_REQUEST_RESTORE_CONNECTION = 3, + CONNECTION_REQUEST_MAX_FAILED = 4, CONNECTION_REQUEST_MAX = 0x7fffffff /*force the creation of this enum as a 32 bit int */ }connection_request_made_by_code_t; @@ -240,25 +267,24 @@ typedef enum connection_request_made_by_code_t{ //}; //extern struct wifi_settings_t wifi_settings; -/** - * @brief Structure used to store one message in the queue. - */ -typedef struct{ - message_code_t code; - void *param; -} queue_message; +// /** +// * @brief Structure used to store one message in the queue. +// */ +// typedef struct{ +// message_code_t code; +// void *param; +// } queue_message; + + + -/** - * Allocate heap memory for the wifi manager and start the wifi_manager RTOS task - */ -void wifi_manager_start(); /** * Frees up all memory allocated by the wifi_manager and kill the task. */ -void wifi_manager_destroy(); +void network_manager_destroy(); /** * Filters the AP scan list to unique SSIDs @@ -268,27 +294,14 @@ void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num); /** * Main task for the wifi_manager */ -void wifi_manager( void * pvParameters ); +void network_manager( void * pvParameters ); char* wifi_manager_alloc_get_ap_list_json(); -char* wifi_manager_alloc_get_ip_info_json(); cJSON * wifi_manager_clear_ap_list_json(cJSON **old); -/** - * @brief saves the current STA wifi config to flash ram storage. - */ -esp_err_t wifi_manager_save_sta_config(); -/** - * @brief fetch a previously STA wifi config in the flash ram storage. - * @return true if a previously saved config was found, false otherwise. - */ -bool wifi_manager_fetch_wifi_sta_config(); - -wifi_config_t* wifi_manager_get_wifi_sta_config(); - /** * @brief A standard wifi event handler as recommended by Espressif */ @@ -296,71 +309,13 @@ esp_err_t wifi_manager_event_handler(void *ctx, system_event_t *event); -/** - * @brief Registers handler for wifi and ip events - */ -void wifi_manager_register_handlers(); - - -/** - * @brief requests a connection to an access point that will be process in the main task thread. - */ -void wifi_manager_connect_async(); - -/** - * @brief requests a wifi scan - */ -void wifi_manager_scan_async(); - -/** - * @brief requests to disconnect and forget about the access point. - */ -void wifi_manager_disconnect_async(); - -/** - * @brief Tries to get access to json buffer mutex. - * - * The HTTP server can try to access the json to serve clients while the wifi manager thread can try - * to update it. These two tasks are synchronized through a mutex. - * - * The mutex is used by both the access point list json and the connection status json.\n - * These two resources should technically have their own mutex but we lose some flexibility to save - * on memory. - * - * This is a simple wrapper around freeRTOS function xSemaphoreTake. - * - * @param xTicksToWait The time in ticks to wait for the semaphore to become available. - * @return true in success, false otherwise. - */ -bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait); - -/** - * @brief Releases the json buffer mutex. - */ -void wifi_manager_unlock_json_buffer(); - -/** - * @brief Generates the connection status json: ssid and IP addresses. - * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. - */ -void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code); /** * @brief Clears the connection status json. * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. */ cJSON * wifi_manager_clear_ip_info_json(cJSON **old); cJSON * wifi_manager_get_new_json(cJSON **old); -/** - * @brief Generates the list of access points after a wifi scan. - * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. - */ -void wifi_manager_generate_access_points_json(cJSON ** ap_list); -/** - * @brief Clear the list of access points. - * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. - */ -void wifi_manager_clear_access_points_json(); /** @@ -369,19 +324,6 @@ void wifi_manager_clear_access_points_json(); void wifi_manager_initialise_mdns(); -bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait); -void wifi_manager_unlock_sta_ip_string(); - -/** - * @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69" - */ -char* wifi_manager_get_sta_ip_string(); - -/** - * @brief thread safe char representation of the STA IP update - */ -void wifi_manager_safe_update_sta_ip_string(struct ip4_addr * ip4); - /** * @brief Register a callback to a custom function when specific event message_code happens. @@ -389,8 +331,9 @@ void wifi_manager_safe_update_sta_ip_string(struct ip4_addr * ip4); void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) ); -BaseType_t wifi_manager_send_message(message_code_t code, void *param); -BaseType_t wifi_manager_send_message_to_front(message_code_t code, void *param); +bool network_manager_is_flag_set(EventBits_t bit); +void network_manager_set_flag(EventBits_t bit); +void network_manager_clear_flag(EventBits_t bit); #ifdef __cplusplus } diff --git a/components/wifi-manager/network_status.c b/components/wifi-manager/network_status.c new file mode 100644 index 00000000..ebee7c82 --- /dev/null +++ b/components/wifi-manager/network_status.c @@ -0,0 +1,381 @@ +#include "network_status.h" +#include +#include "bt_app_core.h" +#include "esp_log.h" +#include "globdefs.h" +#include "lwip/inet.h" +#include "monitor.h" +#include "network_ethernet.h" +#include "network_wifi.h" +#include "platform_config.h" +#include "platform_esp32.h" +#include "tools.h" +#include "trace.h" +#ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL +#pragma message "Defaulting release url" +#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases" +#endif +static const char TAG[] = "network_status"; +SemaphoreHandle_t wifi_manager_json_mutex = NULL; +SemaphoreHandle_t wifi_manager_sta_ip_mutex = NULL; +char* release_url = NULL; +char* wifi_manager_sta_ip = NULL; +char* ip_info_json = NULL; +cJSON* ip_info_cjson = NULL; +static char lms_server_ip[IP4ADDR_STRLEN_MAX] = {0}; +static uint16_t lms_server_port = 0; +static uint16_t lms_server_cport = 0; +static void (*chained_notify)(in_addr_t, u16_t, u16_t); +static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport); +#define STA_IP_LEN sizeof(char) * IP4ADDR_STRLEN_MAX + +void init_network_status() { + chained_notify = server_notify; + server_notify = connect_notify; + ESP_LOGD(TAG, "init_network_status. Creating mutexes"); + wifi_manager_json_mutex = xSemaphoreCreateMutex(); + wifi_manager_sta_ip_mutex = xSemaphoreCreateMutex(); + ip_info_json = NULL; + ESP_LOGD(TAG, "init_network_status. Creating status json structure"); + ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson); + ESP_LOGD(TAG, "Getting release url "); + char* release_url = (char*)config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0); + if (release_url == NULL) { + ESP_LOGE(TAG, "Unable to retrieve the release url from nvs"); + } else { + ESP_LOGD(TAG, "Found release url %s", release_url); + } + ESP_LOGD(TAG, "About to set the STA IP String to 0.0.0.0"); + wifi_manager_sta_ip = (char*)malloc(STA_IP_LEN); + wifi_manager_safe_update_sta_ip_string(NULL); +} +void destroy_network_status() { + FREE_AND_NULL(release_url); + FREE_AND_NULL(ip_info_json); + FREE_AND_NULL(wifi_manager_sta_ip); + cJSON_Delete(ip_info_cjson); + vSemaphoreDelete(wifi_manager_json_mutex); + wifi_manager_json_mutex = NULL; + vSemaphoreDelete(wifi_manager_sta_ip_mutex); + wifi_manager_sta_ip_mutex = NULL; + ip_info_cjson = NULL; +} +cJSON* wifi_manager_get_new_json(cJSON** old) { + ESP_LOGV(TAG, "wifi_manager_get_new_json called"); + cJSON* root = *old; + if (root != NULL) { + cJSON_Delete(root); + *old = NULL; + } + ESP_LOGV(TAG, "wifi_manager_get_new_json done"); + return cJSON_CreateObject(); +} + +cJSON* wifi_manager_clear_ip_info_json(cJSON** old) { + ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json called"); + cJSON* root = wifi_manager_get_basic_info(old); + ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json done"); + return root; +} +void network_status_clear_ip() { + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson); + wifi_manager_unlock_json_buffer(); + } +} +char* wifi_manager_alloc_get_ip_info_json() { + return cJSON_PrintUnformatted(ip_info_cjson); +} + +void wifi_manager_unlock_json_buffer() { + ESP_LOGV(TAG, "Unlocking json buffer!"); + xSemaphoreGive(wifi_manager_json_mutex); +} + +bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait) { + ESP_LOGV(TAG, "Locking json buffer"); + if (wifi_manager_json_mutex) { + if (xSemaphoreTake(wifi_manager_json_mutex, xTicksToWait) == pdTRUE) { + ESP_LOGV(TAG, "Json buffer locked!"); + return true; + } else { + ESP_LOGE(TAG, "Semaphore take failed. Unable to lock json buffer mutex"); + return false; + } + } else { + ESP_LOGV(TAG, "Unable to lock json buffer mutex"); + return false; + } +} + +bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait) { + if (wifi_manager_sta_ip_mutex) { + if (xSemaphoreTake(wifi_manager_sta_ip_mutex, xTicksToWait) == pdTRUE) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +void wifi_manager_unlock_sta_ip_string() { + xSemaphoreGive(wifi_manager_sta_ip_mutex); +} + +void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t* ip4) { + if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) { + strcpy(wifi_manager_sta_ip, ip4 != NULL ? ip4addr_ntoa(ip4) : "0.0.0.0"); + ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip); + wifi_manager_unlock_sta_ip_string(); + } +} +void wifi_manager_safe_reset_sta_ip_string() { + if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) { + strcpy(wifi_manager_sta_ip, "0.0.0.0"); + ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip); + wifi_manager_unlock_sta_ip_string(); + } +} +char* wifi_manager_get_sta_ip_string() { + return wifi_manager_sta_ip; +} +void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport) { + strncpy(lms_server_ip, inet_ntoa(ip), sizeof(lms_server_ip)); + lms_server_ip[sizeof(lms_server_ip) - 1] = '\0'; + ESP_LOGI(TAG, "LMS IP: %s, hport: %d, cport: %d", lms_server_ip, hport, cport); + lms_server_port = hport; + lms_server_cport = cport; +} +static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) { + set_lms_server_details(ip, hport, cport); + if (chained_notify) + (*chained_notify)(ip, hport, cport); + network_manager_async_update_status(); +} +void wifi_manager_update_basic_info() { + int32_t total_connected_time = 0; + int64_t last_connected = 0; + uint16_t num_disconnect = 0; + network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect); + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + monitor_gpio_t* mgpio = get_jack_insertion_gpio(); + + cJSON* voltage = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Voltage"); + if (voltage) { + cJSON_SetNumberValue(voltage, battery_value_svc()); + } + cJSON* bt_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_status"); + if (bt_status) { + cJSON_SetNumberValue(bt_status, bt_app_source_get_a2d_state()); + } + cJSON* bt_sub_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_sub_status"); + if (bt_sub_status) { + cJSON_SetNumberValue(bt_sub_status, bt_app_source_get_media_state()); + } + cJSON* jack = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Jack"); + if (jack) { + jack->type = mgpio->gpio >= 0 && jack_inserted_svc() ? cJSON_True : cJSON_False; + } + cJSON* disconnect_count = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "disconnect_count"); + if (disconnect_count) { + cJSON_SetNumberValue(disconnect_count, num_disconnect); + } + cJSON* avg_conn_time = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "avg_conn_time"); + if (avg_conn_time) { + cJSON_SetNumberValue(avg_conn_time, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0); + } + if (lms_server_cport > 0) { + cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport"); + if (value) { + cJSON_SetNumberValue(value, lms_server_cport); + } else { + cJSON_AddNumberToObject(ip_info_cjson, "lms_cport", lms_server_cport); + } + } + + if (lms_server_port > 0) { + cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port"); + if (value) { + cJSON_SetNumberValue(value, lms_server_port); + } else { + cJSON_AddNumberToObject(ip_info_cjson, "lms_port", lms_server_port); + } + } + + if (strlen(lms_server_ip) > 0) { + cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip"); + if (!value) { + // only create if it does not exist. Since we're creating a reference + // to a char buffer, updates to cJSON aren't needed + cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip)); + } + } + if (network_ethernet_enabled()) { + cJSON* eth = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "eth_up"); + if (eth) { + eth->type = network_ethernet_is_up() ? cJSON_True : cJSON_False; + } + } + wifi_manager_unlock_json_buffer(); + } +} +cJSON* network_status_update_string(cJSON** root, const char* key, const char* value) { + if (*root == NULL) { + *root = cJSON_CreateObject(); + } + + if (!key || !value || strlen(key) == 0) + return *root; + cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); + if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) { + ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value); + cJSON_SetValuestring(cjsonvalue, value); + } else { + cJSON_AddItemToObject(*root, key, cJSON_CreateString(value)); + } + return *root; +} +cJSON* network_status_update_number(cJSON** root, const char* key, int value) { + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + if (*root == NULL) { + *root = cJSON_CreateObject(); + } + + if (key && value && strlen(key) != 0) { + cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); + if (cjsonvalue) { + cJSON_SetNumberValue(cjsonvalue, value); + } else { + cJSON_AddNumberToObject(*root, key, value); + } + } + wifi_manager_unlock_json_buffer(); + } else { + ESP_LOGW(TAG, "Unable to lock status json buffer. "); + } + return *root; +} +cJSON* network_status_update_float(cJSON** root, const char* key, float value) { + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + if (*root == NULL) { + *root = cJSON_CreateObject(); + } + + if (key && strlen(key) != 0) { + cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); + if (cjsonvalue) { + cJSON_SetNumberValue(cjsonvalue, value); + } else { + cJSON_AddNumberToObject(*root, key, value); + } + } + wifi_manager_unlock_json_buffer(); + } else { + ESP_LOGW(TAG, "Unable to lock status json buffer. "); + } + return *root; +} +cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) { + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + if (*root == NULL) { + *root = cJSON_CreateObject(); + } + + if (key && strlen(key) != 0) { + cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key); + if (cjsonvalue) { + cjsonvalue->type = value ? cJSON_True : cJSON_False; + } else { + cJSON_AddBoolToObject(*root, key, value); + } + } + wifi_manager_unlock_json_buffer(); + } else { + ESP_LOGW(TAG, "Unable to lock status json buffer. "); + } + return *root; +} +cJSON* wifi_manager_get_basic_info(cJSON** old) { + int32_t total_connected_time = 0; + int64_t last_connected = 0; + uint16_t num_disconnect = 0; + network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect); + + monitor_gpio_t* mgpio = get_jack_insertion_gpio(); + const esp_app_desc_t* desc = esp_ota_get_app_description(); + ESP_LOGV(TAG, "wifi_manager_get_basic_info called"); + cJSON* root = network_status_update_string(&root, "project_name", desc->project_name); +#ifdef CONFIG_FW_PLATFORM_NAME + root = network_status_update_string(&root, "platform_name", CONFIG_FW_PLATFORM_NAME); +#endif + root = network_status_update_string(&root, "version", desc->version); + if (release_url != NULL) + root = network_status_update_string(&root, "release_url", release_url); + root = network_status_update_number(&root, "recovery", is_recovery_running ? 1 : 0); + root = network_status_update_bool(&root, "Jack", mgpio->gpio >= 0 && jack_inserted_svc()); + root = network_status_update_float(&root, "Voltage", battery_value_svc()); + root = network_status_update_number(&root, "disconnect_count", num_disconnect); + root = network_status_update_float(&root, "avg_conn_time", num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0); + root = network_status_update_number(&root, "bt_status", bt_app_source_get_a2d_state()); + root = network_status_update_number(&root, "bt_sub_status", bt_app_source_get_media_state()); + +#if CONFIG_I2C_LOCKED + root = network_status_update_bool(&root, "is_i2c_locked", true); +#else + root = network_status_update_bool(&root, "is_i2c_locked", false); +#endif + if (network_ethernet_enabled()) { + root = network_status_update_bool(&root, "eth_up", network_ethernet_is_up()); + } + ESP_LOGV(TAG, "wifi_manager_get_basic_info done"); + return root; +} + +void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code) { + ESP_LOGD(TAG, "wifi_manager_generate_ip_info_json called"); + + if (wifi_manager_lock_json_buffer(portMAX_DELAY)) { + /* generate the connection info with success */ + + ip_info_cjson = wifi_manager_get_basic_info(&ip_info_cjson); + wifi_manager_unlock_json_buffer(); + } else { + ESP_LOGW(TAG, "Unable to lock status json buffer. "); + } + ip_info_cjson = network_status_update_number(&ip_info_cjson, "urc", update_reason_code); + if (update_reason_code == UPDATE_CONNECTION_OK || update_reason_code == UPDATE_ETHERNET_CONNECTED) { + /* rest of the information is copied after the ssid */ + tcpip_adapter_ip_info_t ip_info; + esp_netif_get_ip_info(network_wifi_get_interface(), &ip_info); + + network_status_update_string(&ip_info_cjson, "ip", ip4addr_ntoa((ip4_addr_t*)&ip_info.ip)); + network_status_update_string(&ip_info_cjson, "netmask", ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask)); + network_status_update_string(&ip_info_cjson, "gw", ip4addr_ntoa((ip4_addr_t*)&ip_info.gw)); + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) == ESP_OK && (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA)) { + /* wifi is active, and associated to an AP */ + wifi_ap_record_t ap; + esp_wifi_sta_get_ap_info(&ap); + network_status_update_string(&ip_info_cjson, "ssid", ((char*)ap.ssid)); + network_status_update_number(&ip_info_cjson, "rssi", ap.rssi); + } + if (network_ethernet_is_up()) { + esp_netif_get_ip_info(network_ethernet_get_interface(), &ip_info); + cJSON* ethernet_ip = cJSON_CreateObject(); + cJSON_AddItemToObject(ethernet_ip, "ip", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.ip))); + cJSON_AddItemToObject(ethernet_ip, "netmask", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask))); + cJSON_AddItemToObject(ethernet_ip, "gw", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.gw))); + cJSON_AddItemToObject(ip_info_cjson, "eth", ethernet_ip); + } + } else { + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ip"); + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "netmask"); + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "gw"); + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "rssi"); + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ssid"); + cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "eth"); + } + ESP_LOGV(TAG, "wifi_manager_generate_ip_info_json done"); +} diff --git a/components/wifi-manager/network_status.h b/components/wifi-manager/network_status.h new file mode 100644 index 00000000..25f46cf4 --- /dev/null +++ b/components/wifi-manager/network_status.h @@ -0,0 +1,59 @@ +#pragma once +#include "network_manager.h" +#include "cJSON.h" +#ifdef __cplusplus +extern "C" { + +#endif +char* wifi_manager_alloc_get_ip_info_json(); +/** + * @brief Tries to get access to json buffer mutex. + * + * The HTTP server can try to access the json to serve clients while the wifi manager thread can try + * to update it. These two tasks are synchronized through a mutex. + * + * The mutex is used by both the access point list json and the connection status json.\n + * These two resources should technically have their own mutex but we lose some flexibility to save + * on memory. + * + * This is a simple wrapper around freeRTOS function xSemaphoreTake. + * + * @param xTicksToWait The time in ticks to wait for the semaphore to become available. + * @return true in success, false otherwise. + */ +bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait); + +/** + * @brief Releases the json buffer mutex. + */ +void wifi_manager_unlock_json_buffer(); + +bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait); +void wifi_manager_unlock_sta_ip_string(); + +/** + * @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69" + */ +char* wifi_manager_get_sta_ip_string(); + +/** + * @brief thread safe char representation of the STA IP update + */ +void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t * ip4); + +/** + * @brief Generates the connection status json: ssid and IP addresses. + * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. + */ +void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code); + +void init_network_status(); +void destroy_network_status(); +cJSON* wifi_manager_get_basic_info(cJSON** old); + +void wifi_manager_update_basic_info(); +void network_status_clear_ip(); +void wifi_manager_safe_reset_sta_ip_string(); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/wifi-manager/network_wifi.c b/components/wifi-manager/network_wifi.c new file mode 100644 index 00000000..b4de4489 --- /dev/null +++ b/components/wifi-manager/network_wifi.c @@ -0,0 +1,990 @@ +#include "network_wifi.h" +#include +#include "cJSON.h" +#include "dns_server.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "globdefs.h" +#include "lwip/sockets.h" +#include "messaging.h" +#include "network_status.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "platform_config.h" +#include "platform_esp32.h" +#include "tools.h" +#include "trace.h" + +static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); +static void network_manager_wifi_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) ; +static char* get_disconnect_code_desc(uint8_t reason); + +cJSON* accessp_cjson = NULL; +wifi_config_t* wifi_manager_config_sta = NULL; +static const char TAG[] = "network_wifi"; +const char wifi_manager_nvs_namespace[] = "config"; + +uint16_t ap_num = MAX_AP_NUM; + + + + +esp_netif_t *wifi_netif; + +wifi_ap_record_t* accessp_records = NULL; +/* wifi scanner config */ +wifi_scan_config_t scan_config = { + .ssid = 0, + .bssid = 0, + .channel = 0, + .show_hidden = true}; +#ifndef STR_OR_BLANK +#define STR_OR_BLANK(p) p == NULL ? "" : p +#endif + +esp_netif_t *network_wifi_get_interface(){ + return wifi_netif; +} + +void init_network_wifi() { + ESP_LOGD(TAG, "WIFI Starting."); + accessp_cjson = NULL; + accessp_cjson = wifi_manager_clear_ap_list_json(&accessp_cjson); + wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t)); + memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); + ESP_LOGD(TAG, "Init. "); + wifi_netif = esp_netif_create_default_wifi_sta(); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_LOGD(TAG, "Handlers"); + //wifi_manager_register_handlers(); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &network_wifi_event_handler, + NULL, + NULL)); + esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &network_manager_wifi_ip_event_handler, NULL); + ESP_LOGD(TAG, "Storage"); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_LOGD(TAG, "Set Mode"); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); + ESP_LOGD(TAG, "Start"); + ESP_ERROR_CHECK(esp_wifi_start()); +} +void destroy_network_wifi() { + cJSON_Delete(accessp_cjson); + accessp_cjson = NULL; + FREE_AND_NULL(wifi_manager_config_sta); +} +bool network_wifi_sta_config_changed() { + bool changed = true; + wifi_config_t wifi_manager_config_sta_existing; + if(wifi_manager_config_sta && wifi_manager_load_wifi_sta_config(&wifi_manager_config_sta_existing )){ + changed = strcmp( (char *)wifi_manager_config_sta_existing.sta.ssid,(char *)wifi_manager_config_sta->sta.ssid ) !=0 || + strcmp((char *) wifi_manager_config_sta_existing.sta.password,(char *)wifi_manager_config_sta->sta.password ) !=0; + } + return changed; + +} + +esp_err_t network_wifi_save_sta_config() { + nvs_handle handle; + esp_err_t esp_err; + ESP_LOGD(TAG, "Config Save"); + + if (wifi_manager_config_sta) { + esp_err = nvs_open(wifi_manager_nvs_namespace, NVS_READWRITE, &handle); + if (esp_err != ESP_OK) { + ESP_LOGE(TAG, "%s failure. Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); + return esp_err; + } + + esp_err = nvs_set_blob(handle, "ssid", wifi_manager_config_sta->sta.ssid, sizeof(wifi_manager_config_sta->sta.ssid)); + if (esp_err != ESP_OK) { + ESP_LOGE(TAG, "ssid (%s). Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); + return esp_err; + } + + esp_err = nvs_set_blob(handle, "password", wifi_manager_config_sta->sta.password, sizeof(wifi_manager_config_sta->sta.password)); + if (esp_err != ESP_OK) { + ESP_LOGE(TAG, "pass (%s). Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); + return esp_err; + } + + esp_err = nvs_commit(handle); + if (esp_err != ESP_OK) { + ESP_LOGE(TAG, "Commit error: %s", esp_err_to_name(esp_err)); + messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Unable to save wifi credentials. %s", esp_err_to_name(esp_err)); + return esp_err; + } + nvs_close(handle); + + ESP_LOGD(TAG, "saved: ssid:%s password:%s", wifi_manager_config_sta->sta.ssid, wifi_manager_config_sta->sta.password); + } + + return ESP_OK; +} +bool wifi_manager_load_wifi_sta_config(wifi_config_t* config ){ + nvs_handle handle; + esp_err_t esp_err; + + ESP_LOGD(TAG, "Fetching wifi sta config."); + esp_err = nvs_open(wifi_manager_nvs_namespace, NVS_READONLY, &handle); + if (esp_err == ESP_OK) { + + + /* ssid */ + ESP_LOGD(TAG, "Fetching value for ssid."); + size_t sz = sizeof(config->sta.ssid); + uint8_t* buff = (uint8_t*)malloc(sizeof(uint8_t) * sz); + memset(buff, 0x00, sizeof(uint8_t) * sz); + esp_err = nvs_get_blob(handle, "ssid", buff, &sz); + if (esp_err != ESP_OK) { + ESP_LOGD(TAG, "No ssid found in nvs."); + FREE_AND_NULL(buff); + nvs_close(handle); + return false; + } + memcpy(config->sta.ssid, buff, sizeof(config->sta.ssid)); + FREE_AND_NULL(buff); + ESP_LOGD(TAG, "wifi_manager_fetch_wifi_sta_config: ssid:%s ", config->sta.ssid); + + /* password */ + sz = sizeof(config->sta.password); + buff = (uint8_t*)malloc(sizeof(uint8_t) * sz); + memset(buff, 0x00, sizeof(uint8_t) * sz); + esp_err = nvs_get_blob(handle, "password", buff, &sz); + if (esp_err != ESP_OK) { + // Don't take this as an error. This could be an opened access point? + ESP_LOGW(TAG, "No wifi password found in nvs"); + } else { + memcpy(config->sta.password, buff, sizeof(config->sta.password)); + ESP_LOGD(TAG, "wifi_manager_fetch_wifi_sta_config: password:%s", config->sta.password); + } + FREE_AND_NULL(buff); + nvs_close(handle); + config->sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + return config->sta.ssid[0] != '\0'; + } else { + ESP_LOGW(TAG, "wifi manager has no previous configuration. %s", esp_err_to_name(esp_err)); + return false; + } +} + +bool wifi_manager_fetch_wifi_sta_config() { + if (wifi_manager_config_sta == NULL) { + ESP_LOGD(TAG, "Allocating memory for structure."); + wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t)); + } + memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); + return wifi_manager_load_wifi_sta_config(wifi_manager_config_sta); +} + +wifi_config_t* wifi_manager_get_wifi_sta_config() { + return wifi_manager_config_sta; +} +// void wifi_manager_register_handlers() { +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_WIFI_READY, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_AUTHMODE_CHANGE, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_START, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STOP, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_PROBEREQRECVED, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_FAILED, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_TIMEOUT, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_PIN, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_START, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_STOP, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &network_wifi_event_handler, NULL)); +// ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &network_wifi_event_handler, NULL)); +// } +#define LOCAL_MAC_SIZE 20 +char* get_mac_string(uint8_t mac[6]) { + char* macStr = malloc(LOCAL_MAC_SIZE); + memset(macStr, 0x00, LOCAL_MAC_SIZE); + snprintf(macStr, LOCAL_MAC_SIZE, MACSTR, MAC2STR(mac)); + return macStr; +} +static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + if (event_base != WIFI_EVENT) + return; + switch (event_id) { + case WIFI_EVENT_WIFI_READY: + ESP_LOGD(TAG, "WIFI_EVENT_WIFI_READY"); + break; + + case WIFI_EVENT_SCAN_DONE: + ESP_LOGD(TAG, "WIFI_EVENT_SCAN_DONE"); + network_manager_async_scan_done(); + break; + + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + ESP_LOGD(TAG, "WIFI_EVENT_STA_AUTHMODE_CHANGE"); + break; + + case WIFI_EVENT_AP_START: + ESP_LOGD(TAG, "WIFI_EVENT_AP_START"); + break; + + case WIFI_EVENT_AP_STOP: + ESP_LOGD(TAG, "WIFI_EVENT_AP_STOP"); + break; + + case WIFI_EVENT_AP_PROBEREQRECVED: { + // wifi_event_ap_probe_req_rx_t + // Argument structure for WIFI_EVENT_AP_PROBEREQRECVED event + // + // Public Members + // + // int rssi + // Received probe request signal strength + // + // uint8_t mac[6] + // MAC address of the station which send probe request + + wifi_event_ap_probe_req_rx_t* s = (wifi_event_ap_probe_req_rx_t*)event_data; + char* mac = get_mac_string(s->mac); + ESP_LOGD(TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s", s->rssi, STR_OR_BLANK(mac)); + FREE_AND_NULL(mac); + } break; + case WIFI_EVENT_STA_WPS_ER_SUCCESS: + ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS"); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED"); + break; + case WIFI_EVENT_STA_WPS_ER_TIMEOUT: + ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT"); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN"); + break; + case WIFI_EVENT_AP_STACONNECTED: { + wifi_event_ap_staconnected_t* stac = (wifi_event_ap_staconnected_t*)event_data; + char* mac = get_mac_string(stac->mac); + ESP_LOGD(TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s", stac->aid, STR_OR_BLANK(mac)); + FREE_AND_NULL(mac); + } break; + case WIFI_EVENT_AP_STADISCONNECTED: + ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED"); + break; + + case WIFI_EVENT_STA_START: + ESP_LOGD(TAG, "WIFI_EVENT_STA_START"); + break; + + case WIFI_EVENT_STA_STOP: + ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP"); + break; + + case WIFI_EVENT_STA_CONNECTED: { + // structwifi_event_sta_connected_t + // Argument structure for WIFI_EVENT_STA_CONNECTED event + // + // Public Members + // + // uint8_t ssid[32] + // SSID of connected AP + // + // uint8_t ssid_len + // SSID length of connected AP + // + // uint8_t bssid[6] + // BSSID of connected AP + // + // uint8_t channel + // channel of connected AP + // + // wifi_auth_mode_tauthmode + // authentication mode used by AP + //, get_mac_string(EVENT_HANDLER_ARG_FIELD(wifi_event_ap_probe_req_rx_t, mac))); + + ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. "); + wifi_event_sta_connected_t* s = (wifi_event_sta_connected_t*)event_data; + char* bssid = get_mac_string(s->bssid); + char* ssid = strdup((char*)s->ssid); + ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. Channel: %d, Access point: %s, BSSID: %s ", s->channel, STR_OR_BLANK(ssid), (bssid)); + FREE_AND_NULL(bssid); + FREE_AND_NULL(ssid); + network_manager_async_success(); + + } break; + + case WIFI_EVENT_STA_DISCONNECTED: { + // structwifi_event_sta_disconnected_t + // Argument structure for WIFI_EVENT_STA_DISCONNECTED event + // + // Public Members + // + // uint8_t ssid[32] + // SSID of disconnected AP + // + // uint8_t ssid_len + // SSID length of disconnected AP + // + // uint8_t bssid[6] + // BSSID of disconnected AP + // + // uint8_t reason + // reason of disconnection + wifi_event_sta_disconnected_t* s = (wifi_event_sta_disconnected_t*)event_data; + char* bssid = get_mac_string(s->bssid); + ESP_LOGD(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)", STR_OR_BLANK(bssid), s->reason, get_disconnect_code_desc(s->reason)); + FREE_AND_NULL(bssid); + + + /* if a DISCONNECT message is posted while a scan is in progress this scan will NEVER end, causing scan to never work again. For this reason SCAN_BIT is cleared too */ + // todo: check for implementation of this: network_manager_clear_flag(WIFI_MANAGER_WIFI_CONNECTED_BIT | WIFI_MANAGER_SCAN_BIT); + wifi_event_sta_disconnected_t * disconnected_event = malloc(sizeof(wifi_event_sta_disconnected_t)); + memcpy(disconnected_event, event_data, sizeof(wifi_event_sta_disconnected_t)); + network_manager_async_lost_connection(disconnected_event); + } break; + + default: + break; + } +} + + +cJSON* wifi_manager_get_new_array_json(cJSON** old) { + ESP_LOGV(TAG, "wifi_manager_get_new_array_json called"); + cJSON* root = *old; + if (root != NULL) { + cJSON_Delete(root); + *old = NULL; + } + ESP_LOGV(TAG, "wifi_manager_get_new_array_json done"); + return cJSON_CreateArray(); +} +void wifi_manager_generate_access_points_json(cJSON** ap_list) { + *ap_list = wifi_manager_get_new_array_json(ap_list); + + if (*ap_list == NULL) + return; + for (int i = 0; i < ap_num; i++) { + cJSON* ap = cJSON_CreateObject(); + if (ap == NULL) { + ESP_LOGE(TAG, "Unable to allocate memory for access point entry #%d", i); + return; + } + cJSON* radio = cJSON_CreateObject(); + if (radio == NULL) { + ESP_LOGE(TAG, "Unable to allocate memory for access point entry #%d", i); + cJSON_Delete(ap); + return; + } + wifi_ap_record_t ap_rec = accessp_records[i]; + cJSON_AddNumberToObject(ap, "chan", ap_rec.primary); + cJSON_AddNumberToObject(ap, "rssi", ap_rec.rssi); + cJSON_AddNumberToObject(ap, "auth", ap_rec.authmode); + cJSON_AddItemToObject(ap, "ssid", cJSON_CreateString((char*)ap_rec.ssid)); + + char* bssid = get_mac_string(ap_rec.bssid); + cJSON_AddItemToObject(ap, "bssid", cJSON_CreateString(STR_OR_BLANK(bssid))); + FREE_AND_NULL(bssid); + cJSON_AddNumberToObject(radio, "b", ap_rec.phy_11b ? 1 : 0); + cJSON_AddNumberToObject(radio, "g", ap_rec.phy_11g ? 1 : 0); + cJSON_AddNumberToObject(radio, "n", ap_rec.phy_11n ? 1 : 0); + cJSON_AddNumberToObject(radio, "low_rate", ap_rec.phy_lr ? 1 : 0); + cJSON_AddItemToObject(ap, "radio", radio); + cJSON_AddItemToArray(*ap_list, ap); + char* ap_json = cJSON_PrintUnformatted(ap); + if (ap_json != NULL) { + ESP_LOGD(TAG, "New access point found: %s", ap_json); + free(ap_json); + } + } + char* ap_list_json = cJSON_PrintUnformatted(*ap_list); + if (ap_list_json != NULL) { + ESP_LOGV(TAG, "Full access point list: %s", ap_list_json); + free(ap_list_json); + } +} +void wifi_manager_set_ipv4val(const char* key, char* default_value, ip4_addr_t * target) { + char* value = config_alloc_get_default(NVS_TYPE_STR, key, default_value, 0); + if (value != NULL) { + ESP_LOGD(TAG, "%s: %s", key, value); + inet_pton(AF_INET, value, target); /* access point is on a static IP */ + } + FREE_AND_NULL(value); +} +void wifi_manager_config_ap() { + tcpip_adapter_ip_info_t info; + esp_err_t err = ESP_OK; + char* value = NULL; + wifi_config_t ap_config = { + .ap = { + .ssid_len = 0, + }, + }; + ESP_LOGI(TAG, "Configuring Access Point."); + wifi_netif = esp_netif_create_default_wifi_ap(); + + /* In order to change the IP info structure, we have to first stop + * the DHCP server on the new interface + */ + esp_netif_dhcps_stop(wifi_netif); + + // tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); + // if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED) { + // ESP_LOGD(TAG, "Stopping DHCP on interface so we can "); + // if ((err = tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)) != ESP_OK) /* stop AP DHCP server */ + // { + // ESP_LOGW(TAG, "Stopping DHCP failed. Error %s", esp_err_to_name(err)); + // } + // } + /* + * Set access point mode IP adapter configuration + */ + + wifi_manager_set_ipv4val("ap_ip_address", DEFAULT_AP_IP, &info.ip); + wifi_manager_set_ipv4val("ap_ip_gateway", CONFIG_DEFAULT_AP_GATEWAY, &info.gw); + wifi_manager_set_ipv4val("ap_ip_netmask", CONFIG_DEFAULT_AP_NETMASK, &info.netmask); + ESP_LOGD(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP"); + if ((err = esp_netif_set_ip_info(wifi_netif, &info)) != ESP_OK) { + ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s", esp_err_to_name(err)); + return; + } + /* + * Set Access Point configuration + */ + value = config_alloc_get_default(NVS_TYPE_STR, "ap_ssid", CONFIG_DEFAULT_AP_SSID, 0); + if (value != NULL) { + strlcpy((char*)ap_config.ap.ssid, value, sizeof(ap_config.ap.ssid)); + ESP_LOGI(TAG, "AP SSID: %s", (char*)ap_config.ap.ssid); + } + FREE_AND_NULL(value); + + value = config_alloc_get_default(NVS_TYPE_STR, "ap_pwd", DEFAULT_AP_PASSWORD, 0); + if (value != NULL) { + strlcpy((char*)ap_config.ap.password, value, sizeof(ap_config.ap.password)); + ESP_LOGI(TAG, "AP Password: %s", (char*)ap_config.ap.password); + } + FREE_AND_NULL(value); + + value = config_alloc_get_default(NVS_TYPE_STR, "ap_channel", STR(CONFIG_DEFAULT_AP_CHANNEL), 0); + if (value != NULL) { + ESP_LOGD(TAG, "Channel: %s", value); + ap_config.ap.channel = atoi(value); + } + FREE_AND_NULL(value); + + ap_config.ap.authmode = AP_AUTHMODE; + ap_config.ap.ssid_hidden = DEFAULT_AP_SSID_HIDDEN; + ap_config.ap.max_connection = DEFAULT_AP_MAX_CONNECTIONS; + ap_config.ap.beacon_interval = DEFAULT_AP_BEACON_INTERVAL; + + ESP_LOGD(TAG, "Auth Mode: %d", ap_config.ap.authmode); + ESP_LOGD(TAG, "SSID Hidden: %d", ap_config.ap.ssid_hidden); + ESP_LOGD(TAG, "Max Connections: %d", ap_config.ap.max_connection); + ESP_LOGD(TAG, "Beacon interval: %d", ap_config.ap.beacon_interval); + + const char* msg = "Setting wifi mode as WIFI_MODE_APSTA"; + ESP_LOGD(TAG, "%s",msg); + if ((err = esp_wifi_set_mode(WIFI_MODE_APSTA)) != ESP_OK) { + ESP_LOGE(TAG, "%s. Error %s",msg, esp_err_to_name(err)); + return; + } + msg = "Setting wifi AP configuration for WIFI_IF_AP"; + ESP_LOGD(TAG, "%s", msg); + if ((err = esp_wifi_set_config(WIFI_IF_AP, &ap_config)) != ESP_OK) /* stop AP DHCP server */ + { + ESP_LOGE(TAG, "%s . Error %s", msg, esp_err_to_name(err)); + return; + } + + msg = "Setting wifi bandwidth"; + ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_AP_BANDWIDTH); + if ((err = esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH)) != ESP_OK) /* stop AP DHCP server */ + { + ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err)); + return; + } + + msg = "Setting wifi power save"; + ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_STA_POWER_SAVE); + + if ((err = esp_wifi_set_ps(DEFAULT_STA_POWER_SAVE)) != ESP_OK) /* stop AP DHCP server */ + { + ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err)); + return; + } + esp_netif_dhcps_start(wifi_netif); + ESP_LOGD(TAG, "Done configuring Soft Access Point"); + dns_server_start(); +} + +void wifi_manager_filter_unique(wifi_ap_record_t* aplist, uint16_t* aps) { + int total_unique; + wifi_ap_record_t* first_free; + total_unique = *aps; + + first_free = NULL; + + for (int i = 0; i < *aps - 1; i++) { + wifi_ap_record_t* ap = &aplist[i]; + + /* skip the previously removed APs */ + if (ap->ssid[0] == 0) + continue; + + /* remove the identical SSID+authmodes */ + for (int j = i + 1; j < *aps; j++) { + wifi_ap_record_t* ap1 = &aplist[j]; + if ((strcmp((const char*)ap->ssid, (const char*)ap1->ssid) == 0) && + (ap->authmode == ap1->authmode)) { /* same SSID, different auth mode is skipped */ + /* save the rssi for the display */ + if ((ap1->rssi) > (ap->rssi)) + ap->rssi = ap1->rssi; + /* clearing the record */ + memset(ap1, 0, sizeof(wifi_ap_record_t)); + } + } + } + /* reorder the list so APs follow each other in the list */ + for (int i = 0; i < *aps; i++) { + wifi_ap_record_t* ap = &aplist[i]; + /* skipping all that has no name */ + if (ap->ssid[0] == 0) { + /* mark the first free slot */ + if (first_free == NULL) + first_free = ap; + total_unique--; + continue; + } + if (first_free != NULL) { + memcpy(first_free, ap, sizeof(wifi_ap_record_t)); + memset(ap, 0, sizeof(wifi_ap_record_t)); + /* find the next free slot */ + for (int j = 0; j < *aps; j++) { + if (aplist[j].ssid[0] == 0) { + first_free = &aplist[j]; + break; + } + } + } + } + /* update the length of the list */ + *aps = total_unique; +} + +char* wifi_manager_alloc_get_ap_list_json() { + return cJSON_PrintUnformatted(accessp_cjson); +} +cJSON* wifi_manager_clear_ap_list_json(cJSON** old) { + ESP_LOGV(TAG, "wifi_manager_clear_ap_list_json called"); + cJSON* root = wifi_manager_get_new_array_json(old); + ESP_LOGV(TAG, "wifi_manager_clear_ap_list_json done"); + return root; +} +esp_err_t wifi_scan_done(queue_message* msg) { + esp_err_t err = ESP_OK; + /* As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns. + * As a consequence, ap_num MUST be reset to MAX_AP_NUM at every scan */ + ESP_LOGD(TAG, "Getting AP list records"); + if ((err = esp_wifi_scan_get_ap_num(&ap_num)) != ESP_OK) { + ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s", esp_err_to_name(err)); + return err; + } + + if (ap_num > 0) { + accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * ap_num); + if ((err = esp_wifi_scan_get_ap_records(&ap_num, accessp_records)) != ESP_OK) { + ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s", esp_err_to_name(err)); + return err; + } + /* make sure the http server isn't trying to access the list while it gets refreshed */ + ESP_LOGD(TAG, "Preparing to build ap JSON list"); + if (wifi_manager_lock_json_buffer(pdMS_TO_TICKS(1000))) { + /* Will remove the duplicate SSIDs from the list and update ap_num */ + wifi_manager_filter_unique(accessp_records, &ap_num); + wifi_manager_generate_access_points_json(&accessp_cjson); + wifi_manager_unlock_json_buffer(); + ESP_LOGD(TAG, "Done building ap JSON list"); + + } else { + ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan"); + err = ESP_FAIL; + } + free(accessp_records); + } else { + // + ESP_LOGD(TAG, "No AP Found. Emptying the list."); + accessp_cjson = wifi_manager_get_new_array_json(&accessp_cjson); + } + return err; +} +bool is_wifi_up(){ + return wifi_netif!=NULL; +} +esp_err_t network_wifi_start_scan(queue_message* msg) { + esp_err_t err = ESP_OK; + ESP_LOGD(TAG, "MESSAGE: ORDER_START_WIFI_SCAN"); + if(!is_wifi_up()) { + messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot scan"); + return ESP_FAIL; + } + /* if a scan is already in progress this message is simply ignored thanks to the WIFI_MANAGER_SCAN_BIT uxBit */ + if (!network_manager_is_flag_set(WIFI_MANAGER_SCAN_BIT)) { + if ((err = esp_wifi_scan_start(&scan_config, false)) != ESP_OK) { + ESP_LOGW(TAG, "Unable to start scan; %s ", esp_err_to_name(err)); + // set_status_message(WARNING, "Wifi Connecting. Cannot start scan."); + messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Scanning failed: %s", esp_err_to_name(err)); + } else { + network_manager_set_flag(WIFI_MANAGER_SCAN_BIT); + } + } else { + ESP_LOGW(TAG, "Scan already in progress!"); + } + + return err; +} +static void polling_STA(void* timer_id) { + network_manager_async_connect(wifi_manager_get_wifi_sta_config()); +} + +void set_host_name() { + esp_err_t err; + ESP_LOGD(TAG, "Retrieving host name from nvs"); + char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name"); + if (host_name == NULL) { + ESP_LOGE(TAG, "Could not retrieve host name from nvs"); + } else { + ESP_LOGD(TAG, "Setting host name to : %s", host_name); + if ((err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, host_name)) != ESP_OK) { + ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err)); + } + // if((err=tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_AP, host_name)) !=ESP_OK){ + // ESP_LOGE(TAG, "Unable to set host name. Error: %s",esp_err_to_name(err)); + // } + free(host_name); + } +} + +esp_err_t network_wifi_connect(wifi_config_t * cfg){ + esp_err_t err = ESP_OK; + ESP_LOGD(TAG, "network_wifi_connect"); + if(!is_wifi_up()) { + messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot connect"); + return ESP_FAIL; + } + tcpip_adapter_dhcp_status_t status; + ESP_LOGD(TAG, "wifi_manager: Checking if DHCP client for STA interface is running"); + ESP_ERROR_CHECK_WITHOUT_ABORT(tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &status)); + if (status != TCPIP_ADAPTER_DHCP_STARTED) { + ESP_LOGD(TAG, "wifi_manager: Start DHCP client for STA interface"); + ESP_ERROR_CHECK_WITHOUT_ABORT(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA)); + } + wifi_mode_t mode; + /* update config to latest and attempt connection */ + esp_wifi_get_mode(&mode); + if (WIFI_MODE_APSTA != mode && WIFI_MODE_STA != mode) { + // the soft ap is not started, so let's set the WiFi mode to STA + ESP_LOGD(TAG, "MESSAGE: network_wifi_connect_existing - setting mode WIFI_MODE_STA"); + if ((err = esp_wifi_set_mode(WIFI_MODE_STA)) != ESP_OK) { + ESP_LOGE(TAG, "Failed to set wifi mode to STA. Error %s", esp_err_to_name(err)); + return err; + } + } + + if ((err = esp_wifi_set_config(WIFI_IF_STA, cfg)) != ESP_OK) { + ESP_LOGE(TAG, "Failed to set STA configuration. Error %s", esp_err_to_name(err)); + return err; + } + + set_host_name(); + ESP_LOGI(TAG, "Wifi Connecting..."); + if ((err = esp_wifi_connect()) != ESP_OK) { + ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s", esp_err_to_name(err)); + return err; + } + return err; +} +void network_wifi_clear_config(){ + + /* erase configuration */ + if (wifi_manager_config_sta) { + ESP_LOGI(TAG, "Erasing WiFi Configuration."); + memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); + /* save NVS memory */ + network_wifi_save_sta_config(); + } + +} + + +// esp_err_t network_wifi_disconnected(queue_message* msg) { +// esp_err_t err = ESP_OK; +// wifi_event_sta_disconnected_t disc_event; + +// // ESP_LOGD(TAG, "MESSAGE: EVENT_STA_DISCONNECTED"); +// // if (msg->param == NULL) { +// // ESP_LOGE(TAG, "MESSAGE: EVENT_STA_DISCONNECTED - expected parameter not found!"); +// // } else { +// // memcpy(&disc_event, (wifi_event_sta_disconnected_t*)msg->param, sizeof(disc_event)); +// // free(msg->param); +// // ESP_LOGD(TAG, "MESSAGE: EVENT_STA_DISCONNECTED with Reason code: %d (%s)", disc_event.reason, get_disconnect_code_desc(disc_event.reason)); +// // } + +// /* this even can be posted in numerous different conditions +// * +// * 1. SSID password is wrong +// * 2. Manual disconnection ordered +// * 3. Connection lost +// * +// * Having clear understand as to WHY the event was posted is key to having an efficient wifi manager +// * +// * With wifi_manager, we determine: +// * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, We consider it's a client that requested the connection. +// * When SYSTEM_EVENT_STA_DISCONNECTED is posted, it's probably a password/something went wrong with the handshake. +// * +// * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, it's a disconnection that was ASKED by the client (clicking disconnect in the app) +// * When SYSTEM_EVENT_STA_DISCONNECTED is posted, saved wifi is erased from the NVS memory. +// * +// * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT and WIFI_MANAGER_REQUEST_STA_CONNECT_BIT are NOT set, it's a lost connection +// * +// * In this version of the software, reason codes are not used. They are indicated here for potential future usage. +// * +// * REASON CODE: +// * 1 UNSPECIFIED +// * 2 AUTH_EXPIRE auth no longer valid, this smells like someone changed a password on the AP +// * 3 AUTH_LEAVE +// * 4 ASSOC_EXPIRE +// * 5 ASSOC_TOOMANY too many devices already connected to the AP => AP fails to respond +// * 6 NOT_AUTHED +// * 7 NOT_ASSOCED +// * 8 ASSOC_LEAVE +// * 9 ASSOC_NOT_AUTHED +// * 10 DISASSOC_PWRCAP_BAD +// * 11 DISASSOC_SUPCHAN_BAD +// * 12 +// * 13 IE_INVALID +// * 14 MIC_FAILURE +// * 15 4WAY_HANDSHAKE_TIMEOUT wrong password! This was personnaly tested on my home wifi with a wrong password. +// * 16 GROUP_KEY_UPDATE_TIMEOUT +// * 17 IE_IN_4WAY_DIFFERS +// * 18 GROUP_CIPHER_INVALID +// * 19 PAIRWISE_CIPHER_INVALID +// * 20 AKMP_INVALID +// * 21 UNSUPP_RSN_IE_VERSION +// * 22 INVALID_RSN_IE_CAP +// * 23 802_1X_AUTH_FAILED wrong password? +// * 24 CIPHER_SUITE_REJECTED +// * 200 BEACON_TIMEOUT +// * 201 NO_AP_FOUND +// * 202 AUTH_FAIL +// * 203 ASSOC_FAIL +// * 204 HANDSHAKE_TIMEOUT +// * +// * */ + +// /* reset saved sta IP */ +// wifi_manager_safe_reset_sta_ip_string(); + +// if (network_manager_is_flag_set(WIFI_MANAGER_REQUEST_STA_CONNECT_BIT)) { +// network_manager_clear_flag(WIFI_MANAGER_REQUEST_STA_CONNECT_BIT); +// ESP_LOGW(TAG, "WiFi Disconnected while processing user connect request. Wrong password?"); +// /* there are no retries when it's a user requested connection by design. This avoids a user hanging too much +// * in case they typed a wrong password for instance. Here we simply clear the request bit and move on */ + + +// wifi_mode_t mode; +// esp_wifi_get_mode(&mode); +// if (WIFI_MODE_STA == mode) { +// network_manager_set_flag(WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT); +// // if wifi was STA, attempt to reload the previous network connection +// ESP_LOGW(TAG, "Attempting to restore previous network"); +// wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL); +// } +// } else if (network_manager_is_flag_set(WIFI_MANAGER_REQUEST_DISCONNECT_BIT)) { +// // ESP_LOGD(TAG, "WiFi disconnected by user"); +// // /* user manually requested a disconnect so the lost connection is a normal event. Clear the flag and restart the AP */ +// // network_manager_clear_flag(WIFI_MANAGER_REQUEST_DISCONNECT_BIT); +// // wifi_manager_generate_ip_info_json(UPDATE_USER_DISCONNECT, wifi_netif,false); +// // /* erase configuration */ +// // if (wifi_manager_config_sta) { +// // ESP_LOGI(TAG, "Erasing WiFi Configuration."); +// // memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); +// // /* save NVS memory */ +// // network_wifi_save_sta_config(); +// // } +// // /* start SoftAP */ +// // ESP_LOGD(TAG, "Disconnect processing complete. Ordering an AP start."); +// // wifi_manager_send_message(ORDER_START_AP, NULL); +// } else { +// /* lost connection ? */ +// // ESP_LOGE(TAG, "WiFi Connection lost."); +// // messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "WiFi Connection lost"); +// // wifi_manager_generate_ip_info_json(UPDATE_LOST_CONNECTION, wifi_netif,false); + +// // if (retries < WIFI_MANAGER_MAX_RETRY) { +// // ESP_LOGD(TAG, "Issuing ORDER_CONNECT_STA to retry connection."); +// // retries++; +// // wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_AUTO_RECONNECT); +// // } else { +// // /* In this scenario the connection was lost beyond repair: kick start the AP! */ +// // retries = 0; +// // wifi_mode_t mode; +// // ESP_LOGW(TAG, "All connect retry attempts failed."); + +// // /* put us in softAP mode first */ +// // esp_wifi_get_mode(&mode); +// // /* if it was a restore attempt connection, we clear the bit */ +// // network_manager_clear_flag(WIFI_MANAGER_REQUEST_RESTORE_STA_BIT); + +// // if (WIFI_MODE_APSTA != mode) { +// // STA_duration = STA_POLLING_MIN; +// // wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_MAX_FAILED); +// // } else if (STA_duration < STA_POLLING_MAX) { +// // STA_duration *= 1.25; +// // } + +// // xTimerChangePeriod(STA_timer, pdMS_TO_TICKS(STA_duration), portMAX_DELAY); +// // xTimerStart(STA_timer, portMAX_DELAY); +// // ESP_LOGD(TAG, "STA search slow polling of %d", STA_duration); +// // } +// } +// return err; +// } + + +char* get_disconnect_code_desc(uint8_t reason) { + switch (reason) { + case 1: + return "UNSPECIFIED"; + break; + case 2: + return "AUTH_EXPIRE"; + break; + case 3: + return "AUTH_LEAVE"; + break; + case 4: + return "ASSOC_EXPIRE"; + break; + case 5: + return "ASSOC_TOOMANY"; + break; + case 6: + return "NOT_AUTHED"; + break; + case 7: + return "NOT_ASSOCED"; + break; + case 8: + return "ASSOC_LEAVE"; + break; + case 9: + return "ASSOC_NOT_AUTHED"; + break; + case 10: + return "DISASSOC_PWRCAP_BAD"; + break; + case 11: + return "DISASSOC_SUPCHAN_BAD"; + break; + case 12: + return ""; + break; + case 13: + return "IE_INVALID"; + break; + case 14: + return "MIC_FAILURE"; + break; + case 15: + return "4WAY_HANDSHAKE_TIMEOUT"; + break; + case 16: + return "GROUP_KEY_UPDATE_TIMEOUT"; + break; + case 17: + return "IE_IN_4WAY_DIFFERS"; + break; + case 18: + return "GROUP_CIPHER_INVALID"; + break; + case 19: + return "PAIRWISE_CIPHER_INVALID"; + break; + case 20: + return "AKMP_INVALID"; + break; + case 21: + return "UNSUPP_RSN_IE_VERSION"; + break; + case 22: + return "INVALID_RSN_IE_CAP"; + break; + case 23: + return "802_1X_AUTH_FAILED"; + break; + case 24: + return "CIPHER_SUITE_REJECTED"; + break; + case 200: + return "BEACON_TIMEOUT"; + break; + case 201: + return "NO_AP_FOUND"; + break; + case 202: + return "AUTH_FAIL"; + break; + case 203: + return "ASSOC_FAIL"; + break; + case 204: + return "HANDSHAKE_TIMEOUT"; + break; + default: + return "UNKNOWN"; + break; + } + return ""; +} + + +static void network_manager_wifi_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + ip_event_got_ip_t* s = NULL; + tcpip_adapter_if_t index; + esp_netif_ip_info_t* ip_info = NULL; + + if (event_base != IP_EVENT) + return; + switch (event_id) { + case IP_EVENT_ETH_GOT_IP: + case IP_EVENT_STA_GOT_IP: + s = (ip_event_got_ip_t*)event_data; + //tcpip_adapter_if_t index = s->if_index; + network_manager_async_got_ip(); + ip_info = &s->ip_info; + index = s->if_index; + + ESP_LOGI(TAG, "Got an IP address from interface #%i. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s", + index, + IP2STR(&ip_info->ip), + IP2STR(&ip_info->gw), + IP2STR(&ip_info->netmask), + s->ip_changed ? "Address was changed" : "Address unchanged"); + + break; + case IP_EVENT_STA_LOST_IP: + ESP_LOGD(TAG, "IP_EVENT_STA_LOST_IP"); + break; + case IP_EVENT_AP_STAIPASSIGNED: + ESP_LOGD(TAG, "IP_EVENT_AP_STAIPASSIGNED"); + break; + case IP_EVENT_GOT_IP6: + ESP_LOGD(TAG, "IP_EVENT_GOT_IP6"); + break; + default: + break; + } +} \ No newline at end of file diff --git a/components/wifi-manager/network_wifi.h b/components/wifi-manager/network_wifi.h new file mode 100644 index 00000000..1ab44074 --- /dev/null +++ b/components/wifi-manager/network_wifi.h @@ -0,0 +1,61 @@ +#pragma once +#include "network_manager.h" +#ifdef __cplusplus +extern "C" { + +#endif +void init_network_wifi(); +void destroy_network_wifi(); +/** + * @brief saves the current STA wifi config to flash ram storage. + */ +esp_err_t network_wifi_save_sta_config(); + + +/** + * @brief fetch a previously STA wifi config in the flash ram storage. + * @return true if a previously saved config was found, false otherwise. + */ +bool wifi_manager_fetch_wifi_sta_config(); + +wifi_config_t* wifi_manager_get_wifi_sta_config(); + +/** + * @brief Registers handler for wifi and ip events + */ +void wifi_manager_register_handlers(); + +/** + * @brief Generates the list of access points after a wifi scan. + * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. + */ +void wifi_manager_generate_access_points_json(cJSON ** ap_list); + +/** + * @brief Clear the list of access points. + * @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful. + */ +void wifi_manager_clear_access_points_json(); + + +void wifi_manager_config_ap(); + +void wifi_manager_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps); +esp_err_t wifi_scan_done(queue_message *msg); +esp_err_t network_wifi_start_scan(queue_message *msg); +esp_err_t network_wifi_load_restore(queue_message *msg); +esp_err_t network_wifi_order_connect(queue_message *msg); +esp_err_t network_wifi_disconnected(queue_message *msg); +esp_err_t network_wifi_start_ap(queue_message *msg); +bool wifi_manager_load_wifi_sta_config(wifi_config_t* config ); +esp_err_t network_wifi_handle_event(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); +esp_err_t network_wifi_connect(wifi_config_t * cfg); +bool is_wifi_up(); +void network_wifi_clear_config(); +esp_netif_t *network_wifi_get_interface(); +bool network_wifi_sta_config_changed(); +void network_wifi_get_stats( int32_t * ret_total_connected_time, int64_t * ret_last_connected, uint16_t * ret_num_disconnect); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/wifi-manager/state_machine.cpp b/components/wifi-manager/state_machine.cpp new file mode 100644 index 00000000..525ec794 --- /dev/null +++ b/components/wifi-manager/state_machine.cpp @@ -0,0 +1,793 @@ +#include + +#include +#include +#include +#include +#include "cmd_system.h" +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "esp_log.h" +#include "esp_wifi_types.h" +#include "http_server_handlers.h" +#include "messaging.h" +#include "network_ethernet.h" +#include "network_status.h" +#include "network_wifi.h" +#include "state_machine.h" +#include "trace.h" +#include "dns_server.h" +BaseType_t network_manager_task; +/* objects used to manipulate the main queue of events */ +QueueHandle_t network_manager_queue; + +using namespace stateless; +using namespace std::placeholders; +static const char TAG[] = "network_manager"; +static TaskHandle_t task_network_manager = NULL; +TimerHandle_t STA_timer = NULL; +uint32_t STA_duration; + +static int32_t total_connected_time = 0; +static int64_t last_connected = 0; +static uint16_t num_disconnect = 0; +void network_wifi_get_stats(int32_t* ret_total_connected_time, int64_t* ret_last_connected, uint16_t* ret_num_disconnect) { + *ret_total_connected_time = total_connected_time; + *ret_last_connected = last_connected; + *ret_num_disconnect = num_disconnect; +} +namespace { + +std::ostream& operator<<(std::ostream& os, const state_t s) { + //static const char* name[] = { "idle", "stopped", "started", "running" }; + static const char* name[] = { + + "initializing", + "global", + "eth_starting", + "eth_active", + "eth_active_linkup", + "eth_active_connected", + "eth_active_linkdown", + "wifi_up", + "wifi_initializing", + "network_manager_async", + "wifi_connecting_scanning", + "wifi_connecting", + "wifi_connected", + "wifi_disconnecting", + "wifi_user_disconnected", + "wifi_connected_waiting_for_ip", + "wifi_connected_scanning", + "wifi_lost_connection", + "wifi_ap_mode", + "wifi_ap_mode_scanning", + "wifi_ap_mode_scan_done", + "wifi_ap_mode_connecting", + "wifi_ap_mode_connected", + "system_rebooting"}; + os << name[(int)s]; + return os; +} + +const char* trigger_to_string(trig_t trigger) { + switch (trigger) { + ENUM_TO_STRING(t_link_up); + ENUM_TO_STRING(t_link_down); + ENUM_TO_STRING(t_configure); + ENUM_TO_STRING(t_got_ip); + ENUM_TO_STRING(t_next); + ENUM_TO_STRING(t_start); + ENUM_TO_STRING(t_scan); + ENUM_TO_STRING(t_fail); + ENUM_TO_STRING(t_success); + ENUM_TO_STRING(t_scan_done); + ENUM_TO_STRING(t_connect); + ENUM_TO_STRING(t_reboot); + ENUM_TO_STRING(t_reboot_url); + ENUM_TO_STRING(t_lost_connection); + ENUM_TO_STRING(t_update_status); + ENUM_TO_STRING(t_disconnect); + default: + + break; + } + return "Unknown trigger"; +} +std::ostream& operator<<(std::ostream& os, const trig_t & t) { + //static const char* name[] = { "start", "stop", "set_speed", "halt" }; + os << trigger_to_string(t); + return os; +} + +} // namespace + +// namespace stateless +// { + +// template<> void print_state(std::ostream& os, const state& s) +// { os << s; } + +// template<> void print_trigger 0) + total_connected_time += ((esp_timer_get_time() - last_connected) / (1000 * 1000)); + last_connected = 0; + num_disconnect++; + ESP_LOGW(TAG, "Wifi disconnected. Number of disconnects: %d, Average time connected: %d", num_disconnect, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0); + //network_manager_async_connect(wifi_manager_get_wifi_sta_config()); + if (retries < WIFI_MANAGER_MAX_RETRY) { + ESP_LOGD(TAG, "Issuing ORDER_CONNECT_STA to retry connection."); + retries++; + network_manager_async_connect(wifi_manager_get_wifi_sta_config()); + free(disconnected_event); + } else { + /* In this scenario the connection was lost beyond repair: kick start the AP! */ + retries = 0; + wifi_mode_t mode; + ESP_LOGW(TAG, "All connect retry attempts failed."); + + /* put us in softAP mode first */ + esp_wifi_get_mode(&mode); + if (WIFI_MODE_APSTA != mode) { + STA_duration = STA_POLLING_MIN; + network_manager_async_lost_connection(disconnected_event); + } else if (STA_duration < STA_POLLING_MAX) { + STA_duration *= 1.25; + free(disconnected_event); + } + /* keep polling for existing connection */ + xTimerChangePeriod(STA_timer, pdMS_TO_TICKS(STA_duration), portMAX_DELAY); + xTimerStart(STA_timer, portMAX_DELAY); + ESP_LOGD(TAG, "STA search slow polling of %d", STA_duration); + } + }) + .on_entry([=](const TTransition& t) { + wifi_manager_safe_reset_sta_ip_string(); + }) + .permit(trig_t::t_connect, state_t::wifi_connecting) + .permit(trig_t::t_lost_connection, state_t::wifi_ap_mode); + // Register a callback for state transitions (the default does nothing). + sm_.on_transition([](const TTransition& t) { + std::cout << "transition from [" << t.source() << "] to [" + << t.destination() << "] via trigger [" << t.trigger() << "]" + << std::endl; + }); + + // Override the default behaviour of throwing when a trigger is unhandled. + sm_.on_unhandled_trigger([](const state_t s, const trig_t t) { + std::cerr << "ignore unhandled trigger [" << t << "] in state [" << s + << "]" << std::endl; + }); + } + + public: + bool + Allowed(trig_t trigger) { + if (!sm_.can_fire(trigger)) { + ESP_LOGW(TAG, "Network manager might not be able to process trigger %s", trigger_to_string(trigger)); + return false; + } + return true; + } + bool Fire(trig_t trigger) { + try { + sm_.fire(trigger); + return true; + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + } + return false; + } + bool Event(queue_message& msg) { + trig_t trigger = msg.trigger; + try { + if (trigger == trig_t::t_connect) { + sm_.fire(connect_trigger_, msg.wifi_config); + } else if (trigger == trig_t::t_reboot) { + sm_.fire(reboot_trigger_, msg.rtype); + } else if (trigger == trig_t::t_reboot_url) { + sm_.fire(reboot_ota_, msg.strval); + } else if (trigger == trig_t::t_lost_connection) { + sm_.fire(disconnected_, msg.disconnected_event); + } else { + sm_.fire(trigger); + } + return true; + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + return false; + } + } + + private: + uint8_t reconnect_attempt = 0; + bool existing_connection = false; + uint8_t retries = 0; + TStateMachine sm_; + TConnectTrigger connect_trigger_; + TRebootTrigger reboot_trigger_; + TRebootOTATrigger reboot_ota_; + TDisconnectTrigger disconnected_; +}; + +NetworkManager nm; +void network_manager_start() { + nm.Fire(trig_t::t_start); +} + +bool network_manager_async(trig_t trigger) { + queue_message msg; + msg.trigger = trigger; + if (nm.Allowed(trigger)) { + return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY); + } + return false; +} +bool network_manager_async_fail() { + return network_manager_async(trig_t::t_fail); +} +bool network_manager_async_success() { + return network_manager_async(trig_t::t_success); +} + +bool network_manager_async_link_up() { + return network_manager_async(trig_t::t_link_up); +} +bool network_manager_async_link_down() { + return network_manager_async(trig_t::t_link_down); +} +bool network_manager_async_configure() { + return network_manager_async(trig_t::t_configure); +} +bool network_manager_async_got_ip() { + return network_manager_async(trig_t::t_got_ip); +} +bool network_manager_async_next() { + return network_manager_async(trig_t::t_next); +} +bool network_manager_async_start() { + return network_manager_async(trig_t::t_start); +} +bool network_manager_async_scan() { + return network_manager_async(trig_t::t_scan); +} + +bool network_manager_async_update_status() { + return network_manager_async(trig_t::t_update_status); +} + +bool network_manager_async_disconnect() { + return network_manager_async(trig_t::t_disconnect); +} + +bool network_manager_async_scan_done() { + return network_manager_async(trig_t::t_scan_done); +} +bool network_manager_async_connect(wifi_config_t* wifi_config) { + queue_message msg; + msg.trigger = trig_t::t_connect; + msg.wifi_config = wifi_config; + if (nm.Allowed(msg.trigger)) { + return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY); + } + return false; +} +bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) { + queue_message msg; + msg.trigger = trig_t::t_lost_connection; + msg.disconnected_event = disconnected_event; + if (nm.Allowed(msg.trigger)) { + return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY); + } + return false; +} +bool network_manager_async_reboot(reboot_type_t rtype) { + queue_message msg; + msg.trigger = trig_t::t_reboot; + msg.rtype = rtype; + if (nm.Allowed(msg.trigger)) { + return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY); + } + return false; +} + +void network_manager_reboot_ota(char* url) { + queue_message msg; + + if (url == NULL) { + msg.trigger = trig_t::t_reboot; + msg.rtype = reboot_type_t::OTA; + } else { + msg.trigger = trig_t::t_reboot_url; + msg.strval = strdup(url); + } + if (nm.Allowed(msg.trigger)) { + xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY); + } + return; +} + +// switch (msg.code) { +// case EVENT_SCAN_DONE: +// err = wifi_scan_done(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) { +// ESP_LOGD(TAG, "Invoking SCAN DONE callback"); +// (*cb_ptr_arr[msg.code])(NULL); +// ESP_LOGD(TAG, "Done Invoking SCAN DONE callback"); +// } +// break; +// case ORDER_START_WIFI_SCAN: +// err = network_wifi_start_scan(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; + +// case ORDER_LOAD_AND_RESTORE_STA: +// err = network_wifi_load_restore(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); + +// break; + +// case ORDER_CONNECT_STA: +// err = network_wifi_order_connect(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); + +// break; + +// case EVENT_STA_DISCONNECTED: +// err = network_wifi_disconnected(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; + +// case ORDER_START_AP: +// err = network_wifi_start_ap(&msg); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; + +// case EVENT_GOT_IP: +// ESP_LOGD(TAG, "MESSAGE: EVENT_GOT_IP"); +// /* save IP as a string for the HTTP server host */ +// //s->ip_info.ip.addr +// ip_event_got_ip_t* event = (ip_event_got_ip_t*)msg.param; +// wifi_manager_safe_update_sta_ip_string(&(event->ip_info.ip)); +// wifi_manager_generate_ip_info_json(network_manager_is_flag_set(WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT)? UPDATE_FAILED_ATTEMPT_AND_RESTORE : UPDATE_CONNECTION_OK, event->esp_netif, event->ip_changed); +// free(msg.param); +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; +// case UPDATE_CONNECTION_OK: +// messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "UPDATE_CONNECTION_OK not implemented"); +// break; +// case ORDER_DISCONNECT_STA: +// ESP_LOGD(TAG, "MESSAGE: ORDER_DISCONNECT_STA. Calling esp_wifi_disconnect()"); + +// /* precise this is coming from a user request */ +// xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT); + +// /* order wifi discconect */ +// ESP_ERROR_CHECK(esp_wifi_disconnect()); + +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); + +// break; + +// case ORDER_RESTART_OTA_URL: +// ESP_LOGD(TAG, "Calling start_ota."); +// start_ota(msg.param, NULL, 0); +// free(msg.param); +// break; + +// case ORDER_RESTART_RECOVERY: + +// break; +// case ORDER_RESTART: +// ESP_LOGD(TAG, "Calling simple_restart."); +// simple_restart(); +// break; +// case ORDER_UPDATE_STATUS: +// ; +// break; +// case EVENT_ETH_TIMEOUT: +// ESP_LOGW(TAG, "Ethernet connection timeout. Rebooting with WiFi Active"); +// network_manager_reboot(RESTART); +// break; +// case EVENT_ETH_LINK_UP: +// /* callback */ +// ESP_LOGD(TAG,"EVENT_ETH_LINK_UP message received"); +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; +// case EVENT_ETH_LINK_DOWN: +// /* callback */ +// if (cb_ptr_arr[msg.code]) +// (*cb_ptr_arr[msg.code])(NULL); +// break; +// default: +// break; + +// } /* end of switch/case */ + +// if (!network_ethernet_wait_for_link(500)) { +// if(network_ethernet_enabled()){ +// ESP_LOGW(TAG, "Ethernet not connected. Starting Wifi"); +// } +// init_network_wifi(); +// wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL); +// } + +void network_manager(void* pvParameters) { + queue_message msg; + esp_err_t err = ESP_OK; + BaseType_t xStatus; + network_manager_async(trig_t::t_start); + + /* main processing loop */ + for (;;) { + xStatus = xQueueReceive(network_manager_queue, &msg, portMAX_DELAY); + + if (xStatus == pdPASS) { + // pass the event to the sync processor + nm.Event(msg); + } /* end of if status=pdPASS */ + } /* end of for loop */ + + vTaskDelete(NULL); +} + +void network_manager_destroy() { + vTaskDelete(task_network_manager); + task_network_manager = NULL; + /* heap buffers */ + destroy_network_status(); + destroy_network_wifi(); + destroy_network_status(); + /* RTOS objects */ + vQueueDelete(network_manager_queue); + network_manager_queue = NULL; +} \ No newline at end of file diff --git a/components/wifi-manager/state_machine.h b/components/wifi-manager/state_machine.h new file mode 100644 index 00000000..dd09f39a --- /dev/null +++ b/components/wifi-manager/state_machine.h @@ -0,0 +1,108 @@ +#pragma once +#ifdef __cplusplus +extern "C" { + +#endif + +#include "esp_wifi.h" +#include "esp_wifi_types.h" + + +#define STA_POLLING_MIN (15 * 1000) +#define STA_POLLING_MAX (10 * 60 * 1000) + +//enum class state { idle, stopped, started, running }; + +//enum class trigger { start, stop, set_speed, halt }; +typedef enum { + t_link_up, + t_link_down, + t_configure, + t_got_ip, + t_disconnect, + t_next, + t_start, + t_scan, + t_fail, + t_success, + t_scan_done, + t_connect, + t_reboot, + t_reboot_url, + t_lost_connection, + t_update_status +} trig_t; + +typedef enum { + instantiated, + initializing, + global, + eth_starting, + eth_active, + eth_active_linkup, + eth_active_connected, + eth_active_linkdown, + wifi_up, + wifi_initializing, + wifi_connecting_scanning, + wifi_connecting, + wifi_connected, + wifi_disconnecting, + wifi_user_disconnected, + wifi_connected_waiting_for_ip, + wifi_connected_scanning, + wifi_lost_connection, + wifi_ap_mode, + wifi_ap_mode_scanning, + wifi_ap_mode_scan_done, + wifi_ap_mode_connecting, + wifi_ap_mode_connected, + system_rebooting +} state_t; +typedef enum { + OTA, + RECOVERY, + RESTART, +} reboot_type_t; +typedef struct { + trig_t trigger; + union + { + wifi_config_t* wifi_config; + reboot_type_t rtype; + char * strval; + wifi_event_sta_disconnected_t * disconnected_event; + } ; + + +} queue_message; + +bool network_manager_event_simple(trig_t trigger); +bool network_manager_event(trig_t trigger, void* param); +bool network_t_connect_event(wifi_config_t* wifi_config); +bool network_t_link_event(bool link_up); +bool network_manager_async_event(trig_t trigger, void* param); +bool network_manager_async(trig_t trigger); +bool network_manager_async_fail(); +bool network_manager_async_success(); +bool network_manager_async_link_up(); +bool network_manager_async_link_down(); +bool network_manager_async_configure(); +bool network_manager_async_got_ip(); +bool network_manager_async_next(); +bool network_manager_async_start(); +bool network_manager_async_scan(); +bool network_manager_async_scan_done(); +bool network_manager_async_connect(wifi_config_t* wifi_config); +bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t * disconnected_event); +bool network_manager_async_reboot(reboot_type_t rtype); +void network_manager_reboot_ota(char* url); +bool network_manager_async_disconnect(); +bool network_manager_async_update_status(); +/** + * Allocate heap memory for the wifi manager and start the wifi_manager RTOS task + */ +void network_manager_start(); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c deleted file mode 100644 index c3c725b5..00000000 --- a/components/wifi-manager/wifi_manager.c +++ /dev/null @@ -1,1803 +0,0 @@ -/* -Copyright (c) 2017-2019 Tony Pottier - -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. - -@file wifi_manager.c -@author Tony Pottier -@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis - -Contains the freeRTOS task and all necessary support - -@see https://idyl.io -@see https://github.com/tonyp7/esp32-wifi-manager -*/ - -#include "wifi_manager.h" -#include "platform_esp32.h" -#include -#include -#include -#include - -#include "dns_server.h" -#include "esp_system.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include -#include "esp_event_loop.h" -#include "tcpip_adapter.h" -// IDF-V4++ #include "esp_netif.h" -#include "esp_event.h" -#include "esp_eth.h" -#include "esp_wifi.h" -#include "esp_wifi_types.h" -#include "esp_log.h" -#include "nvs.h" -#include "nvs_flash.h" -#include "mdns.h" -#include "lwip/api.h" -#include "lwip/err.h" -#include "lwip/netdb.h" -#include "lwip/ip4_addr.h" -#include "esp_ota_ops.h" -#include "esp_app_format.h" -#include "cJSON.h" -#include "platform_config.h" -#include "trace.h" -#include "cmd_system.h" -#include "messaging.h" -#include "bt_app_core.h" - -#include "http_server_handlers.h" -#include "monitor.h" -#include "accessors.h" -#include "globdefs.h" - - -#ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL -#pragma message "Defaulting release url" -#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases" -#endif - -#define STR_OR_BLANK(p) p==NULL?"":p -BaseType_t wifi_manager_task; - -/* objects used to manipulate the main queue of events */ -QueueHandle_t wifi_manager_queue; -SemaphoreHandle_t wifi_manager_json_mutex = NULL; -SemaphoreHandle_t wifi_manager_sta_ip_mutex = NULL; -char *wifi_manager_sta_ip = NULL; -#define STA_IP_LEN sizeof(char) * IP4ADDR_STRLEN_MAX -uint16_t ap_num = MAX_AP_NUM; -wifi_ap_record_t *accessp_records=NULL; -cJSON * accessp_cjson=NULL; -char *ip_info_json = NULL; -char * release_url=NULL; -cJSON * ip_info_cjson=NULL; -wifi_config_t* wifi_manager_config_sta = NULL; -static void (*chained_notify)(in_addr_t, u16_t, u16_t); -static int32_t total_connected_time=0; -static int64_t last_connected=0; -static uint16_t num_disconnect=0; -static char lms_server_ip[IP4ADDR_STRLEN_MAX]={0}; -static uint16_t lms_server_port=0; -static uint16_t lms_server_cport=0; - -void (**cb_ptr_arr)(void*) = NULL; - -/* @brief tag used for ESP serial console messages */ -static const char TAG[] = "wifi_manager"; - -/* @brief task handle for the main wifi_manager task */ -static TaskHandle_t task_wifi_manager = NULL; - -#define STA_POLLING_MIN (15*1000) -#define STA_POLLING_MAX (10*60*1000) - -/** - * The actual WiFi settings in use - */ -//struct wifi_settings_t wifi_settings = { -// .sta_only = DEFAULT_STA_ONLY, -// .sta_power_save = DEFAULT_STA_POWER_SAVE, -// .sta_static_ip = 0 -//}; - - -/* wifi scanner config */ -wifi_scan_config_t scan_config = { - .ssid = 0, - .bssid = 0, - .channel = 0, - .show_hidden = true -}; - - -const char wifi_manager_nvs_namespace[] = "config"; - -EventGroupHandle_t wifi_manager_event_group; - -/* @brief indicate that the ESP32 is currently connected. */ -const int WIFI_MANAGER_WIFI_CONNECTED_BIT = BIT0; - -const int WIFI_MANAGER_AP_STA_CONNECTED_BIT = BIT1; - -/* @brief Set automatically once the SoftAP is started */ -const int WIFI_MANAGER_AP_STARTED_BIT = BIT2; - -/* @brief When set, means a client requested to connect to an access point.*/ -const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT = BIT3; - -/* @brief This bit is set automatically as soon as a connection was lost */ -const int WIFI_MANAGER_STA_DISCONNECT_BIT = BIT4; - -/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */ -const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT = BIT5; - -/* @brief When set, means a client requested to disconnect from currently connected AP. */ -const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT = BIT6; - -/* @brief When set, means a scan is in progress */ -const int WIFI_MANAGER_SCAN_BIT = BIT7; - -/* @brief When set, means user requested for a disconnect */ -const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT = BIT8; - -/* @brief When set, means user requested connecting to a new network and it failed */ -const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT = BIT9; - - -char * get_disconnect_code_desc(uint8_t reason){ - switch (reason) { - case 1 : return "UNSPECIFIED"; break; - case 2 : return "AUTH_EXPIRE"; break; - case 3 : return "AUTH_LEAVE"; break; - case 4 : return "ASSOC_EXPIRE"; break; - case 5 : return "ASSOC_TOOMANY"; break; - case 6 : return "NOT_AUTHED"; break; - case 7 : return "NOT_ASSOCED"; break; - case 8 : return "ASSOC_LEAVE"; break; - case 9 : return "ASSOC_NOT_AUTHED"; break; - case 10 : return "DISASSOC_PWRCAP_BAD"; break; - case 11 : return "DISASSOC_SUPCHAN_BAD"; break; - case 12 : return ""; break; - case 13 : return "IE_INVALID"; break; - case 14 : return "MIC_FAILURE"; break; - case 15 : return "4WAY_HANDSHAKE_TIMEOUT"; break; - case 16 : return "GROUP_KEY_UPDATE_TIMEOUT"; break; - case 17 : return "IE_IN_4WAY_DIFFERS"; break; - case 18 : return "GROUP_CIPHER_INVALID"; break; - case 19 : return "PAIRWISE_CIPHER_INVALID"; break; - case 20 : return "AKMP_INVALID"; break; - case 21 : return "UNSUPP_RSN_IE_VERSION"; break; - case 22 : return "INVALID_RSN_IE_CAP"; break; - case 23 : return "802_1X_AUTH_FAILED"; break; - case 24 : return "CIPHER_SUITE_REJECTED"; break; - case 200 : return "BEACON_TIMEOUT"; break; - case 201 : return "NO_AP_FOUND"; break; - case 202 : return "AUTH_FAIL"; break; - case 203 : return "ASSOC_FAIL"; break; - case 204 : return "HANDSHAKE_TIMEOUT"; break; - default: return "UNKNOWN"; break; - } - return ""; -} -void wifi_manager_update_status(){ - wifi_manager_send_message(ORDER_UPDATE_STATUS,NULL); -} -void set_host_name(){ - esp_err_t err; - ESP_LOGD(TAG, "Retrieving host name from nvs"); - char * host_name = (char * )config_alloc_get(NVS_TYPE_STR, "host_name"); - if(host_name ==NULL){ - ESP_LOGE(TAG, "Could not retrieve host name from nvs"); - } - else { - ESP_LOGD(TAG, "Setting host name to : %s",host_name); - if((err=tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, host_name)) !=ESP_OK){ - ESP_LOGE(TAG, "Unable to set host name. Error: %s",esp_err_to_name(err)); - } -// if((err=tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_AP, host_name)) !=ESP_OK){ -// ESP_LOGE(TAG, "Unable to set host name. Error: %s",esp_err_to_name(err)); -// } - free(host_name); - } - -} - -bool isGroupBitSet(uint8_t bit){ - EventBits_t uxBits= xEventGroupGetBits(wifi_manager_event_group); - return (uxBits & bit); -} - -void wifi_manager_scan_async(){ - wifi_manager_send_message(ORDER_START_WIFI_SCAN, NULL); -} - -void wifi_manager_disconnect_async(){ - wifi_manager_send_message(ORDER_DISCONNECT_STA, NULL); - //xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT); TODO: delete -} - -void wifi_manager_reboot_ota(char * url){ - if(url == NULL){ - wifi_manager_send_message(ORDER_RESTART_OTA, NULL); - } - else { - wifi_manager_send_message(ORDER_RESTART_OTA_URL,strdup(url) ); - } - -} - -void wifi_manager_reboot(reboot_type_t rtype){ - switch (rtype) { - case OTA: - wifi_manager_send_message(ORDER_RESTART_OTA, NULL); - break; - case RECOVERY: - wifi_manager_send_message(ORDER_RESTART_RECOVERY, NULL); - break; - case RESTART: - wifi_manager_send_message(ORDER_RESTART, NULL); - break; - default: - ESP_LOGE(TAG,"Unknown reboot type %d", rtype); - break; - } - wifi_manager_send_message(ORDER_DISCONNECT_STA, NULL); - //xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT); TODO: delete -} - -/** Event handler for Ethernet events */ -static void eth_event_handler(void *arg, esp_event_base_t event_base, - int32_t event_id, void *event_data) -{ - 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; - - switch (event_id) { - case ETHERNET_EVENT_CONNECTED: - esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); - ESP_LOGI(TAG, "Ethernet Link Up"); - 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]); - break; - case ETHERNET_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "Ethernet Link Down"); - break; - case ETHERNET_EVENT_START: - ESP_LOGI(TAG, "Ethernet Started"); - break; - case ETHERNET_EVENT_STOP: - ESP_LOGI(TAG, "Ethernet Stopped"); - break; - default: - break; - } -} - -static void eth_init(void) { - esp_eth_mac_t *mac; - esp_eth_phy_t *phy; - esp_err_t err = ESP_OK; - eth_config_t const *eth = config_eth_get( ); - - // quick check if we have a valid ethernet configuration - if ((eth->mdc == -1 && eth->mosi == -1) || !*eth->model) { - ESP_LOGI(TAG, "No ethernet"); - return; - } - - tcpip_adapter_set_default_eth_handlers(); - esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL); - - eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); - eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); - phy_config.phy_addr = 1; - phy_config.reset_gpio_num = eth->rst; - - if (eth->rmii) { -#ifdef CONFIG_ETH_USE_ESP32_EMAC - mac_config.smi_mdc_gpio_num = eth->mdc; - mac_config.smi_mdio_gpio_num = eth->mdio; - mac = esp_eth_mac_new_esp32(&mac_config); - phy = esp_eth_phy_new_lan8720(&phy_config); - ESP_LOGI(TAG, "Adding ethernet RMII with mdc %d and mdio %d", eth->mdc, eth->mdio); -#else - ESP_LOGE(TAG, "Ethernet RMII set but not included in compilation"); - return; -#endif - } else { -#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051 - spi_device_handle_t spi_handle = NULL; - spi_host_device_t host = SPI3_HOST; - - if (eth->host != -1) { - // don't use system's shared SPI - spi_bus_config_t buscfg = { - .miso_io_num = eth->miso, - .mosi_io_num = eth->mosi, - .sclk_io_num = eth->clk, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - }; - - // can't use SPI0 - if (eth->host == 1) host = SPI2_HOST; - err |= spi_bus_initialize(host, &buscfg, 1); - } else { - // when we use shared SPI, we assume it has been initialized - host = spi_system_host; - } - - spi_device_interface_config_t devcfg = { - .command_bits = 1, - .address_bits = 7, - .mode = 0, - .clock_speed_hz = eth->speed, - .spics_io_num = eth->cs, - .queue_size = 20 - }; - - err |= spi_bus_add_device(host, &devcfg, &spi_handle); - - // dm9051 ethernet driver is based on spi driver - eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); - // we assume that isr has been installed already - dm9051_config.int_gpio_num = eth->intr; - mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); - phy = esp_eth_phy_new_dm9051(&phy_config); - ESP_LOGI(TAG, "Adding ethernet SPI on host %d with mosi %d and miso %d", host, eth->mosi, eth->miso); -#else - ESP_LOGE(TAG, "Ethernet SPI set but not included in compilation"); - return; -#endif - } - - esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); - esp_eth_handle_t eth_handle = NULL; - err |= esp_eth_driver_install(&config, ð_handle); - err |= esp_eth_start(eth_handle); - - if (err != ESP_OK) { - ESP_LOGE(TAG, "Can't install Ethernet driver %d", err); - } -} - -void wifi_manager_init_wifi(){ - /* event handler and event group for the wifi driver */ - ESP_LOGD(TAG, "Initializing wifi. Creating event group"); - wifi_manager_event_group = xEventGroupCreate(); - // Now Initialize the Wifi Stack - ESP_LOGD(TAG, "Initializing wifi. Initializing tcp_ip adapter"); - tcpip_adapter_init(); - ESP_LOGD(TAG, "Initializing wifi. Creating the default event loop"); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_LOGD(TAG, "Initializing wifi. Getting default wifi configuration"); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_LOGD(TAG, "Initializing wifi. Initializing wifi. "); - ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); - ESP_LOGD(TAG, "Initializing wifi. Calling register handlers"); - wifi_manager_register_handlers(); - ESP_LOGD(TAG, "Initializing wifi. Setting WiFi storage as RAM"); - ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); - ESP_LOGD(TAG, "Initializing wifi. Setting WiFi mode to WIFI_MODE_NULL"); - ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) ); - ESP_LOGD(TAG, "Initializing wifi. Starting wifi"); - ESP_ERROR_CHECK( esp_wifi_start() ); - - eth_init(); - - taskYIELD(); - ESP_LOGD(TAG, "Initializing wifi. done"); -} - -void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport){ - strncpy(lms_server_ip,inet_ntoa(ip),sizeof(lms_server_ip)); - lms_server_ip[sizeof(lms_server_ip)-1]='\0'; - ESP_LOGI(TAG,"LMS IP: %s, hport: %d, cport: %d",lms_server_ip, hport, cport); - lms_server_port = hport; - lms_server_cport = cport; - -} - -static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) { - set_lms_server_details(ip,hport,cport); - if (chained_notify) (*chained_notify)(ip, hport, cport); - wifi_manager_update_status(); -} - -static void polling_STA(void* timer_id) { - wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_AUTO_RECONNECT); -} - -void wifi_manager_start(){ - - - /* memory allocation */ - ESP_LOGD(TAG, "wifi_manager_start. Creating message queue"); - wifi_manager_queue = xQueueCreate( 3, sizeof( queue_message) ); - ESP_LOGD(TAG, "wifi_manager_start. Creating mutexes"); - wifi_manager_json_mutex = xSemaphoreCreateMutex(); - wifi_manager_sta_ip_mutex = xSemaphoreCreateMutex(); - - ESP_LOGD(TAG, "wifi_manager_start. Creating access point json structure"); - - accessp_cjson = NULL; - accessp_cjson = wifi_manager_clear_ap_list_json(&accessp_cjson); - ip_info_json = NULL; - ESP_LOGD(TAG, "wifi_manager_start. Creating status jcon structure"); - ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson); - - ESP_LOGD(TAG, "wifi_manager_start. Allocating memory for wifi configuration structure"); - wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t)); - memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); -// memset(&wifi_settings, 0x00, sizeof(wifi_settings)); - - ESP_LOGD(TAG, "wifi_manager_start. Allocating memory for callback functions registration"); - cb_ptr_arr = malloc( sizeof( sizeof( void (*)( void* ) )) * MESSAGE_CODE_COUNT); - for(int i=0; ista.ssid, sizeof(wifi_manager_config_sta->sta.ssid)); - if (esp_err != ESP_OK) { - ESP_LOGE(TAG, "Unable to save ssid in name namespace %s. Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); - return esp_err; - } - - esp_err = nvs_set_blob(handle, "password", wifi_manager_config_sta->sta.password, sizeof(wifi_manager_config_sta->sta.password)); - if (esp_err != ESP_OK) { - ESP_LOGE(TAG, "Unable to save password in name namespace %s. Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); - return esp_err; - } - -// esp_err = nvs_set_blob(handle, "settings", &wifi_settings, sizeof(wifi_settings)); -// if (esp_err != ESP_OK) { -// ESP_LOGE(TAG, "Unable to save wifi_settings in name namespace %s. Error %s", wifi_manager_nvs_namespace, esp_err_to_name(esp_err)); -// return esp_err; -// } - - esp_err = nvs_commit(handle); - if (esp_err != ESP_OK) { - ESP_LOGE(TAG, "Unable to commit changes. Error %s", esp_err_to_name(esp_err)); - messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Unable to save wifi credentials. %s",esp_err_to_name(esp_err)); - return esp_err; - } - nvs_close(handle); - - ESP_LOGD(TAG, "wifi_manager_wrote wifi_sta_config: ssid:%s password:%s",wifi_manager_config_sta->sta.ssid,wifi_manager_config_sta->sta.password); - } - - return ESP_OK; -} - -bool wifi_manager_fetch_wifi_sta_config(){ - nvs_handle handle; - esp_err_t esp_err; - - ESP_LOGD(TAG, "Fetching wifi sta config."); - esp_err=nvs_open(wifi_manager_nvs_namespace, NVS_READONLY, &handle); - if(esp_err == ESP_OK){ - if(wifi_manager_config_sta == NULL){ - ESP_LOGD(TAG, "Allocating memory for structure."); - wifi_manager_config_sta = (wifi_config_t*)malloc(sizeof(wifi_config_t)); - } - memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); - - /* ssid */ - ESP_LOGD(TAG, "Fetching value for ssid."); - size_t sz = sizeof(wifi_manager_config_sta->sta.ssid); - uint8_t *buff = (uint8_t*)malloc(sizeof(uint8_t) * sz); - memset(buff,0x00,sizeof(uint8_t) * sz); - esp_err = nvs_get_blob(handle, "ssid", buff, &sz); - if(esp_err != ESP_OK){ - ESP_LOGD(TAG, "No ssid found in nvs."); - FREE_AND_NULL(buff); - nvs_close(handle); - return false; - } - memcpy(wifi_manager_config_sta->sta.ssid, buff, sizeof(wifi_manager_config_sta->sta.ssid)); - FREE_AND_NULL(buff); - ESP_LOGD(TAG, "wifi_manager_fetch_wifi_sta_config: ssid:%s ",wifi_manager_config_sta->sta.ssid); - - /* password */ - sz = sizeof(wifi_manager_config_sta->sta.password); - buff = (uint8_t*)malloc(sizeof(uint8_t) * sz); - memset(buff,0x00,sizeof(uint8_t) * sz); - esp_err = nvs_get_blob(handle, "password", buff, &sz); - if(esp_err != ESP_OK){ - // Don't take this as an error. This could be an opened access point? - ESP_LOGW(TAG, "No wifi password found in nvs"); - } - else { - memcpy(wifi_manager_config_sta->sta.password, buff, sizeof(wifi_manager_config_sta->sta.password)); - ESP_LOGD(TAG, "wifi_manager_fetch_wifi_sta_config: password:%s",wifi_manager_config_sta->sta.password); - } - FREE_AND_NULL(buff); - nvs_close(handle); - - return wifi_manager_config_sta->sta.ssid[0] != '\0'; - } - else{ - ESP_LOGW(TAG, "wifi manager has no previous configuration. %s",esp_err_to_name(esp_err)); - return false; - } - -} - -cJSON * wifi_manager_get_new_json(cJSON **old){ - ESP_LOGV(TAG, "wifi_manager_get_new_json called"); - cJSON * root=*old; - if(root!=NULL){ - cJSON_Delete(root); - *old=NULL; - } - ESP_LOGV(TAG, "wifi_manager_get_new_json done"); - return cJSON_CreateObject(); -} -cJSON * wifi_manager_get_new_array_json(cJSON **old){ - ESP_LOGV(TAG, "wifi_manager_get_new_array_json called"); - cJSON * root=*old; - if(root!=NULL){ - cJSON_Delete(root); - *old=NULL; - } - ESP_LOGV(TAG, "wifi_manager_get_new_array_json done"); - return cJSON_CreateArray(); -} -void wifi_manager_update_basic_info(){ - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - - monitor_gpio_t *mgpio= get_jack_insertion_gpio(); - - cJSON * voltage = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Voltage"); - if(voltage){ - cJSON_SetNumberValue(voltage, battery_value_svc()); - } - cJSON * bt_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_status"); - if(bt_status){ - cJSON_SetNumberValue(bt_status, bt_app_source_get_a2d_state()); - } - cJSON * bt_sub_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_sub_status"); - if(bt_sub_status){ - cJSON_SetNumberValue(bt_sub_status, bt_app_source_get_media_state()); - } - cJSON * jack = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Jack"); - if(jack){ - jack->type=mgpio->gpio>=0 && jack_inserted_svc()?cJSON_True:cJSON_False; - } - cJSON * disconnect_count = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "disconnect_count"); - if(disconnect_count){ - cJSON_SetNumberValue(disconnect_count, num_disconnect); - } - cJSON * avg_conn_time = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "avg_conn_time"); - if(avg_conn_time){ - cJSON_SetNumberValue(avg_conn_time, num_disconnect>0?(total_connected_time/num_disconnect):0); - } - if(lms_server_cport>0){ - cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport"); - if(value){ - cJSON_SetNumberValue(value,lms_server_cport); - } - else { - cJSON_AddNumberToObject(ip_info_cjson,"lms_cport",lms_server_cport); - } - } - - if(lms_server_port>0){ - cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port"); - if(value){ - cJSON_SetNumberValue(value,lms_server_port); - } - else { - cJSON_AddNumberToObject(ip_info_cjson,"lms_port",lms_server_port); - } - } - - - if(strlen(lms_server_ip) >0){ - cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip"); - if(!value){ - // only create if it does not exist. Since we're creating a reference - // to a char buffer, updates to cJSON aren't needed - cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip)); - } - } - wifi_manager_unlock_json_buffer(); - } -} -cJSON * wifi_manager_get_basic_info(cJSON **old){ - monitor_gpio_t *mgpio= get_jack_insertion_gpio(); - const esp_app_desc_t* desc = esp_ota_get_app_description(); - ESP_LOGV(TAG, "wifi_manager_get_basic_info called"); - cJSON *root = wifi_manager_get_new_json(old); - cJSON_AddItemToObject(root, "project_name", cJSON_CreateString(desc->project_name)); - #ifdef CONFIG_FW_PLATFORM_NAME - cJSON_AddItemToObject(root, "platform_name", cJSON_CreateString(CONFIG_FW_PLATFORM_NAME)); - #endif - cJSON_AddItemToObject(root, "version", cJSON_CreateString(desc->version)); - if(release_url !=NULL) cJSON_AddItemToObject(root, "release_url", cJSON_CreateString(release_url)); - cJSON_AddNumberToObject(root,"recovery", is_recovery_running?1:0); - cJSON_AddBoolToObject(root, "Jack", mgpio->gpio>=0 && jack_inserted_svc() ); - cJSON_AddNumberToObject(root,"Voltage", battery_value_svc()); - cJSON_AddNumberToObject(root,"disconnect_count", num_disconnect ); - cJSON_AddNumberToObject(root,"avg_conn_time", num_disconnect>0?(total_connected_time/num_disconnect):0 ); - cJSON_AddNumberToObject(root,"bt_status", bt_app_source_get_a2d_state()); - cJSON_AddNumberToObject(root,"bt_sub_status", bt_app_source_get_media_state()); -#if CONFIG_I2C_LOCKED - cJSON_AddTrueToObject(root, "is_i2c_locked"); -#else - cJSON_AddFalseToObject(root, "is_i2c_locked"); -#endif - - ESP_LOGV(TAG, "wifi_manager_get_basic_info done"); - return root; -} -cJSON * wifi_manager_clear_ip_info_json(cJSON **old){ - ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json called"); - cJSON *root = wifi_manager_get_basic_info(old); - ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json done"); - return root; -} -cJSON * wifi_manager_clear_ap_list_json(cJSON **old){ - ESP_LOGV(TAG, "wifi_manager_clear_ap_list_json called"); - cJSON *root = wifi_manager_get_new_array_json(old); - ESP_LOGV(TAG, "wifi_manager_clear_ap_list_json done"); - return root; -} - - - -void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code){ - ESP_LOGD(TAG, "wifi_manager_generate_ip_info_json called"); - wifi_config_t *config = wifi_manager_get_wifi_sta_config(); - ip_info_cjson = wifi_manager_get_basic_info(&ip_info_cjson); - - cJSON_AddNumberToObject(ip_info_cjson, "urc", update_reason_code); - if(config){ - if(update_reason_code == UPDATE_CONNECTION_OK || update_reason_code == UPDATE_LOST_CONNECTION || update_reason_code == UPDATE_FAILED_ATTEMPT){ - cJSON_AddItemToObject(ip_info_cjson, "ssid", cJSON_CreateString((char *)config->sta.ssid)); - } - if(update_reason_code == UPDATE_CONNECTION_OK){ - /* rest of the information is copied after the ssid */ - tcpip_adapter_ip_info_t ip_info; - ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info)); - cJSON_AddItemToObject(ip_info_cjson, "ip", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t *)&ip_info.ip))); - cJSON_AddItemToObject(ip_info_cjson, "netmask", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t *)&ip_info.netmask))); - cJSON_AddItemToObject(ip_info_cjson, "gw", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t *)&ip_info.gw))); - wifi_ap_record_t ap; - esp_wifi_sta_get_ap_info(&ap); - cJSON_AddItemToObject(ip_info_cjson, "rssi", cJSON_CreateNumber(ap.rssi)); - } - } - - ESP_LOGV(TAG, "wifi_manager_generate_ip_info_json done"); -} -#define LOCAL_MAC_SIZE 20 -char * get_mac_string(uint8_t mac[6]){ - - char * macStr=malloc(LOCAL_MAC_SIZE); - memset(macStr, 0x00, LOCAL_MAC_SIZE); - snprintf(macStr, LOCAL_MAC_SIZE,MACSTR, MAC2STR(mac)); - return macStr; - -} -void wifi_manager_generate_access_points_json(cJSON ** ap_list){ - *ap_list = wifi_manager_get_new_array_json(ap_list); - - if(*ap_list==NULL) return; - for(int i=0; imac); - ESP_LOGD(TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s",s->rssi, STR_OR_BLANK(mac)); - FREE_AND_NULL(mac); - } - break; - case WIFI_EVENT_STA_WPS_ER_SUCCESS: - ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS"); - break; - case WIFI_EVENT_STA_WPS_ER_FAILED: - ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED"); - break; - case WIFI_EVENT_STA_WPS_ER_TIMEOUT: - ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT"); - break; - case WIFI_EVENT_STA_WPS_ER_PIN: - ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN"); - break; - case WIFI_EVENT_AP_STACONNECTED:{ /* a user disconnected from the SoftAP */ - wifi_event_ap_staconnected_t * stac = (wifi_event_ap_staconnected_t *)event_data; - char * mac = get_mac_string(stac->mac); - ESP_LOGD(TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s",stac->aid,STR_OR_BLANK(mac)); - FREE_AND_NULL(mac); - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_AP_STA_CONNECTED_BIT); - } - break; - case WIFI_EVENT_AP_STADISCONNECTED: - ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED"); - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_AP_STA_CONNECTED_BIT); - break; - - case WIFI_EVENT_STA_START: - ESP_LOGD(TAG, "WIFI_EVENT_STA_START"); - break; - - case WIFI_EVENT_STA_STOP: - ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP"); - break; - - case WIFI_EVENT_STA_CONNECTED:{ -// structwifi_event_sta_connected_t -// Argument structure for WIFI_EVENT_STA_CONNECTED event -// -// Public Members -// -// uint8_t ssid[32] -// SSID of connected AP -// -// uint8_t ssid_len -// SSID length of connected AP -// -// uint8_t bssid[6] -// BSSID of connected AP -// -// uint8_t channel -// channel of connected AP -// -// wifi_auth_mode_tauthmode -// authentication mode used by AP - //, get_mac_string(EVENT_HANDLER_ARG_FIELD(wifi_event_ap_probe_req_rx_t, mac))); - - ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. "); - wifi_event_sta_connected_t * s =(wifi_event_sta_connected_t*)event_data; - char * bssid = get_mac_string(s->bssid); - char * ssid = strdup((char*)s->ssid); - ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. Channel: %d, Access point: %s, BSSID: %s ", s->channel, STR_OR_BLANK(ssid), (bssid)); - FREE_AND_NULL(bssid); - FREE_AND_NULL(ssid); - - } - break; - - case WIFI_EVENT_STA_DISCONNECTED:{ -// structwifi_event_sta_disconnected_t -// Argument structure for WIFI_EVENT_STA_DISCONNECTED event -// -// Public Members -// -// uint8_t ssid[32] -// SSID of disconnected AP -// -// uint8_t ssid_len -// SSID length of disconnected AP -// -// uint8_t bssid[6] -// BSSID of disconnected AP -// -// uint8_t reason -// reason of disconnection - wifi_event_sta_disconnected_t * s =(wifi_event_sta_disconnected_t*)event_data; - char * bssid = get_mac_string(s->bssid); - ESP_LOGD(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)", STR_OR_BLANK(bssid),s->reason, get_disconnect_code_desc(s->reason)); - FREE_AND_NULL(bssid); - if(last_connected>0) total_connected_time+=((esp_timer_get_time()-last_connected)/(1000*1000)); - last_connected = 0; - num_disconnect++; - ESP_LOGW(TAG, "Wifi disconnected. Number of disconnects: %d, Average time connected: %d", num_disconnect, num_disconnect>0?(total_connected_time/num_disconnect):0); - - /* if a DISCONNECT message is posted while a scan is in progress this scan will NEVER end, causing scan to never work again. For this reason SCAN_BIT is cleared too */ - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_WIFI_CONNECTED_BIT | WIFI_MANAGER_SCAN_BIT); - - - // We want to process this message asynchronously, so make sure we copy the event buffer - ESP_LOGD(TAG, "Preparing to trigger event EVENT_STA_DISCONNECTED "); - void * parm=malloc(sizeof(wifi_event_sta_disconnected_t)); - memcpy(parm,event_data,sizeof(wifi_event_sta_disconnected_t)); - ESP_LOGD(TAG, "Triggering EVENT_STA_DISCONNECTED "); - /* post disconnect event with reason code */ - wifi_manager_send_message(EVENT_STA_DISCONNECTED, parm ); - } - break; - - default: - break; - } - } - else if(event_base== IP_EVENT){ - switch (event_id) { - case IP_EVENT_STA_GOT_IP:{ -// structip_event_got_ip_t -// tcpip_adapter_if_t if_index; /*!< Interface for which the event is received */ -// tcpip_adapter_ip6_info_t ip6_info; /*!< IPv6 address of the interface */ -// // Event structure for IP_EVENT_STA_GOT_IP, IP_EVENT_ETH_GOT_IP events -// -// Public Members -// -// tcpip_adapter_if_tif_index -// Interface for which the event is received -// -// tcpip_adapter_ip_info_t ip_info -// IP address, netmask, gatway IP address -// -// bool ip_changed -// Whether the assigned IP has changed or not - - ip_event_got_ip_t * s =(ip_event_got_ip_t*)event_data; - //tcpip_adapter_if_t index = s->if_index; - const tcpip_adapter_ip_info_t *ip_info = &s->ip_info; - ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP. IP="IPSTR", Gateway="IPSTR", NetMask="IPSTR", %s", - IP2STR(&ip_info->ip), - IP2STR(&ip_info->gw), - IP2STR(&ip_info->netmask), - s->ip_changed?"Address was changed":"Address unchanged"); - // todo: if ip address was changed, we probably need to restart, as all sockets - // will become abnormal - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_WIFI_CONNECTED_BIT); - last_connected = esp_timer_get_time(); - - void * parm=malloc(sizeof(ip_event_got_ip_t)); - memcpy(parm,event_data,sizeof(ip_event_got_ip_t)); - wifi_manager_send_message(EVENT_STA_GOT_IP, parm ); - } - break; - case IP_EVENT_STA_LOST_IP: - ESP_LOGD(TAG, "IP_EVENT_STA_LOST_IP"); - break; - case IP_EVENT_AP_STAIPASSIGNED: - ESP_LOGD(TAG, "IP_EVENT_AP_STAIPASSIGNED"); - break; - case IP_EVENT_GOT_IP6: - ESP_LOGD(TAG, "IP_EVENT_GOT_IP6"); - break; - case IP_EVENT_ETH_GOT_IP: - ESP_LOGD(TAG, "IP_EVENT_ETH_GOT_IP"); - wifi_manager_send_message(EVENT_ETH_GOT_IP, NULL); - break; - default: - break; - } - } - -} - - -wifi_config_t* wifi_manager_get_wifi_sta_config(){ - return wifi_manager_config_sta; -} - - - -void wifi_manager_connect_async(){ - /* in order to avoid a false positive on the front end app we need to quickly flush the ip json - * There'se a risk the front end sees an IP or a password error when in fact - * it's a remnant from a previous connection - */ - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - ip_info_cjson= wifi_manager_clear_ip_info_json(&ip_info_cjson); - wifi_manager_unlock_json_buffer(); - } - wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_USER); -} - - -char* wifi_manager_alloc_get_ip_info_json(){ - return cJSON_PrintUnformatted(ip_info_cjson); -} - -void wifi_manager_destroy(){ - vTaskDelete(task_wifi_manager); - task_wifi_manager = NULL; - /* heap buffers */ - free(ip_info_json); - free(release_url); - cJSON_Delete(ip_info_cjson); - cJSON_Delete(accessp_cjson); - ip_info_cjson=NULL; - accessp_cjson=NULL; - free(wifi_manager_sta_ip); - wifi_manager_sta_ip = NULL; - if(wifi_manager_config_sta){ - free(wifi_manager_config_sta); - wifi_manager_config_sta = NULL; - } - - /* RTOS objects */ - vSemaphoreDelete(wifi_manager_json_mutex); - wifi_manager_json_mutex = NULL; - vSemaphoreDelete(wifi_manager_sta_ip_mutex); - wifi_manager_sta_ip_mutex = NULL; - vEventGroupDelete(wifi_manager_event_group); - wifi_manager_event_group = NULL; - vQueueDelete(wifi_manager_queue); - wifi_manager_queue = NULL; -} - -void wifi_manager_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps) { - int total_unique; - wifi_ap_record_t * first_free; - total_unique=*aps; - - first_free=NULL; - - for(int i=0; i<*aps-1;i++) { - wifi_ap_record_t * ap = &aplist[i]; - - /* skip the previously removed APs */ - if (ap->ssid[0] == 0) continue; - - /* remove the identical SSID+authmodes */ - for(int j=i+1; j<*aps;j++) { - wifi_ap_record_t * ap1 = &aplist[j]; - if ( (strcmp((const char *)ap->ssid, (const char *)ap1->ssid)==0) && - (ap->authmode == ap1->authmode) ) { /* same SSID, different auth mode is skipped */ - /* save the rssi for the display */ - if ((ap1->rssi) > (ap->rssi)) ap->rssi=ap1->rssi; - /* clearing the record */ - memset(ap1,0, sizeof(wifi_ap_record_t)); - } - } - } - /* reorder the list so APs follow each other in the list */ - for(int i=0; i<*aps;i++) { - wifi_ap_record_t * ap = &aplist[i]; - /* skipping all that has no name */ - if (ap->ssid[0] == 0) { - /* mark the first free slot */ - if (first_free==NULL) first_free=ap; - total_unique--; - continue; - } - if (first_free!=NULL) { - memcpy(first_free, ap, sizeof(wifi_ap_record_t)); - memset(ap,0, sizeof(wifi_ap_record_t)); - /* find the next free slot */ - for(int j=0; j<*aps;j++) { - if (aplist[j].ssid[0]==0) { - first_free=&aplist[j]; - break; - } - } - } - } - /* update the length of the list */ - *aps = total_unique; -} - -BaseType_t wifi_manager_send_message_to_front(message_code_t code, void *param){ - queue_message msg; - msg.code = code; - msg.param = param; - return xQueueSendToFront( wifi_manager_queue, &msg, portMAX_DELAY); -} - -BaseType_t wifi_manager_send_message(message_code_t code, void *param){ - queue_message msg; - msg.code = code; - msg.param = param; - return xQueueSend( wifi_manager_queue, &msg, portMAX_DELAY); -} - -void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) ){ - if(cb_ptr_arr && message_code < MESSAGE_CODE_COUNT){ - cb_ptr_arr[message_code] = func_ptr; - } -} -void wifi_manager_register_handlers(){ - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_WIFI_READY, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_AUTHMODE_CHANGE, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_START, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STOP, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_PROBEREQRECVED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_FAILED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_TIMEOUT, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_PIN, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &event_handler, NULL )); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_START, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_STOP, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_LOST_IP, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &event_handler, NULL)); -} - -void wifi_manager_config_ap(){ - /* SoftAP - Wifi Access Point configuration setup */ - tcpip_adapter_ip_info_t info; - esp_err_t err=ESP_OK; - memset(&info, 0x00, sizeof(info)); - char * value = NULL; - wifi_config_t ap_config = { - .ap = { - .ssid_len = 0, - }, - }; - ESP_LOGI(TAG, "Configuring Access Point."); - - ESP_LOGD(TAG,"Stopping DHCP on interface "); - if((err= tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGW(TAG, "Stopping DHCP failed. Error %s",esp_err_to_name(err)); - } - /* - * Set access point mode IP adapter configuration - */ - value = config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(value!=NULL){ - ESP_LOGD(TAG, "IP Address: %s", value); - inet_pton(AF_INET,value, &info.ip); /* access point is on a static IP */ - } - FREE_AND_NULL(value); - value = config_alloc_get_default(NVS_TYPE_STR, "ap_ip_gateway", CONFIG_DEFAULT_AP_GATEWAY, 0); - if(value!=NULL){ - ESP_LOGD(TAG, "Gateway: %s", value); - inet_pton(AF_INET,value, &info.gw); /* access point is on a static IP */ - } - FREE_AND_NULL(value); - value = config_alloc_get_default(NVS_TYPE_STR, "ap_ip_netmask", CONFIG_DEFAULT_AP_NETMASK, 0); - if(value!=NULL){ - ESP_LOGD(TAG, "Netmask: %s", value); - inet_pton(AF_INET,value, &info.netmask); /* access point is on a static IP */ - } - FREE_AND_NULL(value); - - ESP_LOGD(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP"); - if((err=tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info))!=ESP_OK){ - ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s",esp_err_to_name(err)); - return; - } - /* - * Set Access Point configuration - */ - value = config_alloc_get_default(NVS_TYPE_STR, "ap_ssid", CONFIG_DEFAULT_AP_SSID, 0); - if(value!=NULL){ - strlcpy((char *)ap_config.ap.ssid, value,sizeof(ap_config.ap.ssid) ); - ESP_LOGI(TAG, "AP SSID: %s", (char *)ap_config.ap.ssid); - } - FREE_AND_NULL(value); - - value = config_alloc_get_default(NVS_TYPE_STR, "ap_pwd", DEFAULT_AP_PASSWORD, 0); - if(value!=NULL){ - strlcpy((char *)ap_config.ap.password, value,sizeof(ap_config.ap.password) ); - ESP_LOGI(TAG, "AP Password: %s", (char *)ap_config.ap.password); - } - FREE_AND_NULL(value); - - value = config_alloc_get_default(NVS_TYPE_STR, "ap_channel", STR(CONFIG_DEFAULT_AP_CHANNEL), 0); - if(value!=NULL){ - ESP_LOGD(TAG, "Channel: %s", value); - ap_config.ap.channel=atoi(value); - } - FREE_AND_NULL(value); - - ap_config.ap.authmode = AP_AUTHMODE; - ap_config.ap.ssid_hidden = DEFAULT_AP_SSID_HIDDEN; - ap_config.ap.max_connection = DEFAULT_AP_MAX_CONNECTIONS; - ap_config.ap.beacon_interval = DEFAULT_AP_BEACON_INTERVAL; - - ESP_LOGD(TAG, "Auth Mode: %d", ap_config.ap.authmode); - ESP_LOGD(TAG, "SSID Hidden: %d", ap_config.ap.ssid_hidden); - ESP_LOGD(TAG, "Max Connections: %d", ap_config.ap.max_connection); - ESP_LOGD(TAG, "Beacon interval: %d", ap_config.ap.beacon_interval); - - ESP_LOGD(TAG, ""); - if((err= esp_wifi_set_mode(WIFI_MODE_APSTA))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGE(TAG, "Setting wifi mode as WIFI_MODE_APSTA failed. Error %s",esp_err_to_name(err)); - return; - } - - - - ESP_LOGD(TAG, "Setting wifi AP configuration for WIFI_IF_AP"); - if((err= esp_wifi_set_config(WIFI_IF_AP, &ap_config))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGE(TAG, "Setting wifi AP configuration for WIFI_IF_AP failed. Error %s",esp_err_to_name(err)); - return; - } - - - ESP_LOGD(TAG, "Setting wifi bandwidth (%d) for WIFI_IF_AP",DEFAULT_AP_BANDWIDTH); - if((err=esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGE(TAG, "Setting wifi bandwidth for WIFI_IF_AP failed. Error %s",esp_err_to_name(err)); - return; - } - - ESP_LOGD(TAG, "Setting wifi power save (%d) for WIFI_IF_AP",DEFAULT_STA_POWER_SAVE); - - if((err=esp_wifi_set_ps(DEFAULT_STA_POWER_SAVE))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGE(TAG, "Setting wifi power savefor WIFI_IF_AP failed. Error %s",esp_err_to_name(err)); - return; - } - - ESP_LOGD(TAG, "Starting dhcps on interface TCPIP_ADAPTER_IF_AP"); - - if((err=tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP))!=ESP_OK) /* stop AP DHCP server */ - { - ESP_LOGE(TAG, "Starting dhcp on TCPIP_ADAPTER_IF_AP failed. Error %s",esp_err_to_name(err)); - return; - } - - ESP_LOGD(TAG, "Done configuring Soft Access Point"); - dns_server_start(); - - -} - -void wifi_manager( void * pvParameters ){ - queue_message msg; - BaseType_t xStatus; - EventBits_t uxBits; - uint8_t retries = 0; - esp_err_t err=ESP_OK; - TimerHandle_t STA_timer; - uint32_t STA_duration = STA_POLLING_MIN; - - /* create timer for background STA connection */ - STA_timer = xTimerCreate("background STA", pdMS_TO_TICKS(STA_duration), pdFALSE, NULL, polling_STA); - - /* start http server */ - http_server_start(); - - /* enqueue first event: load previous config and start AP or STA mode */ - wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL); - /* main processing loop */ - for(;;){ - xStatus = xQueueReceive( wifi_manager_queue, &msg, portMAX_DELAY ); - - if( xStatus == pdPASS ){ - switch(msg.code){ - - case EVENT_SCAN_DONE: - /* As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns. - * As a consequence, ap_num MUST be reset to MAX_AP_NUM at every scan */ - ESP_LOGD(TAG, "Getting AP list records"); - if((err=esp_wifi_scan_get_ap_num(&ap_num))!=ESP_OK) { - ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s",esp_err_to_name(err)); - break; - } - - if(ap_num>0){ - accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * ap_num); - if((err=esp_wifi_scan_get_ap_records(&ap_num, accessp_records))!=ESP_OK) { - ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s",esp_err_to_name(err)); - break; - } - /* make sure the http server isn't trying to access the list while it gets refreshed */ - ESP_LOGD(TAG, "Preparing to build ap JSON list"); - if(wifi_manager_lock_json_buffer( pdMS_TO_TICKS(1000) )){ - /* Will remove the duplicate SSIDs from the list and update ap_num */ - wifi_manager_filter_unique(accessp_records, &ap_num); - wifi_manager_generate_access_points_json(&accessp_cjson); - wifi_manager_unlock_json_buffer(); - ESP_LOGD(TAG, "Done building ap JSON list"); - - } - else{ - ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan"); - } - free(accessp_records); - } - else{ - // - ESP_LOGD(TAG, "No AP Found. Emptying the list."); - accessp_cjson = wifi_manager_get_new_array_json(&accessp_cjson); - } - - /* callback */ - if(cb_ptr_arr[msg.code]) { - ESP_LOGD(TAG, "Invoking SCAN DONE callback"); - (*cb_ptr_arr[msg.code])(NULL); - ESP_LOGD(TAG, "Done Invoking SCAN DONE callback"); - } - break; - - case ORDER_START_WIFI_SCAN: - ESP_LOGD(TAG, "MESSAGE: ORDER_START_WIFI_SCAN"); - - /* if a scan is already in progress this message is simply ignored thanks to the WIFI_MANAGER_SCAN_BIT uxBit */ - if(! isGroupBitSet(WIFI_MANAGER_SCAN_BIT) ){ - if(esp_wifi_scan_start(&scan_config, false)!=ESP_OK){ - ESP_LOGW(TAG, "Unable to start scan; wifi is trying to connect"); -// set_status_message(WARNING, "Wifi Connecting. Cannot start scan."); - messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Wifi connecting. Cannot start scan."); - } - else { - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_SCAN_BIT); - } - } - else { - ESP_LOGW(TAG, "Scan already in progress!"); - } - - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - - break; - - case ORDER_LOAD_AND_RESTORE_STA: - ESP_LOGD(TAG, "MESSAGE: ORDER_LOAD_AND_RESTORE_STA. About to fetch wifi STA configuration"); - if(wifi_manager_fetch_wifi_sta_config()){ - ESP_LOGI(TAG, "Saved wifi found on startup. Will attempt to connect."); - wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_RESTORE_CONNECTION); - } - else{ - /* no wifi saved: start soft AP! This is what should happen during a first run */ - ESP_LOGD(TAG, "No saved wifi found on startup. Starting access point."); - wifi_manager_send_message(ORDER_START_AP, NULL); - } - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - - break; - - case ORDER_CONNECT_STA: - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - Begin"); - break; // DOBREAK; - - /* very important: precise that this connection attempt is specifically requested. - * Param in that case is a boolean indicating if the request was made automatically - * by the wifi_manager. - * */ - if((BaseType_t)msg.param == CONNECTION_REQUEST_USER) { - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - Connection request with no nvs connection saved yet"); - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT); - xEventGroupClearBits(wifi_manager_event_group,WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT); - } - else if((BaseType_t)msg.param == CONNECTION_REQUEST_RESTORE_CONNECTION) { - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - Connection request after restoring the AP configuration"); - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT); - - /* STA - Wifi Station configuration setup */ - //todo: support static ip address -// if(wifi_settings.sta_static_ip) { -// // There's a static ip address configured, so -// ESP_LOGD(TAG, "Assigning static ip to STA interface. IP: %s , GW: %s , Mask: %s", -// ip4addr_ntoa(&wifi_settings.sta_static_ip_config.ip), -// ip4addr_ntoa(&wifi_settings.sta_static_ip_config.gw), -// ip4addr_ntoa(&wifi_settings.sta_static_ip_config.netmask)); -// -// /* stop DHCP client*/ -// ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); -// /* assign a static IP to the STA network interface */ -// ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &wifi_settings.sta_static_ip_config)); -// } -// else { - /* start DHCP client if not started*/ - tcpip_adapter_dhcp_status_t status; - ESP_LOGD(TAG, "wifi_manager: Checking if DHCP client for STA interface is running"); - ESP_ERROR_CHECK_WITHOUT_ABORT(tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &status)); - if (status!=TCPIP_ADAPTER_DHCP_STARTED) { - ESP_LOGD(TAG, "wifi_manager: Start DHCP client for STA interface"); - ESP_ERROR_CHECK_WITHOUT_ABORT(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA)); - } - //} - } - - uxBits = xEventGroupGetBits(wifi_manager_event_group); - if( uxBits & WIFI_MANAGER_WIFI_CONNECTED_BIT ){ - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - Wifi connected bit set, ordering disconnect (WIFI_MANAGER_WIFI_CONNECTED_BIT)"); - wifi_manager_send_message(ORDER_DISCONNECT_STA, NULL); - /* todo: reconnect */ - } - else{ - wifi_mode_t mode; - /* update config to latest and attempt connection */ - esp_wifi_get_mode(&mode); - if( WIFI_MODE_APSTA != mode && WIFI_MODE_STA !=mode ){ - // the soft ap is not started, so let's set the WiFi mode to STA - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - setting mode WIFI_MODE_STA"); - if((err=esp_wifi_set_mode(WIFI_MODE_STA))!=ESP_OK) { - ESP_LOGE(TAG, "Failed to set wifi mode to STA. Error %s",esp_err_to_name(err)); - break; - } - } - ESP_LOGD(TAG, "MESSAGE: ORDER_CONNECT_STA - setting config for WIFI_IF_STA"); - wifi_config_t* cfg = wifi_manager_get_wifi_sta_config(); - char * scan_mode = config_alloc_get_default(NVS_TYPE_STR, "wifi_smode", "f", 0); - if (scan_mode && strcasecmp(scan_mode,"a")==0) { - cfg->sta.scan_method=WIFI_ALL_CHANNEL_SCAN; - } - else { - cfg->sta.scan_method=WIFI_FAST_SCAN; - } - FREE_AND_NULL(scan_mode); - if((err=esp_wifi_set_config(WIFI_IF_STA, cfg))!=ESP_OK) { - ESP_LOGE(TAG, "Failed to set STA configuration. Error %s",esp_err_to_name(err)); - break; - } - - set_host_name(); - ESP_LOGI(TAG, "Wifi Connecting..."); - if((err=esp_wifi_connect())!=ESP_OK) { - ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s",esp_err_to_name(err)); - break; - } - } - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - - break; - - case EVENT_STA_DISCONNECTED:{ - wifi_event_sta_disconnected_t disc_event; - - ESP_LOGD(TAG, "MESSAGE: EVENT_STA_DISCONNECTED"); - if(msg.param == NULL){ - ESP_LOGE(TAG, "MESSAGE: EVENT_STA_DISCONNECTED - expected parameter not found!"); - } - else{ - memcpy(&disc_event,(wifi_event_sta_disconnected_t*)msg.param,sizeof(disc_event)); - free(msg.param); - ESP_LOGD(TAG, "MESSAGE: EVENT_STA_DISCONNECTED with Reason code: %d (%s)", disc_event.reason, get_disconnect_code_desc(disc_event.reason)); - } - - /* this even can be posted in numerous different conditions - * - * 1. SSID password is wrong - * 2. Manual disconnection ordered - * 3. Connection lost - * - * Having clear understand as to WHY the event was posted is key to having an efficient wifi manager - * - * With wifi_manager, we determine: - * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, We consider it's a client that requested the connection. - * When SYSTEM_EVENT_STA_DISCONNECTED is posted, it's probably a password/something went wrong with the handshake. - * - * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT is set, it's a disconnection that was ASKED by the client (clicking disconnect in the app) - * When SYSTEM_EVENT_STA_DISCONNECTED is posted, saved wifi is erased from the NVS memory. - * - * If WIFI_MANAGER_REQUEST_STA_CONNECT_BIT and WIFI_MANAGER_REQUEST_STA_CONNECT_BIT are NOT set, it's a lost connection - * - * In this version of the software, reason codes are not used. They are indicated here for potential future usage. - * - * REASON CODE: - * 1 UNSPECIFIED - * 2 AUTH_EXPIRE auth no longer valid, this smells like someone changed a password on the AP - * 3 AUTH_LEAVE - * 4 ASSOC_EXPIRE - * 5 ASSOC_TOOMANY too many devices already connected to the AP => AP fails to respond - * 6 NOT_AUTHED - * 7 NOT_ASSOCED - * 8 ASSOC_LEAVE - * 9 ASSOC_NOT_AUTHED - * 10 DISASSOC_PWRCAP_BAD - * 11 DISASSOC_SUPCHAN_BAD - * 12 - * 13 IE_INVALID - * 14 MIC_FAILURE - * 15 4WAY_HANDSHAKE_TIMEOUT wrong password! This was personnaly tested on my home wifi with a wrong password. - * 16 GROUP_KEY_UPDATE_TIMEOUT - * 17 IE_IN_4WAY_DIFFERS - * 18 GROUP_CIPHER_INVALID - * 19 PAIRWISE_CIPHER_INVALID - * 20 AKMP_INVALID - * 21 UNSUPP_RSN_IE_VERSION - * 22 INVALID_RSN_IE_CAP - * 23 802_1X_AUTH_FAILED wrong password? - * 24 CIPHER_SUITE_REJECTED - * 200 BEACON_TIMEOUT - * 201 NO_AP_FOUND - * 202 AUTH_FAIL - * 203 ASSOC_FAIL - * 204 HANDSHAKE_TIMEOUT - * - * */ - - /* reset saved sta IP */ - wifi_manager_safe_update_sta_ip_string((struct ip4_addr * )0); - - uxBits = xEventGroupGetBits(wifi_manager_event_group); - if( uxBits & WIFI_MANAGER_REQUEST_STA_CONNECT_BIT ){ - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT); - ESP_LOGW(TAG, "WiFi Disconnected while processing user connect request. Wrong password?"); - /* there are no retries when it's a user requested connection by design. This avoids a user hanging too much - * in case they typed a wrong password for instance. Here we simply clear the request bit and move on */ - - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - wifi_manager_generate_ip_info_json( UPDATE_FAILED_ATTEMPT ); - wifi_manager_unlock_json_buffer(); - } - wifi_mode_t mode; - esp_wifi_get_mode(&mode); - if( WIFI_MODE_STA ==mode ){ - xEventGroupSetBits(wifi_manager_event_group,WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT); - // if wifi was STA, attempt to reload the previous network connection - ESP_LOGW(TAG,"Attempting to restore previous network"); - wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL); - } - } - else if (uxBits & WIFI_MANAGER_REQUEST_DISCONNECT_BIT){ - ESP_LOGD(TAG, "WiFi disconnected by user"); - /* user manually requested a disconnect so the lost connection is a normal event. Clear the flag and restart the AP */ - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT); - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - wifi_manager_generate_ip_info_json( UPDATE_USER_DISCONNECT ); - wifi_manager_unlock_json_buffer(); - } - /* erase configuration */ - if(wifi_manager_config_sta){ - ESP_LOGI(TAG, "Erasing WiFi Configuration."); - memset(wifi_manager_config_sta, 0x00, sizeof(wifi_config_t)); - /* save NVS memory */ - wifi_manager_save_sta_config(); - } - /* start SoftAP */ - ESP_LOGD(TAG, "Disconnect processing complete. Ordering an AP start."); - wifi_manager_send_message(ORDER_START_AP, NULL); - } - else{ - /* lost connection ? */ - ESP_LOGE(TAG, "WiFi Connection lost."); - messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"WiFi Connection lost"); - - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - wifi_manager_generate_ip_info_json( UPDATE_LOST_CONNECTION ); - wifi_manager_unlock_json_buffer(); - } - - if(retries < WIFI_MANAGER_MAX_RETRY){ - ESP_LOGD(TAG, "Issuing ORDER_CONNECT_STA to retry connection."); - retries++; - wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_AUTO_RECONNECT); - } - else{ - /* In this scenario the connection was lost beyond repair: kick start the AP! */ - retries = 0; - wifi_mode_t mode; - ESP_LOGW(TAG, "All connect retry attempts failed."); - - /* put us in softAP mode first */ - esp_wifi_get_mode(&mode); - /* if it was a restore attempt connection, we clear the bit */ - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT); - - if(WIFI_MODE_APSTA != mode){ - /* call directly config_ap because we don't want to scan so the message has no benefit */ - ESP_LOGD(TAG, "Starting AP directly."); - wifi_manager_config_ap(); - STA_duration = STA_POLLING_MIN; - /* manual callback if needed */ - if(cb_ptr_arr[ORDER_START_AP]) (*cb_ptr_arr[ORDER_START_AP])(NULL); - } - else if(STA_duration < STA_POLLING_MAX) { - STA_duration *= 1.25; - } - - xTimerChangePeriod(STA_timer, pdMS_TO_TICKS(STA_duration), portMAX_DELAY); - xTimerStart(STA_timer, portMAX_DELAY); - ESP_LOGD(TAG, "STA search slow polling of %d", STA_duration); - } - } - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - } - break; - - case ORDER_START_AP: - ESP_LOGD(TAG, "MESSAGE: ORDER_START_AP"); - wifi_manager_config_ap(); - ESP_LOGD(TAG, "AP Starting, requesting wifi scan."); - wifi_manager_scan_async(); - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - break; - - - case EVENT_ETH_GOT_IP: - ESP_LOGD(TAG, "MESSAGE: EVENT_ETH_GOT_IP"); - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - break; - - case EVENT_STA_GOT_IP: - ESP_LOGD(TAG, "MESSAGE: EVENT_STA_GOT_IP"); - - uxBits = xEventGroupGetBits(wifi_manager_event_group); - - /* reset connection requests bits -- doesn't matter if it was set or not */ - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_STA_CONNECT_BIT); - - /* save IP as a string for the HTTP server host */ - //s->ip_info.ip.addr - ip_event_got_ip_t * event =(ip_event_got_ip_t*)msg.param; - wifi_manager_safe_update_sta_ip_string(&(event->ip_info.ip)); - free(msg.param); - - /* save wifi config in NVS if it wasn't a restored of a connection */ - if(uxBits & WIFI_MANAGER_REQUEST_RESTORE_STA_BIT){ - ESP_LOGD(TAG, "Configuration came from nvs, no need to save."); - xEventGroupClearBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_RESTORE_STA_BIT); - } - else{ - ESP_LOGD(TAG, "Connection was initiated by user, storing config to nvs."); - wifi_manager_save_sta_config(); - } - - /* refresh JSON with the new IP */ - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - /* generate the connection info with success */ - wifi_manager_generate_ip_info_json( uxBits & WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT?UPDATE_FAILED_ATTEMPT_AND_RESTORE:UPDATE_CONNECTION_OK ); - wifi_manager_unlock_json_buffer(); - } - else { - ESP_LOGW(TAG, "Unable to lock status json buffer. "); - } - - /* bring down DNS hijack */ - ESP_LOGD(TAG, "Stopping dns server."); - dns_server_stop(); - - /* stop AP mode */ - esp_wifi_set_mode(WIFI_MODE_STA); - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - break; - case UPDATE_CONNECTION_OK: - /* refresh JSON */ - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - /* generate the connection info with success */ - wifi_manager_generate_ip_info_json( UPDATE_CONNECTION_OK ); - wifi_manager_unlock_json_buffer(); - } - break; - case ORDER_DISCONNECT_STA: - ESP_LOGD(TAG, "MESSAGE: ORDER_DISCONNECT_STA. Calling esp_wifi_disconnect()"); - - /* precise this is coming from a user request */ - xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT); - - /* order wifi discconect */ - ESP_ERROR_CHECK(esp_wifi_disconnect()); - - /* callback */ - if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); - - break; - case ORDER_RESTART_OTA: - ESP_LOGD(TAG, "Calling guided_restart_ota."); - guided_restart_ota(); - break; - case ORDER_RESTART_OTA_URL: - ESP_LOGD(TAG, "Calling start_ota."); - start_ota(msg.param, NULL, 0); - free(msg.param); - break; - - case ORDER_RESTART_RECOVERY: - ESP_LOGD(TAG, "Calling guided_factory."); - guided_factory(); - break; - case ORDER_RESTART: - ESP_LOGD(TAG, "Calling simple_restart."); - simple_restart(); - break; - case ORDER_UPDATE_STATUS: - wifi_manager_update_basic_info(); - break; - default: - break; - - } /* end of switch/case */ - } /* end of if status=pdPASS */ - } /* end of for loop */ - - vTaskDelete( NULL ); -} diff --git a/file-size.txt b/file-size.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a7aadb91befeca706d5405cdee84c4f2492c255 GIT binary patch literal 332410 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 S0jG!6M-6Cgm9e|J68{(ZOj17p literal 0 HcmV?d00001 diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index b5b84113..be5c3f04 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -1,12 +1,12 @@ menu "Squeezelite-ESP32" menu "Logging" config LOGGING_SLIMPROTO - string "logging level for slimproto " + string "logging level for slimproto" default "info" help Set logging level info|debug|sdebug config LOGGING_STREAM - string "logging level for stream " + string "logging level for stream" default "info" help Set logging level info|debug|sdebug @@ -101,103 +101,49 @@ menu "Squeezelite-ESP32" default "" config DAC_CONTROLSET string - default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020 + default '{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and" } ] }' if TWATCH2020 default "" # AGGREGATES - end endmenu - - menu "Ethernet Options" - visible if BASIC_I2C_BT && (ETH_USE_ESP32_EMAC || ETH_USE_SPI_ETHERNET) - choice - prompt "Ethernet Chipset" - default ETH_NODRIVER - config ETH_NODRIVER - bool "Defined in NVS" - config ETH_LAN8720 - bool "Microchip LAN8720 (RMII)" - config ETH_DM9051 - bool "Davicom 9051 (SPI)" - endchoice - config ETH_PHY_RST_IO - int "PHY Reset GPIO number" if !ETH_NODRIVER - default -1 - help - Set the GPIO number used to reset PHY chip. - Set to -1 to disable PHY chip hardware reset. - config ETH_MDC_IO - int "SMI MDC GPIO number" if ETH_LAN8720 - default -1 - help - Set the GPIO number used by SMI MDC. - config ETH_MDIO_IO - int "SMI MDIO GPIO number" if ETH_LAN8720 - default -1 - help - Set the GPIO number used by SMI MDIO. - config ETH_SPI_HOST - int "SPI host number (-1,1 or 2)" if ETH_DM9051 - default -1 - help - Set to -1 to use system's SPI config (see Various I/O) - Set to 2 or 3 to use a dedicated bus - config ETH_SPI_INTR_IO - int "interrupt" if ETH_DM9051 - default -1 - config ETH_SPI_CS_IO - int "Chip Select" if ETH_DM9051 - default -1 - config ETH_SPI_CLK_IO - int "SPI clock" if ETH_SPI_HOST != -1 && ETH_DM9051 - default -1 - config ETH_SPI_MOSI_IO - int "Data Out" if ETH_SPI_HOST != -1 && ETH_DM9051 - default -1 - config ETH_SPI_MISO_IO - int "Data In" if ETH_SPI_HOST != -1 && ETH_DM9051 - default -1 - config ETH_SPI_SPEED - int "SPI speed (Hz)" if ETH_SPI_HOST != -1 && ETH_DM9051 - default 20000000 - endmenu menu "Audio settings" menu "DAC settings" visible if BASIC_I2C_BT menu "I2S settings" config I2S_NUM - int "I2S channel (0 or 1). " + int "I2S channel (0 or 1)." default 0 help I2S dma channel to use. config I2S_BCK_IO - int "I2S Bit clock GPIO number. " + int "I2S Bit clock GPIO number." default -1 help I2S Bit Clock gpio pin to use. config I2S_WS_IO - int "I2S Word Select GPIO number. " + int "I2S Word Select GPIO number." default -1 help I2S Word Select gpio pin to use. config I2S_DO_IO - int "I2S Data Output GPIO number. " + int "I2S Data Output GPIO number." default -1 help I2S data output gpio pin to use. config I2S_DI_IO - int "I2S Data Input GPIO number. " + int "I2S Data Input GPIO number." default -1 help I2S data input gpio pin to use (not used mostly, leave it to -1). endmenu menu "I2C settings" config I2C_SDA - int "I2C SDA GPIO number for DAC control. " + int "I2C SDA GPIO number for DAC control." default -1 help I2C data gpio pin to use with DAC (not used mostly, leave it to -1). config I2C_SCL - int "I2C SCL GPIO number for DAC control. " + int "I2C SCL GPIO number for DAC control." default -1 help I2C clock gpio pin to use with DAC (not used mostly, leave it to -1). @@ -249,7 +195,7 @@ menu "Squeezelite-ESP32" help This is the name of the device that the Bluetooth speaker will see when it is connected to. config A2DP_CONTROL_DELAY_MS - int "Control loop delay. " + int "Control loop delay." default 500 help Decreasing this will lead to a more responsive BT control, but might lead to noisy log files if debug is enabled. @@ -289,7 +235,7 @@ menu "Squeezelite-ESP32" config AIRPLAY_PORT depends on AIRPLAY_SINK string "AirPlay listening port" - default 5000 + default "5000" help AirPlay service listening port endmenu @@ -401,5 +347,9 @@ menu "Squeezelite-ESP32" help Set the scaling factor for this 12 bits ADC endmenu - + config DEFAULT_COMMAND_LINE + string "Default command line to execute" + default "squeezelite -o I2S -b 500:2000 -d all=info -C 30" + help + This is the command to run when starting the device endmenu \ No newline at end of file diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 40c697ab..c355a94e 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -30,7 +30,7 @@ #include "lwip/netdb.h" #include "nvs_utilities.h" #include "trace.h" -#include "wifi_manager.h" +#include "network_manager.h" #include "squeezelite-ota.h" #include #include "audio_controls.h" @@ -256,164 +256,91 @@ const char * get_certificate(){ } #define DEFAULT_NAME_WITH_MAC(var,defval) char var[strlen(defval)+sizeof(macStr)]; strcpy(var,defval); strcat(var,macStr) +void register_default_string_val(const char * key, char * value){ + char * existing =(char *)config_alloc_get(NVS_TYPE_STR,key ); + ESP_LOGD(TAG,"Register default called with: %s= %s",key,value ); + if(!existing) { + ESP_LOGI(TAG,"Registering default value for key %s, value %s",key,value ); + config_set_default(NVS_TYPE_STR, key,value, 0); + } + else { + ESP_LOGD(TAG,"Value found for %s: %s",key,existing ); + } + FREE_AND_NULL(existing); +} + +void register_default_with_mac(const char* key, char* defval) { + uint8_t mac[6]; + char macStr[LOCAL_MAC_SIZE + 1]; + char* fullvalue = NULL; + esp_read_mac((uint8_t*)&mac, ESP_MAC_WIFI_STA); + snprintf(macStr, LOCAL_MAC_SIZE - 1, "-%x%x%x", mac[3], mac[4], mac[5]); + fullvalue = malloc(strlen(defval)+sizeof(macStr)+1); + if(fullvalue){ + strcpy(fullvalue, defval); + strcat(fullvalue, macStr); + register_default_string_val(key,fullvalue); + FREE_AND_NULL(fullvalue); + } + else { + ESP_LOGE(TAG,"Memory allocation failed when registering default value for %s", key); + } + +} + void register_default_nvs(){ - uint8_t mac[6]; - char macStr[LOCAL_MAC_SIZE+1]; - char default_command_line[strlen(CONFIG_DEFAULT_COMMAND_LINE)+sizeof(macStr)]; - - esp_read_mac((uint8_t *)&mac, ESP_MAC_WIFI_STA); - snprintf(macStr, LOCAL_MAC_SIZE-1,"-%x%x%x", mac[3], mac[4], mac[5]); - - DEFAULT_NAME_WITH_MAC(default_bt_name,CONFIG_BT_NAME); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bt_name", default_bt_name); - config_set_default(NVS_TYPE_STR, "bt_name", default_bt_name, 0); - - DEFAULT_NAME_WITH_MAC(default_host_name,DEFAULT_HOST_NAME); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "host_name", default_host_name); - config_set_default(NVS_TYPE_STR, "host_name", default_host_name, 0); - - DEFAULT_NAME_WITH_MAC(default_airplay_name,CONFIG_AIRPLAY_NAME); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "airplay_name",default_airplay_name); - config_set_default(NVS_TYPE_STR, "airplay_name",default_airplay_name , 0); - - DEFAULT_NAME_WITH_MAC(default_ap_name,CONFIG_DEFAULT_AP_SSID); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ap_ssid", default_ap_name); - config_set_default(NVS_TYPE_STR, "ap_ssid",default_ap_name , 0); - - strncpy(default_command_line, CONFIG_DEFAULT_COMMAND_LINE,sizeof(default_command_line)-1); - strncat(default_command_line, " -n ",sizeof(default_command_line)-1); - strncat(default_command_line, default_host_name,sizeof(default_command_line)-1); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "autoexec", "1"); - config_set_default(NVS_TYPE_STR,"autoexec","1", 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "autoexec1",default_command_line); - config_set_default(NVS_TYPE_STR,"autoexec1",default_command_line,0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "a2dp_sink_name", CONFIG_A2DP_SINK_NAME); - config_set_default(NVS_TYPE_STR, "a2dp_sink_name", CONFIG_A2DP_SINK_NAME, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "a2dp_sink_name", STR(CONFIG_A2DP_SINK_NAME)); - config_set_default(NVS_TYPE_STR, "a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS), 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS)); - config_set_default(NVS_TYPE_STR, "a2dp_ctrld", STR(CONFIG_A2DP_CONTROL_DELAY_MS), 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL); - config_set_default(NVS_TYPE_STR, "release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s","ap_ip_address",CONFIG_DEFAULT_AP_IP ); - config_set_default(NVS_TYPE_STR, "ap_ip_address",CONFIG_DEFAULT_AP_IP , 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ap_ip_gateway",CONFIG_DEFAULT_AP_GATEWAY ); - config_set_default(NVS_TYPE_STR, "ap_ip_gateway",CONFIG_DEFAULT_AP_GATEWAY , 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s","ap_ip_netmask",CONFIG_DEFAULT_AP_NETMASK ); - config_set_default(NVS_TYPE_STR, "ap_ip_netmask",CONFIG_DEFAULT_AP_NETMASK , 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ap_channel",STR(CONFIG_DEFAULT_AP_CHANNEL)); - config_set_default(NVS_TYPE_STR, "ap_channel",STR(CONFIG_DEFAULT_AP_CHANNEL) , 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ap_pwd", CONFIG_DEFAULT_AP_PASSWORD); - config_set_default(NVS_TYPE_STR, "ap_pwd", CONFIG_DEFAULT_AP_PASSWORD, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "airplay_port", CONFIG_AIRPLAY_PORT); - config_set_default(NVS_TYPE_STR, "airplay_port", CONFIG_AIRPLAY_PORT, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "a2dp_dev_name", CONFIG_A2DP_DEV_NAME); - config_set_default(NVS_TYPE_STR, "a2dp_dev_name", CONFIG_A2DP_DEV_NAME, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bypass_wm", "0"); - config_set_default(NVS_TYPE_STR, "bypass_wm", "0", 0); - - ESP_LOGD(TAG,"Registering default value for equalizer"); - config_set_default(NVS_TYPE_STR, "equalizer", "", 0); - - ESP_LOGD(TAG,"Registering default Audio control board type %s, value ","actrls_config"); - config_set_default(NVS_TYPE_STR, "actrls_config", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "lms_ctrls_raw"); - config_set_default(NVS_TYPE_STR, "lms_ctrls_raw", "n", 0); - - ESP_LOGD(TAG,"Registering default Audio control board type %s, value %s", "rotary_config", CONFIG_ROTARY_ENCODER); - config_set_default(NVS_TYPE_STR, "rotary_config", CONFIG_ROTARY_ENCODER, 0); + register_default_with_mac("bt_name", CONFIG_BT_NAME); + register_default_with_mac("host_name", DEFAULT_HOST_NAME); + register_default_with_mac("airplay_name", CONFIG_AIRPLAY_NAME); + register_default_with_mac("ap_ssid", CONFIG_DEFAULT_AP_SSID); + register_default_string_val("autoexec","1"); + register_default_with_mac("autoexec1",CONFIG_DEFAULT_COMMAND_LINE " -n " DEFAULT_HOST_NAME); + register_default_string_val("a2dp_sink_name", CONFIG_A2DP_SINK_NAME); + register_default_string_val("a2dp_ctmt", STR(CONFIG_A2DP_CONNECT_TIMEOUT_MS)); + register_default_string_val("a2dp_ctrld", STR(CONFIG_A2DP_CONTROL_DELAY_MS)); + register_default_string_val("release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL); + register_default_string_val("ap_ip_address",CONFIG_DEFAULT_AP_IP); + register_default_string_val("ap_ip_gateway",CONFIG_DEFAULT_AP_GATEWAY ); + register_default_string_val("ap_ip_netmask",CONFIG_DEFAULT_AP_NETMASK); + register_default_string_val("ap_channel",STR(CONFIG_DEFAULT_AP_CHANNEL)); + register_default_string_val("ap_pwd", CONFIG_DEFAULT_AP_PASSWORD); + register_default_string_val("airplay_port", CONFIG_AIRPLAY_PORT); + register_default_string_val("a2dp_dev_name", CONFIG_A2DP_DEV_NAME); + register_default_string_val("bypass_wm", "0"); + register_default_string_val("equalizer", ""); + register_default_string_val("actrls_config", ""); + register_default_string_val("lms_ctrls_raw", "n"); + register_default_string_val("rotary_config", CONFIG_ROTARY_ENCODER); char number_buffer[101] = {}; snprintf(number_buffer,sizeof(number_buffer)-1,"%u",OTA_FLASH_ERASE_BLOCK); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ota_erase_blk", number_buffer); - config_set_default(NVS_TYPE_STR, "ota_erase_blk", number_buffer, 0); - + register_default_string_val( "ota_erase_blk", number_buffer); snprintf(number_buffer,sizeof(number_buffer)-1,"%u",OTA_STACK_SIZE); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ota_stack", number_buffer); - config_set_default(NVS_TYPE_STR, "ota_stack", number_buffer, 0); - + register_default_string_val( "ota_stack", number_buffer); snprintf(number_buffer,sizeof(number_buffer)-1,"%d",OTA_TASK_PRIOTITY); - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ota_prio", number_buffer); - config_set_default(NVS_TYPE_STR, "ota_prio", number_buffer, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "enable_bt_sink", STR(CONFIG_BT_SINK)); - config_set_default(NVS_TYPE_STR, "enable_bt_sink", STR(CONFIG_BT_SINK), 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bt_sink_pin", STR(CONFIG_BT_SINK_PIN)); - config_set_default(NVS_TYPE_STR, "bt_sink_pin", STR(CONFIG_BT_SINK_PIN), 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bt_sink_volume", "127"); - config_set_default(NVS_TYPE_STR, "bt_sink_volume", "127", 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "enable_airplay", STR(CONFIG_AIRPLAY_SINK)); - config_set_default(NVS_TYPE_STR, "enable_airplay", STR(CONFIG_AIRPLAY_SINK), 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "display_config", CONFIG_DISPLAY_CONFIG); - config_set_default(NVS_TYPE_STR, "display_config", CONFIG_DISPLAY_CONFIG, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "eth_config", CONFIG_ETH_CONFIG); - config_set_default(NVS_TYPE_STR, "eth_config", CONFIG_ETH_CONFIG, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "i2c_config", CONFIG_I2C_CONFIG); - config_set_default(NVS_TYPE_STR, "i2c_config", CONFIG_I2C_CONFIG, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "spi_config", CONFIG_SPI_CONFIG); - config_set_default(NVS_TYPE_STR, "spi_config", CONFIG_SPI_CONFIG, 0); - - ESP_LOGD(TAG,"Registering default value for key %s, value %s", "set_GPIO", CONFIG_SET_GPIO); - config_set_default(NVS_TYPE_STR, "set_GPIO", CONFIG_SET_GPIO, 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "led_brightness"); - config_set_default(NVS_TYPE_STR, "led_brightness", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "spdif_config"); - config_set_default(NVS_TYPE_STR, "spdif_config", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "dac_config"); - config_set_default(NVS_TYPE_STR, "dac_config", "", 0); - //todo: add dac_config for known targets - ESP_LOGD(TAG,"Registering default value for key %s", "dac_controlset"); - config_set_default(NVS_TYPE_STR, "dac_controlset", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "jack_mutes_amp"); - config_set_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "bat_config"); - config_set_default(NVS_TYPE_STR, "bat_config", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "metadata_config"); - config_set_default(NVS_TYPE_STR, "metadata_config", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "telnet_enable"); - config_set_default(NVS_TYPE_STR, "telnet_enable", "", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "telnet_buffer"); - config_set_default(NVS_TYPE_STR, "telnet_buffer", "40000", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "telnet_block"); - config_set_default(NVS_TYPE_STR, "telnet_block", "500", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "stats"); - config_set_default(NVS_TYPE_STR, "stats", "n", 0); - - ESP_LOGD(TAG,"Registering default value for key %s", "rel_api"); - config_set_default(NVS_TYPE_STR, "rel_api", CONFIG_RELEASE_API, 0); - + register_default_string_val( "ota_prio", number_buffer); + register_default_string_val( "enable_bt_sink", STR(CONFIG_BT_SINK)); + register_default_string_val( "bt_sink_pin", STR(CONFIG_BT_SINK_PIN)); + register_default_string_val( "bt_sink_volume", "127"); + register_default_string_val( "enable_airplay", STR(CONFIG_AIRPLAY_SINK)); + register_default_string_val( "display_config", CONFIG_DISPLAY_CONFIG); + register_default_string_val( "eth_config", CONFIG_ETH_CONFIG); + register_default_string_val( "i2c_config", CONFIG_I2C_CONFIG); + register_default_string_val( "spi_config", CONFIG_SPI_CONFIG); + register_default_string_val( "set_GPIO", CONFIG_SET_GPIO); + register_default_string_val( "led_brightness", ""); + register_default_string_val( "spdif_config", ""); + register_default_string_val( "dac_config", ""); + register_default_string_val( "dac_controlset", ""); + register_default_string_val( "jack_mutes_amp", "n"); + register_default_string_val( "bat_config", ""); + register_default_string_val( "metadata_config", ""); + register_default_string_val( "telnet_enable", ""); + register_default_string_val( "telnet_buffer", "40000"); + register_default_string_val( "telnet_block", "500"); + register_default_string_val( "stats", "n"); + register_default_string_val( "rel_api", CONFIG_RELEASE_API); + register_default_string_val("wifi_smode", "A"); wait_for_commit(); ESP_LOGD(TAG,"Done setting default values in nvs."); } @@ -507,13 +434,11 @@ void app_main() led_blink_pushed(LED_GREEN, 250, 250); if(bypass_wifi_manager){ - ESP_LOGW(TAG,"*******************************************************************************************"); - ESP_LOGW(TAG,"* wifi manager is disabled. Please use wifi commands to connect to your wifi access point."); - ESP_LOGW(TAG,"*******************************************************************************************"); + ESP_LOGW(TAG,"wifi manager is disabled. Use command line for wifi control."); } else { ESP_LOGI(TAG,"Starting Wifi Manager"); - wifi_manager_start(); + network_manager_start(); //wifi_manager_set_callback(EVENT_STA_GOT_IP, &cb_connection_got_ip); wifi_manager_set_callback(EVENT_ETH_GOT_IP, &cb_connection_got_ip); wifi_manager_set_callback(EVENT_STA_DISCONNECTED, &cb_connection_sta_disconnected); diff --git a/sdkconfig b/sdkconfig index fc68c039..953ab3d5 100644 --- a/sdkconfig +++ b/sdkconfig @@ -2,17 +2,47 @@ # Automatically generated file. DO NOT EDIT. # Espressif IoT Development Framework (ESP-IDF) Project Configuration # -CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 # # SDK tool configuration # CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" +# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set +# end of SDK tool configuration + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# end of Build type + +# +# Application manager +# CONFIG_APP_COMPILE_TIME_DATE=y # CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set # CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set @@ -20,6 +50,7 @@ CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y # CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set CONFIG_BOOTLOADER_LOG_LEVEL=3 +# CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN is not set CONFIG_BOOTLOADER_SPI_WP_PIN=7 CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y # CONFIG_BOOTLOADER_FACTORY_RESET is not set @@ -28,10 +59,26 @@ CONFIG_BOOTLOADER_WDT_ENABLE=y # CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set CONFIG_BOOTLOADER_WDT_TIME_MS=9000 # CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set -# CONFIG_SECURE_BOOT_ENABLED is not set +# CONFIG_SECURE_BOOT is not set # CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Serial flasher config +# CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 +# CONFIG_ESPTOOLPY_NO_STUB is not set CONFIG_ESPTOOLPY_FLASHMODE_QIO=y # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set # CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set @@ -55,6 +102,7 @@ CONFIG_ESPTOOLPY_BEFORE="default_reset" CONFIG_ESPTOOLPY_AFTER_RESET=y # CONFIG_ESPTOOLPY_AFTER_NORESET is not set CONFIG_ESPTOOLPY_AFTER="hard_reset" +# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set # CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set # CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y @@ -64,6 +112,11 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y # CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# # CONFIG_PARTITION_TABLE_SINGLE_APP is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set CONFIG_PARTITION_TABLE_CUSTOM=y @@ -71,55 +124,15 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_MD5=y -CONFIG_LOGGING_SLIMPROTO="info" -CONFIG_LOGGING_STREAM="info" -CONFIG_LOGGING_DECODE="info" -CONFIG_LOGGING_OUTPUT="info" -CONFIG_I2C_LOCKED=y -CONFIG_MUTE_GPIO_LEVEL=0 -# CONFIG_SQUEEZEAMP is not set -CONFIG_A1S=y -# CONFIG_DAC32 is not set -# CONFIG_TWATCH2020 is not set -# CONFIG_BASIC_I2C_BT is not set -CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases" -CONFIG_SQUEEZELITE_ESP32_RELEASE_URL="https://github.com/sle118/squeezelite-esp32/releases" -CONFIG_PROJECT_NAME="Squeezelite ESP32-A1S" -CONFIG_FW_PLATFORM_NAME="ESP32-A1S" -CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" -CONFIG_SPDIF_CONFIG="" -CONFIG_SPI_CONFIG="" -CONFIG_DISPLAY_CONFIG="" -CONFIG_DAC_CONTROLSET="" -CONFIG_I2S_NUM=0 -CONFIG_I2S_BCK_IO=-1 -CONFIG_I2S_WS_IO=-1 -CONFIG_I2S_DO_IO=-1 -CONFIG_I2C_SDA=-1 -CONFIG_I2C_SCL=-1 -CONFIG_MUTE_GPIO=-1 -CONFIG_SDIF_NUM=0 -CONFIG_SPDIF_BCK_IO=-1 -CONFIG_SPDIF_WS_IO=-1 -CONFIG_SPDIF_DO_IO=-1 -CONFIG_A2DP_SINK_NAME="SMSL BT4.2" -CONFIG_A2DP_DEV_NAME="Squeezelite" -CONFIG_A2DP_CONTROL_DELAY_MS=500 -CONFIG_A2DP_CONNECT_TIMEOUT_MS=1000 -CONFIG_BT_SINK=y -CONFIG_BT_NAME="ESP32-BT" -CONFIG_BT_SINK_PIN=1234 -CONFIG_AIRPLAY_SINK=y -CONFIG_AIRPLAY_NAME="ESP32-AirPlay" -CONFIG_AIRPLAY_PORT="5000" -CONFIG_I2C_CONFIG="" -CONFIG_SET_GPIO="" -CONFIG_ROTARY_ENCODER="" -CONFIG_LED_GREEN_GPIO=-1 -CONFIG_LED_RED_GPIO=-1 -CONFIG_JACK_GPIO=-1 -CONFIG_SPKFAULT_GPIO=-1 -CONFIG_BAT_CHANNEL=-1 +# end of Partition Table + +# +# Network Manager Configuration +# + +# +# WiFi Options +# CONFIG_WIFI_MANAGER_TASK_PRIORITY=5 CONFIG_WIFI_MANAGER_MAX_RETRY=2 CONFIG_DEFAULT_AP_SSID="squeezelite" @@ -130,26 +143,213 @@ CONFIG_DEFAULT_AP_GATEWAY="192.168.4.1" CONFIG_DEFAULT_AP_NETMASK="255.255.255.0" CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 +# end of WiFi Options + +# +# Ethernet Options +# +CONFIG_ETH_NODRIVER=y +# CONFIG_ETH_LAN8720 is not set +# CONFIG_ETH_DM9051 is not set +# CONFIG_ETH_W5500 is not set +CONFIG_ETH_PHY_RST_IO=-1 +CONFIG_ETH_MDC_IO=-1 +CONFIG_ETH_MDIO_IO=-1 +CONFIG_ETH_SPI_HOST=-1 +CONFIG_ETH_SPI_INTR_IO=-1 +CONFIG_ETH_SPI_CS_IO=-1 +CONFIG_ETH_SPI_CLK_IO=-1 +CONFIG_ETH_SPI_MOSI_IO=-1 +CONFIG_ETH_SPI_MISO_IO=-1 +CONFIG_ETH_SPI_SPEED=20000000 +# end of Ethernet Options +# end of Network Manager Configuration + +# +# Squeezelite-ESP32 +# + +# +# Logging +# +CONFIG_LOGGING_SLIMPROTO="info" +CONFIG_LOGGING_STREAM="info" +CONFIG_LOGGING_DECODE="info" +CONFIG_LOGGING_OUTPUT="info" +# end of Logging + +CONFIG_MUTE_GPIO_LEVEL=0 + +# +# Target +# +# CONFIG_SQUEEZEAMP is not set +CONFIG_BASIC_I2C_BT=y +# CONFIG_TWATCH2020 is not set +CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases" +CONFIG_SQUEEZELITE_ESP32_RELEASE_URL="https://github.com/sle118/squeezelite-esp32/releases" +CONFIG_PROJECT_NAME="Squeezelite-ESP32" +CONFIG_FW_PLATFORM_NAME="ESP32" +CONFIG_DAC_CONFIG="" +CONFIG_SPDIF_CONFIG="" +CONFIG_SPI_CONFIG="" +CONFIG_DISPLAY_CONFIG="" +CONFIG_ETH_CONFIG="" +CONFIG_DAC_CONTROLSET="" +# end of Target + +# +# Audio settings +# + +# +# DAC settings +# + +# +# I2S settings +# +CONFIG_I2S_NUM=0 +CONFIG_I2S_BCK_IO=-1 +CONFIG_I2S_WS_IO=-1 +CONFIG_I2S_DO_IO=-1 +CONFIG_I2S_DI_IO=-1 +# end of I2S settings + +# +# I2C settings +# +CONFIG_I2C_SDA=-1 +CONFIG_I2C_SCL=-1 +# end of I2C settings + +CONFIG_MUTE_GPIO=-1 +# end of DAC settings + +# +# SPDIF settings +# +CONFIG_SDIF_NUM=0 +CONFIG_SPDIF_BCK_IO=-1 +CONFIG_SPDIF_WS_IO=-1 +CONFIG_SPDIF_DO_IO=-1 +# end of SPDIF settings + +# +# A2DP settings +# +CONFIG_A2DP_SINK_NAME="SMSL BT4.2" +CONFIG_A2DP_DEV_NAME="Squeezelite" +CONFIG_A2DP_CONTROL_DELAY_MS=500 +CONFIG_A2DP_CONNECT_TIMEOUT_MS=1000 +# end of A2DP settings +# end of Audio settings + +# +# Audio Input +# +CONFIG_BT_SINK=y +CONFIG_BT_NAME="ESP32-BT" +CONFIG_BT_SINK_PIN=1234 +CONFIG_AIRPLAY_SINK=y +CONFIG_AIRPLAY_NAME="ESP32-AirPlay" +CONFIG_AIRPLAY_PORT="5000" +# end of Audio Input + +# +# Display Screen +# +# end of Display Screen + +# +# Various I/O +# +CONFIG_I2C_CONFIG="" +CONFIG_SET_GPIO="" +CONFIG_ROTARY_ENCODER="" +# end of Various I/O + +# +# LED configuration +# +CONFIG_LED_GREEN_GPIO=12 +CONFIG_LED_GREEN_GPIO_LEVEL=0 +CONFIG_LED_RED_GPIO=13 +CONFIG_LED_RED_GPIO_LEVEL=0 +# end of LED configuration + +# +# Audio JACK +# +CONFIG_JACK_GPIO=34 +CONFIG_JACK_GPIO_LEVEL=0 +# end of Audio JACK + +# +# Speaker Fault +# +CONFIG_SPKFAULT_GPIO=2 +CONFIG_SPKFAULT_GPIO_LEVEL=0 +# end of Speaker Fault + +# +# Battery measure +# +CONFIG_BAT_CHANNEL=7 +CONFIG_BAT_SCALE="20.24" +# end of Battery measure + CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" -# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set -CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# end of Squeezelite-ESP32 + +# +# Compiler options +# +# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set -CONFIG_COMPILER_CXX_EXCEPTIONS=y -CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +CONFIG_COMPILER_CXX_RTTI=y CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set -# CONFIG_COMPILER_STACK_CHECK is not set # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set # CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set -# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set -CONFIG_ESP32_APPTRACE_DEST_NONE=y -# CONFIG_ESP32_APPTRACE_ENABLE is not set -CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_TRAX is not set +CONFIG_APPTRACE_DEST_NONE=y +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# ESP-ASIO +# +# CONFIG_ASIO_SSL_SUPPORT is not set +# end of ESP-ASIO + +# +# Bluetooth +# CONFIG_BT_ENABLED=y +CONFIG_BT_CTRL_ESP32=y + +# +# Bluetooth controller(ESP32 Dual Mode Bluetooth) +# # CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y # CONFIG_BTDM_CTRL_MODE_BTDM is not set @@ -158,6 +358,15 @@ CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0 # CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_PCM=y CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=1 +CONFIG_BTDM_CTRL_PCM_ROLE_EDGE_CONFIG=y +CONFIG_BTDM_CTRL_PCM_ROLE_MASTER=y +# CONFIG_BTDM_CTRL_PCM_ROLE_SLAVE is not set +CONFIG_BTDM_CTRL_PCM_POLAR_FALLING_EDGE=y +# CONFIG_BTDM_CTRL_PCM_POLAR_RISING_EDGE is not set +CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 +CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT=y +CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF=y CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2 CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 @@ -166,15 +375,56 @@ CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y # CONFIG_BTDM_CTRL_HCI_MODE_UART_H4 is not set -CONFIG_BTDM_MODEM_SLEEP=y -CONFIG_BTDM_MODEM_SLEEP_MODE_ORIG=y -# CONFIG_BTDM_MODEM_SLEEP_MODE_EVED is not set -CONFIG_BTDM_LPCLK_SEL_MAIN_XTAL=y + +# +# MODEM SLEEP Options +# +CONFIG_BTDM_CTRL_MODEM_SLEEP=y +CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=y +# CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_EVED is not set +CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=y +# end of MODEM SLEEP Options + CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 -# CONFIG_BTDM_COEX_BT_OPTIONS is not set +# end of Bluetooth controller(ESP32 Dual Mode Bluetooth) + +CONFIG_BT_CTRL_MODE_EFF=1 +CONFIG_BT_CTRL_BLE_MAX_ACT=10 +CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10 +CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0 +CONFIG_BT_CTRL_PINNED_TO_CORE=0 +CONFIG_BT_CTRL_HCI_TL=1 +CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30 +CONFIG_BT_CTRL_HW_CCA_EFF=0 +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=0 +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100 +CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +CONFIG_BT_CTRL_BLE_SCAN_DUPL=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0 +CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100 + +# +# MODEM SLEEP Options +# +# end of MODEM SLEEP Options + +CONFIG_BT_CTRL_SLEEP_MODE_EFF=0 +CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0 +CONFIG_BT_CTRL_HCI_TL_EFF=1 + +# +# MODEM SLEEP Options +# +# end of MODEM SLEEP Options + CONFIG_BT_BLUEDROID_ENABLED=y # CONFIG_BT_NIMBLE_ENABLED is not set # CONFIG_BT_CONTROLLER_ONLY is not set + +# +# Bluedroid Options +# CONFIG_BT_BTC_TASK_STACK_SIZE=3072 CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y # CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set @@ -185,198 +435,109 @@ CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_A2DP_ENABLE=y # CONFIG_BT_SPP_ENABLED is not set # CONFIG_BT_HFP_ENABLE is not set +# CONFIG_BT_HID_HOST_ENABLED is not set CONFIG_BT_SSP_ENABLED=y # CONFIG_BT_BLE_ENABLED is not set -# CONFIG_BT_STACK_NO_LOG is not set -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_HCI_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_HCI_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_HCI_TRACE_LEVEL=2 -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_BTM_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_BTM_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_BTM_TRACE_LEVEL=2 -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_L2CAP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_L2CAP_TRACE_LEVEL=2 -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_RFCOMM_TRACE_LEVEL=2 -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_SDP_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_SDP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_SDP_TRACE_LEVEL=2 -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_GAP_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_GAP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_GAP_TRACE_LEVEL=2 -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_BNEP_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_BNEP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_BNEP_TRACE_LEVEL=2 -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_PAN_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_PAN_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_PAN_TRACE_LEVEL=2 -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_A2D_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_A2D_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_A2D_TRACE_LEVEL=2 -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_AVDT_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_AVDT_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_AVDT_TRACE_LEVEL=2 -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_AVCT_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_AVCT_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_AVCT_TRACE_LEVEL=2 -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_AVRC_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_AVRC_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_AVRC_TRACE_LEVEL=2 -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_MCA_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_MCA_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_MCA_TRACE_LEVEL=2 -# CONFIG_BT_LOG_HID_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_HID_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_HID_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_HID_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_HID_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_HID_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_HID_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_HID_TRACE_LEVEL=2 -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_APPL_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_APPL_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_APPL_TRACE_LEVEL=2 -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_GATT_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_GATT_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_GATT_TRACE_LEVEL=2 -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_SMP_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_SMP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_SMP_TRACE_LEVEL=2 -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_BTIF_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_BTIF_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_BTIF_TRACE_LEVEL=2 -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_BTC_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_BTC_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_BTC_TRACE_LEVEL=2 -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_OSI_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_OSI_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_OSI_TRACE_LEVEL=2 -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_NONE is not set -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_ERROR is not set -CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_WARNING=y -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_API is not set -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_EVENT is not set -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_DEBUG is not set -# CONFIG_BT_LOG_BLUFI_TRACE_LEVEL_VERBOSE is not set -CONFIG_BT_LOG_BLUFI_TRACE_LEVEL=2 +CONFIG_BT_STACK_NO_LOG=y CONFIG_BT_ACL_CONNECTIONS=4 +CONFIG_BT_MULTI_CONNECTION_ENBALE=y CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y # CONFIG_BT_BLE_HOST_QUEUE_CONG_CHECK is not set CONFIG_BT_SMP_ENABLE=y CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT=30 +# CONFIG_BT_BLE_RPA_SUPPORTED is not set CONFIG_BT_RESERVE_DRAM=0xdb5c +# end of Bluedroid Options + +CONFIG_BT_NIMBLE_USE_ESP_TIMER=y +# end of Bluetooth + # CONFIG_BLE_MESH is not set + +# +# CoAP Configuration +# +CONFIG_COAP_MBEDTLS_PSK=y +# CONFIG_COAP_MBEDTLS_PKI is not set +# CONFIG_COAP_MBEDTLS_DEBUG is not set +CONFIG_COAP_LOG_DEFAULT_LEVEL=0 +# end of CoAP Configuration + +# +# Driver configurations +# + +# +# ADC configuration +# # CONFIG_ADC_FORCE_XPD_FSM is not set CONFIG_ADC_DISABLE_DAC=y +# end of ADC configuration + +# +# SPI configuration +# CONFIG_SPI_MASTER_IN_IRAM=y CONFIG_SPI_MASTER_ISR_IN_IRAM=y CONFIG_SPI_SLAVE_IN_IRAM=y CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI configuration + +# +# TWAI configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC is not set +# CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST is not set +# CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID is not set +# CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT is not set +# end of TWAI configuration + +# +# UART configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART configuration + +# +# RTCIO configuration +# +# CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set +# end of RTCIO configuration + +# +# GPIO Configuration +# +# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set +# end of GPIO Configuration +# end of Driver configurations + +# +# eFuse Bit Manager +# # CONFIG_EFUSE_CUSTOM_TABLE is not set # CONFIG_EFUSE_VIRTUAL is not set # CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y # CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set CONFIG_EFUSE_MAX_BLK_LEN=192 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set # CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ESP32-specific +# +CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y CONFIG_ESP32_REV_MIN_0=y # CONFIG_ESP32_REV_MIN_1 is not set # CONFIG_ESP32_REV_MIN_2 is not set @@ -388,35 +549,67 @@ CONFIG_ESP32_DPORT_WORKAROUND=y CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 CONFIG_ESP32_SPIRAM_SUPPORT=y -CONFIG_SPIRAM_BOOT_INIT=y -# CONFIG_SPIRAM_USE_MEMMAP is not set -# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set -CONFIG_SPIRAM_USE_MALLOC=y + +# +# SPI RAM config +# CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set # CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set # CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set CONFIG_SPIRAM_SIZE=-1 # CONFIG_SPIRAM_SPEED_40M is not set CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y CONFIG_SPIRAM_MEMTEST=y -CONFIG_SPIRAM_CACHE_WORKAROUND=y -CONFIG_SPIRAM_BANKSWITCH_ENABLE=y -CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256 CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65536 -CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y # CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y # CONFIG_SPIRAM_OCCUPY_NO_HOST is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# CONFIG_D0WD_PSRAM_CLK_IO=17 CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# CONFIG_D2WD_PSRAM_CLK_IO=9 CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# CONFIG_PICO_PSRAM_CS_IO=10 -# CONFIG_ESP32_MEMMAP_TRACEMEM is not set -# CONFIG_ESP32_MEMMAP_TRACEMEM_TWOBANKS is not set +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set +# end of SPI RAM config + # CONFIG_ESP32_TRAX is not set CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set @@ -424,12 +617,7 @@ CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 # CONFIG_ESP32_ULP_COPROC_ENABLED is not set CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 -# CONFIG_ESP32_PANIC_PRINT_HALT is not set -CONFIG_ESP32_PANIC_PRINT_REBOOT=y -# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set -# CONFIG_ESP32_PANIC_GDBSTUB is not set CONFIG_ESP32_DEBUG_OCDAWARE=y -# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set CONFIG_ESP32_BROWNOUT_DET=y CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set @@ -457,22 +645,34 @@ CONFIG_ESP32_XTAL_FREQ_40=y CONFIG_ESP32_XTAL_FREQ=40 # CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set # CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set # CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5 -# CONFIG_PM_ENABLE is not set +# end of ESP32-specific + +# +# ADC-Calibration +# CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y CONFIG_ADC_CAL_LUT_ENABLE=y -# CONFIG_ESP_TIMER_PROFILING is not set +# end of ADC-Calibration + +# +# Common ESP-related +# CONFIG_ESP_ERR_TO_NAME_LOOKUP=y CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 -CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 CONFIG_ESP_CONSOLE_UART_DEFAULT=y # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_NONE is not set +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y CONFIG_ESP_CONSOLE_UART_NUM=0 CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP_INT_WDT=y @@ -483,51 +683,177 @@ CONFIG_ESP_TASK_WDT=y CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y -# CONFIG_ETH_USE_ESP32_EMAC is not set -# CONFIG_ETH_USE_SPI_ETHERNET is not set +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_ESP32_EMAC=y +CONFIG_ETH_PHY_INTERFACE_RMII=y +# CONFIG_ETH_PHY_INTERFACE_MII is not set +CONFIG_ETH_RMII_CLK_INPUT=y +# CONFIG_ETH_RMII_CLK_OUTPUT is not set +CONFIG_ETH_RMII_CLK_IN_GPIO=0 +CONFIG_ETH_DMA_BUFFER_SIZE=512 +CONFIG_ETH_DMA_RX_BUFFER_NUM=10 +CONFIG_ETH_DMA_TX_BUFFER_NUM=10 +CONFIG_ETH_USE_SPI_ETHERNET=y +CONFIG_ETH_SPI_ETHERNET_DM9051=y +CONFIG_ETH_SPI_ETHERNET_W5500=y +# CONFIG_ETH_USE_OPENETH is not set +# end of Ethernet + +# +# Event Loop Library +# # CONFIG_ESP_EVENT_LOOP_PROFILING is not set CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# end of ESP HTTP client + +# +# HTTP Server +# CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 # CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# CONFIG_OTA_ALLOW_HTTP=y +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# # CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y +# end of ESP NETIF Adapter + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# end of Power Management + +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set + +# +# Memory protection +# +# end of Memory protection +# end of ESP System Settings + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP_TIMER_IMPL_FRC2 is not set +CONFIG_ESP_TIMER_IMPL_TG0_LAC=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y -# CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_WIFI is not set -# CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BT is not set -CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BALANCE=y -CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_VALUE=2 CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=12 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=40 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=12 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set # CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED is not set # CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 -# CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set +# CONFIG_WIFI_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_WIFI_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_WIFI_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set # CONFIG_ESP32_WIFI_IRAM_OPT is not set # CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set +# end of Wi-Fi + +# +# PHY +# CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP32_PHY_MAX_TX_POWER=20 -# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set -CONFIG_ESP32_ENABLE_COREDUMP_TO_UART=y -# CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE is not set -CONFIG_ESP32_ENABLE_COREDUMP=y -CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM=64 -CONFIG_ESP32_CORE_DUMP_UART_DELAY=0 +# end of PHY + +# +# Core dump +# +CONFIG_ESP_COREDUMP_ENABLE_TO_UART=y +# CONFIG_ESP_COREDUMP_ENABLE_TO_NONE is not set +# CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP_COREDUMP_CHECKSUM_SHA256 is not set +CONFIG_ESP_COREDUMP_ENABLE=y +CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64 +CONFIG_ESP_COREDUMP_UART_DELAY=0 +CONFIG_ESP_COREDUMP_DECODE_INFO=y +# CONFIG_ESP_COREDUMP_DECODE_DISABLE is not set +CONFIG_ESP_COREDUMP_DECODE="info" +# end of Core dump + +# +# FAT Filesystem support +# # CONFIG_FATFS_CODEPAGE_DYNAMIC is not set CONFIG_FATFS_CODEPAGE_437=y # CONFIG_FATFS_CODEPAGE_720 is not set @@ -558,12 +884,26 @@ CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_PER_FILE_CACHE=y CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# Modbus configuration +# +CONFIG_FMB_COMM_MODE_TCP_EN=y +CONFIG_FMB_TCP_PORT_DEFAULT=502 +CONFIG_FMB_TCP_PORT_MAX_CONN=5 +CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20 +CONFIG_FMB_COMM_MODE_RTU_EN=y +CONFIG_FMB_COMM_MODE_ASCII_EN=y CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 CONFIG_FMB_QUEUE_LENGTH=20 -CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048 +CONFIG_FMB_PORT_TASK_STACK_SIZE=4096 CONFIG_FMB_SERIAL_BUF_SIZE=256 -CONFIG_FMB_SERIAL_TASK_PRIO=10 +CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 +CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 +CONFIG_FMB_PORT_TASK_PRIO=10 # CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 @@ -572,6 +912,12 @@ CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 CONFIG_FMB_TIMER_PORT_ENABLED=y CONFIG_FMB_TIMER_GROUP=0 CONFIG_FMB_TIMER_INDEX=0 +# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set +# end of Modbus configuration + +# +# FreeRTOS +# # CONFIG_FREERTOS_UNICORE is not set CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y @@ -588,7 +934,7 @@ CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set # CONFIG_FREERTOS_ASSERT_DISABLE is not set CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 -CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_ISR_STACKSIZE=2096 # CONFIG_FREERTOS_LEGACY_HOOKS is not set CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y @@ -599,96 +945,228 @@ CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set -# CONFIG_FREERTOS_DEBUG_INTERNALS is not set CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +# end of FreeRTOS + +# +# Heap memory debugging +# CONFIG_HEAP_POISONING_DISABLED=y # CONFIG_HEAP_POISONING_LIGHT is not set # CONFIG_HEAP_POISONING_COMPREHENSIVE is not set CONFIG_HEAP_TRACING_OFF=y # CONFIG_HEAP_TRACING_STANDALONE is not set # CONFIG_HEAP_TRACING_TOHOST is not set -# CONFIG_HEAP_TRACING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# jsmn +# +# CONFIG_JSMN_PARENT_LINKS is not set +# CONFIG_JSMN_STRICT is not set +# end of jsmn + +# +# libsodium +# +# end of libsodium + +# +# Log output +# # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set -# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set -CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_DEFAULT_LEVEL=1 CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# CONFIG_LWIP_LOCAL_HOSTNAME="esp32a1s" +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y # CONFIG_LWIP_L2_TO_L3_COPY is not set # CONFIG_LWIP_IRAM_OPTIMIZATION is not set CONFIG_LWIP_TIMERS_ONDEMAND=y CONFIG_LWIP_MAX_SOCKETS=16 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set CONFIG_LWIP_SO_REUSE=y CONFIG_LWIP_SO_REUSE_RXTOALL=y # CONFIG_LWIP_SO_RCVBUF is not set -# CONFIG_LWIP_IP_FRAG is not set -# CONFIG_LWIP_IP_REASSEMBLY is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set # CONFIG_LWIP_STATS is not set # CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set CONFIG_LWIP_ESP_GRATUITOUS_ARP=y CONFIG_LWIP_GARP_TMR_INTERVAL=60 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set CONFIG_LWIP_DHCP_RESTORE_LAST_IP=y + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y CONFIG_LWIP_DHCPS_LEASE_UNIT=60 CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + # CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set CONFIG_LWIP_NETIF_LOOPBACK=y CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# CONFIG_LWIP_MAX_ACTIVE_TCP=16 CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y CONFIG_LWIP_TCP_MAXRTX=12 CONFIG_LWIP_TCP_SYNMAXRTX=6 CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 CONFIG_LWIP_TCP_MSL=60000 CONFIG_LWIP_TCP_SND_BUF_DEFAULT=8192 CONFIG_LWIP_TCP_WND_DEFAULT=32768 CONFIG_LWIP_TCP_RECVMBOX_SIZE=32 CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +# CONFIG_LWIP_TCP_SACK_OUT is not set # CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set CONFIG_LWIP_TCP_OVERSIZE_MSS=y # CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set # CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set # CONFIG_LWIP_WND_SCALE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# CONFIG_LWIP_MAX_UDP_PCBS=16 CONFIG_LWIP_UDP_RECVMBOX_SIZE=32 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF # CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y # CONFIG_LWIP_MULTICAST_PING is not set # CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC is not set CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384 # CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN is not set +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set # CONFIG_MBEDTLS_DEBUG is not set + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# end of Certificate Bundle + # CONFIG_MBEDTLS_ECP_RESTARTABLE is not set # CONFIG_MBEDTLS_CMAC_C is not set CONFIG_MBEDTLS_HARDWARE_AES=y CONFIG_MBEDTLS_HARDWARE_MPI=y -CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set CONFIG_MBEDTLS_HAVE_TIME=y # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y # CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT is not set # CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y # CONFIG_MBEDTLS_TLS_DISABLED is not set CONFIG_MBEDTLS_TLS_CLIENT=y CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# # CONFIG_MBEDTLS_PSK_MODES is not set CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y @@ -697,6 +1175,8 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + CONFIG_MBEDTLS_SSL_RENEGOTIATION=y # CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set # CONFIG_MBEDTLS_SSL_PROTO_TLS1 is not set @@ -705,7 +1185,13 @@ CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y # CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set CONFIG_MBEDTLS_SSL_ALPN=y CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y +CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# CONFIG_MBEDTLS_AES_C=y # CONFIG_MBEDTLS_CAMELLIA_C is not set # CONFIG_MBEDTLS_DES_C is not set @@ -716,14 +1202,24 @@ CONFIG_MBEDTLS_RC4_DISABLED=y # CONFIG_MBEDTLS_XTEA_C is not set CONFIG_MBEDTLS_CCM_C=y CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + # CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# CONFIG_MBEDTLS_PEM_PARSE_C=y CONFIG_MBEDTLS_PEM_WRITE_C=y CONFIG_MBEDTLS_X509_CRL_PARSE_C=y CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + CONFIG_MBEDTLS_ECP_C=y CONFIG_MBEDTLS_ECDH_C=y CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y @@ -737,14 +1233,47 @@ CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# mDNS +# CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +# CONFIG_MDNS_STRICT_MODE is not set +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# end of mDNS + +# +# ESP-MQTT Configurations +# CONFIG_MQTT_PROTOCOL_311=y CONFIG_MQTT_TRANSPORT_SSL=y CONFIG_MQTT_TRANSPORT_WEBSOCKET=y CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set # CONFIG_MQTT_USE_CUSTOM_CONFIG is not set # CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set # CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y # CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set # CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set @@ -752,9 +1281,25 @@ CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y # CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y # CONFIG_NEWLIB_NANO_FORMAT is not set +# end of Newlib + +# +# NVS +# +# end of NVS + +# +# OpenSSL +# # CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_ERROR_STACK=y CONFIG_OPENSSL_ASSERT_DO_NOTHING=y # CONFIG_OPENSSL_ASSERT_EXIT is not set +# end of OpenSSL + +# +# PThreads +# CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 CONFIG_PTHREAD_STACK_MIN=768 @@ -763,6 +1308,11 @@ CONFIG_PTHREAD_STACK_MIN=768 CONFIG_PTHREAD_DEFAULT_CORE_1=y CONFIG_PTHREAD_TASK_CORE_DEFAULT=1 CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# SPI Flash driver +# # CONFIG_SPI_FLASH_VERIFY_WRITE is not set # CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y @@ -770,47 +1320,140 @@ CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y # CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set # CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set # CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set + +# +# Auto-detect flash chips +# CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# CONFIG_SPIFFS_CACHE=y CONFIG_SPIFFS_CACHE_WR=y # CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + CONFIG_SPIFFS_PAGE_CHECK=y CONFIG_SPIFFS_GC_MAX_RUNS=10 # CONFIG_SPIFFS_GC_STATS is not set CONFIG_SPIFFS_PAGE_SIZE=256 CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set CONFIG_SPIFFS_USE_MAGIC=y CONFIG_SPIFFS_USE_MAGIC_LENGTH=y CONFIG_SPIFFS_META_LENGTH=4 CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# # CONFIG_SPIFFS_DBG is not set # CONFIG_SPIFFS_API_DBG is not set # CONFIG_SPIFFS_GC_DBG is not set # CONFIG_SPIFFS_CACHE_DBG is not set # CONFIG_SPIFFS_CHECK_DBG is not set # CONFIG_SPIFFS_TEST_VISUALISATION is not set -CONFIG_NETIF_IP_LOST_TIMER_INTERVAL=120 -CONFIG_TCPIP_LWIP=y +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# end of Websocket +# end of TCP Transport + +# +# TinyUSB +# +# end of TinyUSB + +# +# Unity unit testing library +# CONFIG_UNITY_ENABLE_FLOAT=y CONFIG_UNITY_ENABLE_DOUBLE=y # CONFIG_UNITY_ENABLE_COLOR is not set CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y # CONFIG_UNITY_ENABLE_FIXTURE is not set # CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_VFS_SUPPORT_TERMIOS=y -CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# CONFIG_WL_SECTOR_SIZE_512=y # CONFIG_WL_SECTOR_SIZE_4096 is not set CONFIG_WL_SECTOR_SIZE=512 # CONFIG_WL_SECTOR_MODE_PERF is not set CONFIG_WL_SECTOR_MODE_SAFE=y CONFIG_WL_SECTOR_MODE=1 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# CONFIG_WPA_MBEDTLS_CRYPTO=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# end of Supplicant + +# +# DSP Library +# # CONFIG_DSP_ANSI is not set CONFIG_DSP_OPTIMIZED=y CONFIG_DSP_OPTIMIZATION=1 @@ -822,7 +1465,14 @@ CONFIG_DSP_MAX_FFT_SIZE_512=y # CONFIG_DSP_MAX_FFT_SIZE_16384 is not set # CONFIG_DSP_MAX_FFT_SIZE_32768 is not set CONFIG_DSP_MAX_FFT_SIZE=512 +# end of DSP Library +# end of Component config + +# +# Compatibility options +# # CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set +# end of Compatibility options # Deprecated options for backward compatibility CONFIG_TOOLPREFIX="xtensa-esp32-elf-" @@ -848,20 +1498,21 @@ CONFIG_MONITOR_BAUD_115200B=y # CONFIG_MONITOR_BAUD_OTHER is not set CONFIG_MONITOR_BAUD_OTHER_VAL=115200 CONFIG_MONITOR_BAUD=115200 -# CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set -CONFIG_OPTIMIZATION_LEVEL_RELEASE=y -CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y -# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set +CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y +# CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED is not set +CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=y # CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set -CONFIG_CXX_EXCEPTIONS=y -CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +# CONFIG_CXX_EXCEPTIONS is not set CONFIG_STACK_CHECK_NONE=y # CONFIG_STACK_CHECK_NORM is not set # CONFIG_STACK_CHECK_STRONG is not set # CONFIG_STACK_CHECK_ALL is not set -# CONFIG_STACK_CHECK is not set # CONFIG_WARN_WRITE_STRINGS is not set # CONFIG_DISABLE_GCC8_WARNINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y # CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY is not set CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=y # CONFIG_BTDM_CONTROLLER_MODE_BTDM is not set @@ -875,6 +1526,7 @@ CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y # CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4 is not set CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y CONFIG_BLUEDROID_ENABLED=y +# CONFIG_NIMBLE_ENABLED is not set CONFIG_BTC_TASK_STACK_SIZE=3072 CONFIG_BLUEDROID_PINNED_TO_CORE_0=y # CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set @@ -884,175 +1536,12 @@ CONFIG_BTU_TASK_STACK_SIZE=4096 CONFIG_CLASSIC_BT_ENABLED=y CONFIG_A2DP_ENABLE=y # CONFIG_HFP_ENABLE is not set -# CONFIG_HCI_TRACE_LEVEL_NONE is not set -# CONFIG_HCI_TRACE_LEVEL_ERROR is not set -CONFIG_HCI_TRACE_LEVEL_WARNING=y -# CONFIG_HCI_TRACE_LEVEL_API is not set -# CONFIG_HCI_TRACE_LEVEL_EVENT is not set -# CONFIG_HCI_TRACE_LEVEL_DEBUG is not set -# CONFIG_HCI_TRACE_LEVEL_VERBOSE is not set -CONFIG_HCI_INITIAL_TRACE_LEVEL=2 -# CONFIG_BTM_TRACE_LEVEL_NONE is not set -# CONFIG_BTM_TRACE_LEVEL_ERROR is not set -CONFIG_BTM_TRACE_LEVEL_WARNING=y -# CONFIG_BTM_TRACE_LEVEL_API is not set -# CONFIG_BTM_TRACE_LEVEL_EVENT is not set -# CONFIG_BTM_TRACE_LEVEL_DEBUG is not set -# CONFIG_BTM_TRACE_LEVEL_VERBOSE is not set -CONFIG_BTM_INITIAL_TRACE_LEVEL=2 -# CONFIG_L2CAP_TRACE_LEVEL_NONE is not set -# CONFIG_L2CAP_TRACE_LEVEL_ERROR is not set -CONFIG_L2CAP_TRACE_LEVEL_WARNING=y -# CONFIG_L2CAP_TRACE_LEVEL_API is not set -# CONFIG_L2CAP_TRACE_LEVEL_EVENT is not set -# CONFIG_L2CAP_TRACE_LEVEL_DEBUG is not set -# CONFIG_L2CAP_TRACE_LEVEL_VERBOSE is not set -CONFIG_L2CAP_INITIAL_TRACE_LEVEL=2 -# CONFIG_RFCOMM_TRACE_LEVEL_NONE is not set -# CONFIG_RFCOMM_TRACE_LEVEL_ERROR is not set -CONFIG_RFCOMM_TRACE_LEVEL_WARNING=y -# CONFIG_RFCOMM_TRACE_LEVEL_API is not set -# CONFIG_RFCOMM_TRACE_LEVEL_EVENT is not set -# CONFIG_RFCOMM_TRACE_LEVEL_DEBUG is not set -# CONFIG_RFCOMM_TRACE_LEVEL_VERBOSE is not set -CONFIG_RFCOMM_INITIAL_TRACE_LEVEL=2 -# CONFIG_SDP_TRACE_LEVEL_NONE is not set -# CONFIG_SDP_TRACE_LEVEL_ERROR is not set -CONFIG_SDP_TRACE_LEVEL_WARNING=y -# CONFIG_SDP_TRACE_LEVEL_API is not set -# CONFIG_SDP_TRACE_LEVEL_EVENT is not set -# CONFIG_SDP_TRACE_LEVEL_DEBUG is not set -# CONFIG_SDP_TRACE_LEVEL_VERBOSE is not set -CONFIG_BTH_LOG_SDP_INITIAL_TRACE_LEVEL=2 -# CONFIG_GAP_TRACE_LEVEL_NONE is not set -# CONFIG_GAP_TRACE_LEVEL_ERROR is not set -CONFIG_GAP_TRACE_LEVEL_WARNING=y -# CONFIG_GAP_TRACE_LEVEL_API is not set -# CONFIG_GAP_TRACE_LEVEL_EVENT is not set -# CONFIG_GAP_TRACE_LEVEL_DEBUG is not set -# CONFIG_GAP_TRACE_LEVEL_VERBOSE is not set -CONFIG_GAP_INITIAL_TRACE_LEVEL=2 -CONFIG_BNEP_INITIAL_TRACE_LEVEL=2 -# CONFIG_PAN_TRACE_LEVEL_NONE is not set -# CONFIG_PAN_TRACE_LEVEL_ERROR is not set -CONFIG_PAN_TRACE_LEVEL_WARNING=y -# CONFIG_PAN_TRACE_LEVEL_API is not set -# CONFIG_PAN_TRACE_LEVEL_EVENT is not set -# CONFIG_PAN_TRACE_LEVEL_DEBUG is not set -# CONFIG_PAN_TRACE_LEVEL_VERBOSE is not set -CONFIG_PAN_INITIAL_TRACE_LEVEL=2 -# CONFIG_A2D_TRACE_LEVEL_NONE is not set -# CONFIG_A2D_TRACE_LEVEL_ERROR is not set -CONFIG_A2D_TRACE_LEVEL_WARNING=y -# CONFIG_A2D_TRACE_LEVEL_API is not set -# CONFIG_A2D_TRACE_LEVEL_EVENT is not set -# CONFIG_A2D_TRACE_LEVEL_DEBUG is not set -# CONFIG_A2D_TRACE_LEVEL_VERBOSE is not set -CONFIG_A2D_INITIAL_TRACE_LEVEL=2 -# CONFIG_AVDT_TRACE_LEVEL_NONE is not set -# CONFIG_AVDT_TRACE_LEVEL_ERROR is not set -CONFIG_AVDT_TRACE_LEVEL_WARNING=y -# CONFIG_AVDT_TRACE_LEVEL_API is not set -# CONFIG_AVDT_TRACE_LEVEL_EVENT is not set -# CONFIG_AVDT_TRACE_LEVEL_DEBUG is not set -# CONFIG_AVDT_TRACE_LEVEL_VERBOSE is not set -CONFIG_AVDT_INITIAL_TRACE_LEVEL=2 -# CONFIG_AVCT_TRACE_LEVEL_NONE is not set -# CONFIG_AVCT_TRACE_LEVEL_ERROR is not set -CONFIG_AVCT_TRACE_LEVEL_WARNING=y -# CONFIG_AVCT_TRACE_LEVEL_API is not set -# CONFIG_AVCT_TRACE_LEVEL_EVENT is not set -# CONFIG_AVCT_TRACE_LEVEL_DEBUG is not set -# CONFIG_AVCT_TRACE_LEVEL_VERBOSE is not set -CONFIG_AVCT_INITIAL_TRACE_LEVEL=2 -# CONFIG_AVRC_TRACE_LEVEL_NONE is not set -# CONFIG_AVRC_TRACE_LEVEL_ERROR is not set -CONFIG_AVRC_TRACE_LEVEL_WARNING=y -# CONFIG_AVRC_TRACE_LEVEL_API is not set -# CONFIG_AVRC_TRACE_LEVEL_EVENT is not set -# CONFIG_AVRC_TRACE_LEVEL_DEBUG is not set -# CONFIG_AVRC_TRACE_LEVEL_VERBOSE is not set -CONFIG_AVRC_INITIAL_TRACE_LEVEL=2 -# CONFIG_MCA_TRACE_LEVEL_NONE is not set -# CONFIG_MCA_TRACE_LEVEL_ERROR is not set -CONFIG_MCA_TRACE_LEVEL_WARNING=y -# CONFIG_MCA_TRACE_LEVEL_API is not set -# CONFIG_MCA_TRACE_LEVEL_EVENT is not set -# CONFIG_MCA_TRACE_LEVEL_DEBUG is not set -# CONFIG_MCA_TRACE_LEVEL_VERBOSE is not set -CONFIG_MCA_INITIAL_TRACE_LEVEL=2 -# CONFIG_HID_TRACE_LEVEL_NONE is not set -# CONFIG_HID_TRACE_LEVEL_ERROR is not set -CONFIG_HID_TRACE_LEVEL_WARNING=y -# CONFIG_HID_TRACE_LEVEL_API is not set -# CONFIG_HID_TRACE_LEVEL_EVENT is not set -# CONFIG_HID_TRACE_LEVEL_DEBUG is not set -# CONFIG_HID_TRACE_LEVEL_VERBOSE is not set -CONFIG_HID_INITIAL_TRACE_LEVEL=2 -# CONFIG_APPL_TRACE_LEVEL_NONE is not set -# CONFIG_APPL_TRACE_LEVEL_ERROR is not set -CONFIG_APPL_TRACE_LEVEL_WARNING=y -# CONFIG_APPL_TRACE_LEVEL_API is not set -# CONFIG_APPL_TRACE_LEVEL_EVENT is not set -# CONFIG_APPL_TRACE_LEVEL_DEBUG is not set -# CONFIG_APPL_TRACE_LEVEL_VERBOSE is not set -CONFIG_APPL_INITIAL_TRACE_LEVEL=2 -# CONFIG_GATT_TRACE_LEVEL_NONE is not set -# CONFIG_GATT_TRACE_LEVEL_ERROR is not set -CONFIG_GATT_TRACE_LEVEL_WARNING=y -# CONFIG_GATT_TRACE_LEVEL_API is not set -# CONFIG_GATT_TRACE_LEVEL_EVENT is not set -# CONFIG_GATT_TRACE_LEVEL_DEBUG is not set -# CONFIG_GATT_TRACE_LEVEL_VERBOSE is not set -CONFIG_GATT_INITIAL_TRACE_LEVEL=2 -# CONFIG_SMP_TRACE_LEVEL_NONE is not set -# CONFIG_SMP_TRACE_LEVEL_ERROR is not set -CONFIG_SMP_TRACE_LEVEL_WARNING=y -# CONFIG_SMP_TRACE_LEVEL_API is not set -# CONFIG_SMP_TRACE_LEVEL_EVENT is not set -# CONFIG_SMP_TRACE_LEVEL_DEBUG is not set -# CONFIG_SMP_TRACE_LEVEL_VERBOSE is not set -CONFIG_SMP_INITIAL_TRACE_LEVEL=2 -# CONFIG_BTIF_TRACE_LEVEL_NONE is not set -# CONFIG_BTIF_TRACE_LEVEL_ERROR is not set -CONFIG_BTIF_TRACE_LEVEL_WARNING=y -# CONFIG_BTIF_TRACE_LEVEL_API is not set -# CONFIG_BTIF_TRACE_LEVEL_EVENT is not set -# CONFIG_BTIF_TRACE_LEVEL_DEBUG is not set -# CONFIG_BTIF_TRACE_LEVEL_VERBOSE is not set -CONFIG_BTIF_INITIAL_TRACE_LEVEL=2 -# CONFIG_BTC_TRACE_LEVEL_NONE is not set -# CONFIG_BTC_TRACE_LEVEL_ERROR is not set -CONFIG_BTC_TRACE_LEVEL_WARNING=y -# CONFIG_BTC_TRACE_LEVEL_API is not set -# CONFIG_BTC_TRACE_LEVEL_EVENT is not set -# CONFIG_BTC_TRACE_LEVEL_DEBUG is not set -# CONFIG_BTC_TRACE_LEVEL_VERBOSE is not set -CONFIG_BTC_INITIAL_TRACE_LEVEL=2 -# CONFIG_OSI_TRACE_LEVEL_NONE is not set -# CONFIG_OSI_TRACE_LEVEL_ERROR is not set -CONFIG_OSI_TRACE_LEVEL_WARNING=y -# CONFIG_OSI_TRACE_LEVEL_API is not set -# CONFIG_OSI_TRACE_LEVEL_EVENT is not set -# CONFIG_OSI_TRACE_LEVEL_DEBUG is not set -# CONFIG_OSI_TRACE_LEVEL_VERBOSE is not set -CONFIG_OSI_INITIAL_TRACE_LEVEL=2 -# CONFIG_BLUFI_TRACE_LEVEL_NONE is not set -# CONFIG_BLUFI_TRACE_LEVEL_ERROR is not set -CONFIG_BLUFI_TRACE_LEVEL_WARNING=y -# CONFIG_BLUFI_TRACE_LEVEL_API is not set -# CONFIG_BLUFI_TRACE_LEVEL_EVENT is not set -# CONFIG_BLUFI_TRACE_LEVEL_DEBUG is not set -# CONFIG_BLUFI_TRACE_LEVEL_VERBOSE is not set -CONFIG_BLUFI_INITIAL_TRACE_LEVEL=2 # CONFIG_BLE_HOST_QUEUE_CONGESTION_CHECK is not set CONFIG_SMP_ENABLE=y CONFIG_BLE_ESTABLISH_LINK_CONNECTION_TIMEOUT=30 CONFIG_ADC2_DISABLE_DAC=y CONFIG_SPIRAM_SUPPORT=y CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=y -# CONFIG_MEMMAP_TRACEMEM is not set -# CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set CONFIG_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y @@ -1080,10 +1569,10 @@ CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_MAIN_TASK_STACK_SIZE=8192 CONFIG_IPC_TASK_STACK_SIZE=1024 -CONFIG_TIMER_TASK_STACK_SIZE=3584 CONFIG_CONSOLE_UART_DEFAULT=y # CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y CONFIG_CONSOLE_UART_NUM=0 CONFIG_CONSOLE_UART_BAUDRATE=115200 CONFIG_INT_WDT=y @@ -1097,15 +1586,28 @@ CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y # CONFIG_EVENT_LOOP_PROFILING is not set CONFIG_POST_EVENTS_FROM_ISR=y CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set +CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32S2_PANIC_GDBSTUB is not set +CONFIG_TIMER_TASK_STACK_SIZE=3584 CONFIG_SW_COEXIST_ENABLE=y -# CONFIG_SW_COEXIST_PREFERENCE_WIFI is not set -# CONFIG_SW_COEXIST_PREFERENCE_BT is not set -CONFIG_SW_COEXIST_PREFERENCE_BALANCE=y -CONFIG_SW_COEXIST_PREFERENCE_VALUE=2 +CONFIG_ESP32_ENABLE_COREDUMP_TO_UART=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE is not set +# CONFIG_ESP32_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256 is not set +CONFIG_ESP32_ENABLE_COREDUMP=y +CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM=64 +CONFIG_ESP32_CORE_DUMP_UART_DELAY=0 +CONFIG_ESP32_CORE_DUMP_DECODE_INFO=y +# CONFIG_ESP32_CORE_DUMP_DECODE_DISABLE is not set +CONFIG_ESP32_CORE_DUMP_DECODE="info" CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 CONFIG_MB_QUEUE_LENGTH=20 -CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048 +CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096 CONFIG_MB_SERIAL_BUF_SIZE=256 CONFIG_MB_SERIAL_TASK_PRIO=10 # CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set @@ -1116,7 +1618,6 @@ CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 CONFIG_MB_TIMER_PORT_ENABLED=y CONFIG_MB_TIMER_GROUP=0 CONFIG_MB_TIMER_INDEX=0 -CONFIG_SUPPORT_STATIC_ALLOCATION=y # CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set CONFIG_TIMER_TASK_PRIORITY=1 CONFIG_TIMER_TASK_STACK_DEPTH=2432 @@ -1156,7 +1657,8 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -CONFIG_IP_LOST_TIMER_INTERVAL=120 CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 # End of deprecated options diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 7e6db864..6ee64b2e 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -509,7 +509,7 @@ CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP32_PHY_MAX_TX_POWER=20 -CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y CONFIG_FATFS_CODEPAGE_437=y @@ -781,8 +781,8 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y CONFIG_VFS_SUPPORT_TERMIOS=y -CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 CONFIG_WL_SECTOR_SIZE_512=y #CONFIG_WL_SECTOR_SIZE_4096 is not defined diff --git a/squeezelite.cmake b/squeezelite.cmake index d8355a74..2381b5c4 100644 --- a/squeezelite.cmake +++ b/squeezelite.cmake @@ -1,17 +1,13 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) function(___register_flash partition_name sub_type) - message(STATUS "Adding new build target (from build folder): ninja ${partition_name}-flash") partition_table_get_partition_info(otaapp_offset "--partition-type app --partition-subtype ${sub_type}" "offset") - esptool_py_flash_project_args(${partition_name} ${otaapp_offset} ${build_dir}/${partition_name}.bin FLASH_IN_PROJECT ) - esptool_py_custom_target(${partition_name}-flash ${partition_name} "${build_dir}/${partition_name}.bin") -## IDF-V4.2+ idf_component_get_property(main_args esptool_py FLASH_ARGS) -## IDF-V4.2+ idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) -## IDF-V4.2+ esptool_py_flash_target(${target_name}-flash "${main_args}" "${sub_args}") -## IDF-V4.2+ esptool_py_flash_target_image(${target_name}-flash ${target_name} "${otaapp_offset}" "${build_dir}/${target_name}.bin") -## IDF-V4.2+ esptool_py_flash_target_image(flash ${target_name} "${otaapp_offset}" "${build_dir}/${target_name}.bin") - + idf_component_get_property(main_args esptool_py FLASH_ARGS) + idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS) + esptool_py_flash_target(${partition_name}-flash "${main_args}" "${sub_args}") + esptool_py_flash_target_image(${partition_name}-flash ${partition_name} "${otaapp_offset}" "${build_dir}/${partition_name}.bin") + esptool_py_flash_target_image(flash ${partition_name} "${otaapp_offset}" "${build_dir}/${partition_name}.bin") endfunction() # # Removes the specified compile flag from the specified target. diff --git a/test/main/unit_tests.c b/test/main/unit_tests.c index cc2d45bf..355c1321 100644 --- a/test/main/unit_tests.c +++ b/test/main/unit_tests.c @@ -43,7 +43,7 @@ #include "lwip/netdb.h" #include "nvs_utilities.h" #include "trace.h" -#include "wifi_manager.h" +#include "network_manager.h" #include "squeezelite-ota.h" #include #include "audio_controls.h"