From 502e304ab573689d5ff68d58fc13683dfb97a71c Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 25 Nov 2024 13:18:06 +0000 Subject: [PATCH] Fix esp32 event callback serialisation (#2913) This PR addresses the issue raised in #2912 by pushing events into the tcpip thread for handling. Network applications therefore 'live' in the tcpip task and the **Sming** task is created only for non-networked applications. Sming uses a separate event callback queue instead of the IDF one. - Use custom queue for sming messaging - Serialise idf messages to sming queue in networking code - Use idle task watchdogs instead of custom one - Push task callbacks to tcpip thread in network builds - Fix stack sizes. Network builds just use default size for event task stack - Use heap for initial partition table load. Not enough room on event task stack for this. - Add a semaphore to `smg_uart_write` so debug output doesn't get garbled between tasks (e.g. wifi). --- Sming/Arch/Esp32/Components/driver/uart.cpp | 24 ++ Sming/Arch/Esp32/Components/esp32/README.rst | 14 - .../Arch/Esp32/Components/esp32/component.mk | 14 +- .../Esp32/Components/esp32/sdk/config/common | 6 +- .../Esp32/Components/esp32/sdk/config/debug | 3 + .../Esp32/Components/esp32/src/event_loop.cpp | 115 -------- .../Esp32/Components/esp32/src/startup.cpp | 63 +---- .../Esp32/Components/esp32/src/system.cpp | 5 +- .../Arch/Esp32/Components/esp32/src/tasks.cpp | 103 ++++++-- .../Esp32/Components/spi_flash/flashmem.cpp | 3 +- Sming/Arch/Esp32/README.rst | 34 ++- .../Network/Arch/Esp32/Network/DM9051.cpp | 1 + .../Network/Arch/Esp32/Network/W5500.cpp | 1 + .../Arch/Esp32/Platform/AccessPointImpl.cpp | 4 - .../Arch/Esp32/Platform/AccessPointImpl.h | 15 +- .../Arch/Esp32/Platform/EmbeddedEthernet.cpp | 1 + .../Arch/Esp32/Platform/IdfService.cpp | 6 +- .../Arch/Esp32/Platform/StationImpl.cpp | 250 ++++++++---------- .../Network/Arch/Esp32/Platform/StationImpl.h | 36 ++- .../Arch/Esp32/Platform/WifiEventsImpl.cpp | 112 +------- .../Arch/Esp32/Platform/WifiEventsImpl.h | 90 ++++++- .../Network/Arch/Esp32/Platform/init.cpp | 109 +++++++- Sming/Components/Storage/src/Device.cpp | 7 +- Sming/Platform/System.cpp | 7 +- docs/source/upgrading/5.2-6.0.rst | 12 + 25 files changed, 497 insertions(+), 538 deletions(-) delete mode 100644 Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp create mode 100644 docs/source/upgrading/5.2-6.0.rst diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index d608381f97..c30691e960 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -191,6 +191,28 @@ smg_uart_t* get_standard_uart(smg_uart_t* uart) return is_standard_uart(uart) ? uart : nullptr; } +class Lock +{ +public: + Lock() + { + if(!mutex) { + mutex = xSemaphoreCreateMutex(); + } + xSemaphoreTake(mutex, portMAX_DELAY); + } + + ~Lock() + { + xSemaphoreGive(mutex); + } + +private: + static SemaphoreHandle_t mutex; +}; + +SemaphoreHandle_t Lock::mutex; + #if UART_ID_SERIAL_USB_JTAG /** @@ -544,6 +566,8 @@ size_t smg_uart_write(smg_uart_t* uart, const void* buffer, size_t size) auto buf = static_cast(buffer); + Lock lock; + while(written < size) { // If TX buffer not in use or it's empty then write directly to hardware FIFO if(uart->tx_buffer == nullptr || uart->tx_buffer->isEmpty()) { diff --git a/Sming/Arch/Esp32/Components/esp32/README.rst b/Sming/Arch/Esp32/Components/esp32/README.rst index a545642fff..cc5acddda0 100644 --- a/Sming/Arch/Esp32/Components/esp32/README.rst +++ b/Sming/Arch/Esp32/Components/esp32/README.rst @@ -45,20 +45,6 @@ or if multiple versions are installed. By default, the most current version will Location of ESP-IDF python. -.. envvar:: CREATE_EVENT_TASK - - default: disabled - - .. warning:: - - This setting is provided for debugging purposes ONLY. - - Sming uses a custom event loop to ensure that timer and task callbacks are all executed in the same - thread context. - - Sometimes this behaviour can cause issues with IDF code. - Setting this to 1 will create the event loop in a separate thread, which is standard IDF behaviour. - Background ---------- diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index b7f21017a9..eaf4804398 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -8,11 +8,7 @@ COMPONENT_INCDIRS := src/include include # Applications can provide file with custom SDK configuration settings CACHE_VARS += SDK_CUSTOM_CONFIG -COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI CREATE_EVENT_TASK - -ifeq ($(CREATE_EVENT_TASK),1) -COMPONENT_CPPFLAGS += -DCREATE_EVENT_TASK -endif +COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI ifneq (,$(filter v4.%,$(IDF_VERSION))) IDF_VERSION_4x := 1 @@ -392,14 +388,6 @@ EXTRA_LDFLAGS := \ $(call LinkerScript,rom.api) \ $(call LinkerScript,rom.libgcc) \ $(call LinkerScript,rom.newlib-nano) \ - $(call Wrap,\ - esp_event_loop_create_default \ - esp_event_handler_register \ - esp_event_handler_unregister \ - esp_event_handler_instance_register \ - esp_event_handler_instance_unregister \ - esp_event_post \ - esp_event_isr_post) \ $(LDFLAGS_$(ESP_VARIANT)) \ $(call Undef,$(SDK_UNDEF_SYMBOLS)) \ $(call Wrap,$(SDK_WRAP_SYMBOLS)) diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index e5b5711631..8e4c40ba18 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -15,7 +15,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y # Mandatory LWIP changes -CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=8192 +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=16384 CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=n # Ethernet @@ -39,7 +39,6 @@ CONFIG_BT_NIMBLE_MESH=n CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n # Mandatory Sming framework changes -CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=16384 CONFIG_ESP_TASK_WDT_TIMEOUT_S=8 # Required by HardwareSPI library @@ -58,8 +57,5 @@ CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n # Don't change provided flash configuration information CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=n -# We'll handle WDT initialisation ourselves thankyouverymuch -CONFIG_ESP_TASK_WDT_INIT=n - # Issues with dual-core CPU, see #2653 CONFIG_FREERTOS_UNICORE=y diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/debug b/Sming/Arch/Esp32/Components/esp32/sdk/config/debug index c74a1e37de..82e37ffe44 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/debug +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/debug @@ -27,3 +27,6 @@ CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_FREERTOS_USE_TRACE_FACILITY=y CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y + +# Watchdog +CONFIG_ESP_TASK_WDT_PANIC=y diff --git a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp b/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp deleted file mode 100644 index 583d611290..0000000000 --- a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * event_loop.cpp - * - * This code replaces the standard IDF event loop with our own, *without* associated task. - * This not only reduces the system overhead but avoids the need for additional synchronisation - * management because WiFi events, etc. are all called in the context of the main Sming task. - */ - -#include -#include - -namespace -{ -esp_event_loop_handle_t sming_event_loop; -} - -esp_event_loop_handle_t sming_create_event_loop() -{ - esp_event_loop_args_t loop_args = { - .queue_size = CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE, -#ifdef CREATE_EVENT_TASK - .task_name = "sys_evt", - .task_priority = ESP_TASKD_EVENT_PRIO, - .task_stack_size = ESP_TASKD_EVENT_STACK, -#endif - }; - - ESP_ERROR_CHECK(esp_event_loop_create(&loop_args, &sming_event_loop)); - - return sming_event_loop; -} - -namespace -{ -#define WRAP(name) esp_err_t __wrap_##name - -extern "C" { - -WRAP(esp_event_loop_create_default)() -{ - return ESP_ERR_INVALID_STATE; -} - -WRAP(esp_event_handler_register) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_register_with(sming_event_loop, event_base, event_id, event_handler, event_handler_arg); -} - -WRAP(esp_event_handler_unregister) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_unregister_with(sming_event_loop, event_base, event_id, event_handler); -} - -WRAP(esp_event_handler_instance_register) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg, - esp_event_handler_instance_t* instance) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_instance_register_with(sming_event_loop, event_base, event_id, event_handler, - event_handler_arg, instance); -} - -WRAP(esp_event_handler_instance_unregister) -(esp_event_base_t event_base, int32_t event_id, esp_event_handler_instance_t context) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_handler_instance_unregister_with(sming_event_loop, event_base, event_id, context); -} - -WRAP(esp_event_post) -(esp_event_base_t event_base, int32_t event_id, void* event_data, size_t event_data_size, TickType_t ticks_to_wait) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, ticks_to_wait); -} - -#if CONFIG_ESP_EVENT_POST_FROM_ISR -IRAM_ATTR WRAP(esp_event_isr_post)(esp_event_base_t event_base, int32_t event_id, void* event_data, - size_t event_data_size, BaseType_t* task_unblocked) -{ - if(sming_event_loop == nullptr) { - return ESP_ERR_INVALID_STATE; - } - - return esp_event_isr_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, task_unblocked); -} -#endif - -} // extern "C" - -} // namespace diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index 5ea2d72358..d47f2eefe7 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -10,8 +10,6 @@ #include #include -#include -#include #include #include #include @@ -20,73 +18,30 @@ #include extern void init(); -extern esp_event_loop_handle_t sming_create_event_loop(); extern void esp_network_initialise(); +extern void start_sming_task_loop(); -namespace -{ -void main(void*) +extern "C" void __wrap_esp_newlib_init_global_stdio(const char*) { - int err; - (void)err; -#if ESP_IDF_VERSION_MAJOR < 5 - err = esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true); -#else - esp_task_wdt_config_t twdt_config{ - .timeout_ms = 8000, - .trigger_panic = true, - }; - err = esp_task_wdt_init(&twdt_config); -#endif - assert(err == ESP_OK); - - err = esp_task_wdt_add(nullptr); - assert(err == ESP_OK); +} +extern "C" void app_main(void) +{ hw_timer_init(); smg_uart_detach_all(); esp_log_set_vprintf(m_vprintf); - auto loop = sming_create_event_loop(); - #ifndef DISABLE_WIFI esp_network_initialise(); #endif System.initialize(); Storage::initialize(); - init(); - - constexpr unsigned maxEventLoopInterval{1000 / portTICK_PERIOD_MS}; - while(true) { - esp_task_wdt_reset(); -#ifdef CREATE_EVENT_TASK - vTaskDelay(100); -#else - esp_event_loop_run(loop, maxEventLoopInterval); -#endif - } -} -} // namespace - -extern "C" void __wrap_esp_newlib_init_global_stdio(const char*) -{ -} - -extern void sming_create_task(TaskFunction_t); - -extern "C" void app_main(void) -{ -#if defined(SOC_ESP32) && !CONFIG_FREERTOS_UNICORE - constexpr unsigned core_id{1}; -#else - constexpr unsigned core_id{0}; -#endif + // Application gets called outside main thread at startup + // Things like smartconfig won't work if called via task queue + init(); -#if ESP_IDF_VERSION_MAJOR < 5 - esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(core_id)); -#endif - xTaskCreatePinnedToCore(main, "Sming", ESP_TASKD_EVENT_STACK, nullptr, ESP_TASKD_EVENT_PRIO, nullptr, core_id); + start_sming_task_loop(); } diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index a13039592f..5977deb7d9 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #if ESP_IDF_VERSION_MAJOR >= 5 @@ -75,7 +75,8 @@ void system_restart(void) void system_soft_wdt_feed(void) { - esp_task_wdt_reset(); + // Allow the IDLE task to run + vTaskDelay(1); } void system_soft_wdt_stop(void) diff --git a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp index c265a30a94..0e2e06b0fb 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp @@ -1,30 +1,48 @@ #include "include/esp_tasks.h" -#include +#include #include +#ifndef DISABLE_NETWORK +#include +#endif + namespace { -ESP_EVENT_DEFINE_BASE(TaskEvt); - os_task_t taskCallback; +QueueHandle_t eventQueue; -} // namespace +#ifdef DISABLE_NETWORK -bool system_os_task(os_task_t callback, uint8_t prio, os_event_t*, uint8_t) +void sming_task_loop(void*) { - auto handler = [](void*, esp_event_base_t, int32_t event_id, void* event_data) { - assert(taskCallback != nullptr); + os_event_t evt; + while(xQueueReceive(eventQueue, &evt, portMAX_DELAY) == pdTRUE) { + taskCallback(&evt); + } +} - os_event_t ev{os_signal_t(event_id), 0}; - if(event_data != nullptr) { - ev.par = *static_cast(event_data); - } +#else - taskCallback(&ev); - }; +tcpip_callback_msg* callbackMessage; +volatile bool eventQueueFlag; - if(callback == nullptr) { - debug_e("TQ: Callback missing"); +void tcpip_message_handler(void*) +{ + eventQueueFlag = false; + os_event_t evt; + while(xQueueReceive(eventQueue, &evt, 0) == pdTRUE) { + taskCallback(&evt); + } +} + +#endif + +} // namespace + +bool system_os_task(os_task_t callback, uint8_t prio, os_event_t* queue, uint8_t qlen) +{ + if(callback == nullptr || queue == nullptr || qlen == 0) { + debug_e("TQ: Bad parameters"); return false; } @@ -38,29 +56,64 @@ bool system_os_task(os_task_t callback, uint8_t prio, os_event_t*, uint8_t) return false; } - auto err = esp_event_handler_instance_register(TaskEvt, ESP_EVENT_ANY_ID, handler, nullptr, nullptr); - if(err != ESP_OK) { - debug_e("TQ: Failed to register handler"); + eventQueue = xQueueCreate(qlen, sizeof(os_event_t)); + if(eventQueue == nullptr) { return false; } taskCallback = callback; - debug_i("TQ: Registered %s", TaskEvt); - return true; } +void start_sming_task_loop() +{ +#ifdef DISABLE_NETWORK + +#if defined(SOC_ESP32) && !CONFIG_FREERTOS_UNICORE + constexpr unsigned core_id{1}; +#else + constexpr unsigned core_id{0}; +#endif + xTaskCreatePinnedToCore(sming_task_loop, "Sming", CONFIG_LWIP_TCPIP_TASK_STACK_SIZE, nullptr, + CONFIG_LWIP_TCPIP_TASK_PRIO, nullptr, core_id); + +#else + + callbackMessage = tcpip_callbackmsg_new(tcpip_callback_fn(tcpip_message_handler), nullptr); + +#endif +} + bool IRAM_ATTR system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) { if(prio != USER_TASK_PRIO_1) { return false; } - esp_err_t err; - if(par == 0) { - err = esp_event_isr_post(TaskEvt, sig, nullptr, 0, nullptr); + + os_event_t ev{sig, par}; + BaseType_t woken; + auto res = xQueueSendToBackFromISR(eventQueue, &ev, &woken); + if(res != pdTRUE) { + return false; + } + +#ifndef DISABLE_NETWORK + if(!callbackMessage) { + // Message loop not yet active + return true; + } + // If queue isn't empty and we haven't already asked for a tcpip callback, do that now + if(xQueueIsQueueEmptyFromISR(eventQueue) == pdFALSE && !eventQueueFlag) { + eventQueueFlag = true; + auto err = tcpip_callbackmsg_trycallback_fromisr(callbackMessage); + woken = (err == ERR_NEED_SCHED); } else { - err = esp_event_isr_post(TaskEvt, sig, &par, sizeof(par), nullptr); + woken = false; } - return (err == ESP_OK); +#endif + + portYIELD_FROM_ISR_ARG(woken); + + return true; } diff --git a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp index 87791b92a0..6c9738297f 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -40,7 +39,7 @@ uint32_t flashmem_read(void* to, flash_addr_t fromaddr, uint32_t size) bool flashmem_erase_sector(flash_sector_t sector_id) { - esp_task_wdt_reset(); + system_soft_wdt_feed(); debug_d("flashmem_erase_sector(0x%08x)", sector_id); diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index f2c60083c6..4c4e21242e 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -117,12 +117,11 @@ IDF versions ------------ Sming currently supports IDF versions 5.2. This is installed by default. -Older versions 4.3, 4.4 and 5.0 are no longer officially supported. If you use one of the old versions, please, consider upgrading to 5.2. - +Older versions 4.3, 4.4 and 5.0 are no longer supported. A different version can be installed if necessary:: - INSTALL_IDF_VER=4.4 $SMING_HOME/../Tools/install.sh esp32 + INSTALL_IDF_VER=5.3 $SMING_HOME/../Tools/install.sh esp32 The installation script creates a soft-link in ``/opt/esp-idf`` pointing to the last version installed. Use the `IDF_PATH` environment variable or change the soft-link to select which one to use. @@ -136,6 +135,35 @@ See `ESP-IDF Versions AccessPointImpl::getStations() const return std::unique_ptr(new StationListImpl); } -void AccessPointImpl::onSystemReady() -{ -} - } // namespace Network } // namespace SmingInternal diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h index 7135dbe47a..a976e5efb2 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.h @@ -20,14 +20,9 @@ namespace SmingInternal { namespace Network { -class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler +class AccessPointImpl : public AccessPointClass { public: - AccessPointImpl() - { - System.onReady(this); - } - void enable(bool enabled, bool save) override; bool isEnabled() const override; bool config(const String& ssid, String password, WifiAuthMode mode, bool hidden, int channel, @@ -43,14 +38,6 @@ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler String getPassword() const override; std::unique_ptr getStations() const override; - // Called from WifiEventsImpl - void eventHandler(esp_event_base_t base, int32_t id, void* data) - { - } - -protected: - void onSystemReady() override; - private: esp_netif_obj* apNetworkInterface{nullptr}; }; diff --git a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp index fe8ba597e3..92a00afd7e 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp @@ -26,6 +26,7 @@ bool EmbeddedEthernet::begin([[maybe_unused]] const Config& config) #else esp_netif_init(); + esp_event_loop_create_default(); esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&cfg); diff --git a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp index 7dce438f48..19af0a1ac8 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp @@ -9,6 +9,7 @@ ****/ #include +#include #include #include #include @@ -54,10 +55,9 @@ void IdfService::enableEventCallback(bool enable) auto handler = [](void* arg, esp_event_base_t, int32_t event_id, void*) { auto service = static_cast(arg); service->state = Event(event_id); - if(!service->eventCallback) { - return; + if(service->eventCallback) { + System.queueCallback([service, event_id]() { service->eventCallback(Event(event_id)); }); } - service->eventCallback(Event(event_id)); }; if(enable) { diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index bbaddc46c9..10e1569164 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -75,45 +75,56 @@ class BssInfoImpl : public BssInfo } }; -void StationImpl::eventHandler(esp_event_base_t base, int32_t id, [[maybe_unused]] void* data) +void StationImpl::dispatchStaStart() { - if(base == WIFI_EVENT) { - bool allowAutoConnect{true}; #ifdef ENABLE_WPS - if(wpsConfig != nullptr) { - wpsEventHandler(id, data); - allowAutoConnect = false; - } + if(wpsConfig) { + return; + } #endif + #ifdef ENABLE_SMART_CONFIG - if(smartConfigEventInfo) { - allowAutoConnect = false; - } + if(smartConfigEventInfo) { + return; + } #endif - switch(id) { - case WIFI_EVENT_STA_START: - if(allowAutoConnect && getAutoConnect()) { - connectionStatus = eSCS_Connecting; - esp_wifi_connect(); - } - break; - case WIFI_EVENT_STA_DISCONNECTED: { - connectionStatus = eSCS_ConnectionFailed; - break; - } - default:; - } - } else if(base == IP_EVENT) { - switch(id) { - case IP_EVENT_STA_GOT_IP: - connectionStatus = eSCS_GotIP; - break; - case IP_EVENT_STA_LOST_IP: - connectionStatus = eSCS_Connecting; - break; - default:; - } + + if(getAutoConnect()) { + connectionStatus = eSCS_Connecting; + esp_wifi_connect(); + } +} + +void StationImpl::dispatchStaDisconnected(const wifi_event_sta_disconnected_t&) +{ + connectionStatus = eSCS_ConnectionFailed; + +#ifdef ENABLE_WPS + if(wpsConfig == nullptr) { + return; } + + if(wpsConfig->ignoreDisconnects) { + return; + } + if(wpsConfig->numRetries < WpsConfig::maxRetryAttempts) { + esp_wifi_connect(); + ++wpsConfig->numRetries; + return; + } + + if(wpsConfigure(wpsConfig->credIndex + 1)) { + esp_wifi_connect(); + return; + } + + debug_e("[WPS] Failed to connect!"); + if(wpsCallback(WpsStatus::Failed)) { + // try to reconnect with old config + wpsConfigStop(); + esp_wifi_connect(); + } +#endif } void StationImpl::enable(bool enabled, bool save) @@ -394,29 +405,27 @@ bool StationImpl::startScan(ScanCompletedDelegate scanCompleted) return false; } - auto eventHandler = [](void* arg, esp_event_base_t, int32_t id, void* data) { - wifi_event_sta_scan_done_t* event = reinterpret_cast(data); - staticScanCompleted(event, event->status); - }; - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, eventHandler, nullptr)); if(esp_wifi_scan_start(nullptr, false) != ESP_OK) { - auto connectHandler = [](void*, esp_event_base_t, int32_t, void*) { esp_wifi_scan_start(nullptr, false); }; - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, connectHandler, nullptr)); - debug_e("startScan failed"); + return false; } return true; } -void StationImpl::staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t status) +void StationImpl::dispatchStaConnected(const wifi_event_sta_connected_t&) +{ + if(scanCompletedCallback) { + esp_wifi_scan_start(nullptr, false); + } +} + +void StationImpl::dispatchScanDone(const wifi_event_sta_scan_done_t& event) { BssList list; - if(status == OK) { + if(event.status == OK) { if(station.scanCompletedCallback) { - uint16_t number = event->number; + uint16_t number = event.number; wifi_ap_record_t ap_info[number]; memset(ap_info, 0, sizeof(ap_info)); @@ -431,28 +440,22 @@ void StationImpl::staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t debug_i("scan completed: %u found", list.count()); } else { - debug_e("scan failed %u", status); + debug_e("scan failed %u", event.status); if(station.scanCompletedCallback) { station.scanCompletedCallback(false, list); } } } -void StationImpl::onSystemReady() -{ -} - #ifdef ENABLE_SMART_CONFIG -void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) +void StationImpl::smartConfigEventHandler(void*, esp_event_base_t, int32_t event_id, void* data) { - if(!smartConfigEventInfo) { + if(!station.smartConfigEventInfo) { debug_e("[SC] ERROR! eventInfo null"); return; } - auto& evt = *smartConfigEventInfo; - SmartConfigEvent event; switch(event_id) { case SC_EVENT_SCAN_DONE: @@ -469,11 +472,12 @@ void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) break; case SC_EVENT_GOT_SSID_PSWD: { debugf("[SC] GOT_SSID_PSWD"); - auto cfg = static_cast(pdata); + auto cfg = static_cast(data); assert(cfg != nullptr); if(cfg == nullptr) { return; } + auto& evt = *station.smartConfigEventInfo; evt.ssid = reinterpret_cast(cfg->ssid); evt.password = reinterpret_cast(cfg->password); evt.bssidSet = cfg->bssid_set; @@ -487,26 +491,23 @@ void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) return; } - if(smartConfigCallback && !smartConfigCallback(event, evt)) { - return; - } - - switch(event_id) { - case SC_EVENT_GOT_SSID_PSWD: - StationClass::config(evt.ssid, evt.password, true, true); - connect(); - break; - case SC_EVENT_SEND_ACK_DONE: - smartConfigStop(); - break; - default:; - } -} + System.queueCallback([event]() { + auto& evt = *station.smartConfigEventInfo; + if(station.smartConfigCallback && !station.smartConfigCallback(event, evt)) { + return; + } -void StationImpl::smartConfigEventHandler(void* arg, esp_event_base_t, int32_t id, void* data) -{ - auto self = static_cast(arg); - return self->internalSmartConfig(smartconfig_event_t(id), data); + switch(event) { + case SCE_Link: + station.config({evt.ssid, evt.password}); + station.connect(); + break; + case SCE_LinkOver: + station.smartConfigStop(); + break; + default:; + } + }); } bool StationImpl::smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) @@ -552,81 +553,50 @@ void StationImpl::smartConfigStop() #ifdef ENABLE_WPS -void StationImpl::wpsEventHandler(int32_t event_id, void* event_data) +void StationImpl::dispatchStaWpsErFailed() { - switch(event_id) { - case WIFI_EVENT_STA_DISCONNECTED: - debug_w("WIFI_EVENT_STA_DISCONNECTED"); - if(wpsConfig->ignoreDisconnects) { - break; - } - if(wpsConfig->numRetries < WpsConfig::maxRetryAttempts) { - esp_wifi_connect(); - ++wpsConfig->numRetries; - break; - } - - if(wpsConfigure(wpsConfig->credIndex + 1)) { - esp_wifi_connect(); - break; - } - - debug_e("[WPS] Failed to connect!"); - if(wpsCallback(WpsStatus::Failed)) { - // try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; - - case WIFI_EVENT_STA_WPS_ER_SUCCESS: { - debug_i("WIFI_EVENT_STA_WPS_ER_SUCCESS"); - - if(!wpsCallback(WpsStatus::Success)) { - return; - } - - if(event_data != nullptr) { - /* If multiple AP credentials are received from WPS, connect with first one */ - wpsConfig->creds = *static_cast(event_data); - wpsConfigure(0); - } - /* - * If only one AP credential is received from WPS, there will be no event data and - * esp_wifi_set_config() is already called by WPS modules for backward compatibility - * with legacy apps. So directly attempt connection here. - */ + debug_e("WIFI_EVENT_STA_WPS_ER_FAILED"); + if(wpsCallback(WpsStatus::Failed)) { + // Try to reconnect with old config wpsConfigStop(); esp_wifi_connect(); - break; } +} - case WIFI_EVENT_STA_WPS_ER_FAILED: { - debug_e("WIFI_EVENT_STA_WPS_ER_FAILED"); - if(wpsCallback(WpsStatus::Failed)) { - // Try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; +void StationImpl::dispatchStaWpsErTimeout() +{ + debug_e("WIFI_EVENT_STA_WPS_ER_TIMEOUT"); + if(wpsCallback(WpsStatus::Timeout)) { + // Try to reconnect with old config + wpsConfigStop(); + esp_wifi_connect(); } +} - case WIFI_EVENT_STA_WPS_ER_TIMEOUT: - debug_e("WIFI_EVENT_STA_WPS_ER_TIMEOUT"); - if(wpsCallback(WpsStatus::Timeout)) { - // Try to reconnect with old config - wpsConfigStop(); - esp_wifi_connect(); - } - break; +void StationImpl::dispatchStaWpsErPin() +{ + debug_e("WIFI_EVENT_STA_WPS_ER_PIN (not implemented)"); +} - case WIFI_EVENT_STA_WPS_ER_PIN: - debug_e("WIFI_EVENT_STA_WPS_ER_PIN (not implemented)"); - break; +void StationImpl::dispatchWpsErSuccess(const wifi_event_sta_wps_er_success_t& event) +{ + debug_i("WIFI_EVENT_STA_WPS_ER_SUCCESS"); - default: - break; + if(!wpsCallback(WpsStatus::Success)) { + return; } + + /* If multiple AP credentials are received from WPS, connect with first one */ + wpsConfig->creds = event; + wpsConfigure(0); + + /* + * If only one AP credential is received from WPS, there will be no event data and + * esp_wifi_set_config() is already called by WPS modules for backward compatibility + * with legacy apps. So directly attempt connection here. + */ + wpsConfigStop(); + esp_wifi_connect(); } bool StationImpl::wpsConfigure(uint8_t credIndex) diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h index 2fe46a9361..570088aa01 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h @@ -25,14 +25,9 @@ namespace SmingInternal { namespace Network { -class StationImpl : public StationClass, protected ISystemReadyHandler +class StationImpl : public StationClass { public: - StationImpl() - { - System.onReady(this); - } - void enable(bool enabled, bool save) override; bool isEnabled() const override; bool config(const Config& cfg) override; @@ -67,21 +62,36 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void wpsConfigStop() override; #endif - // Called from WifiEventsImpl - void eventHandler(esp_event_base_t base, int32_t id, void* data); + // Called from network event handler (init.cpp) + void dispatchStaStart(); + void dispatchStaConnected(const wifi_event_sta_connected_t& event); + void dispatchStaDisconnected(const wifi_event_sta_disconnected_t& event); + + void dispatchStaGotIp(const ip_event_got_ip_t&) + { + connectionStatus = eSCS_GotIP; + } + + void dispatchStaLostIp() + { + connectionStatus = eSCS_Connecting; + } + + void dispatchScanDone(const wifi_event_sta_scan_done_t& event); -protected: - void onSystemReady() override; +#ifdef ENABLE_WPS + void dispatchStaWpsErFailed(); + void dispatchStaWpsErTimeout(); + void dispatchStaWpsErPin(); + void dispatchWpsErSuccess(const wifi_event_sta_wps_er_success_t& event); +#endif private: - static void staticScanCompleted(wifi_event_sta_scan_done_t* event, uint8_t status); #ifdef ENABLE_WPS - void wpsEventHandler(int32_t event_id, void* event_data); bool wpsCallback(WpsStatus status); bool wpsConfigure(uint8_t credIndex); #endif #ifdef ENABLE_SMART_CONFIG - void internalSmartConfig(smartconfig_event_t event, void* pdata); static void smartConfigEventHandler(void* arg, esp_event_base_t base, int32_t id, void* data); #endif diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp index d6ff95efbe..4073b132b7 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.cpp @@ -9,119 +9,11 @@ #include "WifiEventsImpl.h" #include "StationImpl.h" -#include WifiEventsClass& WifiEvents{SmingInternal::Network::events}; -namespace SmingInternal -{ -namespace Network +namespace SmingInternal::Network { WifiEventsImpl events; -ip_addr_t ip(esp_ip4_addr_t ip) -{ - ip_addr_t r = IPADDR4_INIT(ip.addr); - return r; -} - -void WifiEventsImpl::eventHandler(esp_event_base_t base, int32_t id, void* data) -{ - if(base == WIFI_EVENT) { - switch(id) { - case WIFI_EVENT_STA_START: - break; - case WIFI_EVENT_STA_CONNECTED: { - wifi_event_sta_connected_t* event = reinterpret_cast(data); - debugf("connect to ssid %s, channel %d\n", event->ssid, event->channel); - if(onSTAConnect) { - String ssid(reinterpret_cast(event->ssid), event->ssid_len); - onSTAConnect(ssid, event->bssid, event->channel); - } - break; - } - case WIFI_EVENT_STA_DISCONNECTED: { - wifi_event_sta_disconnected_t* event = reinterpret_cast(data); - debugf("disconnect from ssid %s, reason %d\n", event->ssid, event->reason); - if(onSTADisconnect) { - String ssid(reinterpret_cast(event->ssid), event->ssid_len); - auto reason = WifiDisconnectReason(event->reason); - onSTADisconnect(ssid, event->bssid, reason); - } - break; - } - case WIFI_EVENT_STA_AUTHMODE_CHANGE: { - wifi_event_sta_authmode_change_t* event = reinterpret_cast(data); - auto oldMode = WifiAuthMode(event->old_mode); - auto newMode = WifiAuthMode(event->new_mode); - debugf("mode: %d -> %d\n", oldMode, newMode); - - if((oldMode != AUTH_OPEN) && (newMode == AUTH_OPEN)) { - // CVE-2020-12638 workaround. - // TODO: Remove this workaround once ESP-IDF has the proper fix. - debugf("Potential downgrade attack. Reconnecting WiFi. See CVE-2020-12638 for more details\n"); - WifiStation.disconnect(); - WifiStation.connect(); - break; - } - - if(onSTAAuthModeChange) { - onSTAAuthModeChange(oldMode, newMode); - } - break; - } - case WIFI_EVENT_AP_STACONNECTED: { - wifi_event_ap_staconnected_t* event = reinterpret_cast(data); - debugf("station: " MACSTR " join, AID = %d\n", MAC2STR(event->mac), event->aid); - if(onSOFTAPConnect) { - onSOFTAPConnect(event->mac, event->aid); - } - break; - } - case WIFI_EVENT_AP_STADISCONNECTED: { - wifi_event_ap_stadisconnected_t* event = reinterpret_cast(data); - debugf("station: " MACSTR "leave, AID = %d\n", MAC2STR(event->mac), event->aid); - if(onSOFTAPDisconnect) { - onSOFTAPDisconnect(event->mac, event->aid); - } - break; - } - case WIFI_EVENT_AP_PROBEREQRECVED: { - wifi_event_ap_probe_req_rx_t* event = reinterpret_cast(data); - if(onSOFTAPProbeReqRecved) { - onSOFTAPProbeReqRecved(event->rssi, event->mac); - } - break; - } - - default: - break; - - } // switch id - } else if(base == IP_EVENT) { - switch(id) { - case IP_EVENT_STA_GOT_IP: { - ip_event_got_ip_t* event = reinterpret_cast(data); - debugf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&event->ip_info.ip), - IP2STR(&event->ip_info.netmask), IP2STR(&event->ip_info.gw)); - if(onSTAGotIP) { - onSTAGotIP(ip(event->ip_info.ip), ip(event->ip_info.netmask), ip(event->ip_info.gw)); - } - break; - } - case IP_EVENT_STA_LOST_IP: { - // TODO: ESP32 station lost IP and the IP is reset to 0 - break; - } - case IP_EVENT_AP_STAIPASSIGNED: { - // TODO: ESP32 soft-AP assign an IP to a connected station - break; - } - default: - break; - } // switch id - } -} - -} // namespace Network -} // namespace SmingInternal +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h index 99886ae9f9..c460bdbea6 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/WifiEventsImpl.h @@ -13,17 +13,95 @@ #include #include #include +#include +#include -namespace SmingInternal -{ -namespace Network +namespace SmingInternal::Network { class WifiEventsImpl : public WifiEventsClass { public: - void eventHandler(esp_event_base_t base, int32_t id, void* data); + void dispatchStaStart() + { + } + + void dispatchStaConnected(const wifi_event_sta_connected_t& event) + { + debugf("connect to ssid %s, channel %d\n", event.ssid, event.channel); + if(onSTAConnect) { + String ssid(reinterpret_cast(event.ssid), event.ssid_len); + onSTAConnect(ssid, event.bssid, event.channel); + } + } + + void dispatchStaDisconnected(const wifi_event_sta_disconnected_t& event) + { + debugf("disconnect from ssid %s, reason %d\n", event.ssid, event.reason); + if(onSTADisconnect) { + String ssid(reinterpret_cast(event.ssid), event.ssid_len); + auto reason = WifiDisconnectReason(event.reason); + onSTADisconnect(ssid, event.bssid, reason); + } + } + + void dispatchStaAuthmodeChange(const wifi_event_sta_authmode_change_t& event) + { + auto oldMode = WifiAuthMode(event.old_mode); + auto newMode = WifiAuthMode(event.new_mode); + debugf("mode: %d -> %d\n", oldMode, newMode); + + if(onSTAAuthModeChange) { + onSTAAuthModeChange(oldMode, newMode); + } + } + + void dispatchApStaConnected(const wifi_event_ap_staconnected_t& event) + { + debugf("station: " MACSTR " join, AID = %d\n", MAC2STR(event.mac), event.aid); + if(onSOFTAPConnect) { + onSOFTAPConnect(event.mac, event.aid); + } + } + + void dispatchApStaDisconnected(const wifi_event_ap_stadisconnected_t& event) + { + debugf("station: " MACSTR "leave, AID = %d\n", MAC2STR(event.mac), event.aid); + if(onSOFTAPDisconnect) { + onSOFTAPDisconnect(event.mac, event.aid); + } + } + + void dispatchApProbeReqReceived(const wifi_event_ap_probe_req_rx_t& event) + { + if(onSOFTAPProbeReqRecved) { + onSOFTAPProbeReqRecved(event.rssi, event.mac); + } + } + + void dispatchStaGotIp(const ip_event_got_ip_t& event) + { + debugf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&event.ip_info.ip), IP2STR(&event.ip_info.netmask), + IP2STR(&event.ip_info.gw)); + if(onSTAGotIP) { + auto ip = [](esp_ip4_addr_t ip) -> IpAddress { + ip_addr_t r = IPADDR4_INIT(ip.addr); + return IpAddress{r}; + }; + onSTAGotIP(ip(event.ip_info.ip), ip(event.ip_info.netmask), ip(event.ip_info.gw)); + } + } + + void dispatchStaLostIp() + { + // TODO: ESP32 station lost IP and the IP is reset to 0 + } + + void dispatchApStaIpAssigned() + { + // TODO: ESP32 soft-AP assign an IP to a connected station + } }; extern WifiEventsImpl events; -} // namespace Network -} // namespace SmingInternal + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Esp32/Platform/init.cpp b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp index 8bd40c46d9..14f446cfac 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/init.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/init.cpp @@ -13,6 +13,107 @@ #include #include +namespace +{ +void eventHandler(void*, esp_event_base_t base, int32_t id, void* data) +{ + /* + * This handler is called from the wifi task, but events should only be handled in the Sming task thread. + * We need to interpret the associated data and take a copy for the queue. + * Each event is then passed to an explicit handler method. + */ + + using namespace SmingInternal::Network; + debugf("event %s|%d\n", base, id); + + if(base == WIFI_EVENT) { + switch(id) { +#ifdef ENABLE_WPS + case WIFI_EVENT_STA_WPS_ER_SUCCESS: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchWpsErSuccess(event); + }); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + System.queueCallback([](void*) { station.dispatchStaWpsErFailed(); }); + break; + case WIFI_EVENT_STA_WPS_ER_TIMEOUT: + System.queueCallback([](void*) { station.dispatchStaWpsErTimeout(); }); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + System.queueCallback([](void*) { station.dispatchStaWpsErPin(); }); + break; +#endif + case WIFI_EVENT_SCAN_DONE: + System.queueCallback( + [event = *static_cast(data)]() { station.dispatchScanDone(event); }); + break; + case WIFI_EVENT_STA_START: + System.queueCallback([](void*) { + station.dispatchStaStart(); + events.dispatchStaStart(); + }); + break; + case WIFI_EVENT_STA_CONNECTED: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaConnected(event); + events.dispatchStaConnected(event); + }); + break; + case WIFI_EVENT_STA_DISCONNECTED: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaDisconnected(event); + events.dispatchStaDisconnected(event); + }); + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchStaAuthmodeChange(event); + }); + break; + case WIFI_EVENT_AP_STACONNECTED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApStaConnected(event); + }); + break; + case WIFI_EVENT_AP_STADISCONNECTED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApStaDisconnected(event); + }); + break; + case WIFI_EVENT_AP_PROBEREQRECVED: + System.queueCallback([event = *static_cast(data)]() { + events.dispatchApProbeReqReceived(event); + }); + break; + default: + break; + } + } else if(base == IP_EVENT) { + switch(id) { + case IP_EVENT_STA_GOT_IP: + System.queueCallback([event = *static_cast(data)]() { + station.dispatchStaGotIp(event); + events.dispatchStaGotIp(event); + }); + break; + case IP_EVENT_STA_LOST_IP: + System.queueCallback([](void*) { + station.dispatchStaLostIp(); + events.dispatchStaLostIp(); + }); + break; + case IP_EVENT_AP_STAIPASSIGNED: + System.queueCallback([](void*) { events.dispatchApStaIpAssigned(); }); + break; + default: + break; + } + } +} + +} // namespace + // Called from startup void esp_network_initialise() { @@ -30,13 +131,7 @@ void esp_network_initialise() * Initialise default WiFi stack */ esp_netif_init(); - auto eventHandler = [](void*, esp_event_base_t base, int32_t id, void* data) -> void { - using namespace SmingInternal::Network; - debugf("event %s|%d\n", base, id); - station.eventHandler(base, id, data); - accessPoint.eventHandler(base, id, data); - events.eventHandler(base, id, data); - }; + esp_event_loop_create_default(); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, eventHandler, nullptr)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, eventHandler, nullptr)); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); diff --git a/Sming/Components/Storage/src/Device.cpp b/Sming/Components/Storage/src/Device.cpp index a1d5560f0f..5036d86735 100644 --- a/Sming/Components/Storage/src/Device.cpp +++ b/Sming/Components/Storage/src/Device.cpp @@ -55,8 +55,11 @@ Device::~Device() bool Device::loadPartitions(Device& source, uint32_t tableOffset) { constexpr size_t maxEntries = ESP_PARTITION_TABLE_MAX_LEN / sizeof(esp_partition_info_t); - esp_partition_info_t buffer[maxEntries]; - if(!source.read(tableOffset, buffer, sizeof(buffer))) { + auto buffer = std::make_unique(maxEntries); + if(!buffer) { + return false; + } + if(!source.read(tableOffset, buffer.get(), ESP_PARTITION_TABLE_MAX_LEN)) { debug_e("[Partition] Failed to read partition table at offset 0x%08x", tableOffset); return false; } diff --git a/Sming/Platform/System.cpp b/Sming/Platform/System.cpp index 7e826a426c..7ef1ee6098 100644 --- a/Sming/Platform/System.cpp +++ b/Sming/Platform/System.cpp @@ -14,11 +14,6 @@ SystemClass System; SystemState SystemClass::state = eSS_None; -#ifdef ARCH_ESP32 -#undef TASK_QUEUE_LENGTH -#define TASK_QUEUE_LENGTH 0 -#define taskQueue nullptr -#else #ifdef TASK_QUEUE_LENGTH static_assert(TASK_QUEUE_LENGTH >= 8, "Task queue too small"); #else @@ -28,8 +23,8 @@ static_assert(TASK_QUEUE_LENGTH >= 8, "Task queue too small"); */ #define TASK_QUEUE_LENGTH 10 #endif + os_event_t SystemClass::taskQueue[TASK_QUEUE_LENGTH]; -#endif #ifdef ENABLE_TASK_COUNT volatile uint8_t SystemClass::taskCount; diff --git a/docs/source/upgrading/5.2-6.0.rst b/docs/source/upgrading/5.2-6.0.rst new file mode 100644 index 0000000000..c6e8182d79 --- /dev/null +++ b/docs/source/upgrading/5.2-6.0.rst @@ -0,0 +1,12 @@ +From v5.2 to 6.0 +================ + +.. highlight:: c++ + +**Esp32 task scheduling** + +Sming is a single-threaded framework, so does not impose any requirements on application code to be thread-safe. +However, code could be executed from one of several tasks (wifi, tcpip or Sming) which is a reliability concern. + +With PR#2913 this has been fixed and all Sming code now runs in the same task context. +This has largely be achieved by using a separate callback queue for Sming rather than using the IDF mechanism.