diff --git a/.github/workflows/ci-esp32.yml b/.github/workflows/ci-esp32.yml index 21e3d98dab..7425093506 100644 --- a/.github/workflows/ci-esp32.yml +++ b/.github/workflows/ci-esp32.yml @@ -15,20 +15,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp32, esp32s2, esp32c3, esp32s3, esp32c2] - idf_version: ["4.4", "5.0", "5.2"] - include: - - os: ubuntu-latest - variant: esp32 - idf_version: "4.3" - exclude: - - variant: esp32c2 - idf_version: "4.4" - - os: macos-latest - idf_version: "4.4" - - os: macos-latest - idf_version: "5.0" - - os: windows-latest - idf_version: "5.0" + idf_version: ["5.2"] concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} @@ -58,7 +45,7 @@ jobs: - name: Setup python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.idf_version == '4.3' && '3.8' || '3.12' }} + python-version: '3.12' - name: Fix permissions if: matrix.os != 'windows-latest' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b33ec55ea..133dd9a13e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - variant: [esp8266, host, rp2040] + variant: [esp8266, host, rp2040, rp2350] toolchain: [gcc] include: - variant: esp8266 @@ -31,6 +31,8 @@ jobs: toolchain: gcc64 - variant: rp2040 arch: Rp2040 + - variant: rp2350 + arch: Rp2040 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index 7a02c305b6..fa9c35a995 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -23,7 +23,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] variant: [esp8266, host, esp32, esp32s2, esp32c3, esp32s3, esp32c2, rp2040] - idf_version: ["4.4", ""] # "" denotes default, currently 5.2 + idf_version: [""] # "" denotes default, currently 5.2 toolchain: [gcc] include: - variant: esp8266 @@ -50,17 +50,6 @@ jobs: arch: Esp32 - variant: rp2040 arch: Rp2040 - exclude: - - variant: esp32c2 - idf_version: "4.4" - - variant: esp8266 - idf_version: "4.4" - - variant: host - idf_version: "4.4" - - variant: rp2040 - idf_version: "4.4" - - os: macos-latest - idf_version: "4.4" concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} diff --git a/.gitmodules b/.gitmodules index a1404fb3cd..7a6bfa13a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -122,7 +122,7 @@ [submodule "Rp2040.picotool"] path = Sming/Arch/Rp2040/Components/picotool/picotool - url = https://github.com/mikee47/picotool + url = https://github.com/raspberrypi/picotool ignore = dirty [submodule "Rp2040.Sdk"] @@ -213,6 +213,10 @@ path = Sming/Libraries/Arduino_TensorFlowLite url = https://github.com/slaff/Arduino_TensorFlowLite.git ignore = dirty +[submodule "Libraries.ConfigDB"] + path = Sming/Libraries/ConfigDB + url = https://github.com/mikee47/ConfigDB + ignore = dirty [submodule "Libraries.CS5460"] path = Sming/Libraries/CS5460/CS5460 url = https://github.com/xxzl0130/CS5460.git @@ -281,6 +285,10 @@ path = Sming/Libraries/ITEADLIB_Arduino_Nextion url = https://github.com/itead/ITEADLIB_Arduino_Nextion.git ignore = dirty +[submodule "Libraries.JsonStreamingParser"] + path = Sming/Libraries/JsonStreamingParser + url = https://github.com/mikee47/JsonStreamingParser + ignore = dirty [submodule "Libraries.libsodium"] path = Sming/Libraries/libsodium/libsodium url = https://github.com/jedisct1/libsodium.git diff --git a/README.md b/README.md index b35dca3b58..0c78eb68fa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Sming Sming is an asynchronous embedded C++ framework with superb performance and multiple network features. -Sming is [open source](LICENSE), modular and supports [multiple architectures](https://sming.readthedocs.io/en/latest/features.html) including ESP8266, ESP32 and RP2040. +Sming is [open source](LICENSE), modular and supports [multiple architectures](https://sming.readthedocs.io/en/latest/features.html) including ESP8266, ESP32 and Raspberry Pi Pico (both RP2040 and RP2350). [![Examples](https://github.com/SmingHub/Sming/wiki/images/small/combine.png)](https://github.com/SmingHub/Sming/wiki/examples) @@ -29,14 +29,14 @@ You can also try Sming without installing anything locally. We have an [interact The purpose of Sming is to simplify the creation of embedded applications. The documentation will help you get started in no time. -- [**Documentation for version 5.2.0**](https://sming.readthedocs.io/en/stable) - current stable version. +- [**Documentation for version 6.0.0**](https://sming.readthedocs.io/en/stable) - current stable version. - [Documentation for latest](https://sming.readthedocs.io/en/latest) - development version. ## Releases ### Stable -- [Sming V5.2.0](https://github.com/SmingHub/Sming/releases/tag/5.2.0) - great new features, performance and stability improvements. +- [Sming V6.0.0](https://github.com/SmingHub/Sming/releases/tag/6.0.0) - great new features, performance and stability improvements. ### Development diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h index 1979b45072..623bc5de29 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h @@ -15,11 +15,14 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #if CONFIG_ESP_TIMER_IMPL_TG0_LAC #include #else #include #endif +#pragma GCC diagnostic pop #ifdef __cplusplus extern "C" { diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h index 570369049a..5b6e1c79b2 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h @@ -10,9 +10,6 @@ #pragma once -#ifdef SOC_LEDC_CHANNEL_NUM +#include + #define PWM_CHANNEL_NUM_MAX SOC_LEDC_CHANNEL_NUM -#else -// this should not happen if the correct esp32 includes are used, just to be absolutely sure -#define PWM_CHANNEL_NUM_MAX 8 -#endif 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..66ed206cba 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 @@ -121,7 +117,8 @@ SDK_INCDIRS := \ esp_netif/include \ esp_eth/include \ esp_wifi/include \ - lwip/include/apps/sntp + lwip/include/apps/sntp \ + usb/include ifdef IDF_VERSION_4x SDK_INCDIRS += \ @@ -266,6 +263,10 @@ SDK_COMPONENTS := \ soc \ spi_flash +ifneq (,$(filter esp32s2 esp32s3,$(SMING_SOC))) +SDK_COMPONENTS += usb +endif + ifdef IDF_VERSION_43 SDK_COMPONENTS += $(ESP_VARIANT) else @@ -392,14 +393,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..6a20aa0afa 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,7 @@ 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_MAIN_TASK_STACK_SIZE=16384 CONFIG_ESP_TASK_WDT_TIMEOUT_S=8 # Required by HardwareSPI library @@ -58,8 +58,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/sdk/esp_system.mk b/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk index ec7f205e94..f18108c391 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk +++ b/Sming/Arch/Esp32/Components/esp32/sdk/esp_system.mk @@ -12,10 +12,10 @@ ifndef CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE SDK_UNDEF_SYMBOLS += start_app_other_cores endif -# ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the -# linker will ignore panic_highint_hdl.S as it has no other files depending on any +# ld_include_highint_hdl is added as an undefined symbol because otherwise the +# linker will ignore highint_hdl.S as it has no other files depending on any # symbols in it. -SDK_UNDEF_SYMBOLS += ld_include_panic_highint_hdl +SDK_UNDEF_SYMBOLS += ld_include_highint_hdl # IDF 5.2 SDK_WRAP_SYMBOLS += esp_newlib_init_global_stdio 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/Core/HardwarePWM.cpp b/Sming/Arch/Esp32/Core/HardwarePWM.cpp index fcc387dc34..183accf984 100644 --- a/Sming/Arch/Esp32/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp32/Core/HardwarePWM.cpp @@ -138,13 +138,12 @@ uint32_t maxDuty(ledc_timer_bit_t bits) } //namespace -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) { - debug_d("starting HardwarePWM init"); + assert(no_of_pins > 0 && no_of_pins <= SOC_LEDC_CHANNEL_NUM); + no_of_pins = std::min(uint8_t(SOC_LEDC_CHANNEL_NUM), no_of_pins); + periph_module_enable(PERIPH_LEDC_MODULE); - if((no_of_pins == 0) || (no_of_pins > SOC_LEDC_CHANNEL_NUM)) { - return; - } for(uint8_t i = 0; i < no_of_pins; i++) { channels[i] = pins[i]; @@ -207,17 +206,7 @@ HardwarePWM::~HardwarePWM() } } -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - for(uint8_t i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - return i; - } - } - return -1; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const { // esp32 defines the frequency / period per timer return (chan == PWM_BAD_CHANNEL) ? 0 : ledc_get_duty(pinToGroup(chan), pinToChannel(chan)); @@ -246,7 +235,7 @@ bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { // Sming does not know how to handle different frequencies for channels: this will require an extended interface. // For now, just report the period for group 0 channel 0. @@ -269,7 +258,7 @@ void HardwarePWM::update() // ledc_update_duty(); } -uint32_t HardwarePWM::getFrequency(uint8_t pin) +uint32_t HardwarePWM::getFrequency(uint8_t pin) const { return ledc_get_freq(pinToGroup(pin), pinToTimer(pin)); } diff --git a/Sming/Arch/Esp32/Core/peripheral.h b/Sming/Arch/Esp32/Core/peripheral.h deleted file mode 100644 index be157e6e34..0000000000 --- a/Sming/Arch/Esp32/Core/peripheral.h +++ /dev/null @@ -1,846 +0,0 @@ -#pragma once - -#if 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ESP8266_REG(addr) *((volatile uint32_t*)(0x60000000 + (addr))) -#define ESP8266_DREG(addr) *((volatile uint32_t*)(0x3FF00000 + (addr))) -#define ESP8266_CLOCK 80000000UL - -//CPU Register -#define CPU2X ESP8266_DREG(0x14) //when bit 0 is set, F_CPU = 160MHz - -//OTP Registers -#define MAC0 ESP8266_DREG(0x50) -#define MAC1 ESP8266_DREG(0x54) -#define CHIPID ESP8266_DREG(0x58) - -//GPIO (0-15) Control Registers -#define GPO ESP8266_REG(0x300) //GPIO_OUT R/W (Output Level) -#define GPOS ESP8266_REG(0x304) //GPIO_OUT_SET WO -#define GPOC ESP8266_REG(0x308) //GPIO_OUT_CLR WO -#define GPE ESP8266_REG(0x30C) //GPIO_ENABLE R/W (Enable) -#define GPES ESP8266_REG(0x310) //GPIO_ENABLE_SET WO -#define GPEC ESP8266_REG(0x314) //GPIO_ENABLE_CLR WO -#define GPI ESP8266_REG(0x318) //GPIO_IN RO (Read Input Level) -#define GPIE ESP8266_REG(0x31C) //GPIO_STATUS R/W (Interrupt Enable) -#define GPIES ESP8266_REG(0x320) //GPIO_STATUS_SET WO -#define GPIEC ESP8266_REG(0x324) //GPIO_STATUS_CLR WO - -#define GPOP(p) ((GPO & (1 << ((p)&0xF))) != 0) -#define GPEP(p) ((GPE & (1 << ((p)&0xF))) != 0) -#define GPIP(p) ((GPI & (1 << ((p)&0xF))) != 0) -#define GPIEP(p) ((GPIE & (1 << ((p)&0xF))) != 0) - -//GPIO (0-15) PIN Control Registers -#define GPC(p) ESP8266_REG(0x328 + ((p & 0xF) * 4)) -#define GPC0 ESP8266_REG(0x328) //GPIO_PIN0 -#define GPC1 ESP8266_REG(0x32C) //GPIO_PIN1 -#define GPC2 ESP8266_REG(0x330) //GPIO_PIN2 -#define GPC3 ESP8266_REG(0x334) //GPIO_PIN3 -#define GPC4 ESP8266_REG(0x338) //GPIO_PIN4 -#define GPC5 ESP8266_REG(0x33C) //GPIO_PIN5 -#define GPC6 ESP8266_REG(0x340) //GPIO_PIN6 -#define GPC7 ESP8266_REG(0x344) //GPIO_PIN7 -#define GPC8 ESP8266_REG(0x348) //GPIO_PIN8 -#define GPC9 ESP8266_REG(0x34C) //GPIO_PIN9 -#define GPC10 ESP8266_REG(0x350) //GPIO_PIN10 -#define GPC11 ESP8266_REG(0x354) //GPIO_PIN11 -#define GPC12 ESP8266_REG(0x358) //GPIO_PIN12 -#define GPC13 ESP8266_REG(0x35C) //GPIO_PIN13 -#define GPC14 ESP8266_REG(0x360) //GPIO_PIN14 -#define GPC15 ESP8266_REG(0x364) //GPIO_PIN15 - -//GPIO (0-15) PIN Control Bits -#define GPCWE 10 //WAKEUP_ENABLE (can be 1 only when INT_TYPE is high or low) -#define GPCI 7 //INT_TYPE (3bits) 0:disable,1:rising,2:falling,3:change,4:low,5:high -#define GPCD 2 //DRIVER 0:normal,1:open drain -#define GPCS 0 //SOURCE 0:GPIO_DATA,1:SigmaDelta - -#define GPMUX ESP8266_REG(0x800) -//GPIO (0-15) PIN Function Registers -#define GPF0 ESP8266_REG(0x834) -#define GPF1 ESP8266_REG(0x818) -#define GPF2 ESP8266_REG(0x838) -#define GPF3 ESP8266_REG(0x814) -#define GPF4 ESP8266_REG(0x83C) -#define GPF5 ESP8266_REG(0x840) -#define GPF6 ESP8266_REG(0x81C) -#define GPF7 ESP8266_REG(0x820) -#define GPF8 ESP8266_REG(0x824) -#define GPF9 ESP8266_REG(0x828) -#define GPF10 ESP8266_REG(0x82C) -#define GPF11 ESP8266_REG(0x830) -#define GPF12 ESP8266_REG(0x804) -#define GPF13 ESP8266_REG(0x808) -#define GPF14 ESP8266_REG(0x80C) -#define GPF15 ESP8266_REG(0x810) - -extern const uint8_t esp8266_gpioToFn[16]; -#define GPF(p) ESP8266_REG(0x800 + esp8266_gpioToFn[(p & 0xF)]) - -//GPIO (0-15) PIN Function Bits -#define GPFSOE 0 //Sleep OE -#define GPFSS 1 //Sleep Sel -#define GPFSPD 2 //Sleep Pulldown -#define GPFSPU 3 //Sleep Pullup -#define GPFFS0 4 //Function Select bit 0 -#define GPFFS1 5 //Function Select bit 1 -#define GPFPD 6 //Pulldown -#define GPFPU 7 //Pullup -#define GPFFS2 8 //Function Select bit 2 -#define GPFFS(f) (((((f)&4) != 0) << GPFFS2) | ((((f)&2) != 0) << GPFFS1) | ((((f)&1) != 0) << GPFFS0)) -#define GPFFS_GPIO(p) (((p) == 0 || (p) == 2 || (p) == 4 || (p) == 5) ? 0 : ((p) == 16) ? 1 : 3) -#define GPFFS_BUS(p) \ - (((p) == 1 || (p) == 3) ? 0 \ - : ((p) == 2 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15) ? 2 : ((p) == 0) ? 4 : 1) - -//GPIO 16 Control Registers -#define GP16O ESP8266_REG(0x768) -#define GP16E ESP8266_REG(0x774) -#define GP16I ESP8266_REG(0x78C) - -//GPIO 16 PIN Control Register -#define GP16C ESP8266_REG(0x790) -#define GPC16 GP16C - -//GPIO 16 PIN Function Register -#define GP16F ESP8266_REG(0x7A0) -#define GPF16 GP16F - -//GPIO 16 PIN Function Bits -#define GP16FFS0 0 //Function Select bit 0 -#define GP16FFS1 1 //Function Select bit 1 -#define GP16FPD 3 //Pulldown -#define GP16FSPD 5 //Sleep Pulldown -#define GP16FFS2 6 //Function Select bit 2 -#define GP16FFS(f) (((f)&0x03) | (((f)&0x04) << 4)) - -//Timer 1 Registers (23bit CountDown Timer) -#define T1L ESP8266_REG(0x600) //Load Value (Starting Value of Counter) 23bit (0-8388607) -#define T1V ESP8266_REG(0x604) //(RO) Current Value -#define T1C ESP8266_REG(0x608) //Control Register -#define T1I ESP8266_REG(0x60C) //Interrupt Status Register (1bit) write to clear -//edge interrupt enable register -#define TEIE ESP8266_DREG(0x04) -#define TEIE1 0x02 //bit for timer 1 - -//Timer 2 Registers (32bit CountUp Timer) -#define T2L ESP8266_REG(0x620) //Load Value (Starting Value of Counter) -#define T2V ESP8266_REG(0x624) //(RO) Current Value -#define T2C ESP8266_REG(0x628) //Control Register -#define T2I ESP8266_REG(0x62C) //Interrupt Status Register (1bit) write to clear -#define T2A ESP8266_REG(0x630) //Alarm Value - -//Timer Control Bits -#define TCIS 8 //Interrupt Status -#define TCTE 7 //Timer Enable -#define TCAR 6 //AutoReload (restart timer when condition is reached) -#define TCPD 2 //Prescale Divider (2bit) 0:1(12.5ns/tick), 1:16(0.2us/tick), 2/3:256(3.2us/tick) -#define TCIT 0 //Interrupt Type 0:edge, 1:level - -//RTC Registers -#define RTCSV ESP8266_REG(0x704) //RTC SLEEP COUNTER Target Value -#define RTCCV ESP8266_REG(0x71C) //RTC SLEEP COUNTER Value -#define RTCIS ESP8266_REG(0x720) //RTC INT Status -#define RTCIC ESP8266_REG(0x724) //RTC INT Clear -#define RTCIE ESP8266_REG(0x728) //RTC INT Enable - -#define RTC_USER_MEM ((volatile uint32_t*)0x60001200) - -//IO SWAP Register -#define IOSWAP ESP8266_DREG(0x28) -#define IOSWAPU 0 //Swaps UART -#define IOSWAPS 1 //Swaps SPI -#define IOSWAPU0 2 //Swaps UART 0 pins (u0rxd <-> u0cts), (u0txd <-> u0rts) -#define IOSWAPU1 3 //Swaps UART 1 pins (u1rxd <-> u1cts), (u1txd <-> u1rts) -#define IOSWAPHS 5 //Sets HSPI with higher prio -#define IOSWAP2HS 6 //Sets Two SPI Masters on HSPI -#define IOSWAP2CS 7 //Sets Two SPI Masters on CSPI - -//UART INT Status -#define UIS ESP8266_DREG(0x20020) -#define UIS0 0 -#define UIS1 2 - -//UART 0 Registers -#define U0F ESP8266_REG(0x000) //UART FIFO -#define U0IR ESP8266_REG(0x004) //INT_RAW -#define U0IS ESP8266_REG(0x008) //INT_STATUS -#define U0IE ESP8266_REG(0x00c) //INT_ENABLE -#define U0IC ESP8266_REG(0x010) //INT_CLEAR -#define U0D ESP8266_REG(0x014) //CLKDIV -#define U0A ESP8266_REG(0x018) //AUTOBAUD -#define U0S ESP8266_REG(0x01C) //STATUS -#define U0C0 ESP8266_REG(0x020) //CONF0 -#define U0C1 ESP8266_REG(0x024) //CONF1 -#define U0LP ESP8266_REG(0x028) //LOW_PULSE -#define U0HP ESP8266_REG(0x02C) //HIGH_PULSE -#define U0PN ESP8266_REG(0x030) //PULSE_NUM -#define U0DT ESP8266_REG(0x078) //DATE -#define U0ID ESP8266_REG(0x07C) //ID - -//UART 1 Registers -#define U1F ESP8266_REG(0xF00) //UART FIFO -#define U1IR ESP8266_REG(0xF04) //INT_RAW -#define U1IS ESP8266_REG(0xF08) //INT_STATUS -#define U1IE ESP8266_REG(0xF0c) //INT_ENABLE -#define U1IC ESP8266_REG(0xF10) //INT_CLEAR -#define U1D ESP8266_REG(0xF14) //CLKDIV -#define U1A ESP8266_REG(0xF18) //AUTOBAUD -#define U1S ESP8266_REG(0xF1C) //STATUS -#define U1C0 ESP8266_REG(0xF20) //CONF0 -#define U1C1 ESP8266_REG(0xF24) //CONF1 -#define U1LP ESP8266_REG(0xF28) //LOW_PULSE -#define U1HP ESP8266_REG(0xF2C) //HIGH_PULSE -#define U1PN ESP8266_REG(0xF30) //PULSE_NUM -#define U1DT ESP8266_REG(0xF78) //DATE -#define U1ID ESP8266_REG(0xF7C) //ID - -//UART(uart) Registers -#define USF(u) ESP8266_REG(0x000 + (0xF00 * (u & 1))) //UART FIFO -#define USIR(u) ESP8266_REG(0x004 + (0xF00 * (u & 1))) //INT_RAW -#define USIS(u) ESP8266_REG(0x008 + (0xF00 * (u & 1))) //INT_STATUS -#define USIE(u) ESP8266_REG(0x00c + (0xF00 * (u & 1))) //INT_ENABLE -#define USIC(u) ESP8266_REG(0x010 + (0xF00 * (u & 1))) //INT_CLEAR -#define USD(u) ESP8266_REG(0x014 + (0xF00 * (u & 1))) //CLKDIV -#define USA(u) ESP8266_REG(0x018 + (0xF00 * (u & 1))) //AUTOBAUD -#define USS(u) ESP8266_REG(0x01C + (0xF00 * (u & 1))) //STATUS -#define USC0(u) ESP8266_REG(0x020 + (0xF00 * (u & 1))) //CONF0 -#define USC1(u) ESP8266_REG(0x024 + (0xF00 * (u & 1))) //CONF1 -#define USLP(u) ESP8266_REG(0x028 + (0xF00 * (u & 1))) //LOW_PULSE -#define USHP(u) ESP8266_REG(0x02C + (0xF00 * (u & 1))) //HIGH_PULSE -#define USPN(u) ESP8266_REG(0x030 + (0xF00 * (u & 1))) //PULSE_NUM -#define USDT(u) ESP8266_REG(0x078 + (0xF00 * (u & 1))) //DATE -#define USID(u) ESP8266_REG(0x07C + (0xF00 * (u & 1))) //ID - -//UART INT Registers Bits -#define UITO 8 //RX FIFO TimeOut -#define UIBD 7 //Break Detected -#define UICTS 6 //CTS Changed -#define UIDSR 5 //DSR Change -#define UIOF 4 //RX FIFO OverFlow -#define UIFR 3 //Frame Error -#define UIPE 2 //Parity Error -#define UIFE 1 //TX FIFO Empty -#define UIFF 0 //RX FIFO Full - -//UART STATUS Registers Bits -#define USTX 31 //TX PIN Level -#define USRTS 30 //RTS PIN Level -#define USDTR 39 //DTR PIN Level -#define USTXC 16 //TX FIFO COUNT (8bit) -#define USRXD 15 //RX PIN Level -#define USCTS 14 //CTS PIN Level -#define USDSR 13 //DSR PIN Level -#define USRXC 0 //RX FIFO COUNT (8bit) - -//UART CONF0 Registers Bits -#define UCDTRI 24 //Invert DTR -#define UCRTSI 23 //Invert RTS -#define UCTXI 22 //Invert TX -#define UCDSRI 21 //Invert DSR -#define UCCTSI 20 //Invert CTS -#define UCRXI 19 //Invert RX -#define UCTXRST 18 //Reset TX FIFO -#define UCRXRST 17 //Reset RX FIFO -#define UCTXHFE 15 //TX Hardware Flow Enable -#define UCLBE 14 //LoopBack Enable -#define UCBRK 8 //Send Break on the TX line -#define UCSWDTR 7 //Set this bit to assert DTR -#define UCSWRTS 6 //Set this bit to assert RTS -#define UCSBN 4 //StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit -#define UCBN 2 //DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit -#define UCPAE 1 //Parity Enable -#define UCPA 0 //Parity 0:even, 1:odd - -//UART CONF1 Registers Bits -#define UCTOE 31 //RX TimeOut Enable -#define UCTOT 24 //RX TimeOut Threshold (7bit) -#define UCRXHFE 23 //RX Hardware Flow Enable -#define UCRXHFT 16 //RX Hardware Flow Threshold (7bit) -#define UCFET 8 //TX FIFO Empty Threshold (7bit) -#define UCFFT 0 //RX FIFO Full Threshold (7bit) - -//SPI_READY -#define SPIRDY ESP8266_DREG(0x0C) -#define SPI_BUSY 9 //wait SPI idle - -//SPI0 Registers (SPI0 is used for the flash) -#define SPI0CMD ESP8266_REG(0x200) -#define SPI0A ESP8266_REG(0x204) -#define SPI0C ESP8266_REG(0x208) -#define SPI0C1 ESP8266_REG(0x20C) -#define SPI0RS ESP8266_REG(0x210) -#define SPI0C2 ESP8266_REG(0x214) -#define SPI0CLK ESP8266_REG(0x218) -#define SPI0U ESP8266_REG(0x21C) -#define SPI0U1 ESP8266_REG(0x220) -#define SPI0U2 ESP8266_REG(0x224) -#define SPI0WS ESP8266_REG(0x228) -#define SPI0P ESP8266_REG(0x22C) -#define SPI0S ESP8266_REG(0x230) -#define SPI0S1 ESP8266_REG(0x234) -#define SPI0S2 ESP8266_REG(0x238) -#define SPI0S3 ESP8266_REG(0x23C) -#define SPI0W0 ESP8266_REG(0x240) -#define SPI0W1 ESP8266_REG(0x244) -#define SPI0W2 ESP8266_REG(0x248) -#define SPI0W3 ESP8266_REG(0x24C) -#define SPI0W4 ESP8266_REG(0x250) -#define SPI0W5 ESP8266_REG(0x254) -#define SPI0W6 ESP8266_REG(0x258) -#define SPI0W7 ESP8266_REG(0x25C) -#define SPI0W8 ESP8266_REG(0x260) -#define SPI0W9 ESP8266_REG(0x264) -#define SPI0W10 ESP8266_REG(0x268) -#define SPI0W11 ESP8266_REG(0x26C) -#define SPI0W12 ESP8266_REG(0x270) -#define SPI0W13 ESP8266_REG(0x274) -#define SPI0W14 ESP8266_REG(0x278) -#define SPI0W15 ESP8266_REG(0x27C) -#define SPI0E3 ESP8266_REG(0x2FC) -#define SPI0W(p) ESP8266_REG(0x240 + ((p & 0xF) * 4)) - -//SPI1 Registers -#define SPI1CMD ESP8266_REG(0x100) -#define SPI1A ESP8266_REG(0x104) -#define SPI1C ESP8266_REG(0x108) -#define SPI1C1 ESP8266_REG(0x10C) -#define SPI1RS ESP8266_REG(0x110) -#define SPI1C2 ESP8266_REG(0x114) -#define SPI1CLK ESP8266_REG(0x118) -#define SPI1U ESP8266_REG(0x11C) -#define SPI1U1 ESP8266_REG(0x120) -#define SPI1U2 ESP8266_REG(0x124) -#define SPI1WS ESP8266_REG(0x128) -#define SPI1P ESP8266_REG(0x12C) -#define SPI1S ESP8266_REG(0x130) -#define SPI1S1 ESP8266_REG(0x134) -#define SPI1S2 ESP8266_REG(0x138) -#define SPI1S3 ESP8266_REG(0x13C) -#define SPI1W0 ESP8266_REG(0x140) -#define SPI1W1 ESP8266_REG(0x144) -#define SPI1W2 ESP8266_REG(0x148) -#define SPI1W3 ESP8266_REG(0x14C) -#define SPI1W4 ESP8266_REG(0x150) -#define SPI1W5 ESP8266_REG(0x154) -#define SPI1W6 ESP8266_REG(0x158) -#define SPI1W7 ESP8266_REG(0x15C) -#define SPI1W8 ESP8266_REG(0x160) -#define SPI1W9 ESP8266_REG(0x164) -#define SPI1W10 ESP8266_REG(0x168) -#define SPI1W11 ESP8266_REG(0x16C) -#define SPI1W12 ESP8266_REG(0x170) -#define SPI1W13 ESP8266_REG(0x174) -#define SPI1W14 ESP8266_REG(0x178) -#define SPI1W15 ESP8266_REG(0x17C) -#define SPI1E0 ESP8266_REG(0x1F0) -#define SPI1E1 ESP8266_REG(0x1F4) -#define SPI1E2 ESP8266_REG(0x1F8) -#define SPI1E3 ESP8266_REG(0x1FC) -#define SPI1W(p) ESP8266_REG(0x140 + ((p & 0xF) * 4)) - -//SPI0, SPI1 & I2S Interrupt Register -#define SPIIR ESP8266_DREG(0x20) -#define SPII0 4 //SPI0 Interrupt -#define SPII1 7 //SPI1 Interrupt -#define SPII2 9 //I2S Interrupt - -//SPI CMD -#define SPICMDREAD (1 << 31) //SPI_FLASH_READ -#define SPICMDWREN (1 << 30) //SPI_FLASH_WREN -#define SPICMDWRDI (1 << 29) //SPI_FLASH_WRDI -#define SPICMDRDID (1 << 28) //SPI_FLASH_RDID -#define SPICMDRDSR (1 << 27) //SPI_FLASH_RDSR -#define SPICMDWRSR (1 << 26) //SPI_FLASH_WRSR -#define SPICMDPP (1 << 25) //SPI_FLASH_PP -#define SPICMDSE (1 << 24) //SPI_FLASH_SE -#define SPICMDBE (1 << 23) //SPI_FLASH_BE -#define SPICMDCE (1 << 22) //SPI_FLASH_CE -#define SPICMDDP (1 << 21) //SPI_FLASH_DP -#define SPICMDRES (1 << 20) //SPI_FLASH_RES -#define SPICMDHPM (1 << 19) //SPI_FLASH_HPM -#define SPICMDUSR (1 << 18) //SPI_FLASH_USR -#define SPIBUSY (1 << 18) //SPI_USR - -//SPI CTRL (SPIxC) -#define SPICWBO (1 << 26) //SPI_WR_BIT_ODER -#define SPICRBO (1 << 25) //SPI_RD_BIT_ODER -#define SPICQIO (1 << 24) //SPI_QIO_MODE -#define SPICDIO (1 << 23) //SPI_DIO_MODE -#define SPIC2BSE (1 << 22) //SPI_TWO_BYTE_STATUS_EN -#define SPICWPR (1 << 21) //SPI_WP_REG -#define SPICQOUT (1 << 20) //SPI_QOUT_MODE -#define SPICSHARE (1 << 19) //SPI_SHARE_BUS -#define SPICHOLD (1 << 18) //SPI_HOLD_MODE -#define SPICAHB (1 << 17) //SPI_ENABLE_AHB -#define SPICSSTAAI (1 << 16) //SPI_SST_AAI -#define SPICRESANDRES (1 << 15) //SPI_RESANDRES -#define SPICDOUT (1 << 14) //SPI_DOUT_MODE -#define SPICFASTRD (1 << 13) //SPI_FASTRD_MODE - -//SPI CTRL1 (SPIxC1) -#define SPIC1TCSH 0xF //SPI_T_CSH -#define SPIC1TCSH_S 28 //SPI_T_CSH_S -#define SPIC1TRES 0xFFF //SPI_T_RES -#define SPIC1TRES_S 16 //SPI_T_RES_S -#define SPIC1BTL 0xFFFF //SPI_BUS_TIMER_LIMIT -#define SPIC1BTL_S 0 //SPI_BUS_TIMER_LIMIT_S - -//SPI Status (SPIxRS) -#define SPIRSEXT 0xFF //SPI_STATUS_EXT -#define SPIRSEXT_S 24 //SPI_STATUS_EXT_S -#define SPIRSWB 0xFF //SPI_WB_MODE -#define SPIRSWB_S 16 //SPI_WB_MODE_S -#define SPIRSSP (1 << 7) //SPI_FLASH_STATUS_PRO_FLAG -#define SPIRSTBP (1 << 5) //SPI_FLASH_TOP_BOT_PRO_FLAG -#define SPIRSBP2 (1 << 4) //SPI_FLASH_BP2 -#define SPIRSBP1 (1 << 3) //SPI_FLASH_BP1 -#define SPIRSBP0 (1 << 2) //SPI_FLASH_BP0 -#define SPIRSWRE (1 << 1) //SPI_FLASH_WRENABLE_FLAG -#define SPIRSBUSY (1 << 0) //SPI_FLASH_BUSY_FLAG - -//SPI CTRL2 (SPIxC2) -#define SPIC2CSDN 0xF //SPI_CS_DELAY_NUM -#define SPIC2CSDN_S 28 //SPI_CS_DELAY_NUM_S -#define SPIC2CSDM 0x3 //SPI_CS_DELAY_MODE -#define SPIC2CSDM_S 26 //SPI_CS_DELAY_MODE_S -#define SPIC2MOSIDN 0x7 //SPI_MOSI_DELAY_NUM -#define SPIC2MOSIDN_S 23 //SPI_MOSI_DELAY_NUM_S -#define SPIC2MOSIDM 0x3 //SPI_MOSI_DELAY_MODE -#define SPIC2MOSIDM_S 21 //SPI_MOSI_DELAY_MODE_S -#define SPIC2MISODN 0x7 //SPI_MISO_DELAY_NUM -#define SPIC2MISODN_S 18 //SPI_MISO_DELAY_NUM_S -#define SPIC2MISODM 0x3 //SPI_MISO_DELAY_MODE -#define SPIC2MISODM_S 16 //SPI_MISO_DELAY_MODE_S -#define SPIC2CKOHM 0xF //SPI_CK_OUT_HIGH_MODE -#define SPIC2CKOHM_S 12 //SPI_CK_OUT_HIGH_MODE_S -#define SPIC2CKOLM 0xF //SPI_CK_OUT_LOW_MODE -#define SPIC2CKOLM_S 8 //SPI_CK_OUT_LOW_MODE_S -#define SPIC2HT 0xF //SPI_HOLD_TIME -#define SPIC2HT_S 4 //SPI_HOLD_TIME_S -#define SPIC2ST 0xF //SPI_SETUP_TIME -#define SPIC2ST_S 0 //SPI_SETUP_TIME_S - -//SPI CLK (SPIxCLK) -#define SPICLK_EQU_SYSCLK (1 << 31) //SPI_CLK_EQU_SYSCLK -#define SPICLKDIVPRE 0x1FFF //SPI_CLKDIV_PRE -#define SPICLKDIVPRE_S 18 //SPI_CLKDIV_PRE_S -#define SPICLKCN 0x3F //SPI_CLKCNT_N -#define SPICLKCN_S 12 //SPI_CLKCNT_N_S -#define SPICLKCH 0x3F //SPI_CLKCNT_H -#define SPICLKCH_S 6 //SPI_CLKCNT_H_S -#define SPICLKCL 0x3F //SPI_CLKCNT_L -#define SPICLKCL_S 0 //SPI_CLKCNT_L_S - -//SPI Phases (SPIxU) -#define SPIUCOMMAND (1 << 31) //COMMAND pahse, SPI_USR_COMMAND -#define SPIUADDR (1 << 30) //ADDRESS phase, SPI_FLASH_USR_ADDR -#define SPIUDUMMY (1 << 29) //DUMMY phase, SPI_FLASH_USR_DUMMY -#define SPIUMISO (1 << 28) //MISO phase, SPI_FLASH_USR_DIN -#define SPIUMOSI (1 << 27) //MOSI phase, SPI_FLASH_DOUT -#define SPIUDUMMYIDLE (1 << 26) //SPI_USR_DUMMY_IDLE -#define SPIUMOSIH (1 << 25) //MOSI phase uses W8-W15, SPI_USR_DOUT_HIGHPART -#define SPIUMISOH (1 << 24) //MISO pahse uses W8-W15, SPI_USR_DIN_HIGHPART -#define SPIUPREPHOLD (1 << 23) //SPI_USR_PREP_HOLD -#define SPIUCMDHOLD (1 << 22) //SPI_USR_CMD_HOLD -#define SPIUADDRHOLD (1 << 21) //SPI_USR_ADDR_HOLD -#define SPIUDUMMYHOLD (1 << 20) //SPI_USR_DUMMY_HOLD -#define SPIUMISOHOLD (1 << 19) //SPI_USR_DIN_HOLD -#define SPIUMOSIHOLD (1 << 18) //SPI_USR_DOUT_HOLD -#define SPIUHOLDPOL (1 << 17) //SPI_USR_HOLD_POL -#define SPIUSIO (1 << 16) //SPI_SIO -#define SPIUFWQIO (1 << 15) //SPI_FWRITE_QIO -#define SPIUFWDIO (1 << 14) //SPI_FWRITE_DIO -#define SPIUFWQUAD (1 << 13) //SPI_FWRITE_QUAD -#define SPIUFWDUAL (1 << 12) //SPI_FWRITE_DUAL -#define SPIUWRBYO (1 << 11) //SPI_WR_BYTE_ORDER -#define SPIURDBYO (1 << 10) //SPI_RD_BYTE_ORDER -#define SPIUAHBEM 0x3 //SPI_AHB_ENDIAN_MODE -#define SPIUAHBEM_S 8 //SPI_AHB_ENDIAN_MODE_S -#define SPIUSME (1 << 7) //SPI Master Edge (0:falling, 1:rising), SPI_CK_OUT_EDGE -#define SPIUSSE (1 << 6) //SPI Slave Edge (0:falling, 1:rising), SPI_CK_I_EDGE -#define SPIUCSSETUP (1 << 5) //SPI_CS_SETUP -#define SPIUCSHOLD (1 << 4) //SPI_CS_HOLD -#define SPIUAHBUCMD (1 << 3) //SPI_AHB_USR_COMMAND -#define SPIUAHBUCMD4B (1 << 1) //SPI_AHB_USR_COMMAND_4BYTE -#define SPIUDUPLEX (1 << 0) //SPI_DOUTDIN - -//SPI Phase Length Locations -#define SPILCOMMAND 28 //4 bit in SPIxU2 default 7 (8bit) -#define SPILADDR 26 //6 bit in SPIxU1 default:23 (24bit) -#define SPILDUMMY 0 //8 bit in SPIxU1 default:0 (0 cycles) -#define SPILMISO 8 //9 bit in SPIxU1 default:0 (1bit) -#define SPILMOSI 17 //9 bit in SPIxU1 default:0 (1bit) -//SPI Phase Length Masks -#define SPIMCOMMAND 0xF -#define SPIMADDR 0x3F -#define SPIMDUMMY 0xFF -#define SPIMMISO 0x1FF -#define SPIMMOSI 0x1FF - -//SPI Slave (SPIxS) -#define SPISSRES (1 << 31) //SYNC RESET, SPI_SYNC_RESET -#define SPISE (1 << 30) //Slave Enable, SPI_SLAVE_MODE -#define SPISBE (1 << 29) //WR/RD BUF enable, SPI_SLV_WR_RD_BUF_EN -#define SPISSE (1 << 28) //STA enable, SPI_SLV_WR_RD_STA_EN -#define SPISCD (1 << 27) //CMD define, SPI_SLV_CMD_DEFINE -#define SPISTRCNT 0xF //SPI_TRANS_CNT -#define SPISTRCNT_S 23 //SPI_TRANS_CNT_S -#define SPISSLS 0x7 //SPI_SLV_LAST_STATE -#define SPISSLS_S 20 //SPI_SLV_LAST_STATE_S -#define SPISSLC 0x7 //SPI_SLV_LAST_COMMAND -#define SPISSLC_S 17 //SPI_SLV_LAST_COMMAND_S -#define SPISCSIM 0x3 //SPI_CS_I_MODE -#define SPIDCSIM_S 10 //SPI_CS_I_MODE_S -#define SPISTRIE (1 << 9) //TRANS interrupt enable -#define SPISWSIE (1 << 8) //WR_STA interrupt enable -#define SPISRSIE (1 << 7) //RD_STA interrupt enable -#define SPISWBIE (1 << 6) //WR_BUF interrupt enable -#define SPISRBIE (1 << 5) //RD_BUF interrupt enable -#define SPISTRIS (1 << 4) //TRANS interrupt status -#define SPISWSIS (1 << 3) //WR_STA interrupt status -#define SPISRSIS (1 << 2) //RD_STA interrupt status -#define SPISWBIS (1 << 1) //WR_BUF interrupt status -#define SPISRBIS (1 << 0) //RD_BUF interrupt status - -//SPI Slave1 (SPIxS1) -#define SPIS1LSTA 27 //5 bit in SPIxS1 default:0 (1bit), SPI_SLV_STATUS_BITLEN -#define SPIS1FE (1 << 26) //SPI_SLV_STATUS_FAST_EN -#define SPIS1RSTA (1 << 25) //default:0 enable STA read from Master, SPI_SLV_STATUS_READBACK -#define SPIS1LBUF 16 //9 bit in SPIxS1 default:0 (1bit), SPI_SLV_BUF_BITLEN -#define SPIS1LRBA 10 //6 bit in SPIxS1 default:0 (1bit), SPI_SLV_RD_ADDR_BITLEN -#define SPIS1LWBA 4 //6 bit in SPIxS1 default:0 (1bit), SPI_SLV_WR_ADDR_BITLEN -#define SPIS1WSDE (1 << 3) //SPI_SLV_WRSTA_DUMMY_EN -#define SPIS1RSDE (1 << 2) //SPI_SLV_RDSTA_DUMMY_EN -#define SPIS1WBDE (1 << 1) //SPI_SLV_WRBUF_DUMMY_EN -#define SPIS1RBDE (1 << 0) //SPI_SLV_RDBUF_DUMMY_EN - -//SPI Slave2 (SPIxS2) -#define SPIS2WBDL 0xFF //SPI_SLV_WRBUF_DUMMY_CYCLELEN -#define SPIS2WBDL_S 24 //SPI_SLV_WRBUF_DUMMY_CYCLELEN_S -#define SPIS2RBDL 0xFF //SPI_SLV_RDBUF_DUMMY_CYCLELEN -#define SPIS2RBDL_S 16 //SPI_SLV_RDBUF_DUMMY_CYCLELEN_S -#define SPIS2WSDL 0xFF //SPI_SLV_WRSTA_DUMMY_CYCLELEN -#define SPIS2WSDL_S 8 //SPI_SLV_WRSTA_DUMMY_CYCLELEN_S -#define SPIS2RSDL 0xFF //SPI_SLV_RDSTA_DUMMY_CYCLELEN -#define SPIS2RSDL_S 0 //SPI_SLV_RDSTA_DUMMY_CYCLELEN_S - -//SPI Slave3 (SPIxS3) -#define SPIS3WSCV 0xFF //SPI_SLV_WRSTA_CMD_VALUE -#define SPIS3WSCV_S 24 //SPI_SLV_WRSTA_CMD_VALUE_S -#define SPIS3RSCV 0xFF //SPI_SLV_RDSTA_CMD_VALUE -#define SPIS3RSCV_S 16 //SPI_SLV_RDSTA_CMD_VALUE_S -#define SPIS3WBCV 0xFF //SPI_SLV_WRBUF_CMD_VALUE -#define SPIS3WBCV_S 8 //SPI_SLV_WRBUF_CMD_VALUE_S -#define SPIS3RBCV 0xFF //SPI_SLV_RDBUF_CMD_VALUE -#define SPIS3RBCV_S 0 //SPI_SLV_RDBUF_CMD_VALUE_S - -//SPI EXT0 (SPIxE0) -#define SPIE0TPPEN (1 << 31) //SPI_T_PP_ENA -#define SPIE0TPPS 0xF //SPI_T_PP_SHIFT -#define SPIE0TPPS_S 16 //SPI_T_PP_SHIFT_S -#define SPIE0TPPT 0xFFF //SPI_T_PP_TIME -#define SPIE0TPPT_S 0 //SPI_T_PP_TIME_S - -//SPI EXT1 (SPIxE1) -#define SPIE1TEREN (1 << 31) //SPI_T_ERASE_ENA -#define SPIE1TERS 0xF //SPI_T_ERASE_SHIFT -#define SPIE1TERS_S 16 //SPI_T_ERASE_SHIFT_S -#define SPIE1TERT 0xFFF //SPI_T_ERASE_TIME -#define SPIE1TERT_S 0 //SPI_T_ERASE_TIME_S - -//SPI EXT2 (SPIxE2) -#define SPIE2ST 0x7 //SPI_ST -#define SPIE2ST_S 0 //SPI_ST_S - -//SPI EXT3 (SPIxE3) -#define SPIE2IHEN 0x3 //SPI_INT_HOLD_ENA -#define SPIE2IHEN_S 0 //SPI_INT_HOLD_ENA_S - -//SLC (DMA) Registers -#define SLCC0 ESP8266_REG(0xB00) //SLC_CONF0 -#define SLCIR ESP8266_REG(0xB04) //SLC_INT_RAW -#define SLCIS ESP8266_REG(0xB08) //SLC_INT_STATUS -#define SLCIE ESP8266_REG(0xB0C) //SLC_INT_ENA -#define SLCIC ESP8266_REG(0xB10) //SLC_INT_CLR -#define SLCRXS ESP8266_REG(0xB14) //SLC_RX_STATUS -#define SLCRXP ESP8266_REG(0xB18) //SLC_RX_FIFO_PUSH -#define SLCTXS ESP8266_REG(0xB1C) //SLC_TX_STATUS -#define SLCTXP ESP8266_REG(0xB20) //SLC_TX_FIFO_POP -#define SLCRXL ESP8266_REG(0xB24) //SLC_RX_LINK -#define SLCTXL ESP8266_REG(0xB28) //SLC_TX_LINK -#define SLCIVTH ESP8266_REG(0xB2C) //SLC_INTVEC_TOHOST -#define SLCT0 ESP8266_REG(0xB30) //SLC_TOKEN0 -#define SLCT1 ESP8266_REG(0xB34) //SLC_TOKEN1 -#define SLCC1 ESP8266_REG(0xB38) //SLC_CONF1 -#define SLCS0 ESP8266_REG(0xB3C) //SLC_STATE0 -#define SLCS1 ESP8266_REG(0xB40) //SLC_STATE1 -#define SLCBC ESP8266_REG(0xB44) //SLC_BRIDGE_CONF -#define SLCRXEDA ESP8266_REG(0xB48) //SLC_RX_EOF_DES_ADDR -#define SLCTXEDA ESP8266_REG(0xB4C) //SLC_TX_EOF_DES_ADDR -#define SLCRXEBDA ESP8266_REG(0xB50) //SLC_RX_EOF_BFR_DES_ADDR -#define SLCAT ESP8266_REG(0xB54) //SLC_AHB_TEST -#define SLCSS ESP8266_REG(0xB58) //SLC_SDIO_ST -#define SLCRXDC ESP8266_REG(0xB5C) //SLC_RX_DSCR_CONF -#define SLCTXD ESP8266_REG(0xB60) //SLC_TXLINK_DSCR -#define SLCTXDB0 ESP8266_REG(0xB64) //SLC_TXLINK_DSCR_BF0 -#define SLCTXDB1 ESP8266_REG(0xB68) //SLC_TXLINK_DSCR_BF1 -#define SLCRXD ESP8266_REG(0xB6C) //SLC_RXLINK_DSCR -#define SLCRXDB0 ESP8266_REG(0xB70) //SLC_RXLINK_DSCR_BF0 -#define SLCRXDB1 ESP8266_REG(0xB74) //SLC_RXLINK_DSCR_BF1 -#define SLCDT ESP8266_REG(0xB78) //SLC_DATE -#define SLCID ESP8266_REG(0xB7C) //SLC_ID -#define SLCHIR ESP8266_REG(0xB88) //SLC_HOST_INTR_RAW -#define SLCHC0 ESP8266_REG(0xB94) //SLC_HOST_CONF_W0 -#define SLCHC1 ESP8266_REG(0xB98) //SLC_HOST_CONF_W1 -#define SLCHIS ESP8266_REG(0xB9C) //SLC_HOST_INTR_ST -#define SLCHC2 ESP8266_REG(0xBA0) //SLC_HOST_CONF_W2 -#define SLCHC3 ESP8266_REG(0xBA4) //SLC_HOST_CONF_W3 -#define SLCHC4 ESP8266_REG(0xBA8) //SLC_HOST_CONF_W4 -#define SLCHIC ESP8266_REG(0xBB0) //SLC_HOST_INTR_CLR -#define SLCHIE ESP8266_REG(0xBB4) //SLC_HOST_INTR_ENA -#define SLCHC5 ESP8266_REG(0xBBC) //SLC_HOST_CONF_W5 - -//SLC (DMA) CONF0 -#define SLCMM (0x3) //SLC_MODE -#define SLCM (12) //SLC_MODE_S -#define SLCDTBE (1 << 9) //SLC_DATA_BURST_EN -#define SLCDBE (1 << 8) //SLC_DSCR_BURST_EN -#define SLCRXNRC (1 << 7) //SLC_RX_NO_RESTART_CLR -#define SLCRXAW (1 << 6) //SLC_RX_AUTO_WRBACK -#define SLCRXLT (1 << 5) //SLC_RX_LOOP_TEST -#define SLCTXLT (1 << 4) //SLC_TX_LOOP_TEST -#define SLCAR (1 << 3) //SLC_AHBM_RST -#define SLCAFR (1 << 2) //SLC_AHBM_FIFO_RST -#define SLCRXLR (1 << 1) //SLC_RXLINK_RST -#define SLCTXLR (1 << 0) //SLC_TXLINK_RST - -//SLC (DMA) INT -#define SLCITXDE (1 << 21) //SLC_TX_DSCR_EMPTY_INT -#define SLCIRXDER (1 << 20) //SLC_RX_DSCR_ERR_INT -#define SLCITXDER (1 << 19) //SLC_TX_DSCR_ERR_INT -#define SLCITH (1 << 18) //SLC_TOHOST_INT -#define SLCIRXEOF (1 << 17) //SLC_RX_EOF_INT -#define SLCIRXD (1 << 16) //SLC_RX_DONE_INT -#define SLCITXEOF (1 << 15) //SLC_TX_EOF_INT -#define SLCITXD (1 << 14) //SLC_TX_DONE_INT -#define SLCIT0 (1 << 13) //SLC_TOKEN1_1TO0_INT -#define SLCIT1 (1 << 12) //SLC_TOKEN0_1TO0_INT -#define SLCITXO (1 << 11) //SLC_TX_OVF_INT -#define SLCIRXU (1 << 10) //SLC_RX_UDF_INT -#define SLCITXS (1 << 9) //SLC_TX_START_INT -#define SLCIRXS (1 << 8) //SLC_RX_START_INT -#define SLCIFH7 (1 << 7) //SLC_FRHOST_BIT7_INT -#define SLCIFH6 (1 << 6) //SLC_FRHOST_BIT6_INT -#define SLCIFH5 (1 << 5) //SLC_FRHOST_BIT5_INT -#define SLCIFH4 (1 << 4) //SLC_FRHOST_BIT4_INT -#define SLCIFH3 (1 << 3) //SLC_FRHOST_BIT3_INT -#define SLCIFH2 (1 << 2) //SLC_FRHOST_BIT2_INT -#define SLCIFH1 (1 << 1) //SLC_FRHOST_BIT1_INT -#define SLCIFH0 (1 << 0) //SLC_FRHOST_BIT0_INT - -//SLC (DMA) RX_STATUS -#define SLCRXE (1 << 1) //SLC_RX_EMPTY -#define SLCRXF (1 << 0) //SLC_RX_FULL - -//SLC (DMA) TX_STATUS -#define SLCTXE (1 << 1) //SLC_TX_EMPTY -#define SLCTXF (1 << 0) //SLC_TX_FULL - -//SLC (DMA) RX_FIFO_PUSH -#define SLCRXFP (1 << 16) //SLC_RXFIFO_PUSH -#define SLCRXWDM (0x1FF) //SLC_RXFIFO_WDATA -#define SLCRXWD (0) //SLC_RXFIFO_WDATA_S - -//SLC (DMA) TX_FIFO_POP -#define SLCTXFP (1 << 16) //SLC_TXFIFO_POP -#define SLCTXRDM (0x7FF) //SLC_TXFIFO_RDATA -#define SLCTXRD (0) //SLC_TXFIFO_RDATA_S - -//SLC (DMA) RX_LINK -#define SLCRXLP (1 << 31) //SLC_RXLINK_PARK -#define SLCRXLRS (1 << 30) //SLC_RXLINK_RESTART -#define SLCRXLS (1 << 29) //SLC_RXLINK_START -#define SLCRXLE (1 << 28) //SLC_RXLINK_STOP -#define SLCRXLAM (0xFFFF) //SLC_RXLINK_DESCADDR_MASK -#define SLCRXLA (0) //SLC_RXLINK_ADDR_S - -//SLC (DMA) TX_LINK -#define SLCTXLP (1 << 31) //SLC_TXLINK_PARK -#define SLCTXLRS (1 << 30) //SLC_TXLINK_RESTART -#define SLCTXLS (1 << 29) //SLC_TXLINK_START -#define SLCTXLE (1 << 28) //SLC_TXLINK_STOP -#define SLCTXLAM (0xFFFF) //SLC_TXLINK_DESCADDR_MASK -#define SLCTXLA (0) //SLC_TXLINK_ADDR_S - -//SLC (DMA) TOKENx -#define SLCTM (0xFFF) //SLC_TOKENx_MASK -#define SLCTT (16) //SLC_TOKENx_S -#define SLCTIM (1 << 14) //SLC_TOKENx_LOCAL_INC_MORE -#define SLCTI (1 << 13) //SLC_TOKENx_LOCAL_INC -#define SLCTW (1 << 12) //SLC_TOKENx_LOCAL_WR -#define SLCTDM (0xFFF) //SLC_TOKENx_LOCAL_WDATA -#define SLCTD (0) //SLC_TOKENx_LOCAL_WDATA_S - -//SLC (DMA) BRIDGE_CONF -#define SLCBFMEM (0xF) //SLC_FIFO_MAP_ENA -#define SLCBFME (8) //SLC_FIFO_MAP_ENA_S -#define SLCBTEEM (0x3F) //SLC_TXEOF_ENA -#define SLCBTEE (0) //SLC_TXEOF_ENA_S - -//SLC (DMA) AHB_TEST -#define SLCATAM (0x3) //SLC_AHB_TESTADDR -#define SLCATA (4) //SLC_AHB_TESTADDR_S -#define SLCATMM (0x7) //SLC_AHB_TESTMODE -#define SLCATM (0) //SLC_AHB_TESTMODE_S - -//SLC (DMA) SDIO_ST -#define SLCSBM (0x7) //SLC_BUS_ST -#define SLCSB (12) //SLC_BUS_ST_S -#define SLCSW (1 << 8) //SLC_SDIO_WAKEUP -#define SLCSFM (0xF) //SLC_FUNC_ST -#define SLCSF (4) //SLC_FUNC_ST_S -#define SLCSCM (0x7) //SLC_CMD_ST -#define SLCSC (0) //SLC_CMD_ST_S - -//SLC (DMA) RX_DSCR_CONF -#define SLCBRXFE (1 << 20) //SLC_RX_FILL_EN -#define SLCBRXEM (1 << 19) //SLC_RX_EOF_MODE -#define SLCBRXFM (1 << 18) //SLC_RX_FILL_MODE -#define SLCBINR (1 << 17) //SLC_INFOR_NO_REPLACE -#define SLCBTNR (1 << 16) //SLC_TOKEN_NO_REPLACE -#define SLCBPICM (0xFFFF) //SLC_POP_IDLE_CNT -#define SLCBPIC (0) //SLC_POP_IDLE_CNT_S - -// I2S Registers -#define i2c_bbpll 0x67 -#define i2c_bbpll_hostid 4 -#define i2c_bbpll_en_audio_clock_out 4 -#define i2c_bbpll_en_audio_clock_out_msb 7 -#define i2c_bbpll_en_audio_clock_out_lsb 7 -#define I2S_CLK_ENABLE() i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1) -#define I2SBASEFREQ (160000000L) - -#define I2STXF ESP8266_REG(0xe00) //I2STXFIFO (32bit) -#define I2SRXF ESP8266_REG(0xe04) //I2SRXFIFO (32bit) -#define I2SC ESP8266_REG(0xe08) //I2SCONF -#define I2SIR ESP8266_REG(0xe0C) //I2SINT_RAW -#define I2SIS ESP8266_REG(0xe10) //I2SINT_ST -#define I2SIE ESP8266_REG(0xe14) //I2SINT_ENA -#define I2SIC ESP8266_REG(0xe18) //I2SINT_CLR -#define I2ST ESP8266_REG(0xe1C) //I2STIMING -#define I2SFC ESP8266_REG(0xe20) //I2S_FIFO_CONF -#define I2SRXEN ESP8266_REG(0xe24) //I2SRXEOF_NUM (32bit) -#define I2SCSD ESP8266_REG(0xe28) //I2SCONF_SIGLE_DATA (32bit) -#define I2SCC ESP8266_REG(0xe2C) //I2SCONF_CHAN - -// I2S CONF -#define I2SBDM (0x3F) //I2S_BCK_DIV_NUM -#define I2SBD (22) //I2S_BCK_DIV_NUM_S -#define I2SCDM (0x3F) //I2S_CLKM_DIV_NUM -#define I2SCD (16) //I2S_CLKM_DIV_NUM_S -#define I2SBMM (0xF) //I2S_BITS_MOD -#define I2SBM (12) //I2S_BITS_MOD_S -#define I2SRMS (1 << 11) //I2S_RECE_MSB_SHIFT -#define I2STMS (1 << 10) //I2S_TRANS_MSB_SHIFT -#define I2SRXS (1 << 9) //I2S_I2S_RX_START -#define I2STXS (1 << 8) //I2S_I2S_TX_START -#define I2SMR (1 << 7) //I2S_MSB_RIGHT -#define I2SRF (1 << 6) //I2S_RIGHT_FIRST -#define I2SRSM (1 << 5) //I2S_RECE_SLAVE_MOD -#define I2STSM (1 << 4) //I2S_TRANS_SLAVE_MOD -#define I2SRXFR (1 << 3) //I2S_I2S_RX_FIFO_RESET -#define I2STXFR (1 << 2) //I2S_I2S_TX_FIFO_RESET -#define I2SRXR (1 << 1) //I2S_I2S_RX_RESET -#define I2STXR (1 << 0) //I2S_I2S_TX_RESET -#define I2SRST (0xF) //I2S_I2S_RESET_MASK - -//I2S INT -#define I2SITXRE (1 << 5) //I2S_I2S_TX_REMPTY_INT -#define I2SITXWF (1 << 4) //I2S_I2S_TX_WFULL_INT -#define I2SIRXRE (1 << 3) //I2S_I2S_RX_REMPTY_INT -#define I2SIRXWF (1 << 2) //I2S_I2S_RX_WFULL_INT -#define I2SITXPD (1 << 1) //I2S_I2S_TX_PUT_DATA_INT -#define I2SIRXTD (1 << 0) //I2S_I2S_RX_TAKE_DATA_INT - -//I2S TIMING -#define I2STBII (1 << 22) //I2S_TRANS_BCK_IN_INV -#define I2SRDS (1 << 21) //I2S_RECE_DSYNC_SW -#define I2STDS (1 << 20) //I2S_TRANS_DSYNC_SW -#define I2SRBODM (0x3) //I2S_RECE_BCK_OUT_DELAY -#define I2SRBOD (18) //I2S_RECE_BCK_OUT_DELAY_S -#define I2SRWODM (0x3) //I2S_RECE_WS_OUT_DELAY -#define I2SRWOD (16) //I2S_RECE_WS_OUT_DELAY_S -#define I2STSODM (0x3) //I2S_TRANS_SD_OUT_DELAY -#define I2STSOD (14) //I2S_TRANS_SD_OUT_DELAY_S -#define I2STWODM (0x3) //I2S_TRANS_WS_OUT_DELAY -#define I2STWOD (12) //I2S_TRANS_WS_OUT_DELAY_S -#define I2STBODM (0x3) //I2S_TRANS_BCK_OUT_DELAY -#define I2STBOD (10) //I2S_TRANS_BCK_OUT_DELAY_S -#define I2SRSIDM (0x3) //I2S_RECE_SD_IN_DELAY -#define I2SRSID (8) //I2S_RECE_SD_IN_DELAY_S -#define I2SRWIDM (0x3) //I2S_RECE_WS_IN_DELAY -#define I2SRWID (6) //I2S_RECE_WS_IN_DELAY_S -#define I2SRBIDM (0x3) //I2S_RECE_BCK_IN_DELAY -#define I2SRBID (4) //I2S_RECE_BCK_IN_DELAY_S -#define I2STWIDM (0x3) //I2S_TRANS_WS_IN_DELAY -#define I2STWID (2) //I2S_TRANS_WS_IN_DELAY_S -#define I2STBIDM (0x3) //I2S_TRANS_BCK_IN_DELAY -#define I2STBID (0) //I2S_TRANS_BCK_IN_DELAY_S - -//I2S FIFO CONF -#define I2SRXFMM (0x7) //I2S_I2S_RX_FIFO_MOD -#define I2SRXFM (16) //I2S_I2S_RX_FIFO_MOD_S -#define I2STXFMM (0x7) //I2S_I2S_TX_FIFO_MOD -#define I2STXFM (13) //I2S_I2S_TX_FIFO_MOD_S -#define I2SDE (1 << 12) //I2S_I2S_DSCR_EN -#define I2STXDNM (0x3F) //I2S_I2S_TX_DATA_NUM -#define I2STXDN (6) //I2S_I2S_TX_DATA_NUM_S -#define I2SRXDNM (0x3F) //I2S_I2S_RX_DATA_NUM -#define I2SRXDN (0) //I2S_I2S_RX_DATA_NUM_S - -//I2S CONF CHAN -#define I2SRXCMM (0x3) //I2S_RX_CHAN_MOD -#define I2SRXCM (3) //I2S_RX_CHAN_MOD_S -#define I2STXCMM (0x7) //I2S_TX_CHAN_MOD -#define I2STXCM (0) //I2S_TX_CHAN_MOD_S - -/** - Random Number Generator 32bit - http://esp8266-re.foogod.com/wiki/Random_Number_Generator -**/ -#define RANDOM_REG32 ESP8266_DREG(0x20E44) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Sming/Arch/Esp32/Core/pins_arduino.h b/Sming/Arch/Esp32/Core/pins_arduino.h index 04af3f5be1..e459d5bd5a 100644 --- a/Sming/Arch/Esp32/Core/pins_arduino.h +++ b/Sming/Arch/Esp32/Core/pins_arduino.h @@ -12,8 +12,6 @@ #pragma once -#include "peripheral.h" - #define EXTERNAL_NUM_INTERRUPTS 16 #define NUM_DIGITAL_PINS 40 #define NUM_ANALOG_INPUTS 16 diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index da97dc290f..4c4e21242e 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -116,13 +116,12 @@ See :component-esp32:`esp32` for further details. IDF versions ------------ -Sming currently supports IDF versions 4.3, 4.4, 5.0 and 5.2. -The recommended version is 5.2. -This is installed by default. +Sming currently supports IDF versions 5.2. This is installed by default. +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 (2); @@ -38,13 +38,16 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { + if(!out) { + return false; + } #if CONFIG_FREERTOS_USE_TRACE_FACILITY && CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS // Get current task states auto& info = taskInfo[endIndex]; info.count = uxTaskGetSystemState(info.status, maxTasks, &info.runTime); if(info.count == 0) { - out.println(_F("[TaskStat] uxTaskGetSystemState returned 0")); + out->println(_F("[TaskStat] uxTaskGetSystemState returned 0")); return false; } @@ -79,7 +82,7 @@ bool TaskStat::update() // Calculate totalElapsedTime in units of run time stats clock period. uint32_t totalElapsedTime = endInfo.runTime - startInfo.runTime; if(totalElapsedTime == 0) { - out.println(_F("[TaskStat] Run time was 0: Have you set CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS?")); + out->println(_F("[TaskStat] Run time was 0: Have you set CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS?")); return false; } @@ -87,8 +90,8 @@ bool TaskStat::update() PSTR_ARRAY(hdrfmt, "# | Core | Prio | Handle | Run Time | % Time | Name"); PSTR_ARRAY(datfmt, "%-3u | %c | %4u | %08x | %8u | %3u%% | %s\r\n"); - out.println(); - out.println(hdrfmt); + out->println(); + out->println(hdrfmt); // Match each task in startInfo.status to those in the endInfo.status for(unsigned i = 0; i < startInfo.count; i++) { int k = -1; @@ -108,27 +111,27 @@ bool TaskStat::update() #if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID coreId = status.xCoreID; #endif - out.printf(datfmt, status.xTaskNumber, (coreId == CONFIG_FREERTOS_NO_AFFINITY) ? '-' : ('0' + coreId), - status.uxCurrentPriority, status.xHandle, taskElapsedTime, percentageTime, status.pcTaskName); + out->printf(datfmt, status.xTaskNumber, (coreId == CONFIG_FREERTOS_NO_AFFINITY) ? '-' : ('0' + coreId), + status.uxCurrentPriority, status.xHandle, taskElapsedTime, percentageTime, status.pcTaskName); } } // Print unmatched tasks for(unsigned i = 0; i < startInfo.count; i++) { if(!startMatched[i]) { - out.printf("Deleted: %s\r\n", startInfo.status[i].pcTaskName); + out->printf("Deleted: %s\r\n", startInfo.status[i].pcTaskName); } } for(unsigned i = 0; i < endInfo.count; i++) { if(!endMatched[i]) { - out.printf("Created: %s\r\n", endInfo.status[i].pcTaskName); + out->printf("Created: %s\r\n", endInfo.status[i].pcTaskName); } } return true; #else - out.println("[TaskStat] Tracing disabled"); + out->println("[TaskStat] Tracing disabled"); return false; #endif } diff --git a/Sming/Arch/Esp32/Tools/install.sh b/Sming/Arch/Esp32/Tools/install.sh index 0a872db39d..3ead67befc 100755 --- a/Sming/Arch/Esp32/Tools/install.sh +++ b/Sming/Arch/Esp32/Tools/install.sh @@ -31,6 +31,12 @@ case $DIST in darwin) ;; + *) + check_for_installed_tools dfu-util bison flex gperf + check_for_installed_files "/usr/include/ffi.h" "/usr/include/ssl/ssl.h" + PACKAGES=() + ;; + esac $PKG_INSTALL "${PACKAGES[@]}" diff --git a/Sming/Arch/Esp32/app.mk b/Sming/Arch/Esp32/app.mk index f06d8165a6..5447ac34d1 100644 --- a/Sming/Arch/Esp32/app.mk +++ b/Sming/Arch/Esp32/app.mk @@ -25,9 +25,9 @@ endif .PHONY: application application: $(TARGET_BIN) ifeq ($(IDF_VERSION),v4.3) - @printf "\033[47;1;31mWARNING! ESP-IDF 4.3 reached 'End of Life' in December 2023.\033[0m Upgrade to v5.2 recommended.\n" + @printf "\033[47;1;31mWARNING! ESP-IDF 4.3 reached 'End of Life' in December 2023.\033[0m Please upgrade to v5.2.\n" else ifeq ($(IDF_VERSION),v4.4) - @printf "\033[47;1;31mWARNING! ESP-IDF 4.4 support ends August 2024!\033[0m Upgrade to v5.2 recommended.\n" + @printf "\033[47;1;31mWARNING! ESP-IDF 4.4 support has ended in August 2024!\033[0m Please upgrade to v5.2.\n" else ifeq ($(IDF_VERSION),v5.0) @printf "\033[47;1;34mNOTE! ESP-IDF 5.0 not recommended for new designs.\033[0m Please consider upgrading to v5.2.\n" endif diff --git a/Sming/Arch/Esp8266/Components/heap/alloc.cpp b/Sming/Arch/Esp8266/Components/heap/alloc.cpp index 67e5b1ccbd..ba4e59a96c 100644 --- a/Sming/Arch/Esp8266/Components/heap/alloc.cpp +++ b/Sming/Arch/Esp8266/Components/heap/alloc.cpp @@ -46,7 +46,7 @@ void operator delete(void* ptr, size_t) free(ptr); } -void operator delete[](void* ptr, size_t) +void __attribute__((weak)) operator delete[](void* ptr, size_t) { free(ptr); } diff --git a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp index 13aa43764a..50919441ad 100644 --- a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp @@ -33,7 +33,26 @@ extern const uint8_t esp8266_pinmuxOffset[]; -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) +static const uint8_t gpioPinFunc[]{ + FUNC_GPIO0, // + FUNC_GPIO1, // + FUNC_GPIO2, // + FUNC_GPIO3, // + FUNC_GPIO4, // + FUNC_GPIO5, // + FUNC_GPIO6, // + FUNC_GPIO7, // + FUNC_GPIO8, // + FUNC_GPIO9, // + FUNC_GPIO10, // + FUNC_GPIO11, // + FUNC_GPIO12, // + FUNC_GPIO13, // + FUNC_GPIO14, // + FUNC_GPIO15, // +}; + +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) { if(noOfPins == 0) { return; @@ -49,7 +68,7 @@ HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPi continue; } ioInfo[pinCount][0] = PERIPHS_IO_MUX + esp8266_pinmuxOffset[pin]; - ioInfo[pinCount][1] = esp8266_gpioToFn[pin]; + ioInfo[pinCount][1] = gpioPinFunc[pin]; ioInfo[pinCount][2] = pin; pwmDutyInit[pinCount] = 0; // Start with zero output channels[pinCount] = pin; @@ -66,19 +85,7 @@ HardwarePWM::~HardwarePWM() // There is no function in the SDK to stop PWM output, yet. } -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - for(uint8_t i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - return i; - } - } - - debug_d("getChannel: can't find pin %d", pin); - return PWM_BAD_CHANNEL; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const { return (chan == PWM_BAD_CHANNEL) ? 0 : pwm_get_duty(chan); } @@ -101,7 +108,7 @@ bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { return pwm_get_period(); } @@ -118,7 +125,7 @@ void HardwarePWM::update() pwm_start(); } -uint32_t HardwarePWM::getFrequency(uint8_t pin) +uint32_t HardwarePWM::getFrequency(uint8_t pin) const { (void)pin; auto period = pwm_get_period(); diff --git a/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp b/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Esp8266/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Arch/Host/Core/HardwarePWM.cpp b/Sming/Arch/Host/Core/HardwarePWM.cpp index cf5d2de430..4c867c2ee4 100644 --- a/Sming/Arch/Host/Core/HardwarePWM.cpp +++ b/Sming/Arch/Host/Core/HardwarePWM.cpp @@ -25,36 +25,36 @@ #include -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +HardwarePWM::HardwarePWM(const uint8_t*, uint8_t no_of_pins) : channel_count(no_of_pins) { } HardwarePWM::~HardwarePWM() = default; -uint8_t HardwarePWM::getChannel(uint8_t pin) -{ - return PWM_BAD_CHANNEL; -} - -uint32_t HardwarePWM::getDutyChan(uint8_t chan) +uint32_t HardwarePWM::getDutyChan(uint8_t) const { return 0; } -bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) +bool HardwarePWM::setDutyChan(uint8_t, uint32_t, bool) { return false; } -uint32_t HardwarePWM::getPeriod() +uint32_t HardwarePWM::getPeriod() const { return 0; } -void HardwarePWM::setPeriod(uint32_t period) +void HardwarePWM::setPeriod(uint32_t) { } void HardwarePWM::update() { } + +uint32_t HardwarePWM::getFrequency(uint8_t) const +{ + return 0; +} diff --git a/Sming/Arch/Host/Services/Profiling/TaskStat.cpp b/Sming/Arch/Host/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Host/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Host/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp index 0c8f44c741..03556d271e 100644 --- a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp @@ -18,7 +18,7 @@ namespace { void IRAM_ATTR timer1_isr() { - hw_clear_bits(&timer_hw->intr, BIT(0)); + hw_clear_bits(&timer_hw->intr, BIT(0)); auto& p = hw_timer_private; if(p.timer1_callback != nullptr) { p.timer1_callback(p.timer1_arg); @@ -33,20 +33,22 @@ void IRAM_ATTR timer1_isr() void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) { (void)source_type; + auto irq_num = TIMER_ALARM_IRQ_NUM(HW_TIMER_NUM, 0); + irq_set_enabled(irq_num, false); auto& p = hw_timer_private; - irq_set_enabled(TIMER_IRQ_0, false); p.timer1_callback = callback; p.timer1_arg = arg; - irq_set_exclusive_handler(TIMER_IRQ_0, timer1_isr); + irq_set_exclusive_handler(irq_num, timer1_isr); hw_set_bits(&timer_hw->inte, BIT(0)); - irq_set_enabled(TIMER_IRQ_0, true); + irq_set_enabled(irq_num, true); } void hw_timer1_detach_interrupt() { hw_clear_bits(&timer_hw->inte, BIT(0)); - irq_set_enabled(TIMER_IRQ_0, false); - irq_remove_handler(TIMER_IRQ_0, timer1_isr); + auto irq_num = TIMER_ALARM_IRQ_NUM(HW_TIMER_NUM, 0); + irq_set_enabled(irq_num, false); + irq_remove_handler(irq_num, timer1_isr); } void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) @@ -59,5 +61,5 @@ void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr void hw_timer_init() { - // hardware_alarm_claim(0); + timer_hardware_alarm_claim(HW_TIMER_INST, 0); } diff --git a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h index b94d5b4e34..101382027d 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h @@ -11,7 +11,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { @@ -19,6 +19,9 @@ extern "C" { #define HW_TIMER_BASE_CLK 1000000U +#define HW_TIMER_NUM 0 +#define HW_TIMER_INST TIMER_INSTANCE(HW_TIMER_NUM) + /** * @defgroup hw_timer Hardware Timer Driver * @ingroup drivers @@ -36,7 +39,7 @@ extern "C" { */ __forceinline uint32_t IRAM_ATTR hw_timer_ticks() { - return timer_hw->timerawl; + return timer_time_us_32(HW_TIMER_INST); } /************************************* @@ -116,7 +119,7 @@ __forceinline void IRAM_ATTR hw_timer1_write(uint32_t ticks) { ticks <<= hw_timer_private.timer1_clkdiv; hw_timer_private.timer1_ticks = ticks; - timer_hw->alarm[0] = hw_timer_ticks() + ticks; + HW_TIMER_INST->alarm[0] = hw_timer_ticks() + ticks; } /** @@ -124,7 +127,7 @@ __forceinline void IRAM_ATTR hw_timer1_write(uint32_t ticks) */ __forceinline void IRAM_ATTR hw_timer1_disable() { - timer_hw->armed = BIT(0); + HW_TIMER_INST->armed = BIT(0); } /** @@ -133,7 +136,7 @@ __forceinline void IRAM_ATTR hw_timer1_disable() */ __forceinline uint32_t hw_timer1_read() { - int time = hw_timer_ticks() - timer_hw->alarm[0]; + int time = hw_timer_ticks() - HW_TIMER_INST->alarm[0]; return (time > 0) ? (time >> hw_timer_private.timer1_clkdiv) : 0; } diff --git a/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h b/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h index 8eb9f2560e..b55397e352 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/pwm.h @@ -1,88 +1,8 @@ #pragma once -#if defined(__cplusplus) -extern "C" { -#endif - -// #include - -#define PWM_CHANNEL_NUM_MAX 16 - -/** - * @defgroup pwm_driver PWM driver - * @ingroup drivers - * @{ - */ - -/** - * @fn void pwm_init(uint32 period, uint32 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3]) - * @brief Initialize PWM function, including GPIO selection, period and duty cycle - * @param period PWM period - * @param duty duty cycle of each output - * @param pwm_channel_num PWM channel number - * @param pin_info_list Array containing an entry for each channel giving - * @note This API can be called only once. - * - * Example: - * - * uint32 io_info[][3] = { - * {PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC, PWM_0_OUT_IO_NUM}, - * {PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC, PWM_1_OUT_IO_NUM}, - * {PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC, PWM_2_OUT_IO_NUM} - * }; - * - * pwm_init(light_param.pwm_period, light_param.pwm_duty, 3, io_info); - * - */ - /** - * @fn void pwm_start(void) - * @brief Starts PWM + * @brief Maximum number of active PWM channels. * - * This function needs to be called after PWM configuration is changed. + * The Pico has 8 PWM 'slices', each of which can drive two outputs. */ - -/** - * @fn void pwm_set_duty(uint32 duty, uint8 channel) - * @brief Sets duty cycle of a PWM output - * @param duty The time that high-level single will last, duty cycle will be (duty*45)/(period*1000) - * @param channel PWM channel, which depends on how many PWM channels are used - * - * Set the time that high-level signal will last. - * The range of duty depends on PWM period. Its maximum value of which can be Period * 1000 / 45. - * - * For example, for 1-KHz PWM, the duty range is 0 ~ 22222. - */ - -/** - * @fn uint32 pwm_get_duty(uint8 channel) - * @brief Get duty cycle of PWM output - * @param channel PWM channel, which depends on how many PWM channels are used - * @retval uint32 Duty cycle of PWM output - * - * Duty cycle will be (duty*45) / (period*1000). - */ - -/** - * @fn void pwm_set_period(uint32 period) - * @brief Set PWM period - * @param period PWM period in us. For example, 1-KHz PWM period = 1000us. - */ - -/** - * @fn uint32 pwm_get_period(void) - * @brief Get PWM period - * @retval uint32 Return PWM period in us. - */ - -/** - * @fn uint32 get_pwm_version(void) - * @brief Get version information of PWM - * @retval uint32 PWM version - */ - -/** @} */ - -#if defined(__cplusplus) -} -#endif +#define PWM_CHANNEL_NUM_MAX 16 diff --git a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp index b524d56ceb..d43afb6cfd 100644 --- a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp @@ -75,16 +75,16 @@ void IRAM_ATTR timer_schedule() if(timer_list == nullptr) { debug_tmr("cancel"); // Cancel hardware timer - timer_hw->armed = BIT(1); + HW_TIMER_INST->armed = BIT(1); return; } constexpr int TIMER2_MIN_US{50}; auto now = hw_timer2_read(); if(int(timer_list->timer_expire - now) < TIMER2_MIN_US) { - timer_hw->alarm[1] = now + TIMER2_MIN_US; + HW_TIMER_INST->alarm[1] = now + TIMER2_MIN_US; } else { - timer_hw->alarm[1] = timer_list->timer_expire; + HW_TIMER_INST->alarm[1] = timer_list->timer_expire; } } @@ -95,7 +95,7 @@ os_timer_t* find_expired_timer() } // Using Timer2 hardware to schedule software timers - if(timer_hw->armed & BIT(1)) { + if(HW_TIMER_INST->armed & BIT(1)) { return nullptr; } diff --git a/Sming/Arch/Rp2040/Components/driver/uart.cpp b/Sming/Arch/Rp2040/Components/driver/uart.cpp index c277d41037..9d4867f742 100644 --- a/Sming/Arch/Rp2040/Components/driver/uart.cpp +++ b/Sming/Arch/Rp2040/Components/driver/uart.cpp @@ -13,6 +13,12 @@ #include #include +#ifdef ARCH_RP2040 +#define UART_FUNCSEL_NUM(gpio) GPIO_FUNC_UART +#else +#define UART_FUNCSEL_NUM(gpio) ((gpio) & 0x2 ? GPIO_FUNC_UART_AUX : GPIO_FUNC_UART) +#endif + namespace { using uart_dev_t = uart_hw_t; @@ -721,7 +727,7 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) if(uart->tx_pin != UART_PIN_DEFAULT) { gpio_set_function(uart->tx_pin, GPIO_FUNC_NULL); } - gpio_set_function(tx_pin, GPIO_FUNC_UART); + gpio_set_function(tx_pin, UART_FUNCSEL_NUM(tx_pin)); uart->tx_pin = tx_pin; } @@ -729,7 +735,7 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) if(uart->rx_pin != UART_PIN_DEFAULT) { gpio_set_function(uart->rx_pin, GPIO_FUNC_NULL); } - gpio_set_function(rx_pin, GPIO_FUNC_UART); + gpio_set_function(rx_pin, UART_FUNCSEL_NUM(rx_pin)); uart->rx_pin = rx_pin; } diff --git a/Sming/Arch/Rp2040/Components/libc/src/heap.c b/Sming/Arch/Rp2040/Components/libc/src/heap.c deleted file mode 100644 index de274e3b4e..0000000000 --- a/Sming/Arch/Rp2040/Components/libc/src/heap.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * heap.c - */ - -#include "include/heap.h" -#include - -uint32_t system_get_free_heap_size(void) -{ - // These are set by linker - extern char __end__; - extern char __StackLimit; - uint32_t maxHeap = (uint32_t)&__StackLimit - (uint32_t)&__end__; - struct mallinfo m = mallinfo(); - return maxHeap - m.uordblks; -} diff --git a/Sming/Arch/Rp2040/Components/libc/src/heap.cpp b/Sming/Arch/Rp2040/Components/libc/src/heap.cpp new file mode 100644 index 0000000000..1074e9d8ac --- /dev/null +++ b/Sming/Arch/Rp2040/Components/libc/src/heap.cpp @@ -0,0 +1,58 @@ +/* + * heap.c + */ + +#include "include/heap.h" +#include +#include +#include + +extern "C" uint32_t system_get_free_heap_size(void) +{ + // These are set by linker + extern char __end__; + extern char __StackLimit; + uint32_t maxHeap = (uint32_t)&__StackLimit - (uint32_t)&__end__; + struct mallinfo m = mallinfo(); + return maxHeap - m.uordblks; +} + +void* operator new(size_t size) +{ + return malloc(size); +} + +void* operator new(size_t size, const std::nothrow_t&) +{ + return malloc(size); +} + +void* operator new[](size_t size) +{ + return malloc(size); +} + +void* operator new[](size_t size, const std::nothrow_t&) +{ + return malloc(size); +} + +void operator delete(void* ptr) +{ + free(ptr); +} + +void operator delete[](void* ptr) +{ + free(ptr); +} + +void operator delete(void* ptr, size_t) +{ + free(ptr); +} + +void operator delete[](void* ptr, size_t) +{ + free(ptr); +} diff --git a/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h b/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h index a04deaa0c9..895eb8774d 100644 --- a/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h +++ b/Sming/Arch/Rp2040/Components/libc/src/include/sys/pgmspace.h @@ -21,7 +21,11 @@ extern "C" { /** * @brief Simple check to determine if a pointer refers to flash memory */ +#ifdef XIP_END +#define isFlashPtr(ptr) ((uint32_t)(ptr) >= XIP_BASE && (uint32_t)(ptr) < XIP_END) +#else #define isFlashPtr(ptr) ((uint32_t)(ptr) >= XIP_MAIN_BASE && (uint32_t)(ptr) < XIP_NOALLOC_BASE) +#endif #define PROGMEM STORE_ATTR ICACHE_RODATA_ATTR #define PROGMEM_PSTR PROGMEM diff --git a/Sming/Arch/Rp2040/Components/picotool/README.rst b/Sming/Arch/Rp2040/Components/picotool/README.rst index e887b5d13e..b16fb5ed6a 100644 --- a/Sming/Arch/Rp2040/Components/picotool/README.rst +++ b/Sming/Arch/Rp2040/Components/picotool/README.rst @@ -3,4 +3,10 @@ Picotool Picotool is a tool for inspecting RP2040 binaries, and interacting with RP2040 devices when they are in BOOTSEL mode. -Note for full documentation see https://rptl.io/pico-get-started Appendix B. +See https://rptl.io/pico-get-started Appendix B for an introduction to this tool. + +Sming builds picotool from source and uses it to read back flash memory with build targets such as ``make readpart``. + +The tool can be invoked directly like this:: + + make picotool CMD="info -a" diff --git a/Sming/Arch/Rp2040/Components/picotool/component.mk b/Sming/Arch/Rp2040/Components/picotool/component.mk index 9e2ea04f85..f7e18a3241 100644 --- a/Sming/Arch/Rp2040/Components/picotool/component.mk +++ b/Sming/Arch/Rp2040/Components/picotool/component.mk @@ -33,10 +33,49 @@ $(COMPONENT_RULE)$(PICOTOOL): $(Q) mkdir -p $(@D) $(Q) cd $(@D) && $(CMAKE) $(PICOTOOL_CMAKE_OPTIONS) $(PICOTOOL_SRC) && $(MAKE) +##@Flashing + +.PHONY: picotool +picotool: ##Pass options to picotool, e.g. `make picotool -- help` + $(Q) $(PICOTOOL) $(CMD) + +comma := , +XIP_BASE := 0x10000000 + +define CalcHex +$$(printf "0x%x" $$(( $1 ))) +endef + +define RangeStart +$(call CalcHex,$(XIP_BASE) + $(firstword $(subst $(comma), ,$1))) +endef + +define RangeEnd +$(call CalcHex,$(XIP_BASE) + $(firstword $(subst $(comma), ,$1)) + $(word 2,$(subst $(comma), ,$1))) +endef + +# Read flash memory into file +# $1 -> `Offset,Size` chunk +# $2 -> Output filename +define ReadFlash + $(info ReadFlash $1,$2) + $(Q) $(PICOTOOL) save -r $(call RangeStart,$1) $(call RangeEnd,$1) $2 -t bin +endef # Read flash manufacturer ID and determine actual size define ReadFlashID $(info ReadFlashID) - $(Q) $(PICOTOOL) info -a $(TARGET_BIN) - # $(PICOTOOL) help info - endef + $(Q) $(PICOTOOL) info -a +endef + +# Erase a region of Flash +# $1 -> Offset,Size +define EraseFlashRegion + $(info EraseFlashRegion $1) + $(Q) $(PICOTOOL) erase -r $(call RangeStart,$1) $(call RangeEnd,$1) +endef + +# Erase flash memory contents +define EraseFlash + $(Q) $(PICOTOOL) erase -a +endef diff --git a/Sming/Arch/Rp2040/Components/picotool/picotool b/Sming/Arch/Rp2040/Components/picotool/picotool index 5d6df39033..df21059f7c 160000 --- a/Sming/Arch/Rp2040/Components/picotool/picotool +++ b/Sming/Arch/Rp2040/Components/picotool/picotool @@ -1 +1 @@ -Subproject commit 5d6df39033c7166ea6e76cbde1ff0c0240a4bba4 +Subproject commit df21059f7ca6f1babc7f1f3b92122cacffc85951 diff --git a/Sming/Arch/Rp2040/Components/picotool/picotool.patch b/Sming/Arch/Rp2040/Components/picotool/picotool.patch new file mode 100644 index 0000000000..dbfcf4c51d --- /dev/null +++ b/Sming/Arch/Rp2040/Components/picotool/picotool.patch @@ -0,0 +1,28 @@ +diff --git a/lib/whereami/whereami.c b/lib/whereami/whereami.c +index d052e14..940736e 100644 +--- a/lib/whereami/whereami.c ++++ b/lib/whereami/whereami.c +@@ -60,8 +60,9 @@ extern "C" { + #if defined(_MSC_VER) + #pragma warning(push, 3) + #endif ++#undef _WIN32_WINNT ++#define _WIN32_WINNT _WIN32_WINNT_WINXP + #include +-#include + #if defined(_MSC_VER) + #pragma warning(pop) + #endif +diff --git a/picoboot_connection/picoboot_connection.c b/picoboot_connection/picoboot_connection.c +index 265608c..e487714 100644 +--- a/picoboot_connection/picoboot_connection.c ++++ b/picoboot_connection/picoboot_connection.c +@@ -9,6 +9,8 @@ + #include + #include + ++#define static_assert _Static_assert ++ + #include "picoboot_connection.h" + #include "boot/bootrom_constants.h" + #include "pico/stdio_usb/reset_interface.h" diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index 4c03455044..50fdec72b9 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -6,10 +6,16 @@ else export PICO_SDK_PATH := $(COMPONENT_PATH)/pico-sdk endif +ifeq ($(SMING_SOC),rp2350) +PICO_VARIANT=pico2 +else +PICO_VARIANT=pico +endif + ifeq ($(DISABLE_WIFI),1) -export PICO_BOARD ?= pico +export PICO_BOARD ?= $(PICO_VARIANT) else -export PICO_BOARD ?= pico_w +export PICO_BOARD ?= $(PICO_VARIANT)_w COMPONENT_DEPENDS += uzlib endif @@ -35,29 +41,33 @@ ifeq ($(ENABLE_BOOTSEL),1) COMPONENT_CXXFLAGS += -DENABLE_BOOTSEL=1 endif +# Functions which are wrapped by the SDK WRAPPED_FUNCTIONS := $(foreach c,$(wildcard $(COMPONENT_PATH)/sdk/*.mk),$(eval include $c)) EXTRA_LDFLAGS := \ $(call Wrap,$(WRAPPED_FUNCTIONS)) \ + -Wl,--whole-archive -lpico -Wl,--no-whole-archive \ -T memmap_default.ld SDK_INTERFACES := \ boards \ - common/pico_base \ + common/pico_base_headers \ common/pico_binary_info \ - common/pico_bit_ops \ - common/pico_divider \ + common/pico_bit_ops_headers \ + common/pico_divider_headers \ common/pico_sync \ common/pico_time \ common/pico_util \ - rp2040/hardware_regs \ - rp2040/hardware_structs \ + $(RP_VARIANT)/hardware_regs \ + $(RP_VARIANT)/hardware_structs \ rp2_common/hardware_adc \ rp2_common/hardware_gpio \ - rp2_common/pico_platform \ + $(RP_VARIANT)/pico_platform \ + rp2_common/boot_bootrom_headers \ rp2_common/hardware_base \ + rp2_common/hardware_boot_lock \ rp2_common/hardware_sync \ rp2_common/hardware_divider \ rp2_common/hardware_timer \ @@ -73,17 +83,25 @@ SDK_INTERFACES := \ rp2_common/hardware_rtc \ rp2_common/hardware_pll \ rp2_common/hardware_spi \ + rp2_common/hardware_sync_spin_lock \ rp2_common/hardware_vreg \ rp2_common/hardware_watchdog \ rp2_common/hardware_xosc \ + rp2_common/pico_aon_timer \ rp2_common/pico_async_context \ rp2_common/pico_bootrom \ rp2_common/pico_double \ rp2_common/pico_int64_ops \ rp2_common/pico_float \ + rp2_common/pico_flash \ + rp2_common/pico_mem_ops \ rp2_common/pico_multicore \ + rp2_common/pico_platform_compiler \ + rp2_common/pico_platform_panic \ + rp2_common/pico_platform_sections \ rp2_common/pico_rand \ rp2_common/pico_runtime \ + rp2_common/pico_runtime_init \ rp2_common/pico_unique_id \ rp2_common/pico_cyw43_arch \ rp2_common/pico_cyw43_driver @@ -105,10 +123,10 @@ COMPONENT_INCDIRS += $(PICO_BASE_DIR) LIBDIRS += \ $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link \ + $(PICO_SDK_PATH)/src/rp2_common/pico_crt0/$(RP_VARIANT) \ $(PICO_BUILD_DIR) EXTRA_LIBS += \ - pico \ m \ stdc++ \ gcc @@ -116,7 +134,8 @@ EXTRA_LIBS += \ RP2040_CMAKE_OPTIONS := \ -G Ninja \ -DCMAKE_MAKE_PROGRAM=$(NINJA) \ - -DCMAKE_BUILD_TYPE=$(if $(subst 1,,$(PICO_DEBUG)),RelWithDebInfo,Debug) + -DCMAKE_BUILD_TYPE=$(if $(subst 1,,$(PICO_DEBUG)),RelWithDebInfo,Debug) \ + -DPICO_VARIANT=$(RP_VARIANT) ifeq ($(ENABLE_CCACHE),1) RP2040_CMAKE_OPTIONS += \ @@ -126,7 +145,7 @@ endif COMPONENT_PREREQUISITES := $(PICO_CONFIG) -BOOTLOADER := $(PICO_BUILD_DIR)/pico-sdk/src/rp2_common/boot_stage2/bs2_default_padded_checksummed.S +BOOTLOADER := $(PICO_BUILD_DIR)/pico-sdk/src/$(RP_VARIANT)/boot_stage2/bs2_default_padded_checksummed.S DEBUG_VARS += CYW43_FIRMWARE CYW43_FIRMWARE := $(COMPONENT_BUILD_BASE)/cyw43-fw.gz diff --git a/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch index c7edc5b93e..ff93702411 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch @@ -1,8 +1,8 @@ diff --git a/src/cyw43_ctrl.c b/src/cyw43_ctrl.c -index edec1f3..de03c73 100644 +index cc9973e..ab76673 100644 --- a/src/cyw43_ctrl.c +++ b/src/cyw43_ctrl.c -@@ -296,13 +296,17 @@ static const char *const cyw43_async_event_name_table[89] = { +@@ -288,13 +288,17 @@ static const char *const cyw43_async_event_name_table[89] = { [CYW43_EV_SET_SSID] = "SET_SSID", [CYW43_EV_JOIN] = "JOIN", [CYW43_EV_AUTH] = "AUTH", @@ -21,20 +21,10 @@ index edec1f3..de03c73 100644 [CYW43_EV_ASSOC_REQ_IE] = "ASSOC_REQ_IE", [CYW43_EV_ASSOC_RESP_IE] = "ASSOC_RESP_IE", diff --git a/src/cyw43_ll.c b/src/cyw43_ll.c -index 604335c..4aeb629 100644 +index 033eec2..11f08d5 100644 --- a/src/cyw43_ll.c +++ b/src/cyw43_ll.c -@@ -54,9 +54,6 @@ - #include "cyw43_sdio.h" - #endif - --#define CYW43_FLASH_BLOCK_SIZE (512) --uint32_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); -- - struct pbuf; - uint16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, uint16_t len, uint16_t offset); - -@@ -68,10 +65,6 @@ extern bool enable_spi_packet_dumping; +@@ -65,11 +65,6 @@ extern bool enable_spi_packet_dumping; #define CYW43_RAM_SIZE (512 * 1024) @@ -42,160 +32,146 @@ index 604335c..4aeb629 100644 -#include CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE - -#define CYW43_CLM_ADDR (fw_data + ALIGN_UINT(CYW43_WIFI_FW_LEN, 512)) - #define VERIFY_FIRMWARE_DOWNLOAD (0) - +- #define ALIGN_UINT(val, align) (((val) + (align) - 1) & ~((align) - 1)) -@@ -357,58 +350,31 @@ static void cyw43_write_backplane(cyw43_int_t *self, uint32_t addr, size_t size, - cyw43_set_backplane_window(self, CHIPCOMMON_BASE_ADDRESS); + + // Configure the padding needed for data sent to cyw43_write_bytes(). +@@ -101,18 +96,6 @@ static inline void cyw43_put_le32(uint8_t *buf, uint32_t x) { + buf[3] = x >> 24; } --static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_len, int from_storage, uintptr_t source) { -- // round up len to simplify download -- size_t len = (raw_len + 255) & ~255; +-#if CYW43_RESOURCE_VERIFY_DOWNLOAD +-static void cyw43_xxd(size_t len, const uint8_t *buf) { +- for (size_t i = 0; i < len; ++i) { +- CYW43_PRINTF(" %02x", buf[i]); +- if (i % 32 == 31) { +- CYW43_PRINTF("\n"); +- } +- } +- CYW43_PRINTF("\n"); +-} +-#endif - -- CYW43_VDEBUG("writing %lu bytes to 0x%lx\n", (uint32_t)len, (uint32_t)addr); + /*******************************************************************************/ + // CYW43 constants and types + +@@ -409,10 +392,6 @@ static int cyw43_check_valid_chipset_firmware(cyw43_int_t *self, size_t len, uin + } + + static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, uintptr_t source) { +- // The calls to cyw43_write_bytes() (and cyw43_read_bytes()) require data sizes that +- // are aligned to a certain amount. +- assert(CYW43_WRITE_BYTES_PAD(len) == len); - -- uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; -- if (from_storage) { -- // reused the spid_buf to copy the data (must be larger than 512 storage block size) -- block_size = sizeof(self->spid_buf); -- CYW43_DEBUG("data comes from external storage via buffer of size %u\n", (unsigned int)block_size); -+static uint32_t storage_get_chunksize() -+{ -+ const uint32_t chunkTag = 0x4b4e4843; // "CHNK" -+ struct chunk_t { -+ uint32_t tag; -+ uint32_t length; -+ }; -+ struct chunk_t chunk; -+ int res = cyw43_storage_read(&chunk, sizeof(chunk)); -+ if (res != sizeof(chunk)) { -+ CYW43_WARN("Bad chunk header %d\n", res); -+ return 0; - } -+ if (chunk.tag != chunkTag) { -+ CYW43_WARN("Bad chunk tag %08x\n", chunk.tag); -+ return 0; -+ } -+ CYW43_DEBUG("Chunk %u bytes\n", chunk.length); -+ return chunk.length; -+} + CYW43_VDEBUG("writing %u bytes to 0x%x\n", (uint32_t)len, (uint32_t)addr); + + uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; +@@ -431,12 +410,18 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, + uint32_t dest_addr = addr + offset; + assert(((dest_addr & BACKPLANE_ADDR_MASK) + sz) <= (BACKPLANE_ADDR_MASK + 1)); + cyw43_set_backplane_window(self, dest_addr); +- const uint8_t *src = (const uint8_t *)source + offset; ++ const uint8_t *src; ++ if (source) { ++ src = (const uint8_t *)source + offset; ++ } else { ++ cyw43_storage_read(self->spid_buf, sz); ++ src = self->spid_buf; ++ } + dest_addr &= BACKPLANE_ADDR_MASK; + #if CYW43_USE_SPI + dest_addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + #endif +- int ret = cyw43_write_bytes(self, BACKPLANE_FUNCTION, dest_addr, sz, src); ++ int ret = cyw43_write_bytes(self, BACKPLANE_FUNCTION, dest_addr, CYW43_WRITE_BYTES_PAD(sz), src); + if (ret != 0) { + + return CYW43_FAIL_FAST_CHECK(ret); +@@ -449,42 +434,6 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, + CYW43_VDEBUG("done dnload; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); + #endif -- if (addr == 0) { -- // check that firmware is actually there +- #if CYW43_RESOURCE_VERIFY_DOWNLOAD - -- // get the last bit of the firmware -- const uint8_t *b; -- uint32_t fw_end; -- if (from_storage) { -- // get the last aligned-1024 bytes -- uint32_t last_bl = (raw_len - 1) / CYW43_FLASH_BLOCK_SIZE; -- storage_read_blocks(self->spid_buf, source + last_bl - 1, 2); -- fw_end = raw_len - (last_bl - 1) * CYW43_FLASH_BLOCK_SIZE; -- b = self->spid_buf; -- } else { -- // get the last 800 bytes -- fw_end = 800; -- b = (const uint8_t *)source + raw_len - fw_end; -- } +- // Verification of 380k takes about 40ms using a 512-byte transfer size +- const size_t verify_block_size = CYW43_BUS_MAX_BLOCK_SIZE; +- uint8_t buf[verify_block_size]; - -- // get length of trailer -- fw_end -= 16; // skip DVID trailer -- uint32_t trail_len = b[fw_end - 2] | b[fw_end - 1] << 8; -- int found = -1; -- if (trail_len < 500 && b[fw_end - 3] == '\0') { -- for (int i = 80; i < (int)trail_len; ++i) { -- if (strncmp((const char *)&b[fw_end - 3 - i], "Version: ", 9) == 0) { -- found = i; -- break; -- } -- } -- } +- #if CYW43_VERBOSE_DEBUG +- t_start = cyw43_hal_ticks_us(); +- #endif - -- if (found == -1) { -- CYW43_WARN("could not find valid firmware\n"); +- for (size_t offset = 0; offset < len; offset += verify_block_size) { +- size_t sz = verify_block_size; +- if (offset + sz > len) { +- sz = len - offset; +- } +- uint32_t dest_addr = addr + offset; +- assert(((dest_addr & BACKPLANE_ADDR_MASK) + sz) <= (BACKPLANE_ADDR_MASK + 1)); +- cyw43_set_backplane_window(self, dest_addr); +- cyw43_read_bytes(self, BACKPLANE_FUNCTION, dest_addr & BACKPLANE_ADDR_MASK, sz, buf); +- const uint8_t *src = (const uint8_t *)source + offset; +- if (memcmp(buf, src, sz) != 0) { +- CYW43_WARN("fail verify at address 0x%08x:\n", (unsigned int)dest_addr); +- cyw43_xxd(sz, src); +- cyw43_xxd(sz, buf); - return CYW43_FAIL_FAST_CHECK(-CYW43_EIO); - } -+static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t len, int from_storage, uintptr_t source) { -+ CYW43_VDEBUG("writing %lu bytes to 0x%lx\n", (uint32_t)len, (uint32_t)addr); - -- // print wifi firmware version info -- CYW43_DEBUG("%s\n", &b[fw_end - 3 - found]); - } -+ const uint32_t block_size = CYW43_BUS_MAX_BLOCK_SIZE; - - #if VERIFY_FIRMWARE_DOWNLOAD - uint32_t t_start = cyw43_hal_ticks_us(); -@@ -426,7 +392,7 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - cyw43_set_backplane_window(self, dest_addr); - const uint8_t *src; - if (from_storage) { -- storage_read_blocks(self->spid_buf, source + offset / CYW43_FLASH_BLOCK_SIZE, block_size / CYW43_FLASH_BLOCK_SIZE); -+ cyw43_storage_read(self->spid_buf, sz); - src = self->spid_buf; - } else { - src = (const uint8_t *)source + offset; -@@ -443,6 +409,10 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - } +- +- #if CYW43_VERBOSE_DEBUG +- t_end = cyw43_hal_ticks_us(); +- dt = t_end - t_start; +- CYW43_VDEBUG("done verify; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); +- #endif +- +- #endif // CYW43_RESOURCE_VERIFY_DOWNLOAD +- + return 0; + } - #if VERIFY_FIRMWARE_DOWNLOAD -+ if(from_storage) { -+ cyw43_storage_cleanup(); -+ storage_get_chunksize(); -+ } - uint32_t t_end = cyw43_hal_ticks_us(); - uint32_t dt = t_end - t_start; - CYW43_VDEBUG("done dnload; dt = %u us; speed = %u kbytes/sec\n", (unsigned int)dt, (unsigned int)(len * 1000 / dt)); -@@ -464,7 +434,7 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ - cyw43_read_bytes(self, BACKPLANE_FUNCTION, dest_addr & BACKPLANE_ADDR_MASK, sz, buf); - const uint8_t *src; - if (from_storage) { -- storage_read_blocks(self->spid_buf, source + offset / CYW43_FLASH_BLOCK_SIZE, verify_block_size / CYW43_FLASH_BLOCK_SIZE); -+ cyw43_storage_read(self->spid_buf, verify_block_size); - src = self->spid_buf; - } else { - src = (const uint8_t *)source + offset; -@@ -1372,8 +1342,8 @@ void cyw43_ll_bus_sleep(cyw43_ll_t *self_in, bool can_sleep) { +@@ -1374,7 +1323,7 @@ void cyw43_ll_bus_sleep(cyw43_ll_t *self_in, bool can_sleep) { #define CLM_CHUNK_LEN 1024 + 512 #endif -static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm_len) { -- // Reuse spid_buf but be careful to start at the right offset in it +static void cyw43_clm_load(cyw43_int_t *self, size_t clm_len) { -+ // Reuse spid_buf but be careful to start at the right offset in i + // Reuse spid_buf but be careful to start at the right offset in it uint8_t *buf = &self->spid_buf[SDPCM_HEADER_LEN + 16]; - const size_t clm_dload_chunk_len = CLM_CHUNK_LEN; -@@ -1398,7 +1368,7 @@ static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm +@@ -1400,7 +1349,7 @@ static void cyw43_clm_load(cyw43_int_t *self, const uint8_t *clm_ptr, size_t clm *(uint32_t *)(buf + 12) = len; *(uint32_t *)(buf + 16) = 0; #pragma GCC diagnostic pop - memcpy(buf + 20, clm_ptr + off, len); + cyw43_storage_read(buf + 20, len); - CYW43_VDEBUG("clm data send %lu/%zu\n", off + len, clm_len); + CYW43_VDEBUG("clm data send %u/%u\n", off + len, clm_len); -@@ -1654,12 +1624,9 @@ alp_set: +@@ -1656,14 +1605,11 @@ alp_set: cyw43_write_backplane(self, SOCSRAM_BANKX_INDEX, 4, 0x3); cyw43_write_backplane(self, SOCSRAM_BANKX_PDA, 4, 0); -- // Take firmware from the address space -- cyw43_download_resource(self, 0x00000000, CYW43_WIFI_FW_LEN, 0, fw_data); -- /* - // Take firmware from storage block device -- cyw43_download_resource(self, 0x00000000, CYW43_WIFI_FW_LEN, 1, 0x100 + 0x1000); -- */ +- // Check that valid chipset firmware exists at the given source address. +- int ret = cyw43_check_valid_chipset_firmware(self, CYW43_WIFI_FW_LEN, fw_data); +- if (ret != 0) { +- return ret; +- } ++ // Take firmware from storage block device + cyw43_storage_init(); -+ cyw43_download_resource(self, 0x00000000, storage_get_chunksize(), 1, 0); - size_t wifi_nvram_len = ALIGN_UINT(sizeof(wifi_nvram_4343), 64); - const uint8_t *wifi_nvram_data = wifi_nvram_4343; -@@ -1776,9 +1743,11 @@ f2_ready: + // Download the main WiFi firmware blob to the 43xx device. +- ret = cyw43_download_resource(self, 0x00000000, CYW43_WRITE_BYTES_PAD(CYW43_WIFI_FW_LEN), fw_data); ++ int ret = cyw43_download_resource(self, 0x00000000, cyw43_storage_get_chunksize(), 0); + if (ret != 0) { + return ret; + } +@@ -1784,9 +1730,11 @@ f2_ready: // Load the CLM data; it sits just after main firmware CYW43_VDEBUG("cyw43_clm_load start\n"); - cyw43_clm_load(self, (const uint8_t *)CYW43_CLM_ADDR, CYW43_CLM_LEN); -+ cyw43_clm_load(self, storage_get_chunksize()); ++ cyw43_clm_load(self, cyw43_storage_get_chunksize()); CYW43_VDEBUG("cyw43_clm_load done\n"); + cyw43_storage_cleanup(); @@ -203,18 +179,23 @@ index 604335c..4aeb629 100644 cyw43_write_iovar_u32(self, "bus:txglom", 0, WWD_STA_INTERFACE); // tx glomming off cyw43_write_iovar_u32(self, "apsta", 1, WWD_STA_INTERFACE); // apsta on -@@ -1882,6 +1851,10 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { +@@ -1890,10 +1838,14 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { cyw43_delay_ms(50); #ifndef NDEBUG + // Get and print firmware version + memcpy(buf, "ver\x00", 4); + cyw43_do_ioctl(self, SDPCM_GET, WLC_GET_VAR, 128, buf, WWD_STA_INTERFACE); -+ CYW43_DEBUG("%s", buf); ++ CYW43_DEBUG("CYW43 ver %s", buf); // Get and print CLM version memcpy(buf, "clmver\x00", 7); cyw43_do_ioctl(self, SDPCM_GET, WLC_GET_VAR, 128, buf, WWD_STA_INTERFACE); -@@ -1911,8 +1884,8 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { +- CYW43_DEBUG("%s\n", buf); ++ CYW43_DEBUG("CYW43 clmver %s\n", buf); + #endif + + // Set antenna to chip antenna +@@ -1919,8 +1871,8 @@ int cyw43_ll_wifi_on(cyw43_ll_t *self_in, uint32_t country) { CLR_EV(buf, 19); // roam attempt occurred CLR_EV(buf, 20); // tx fail CLR_EV(buf, 40); // radio @@ -225,7 +206,7 @@ index 604335c..4aeb629 100644 #undef CLR_EV memcpy(buf, "bsscfg:event_msgs", 18); diff --git a/src/cyw43_ll.h b/src/cyw43_ll.h -index 2750238..c281093 100644 +index b5c1ead..6e4ea30 100644 --- a/src/cyw43_ll.h +++ b/src/cyw43_ll.h @@ -67,15 +67,19 @@ @@ -248,12 +229,13 @@ index 2750238..c281093 100644 #define CYW43_EV_CSA_COMPLETE_IND (80) #define CYW43_EV_ASSOC_REQ_IE (87) #define CYW43_EV_ASSOC_RESP_IE (88) -@@ -318,6 +322,11 @@ uint32_t cyw43_ll_read_backplane_reg(cyw43_ll_t *self_in, uint32_t addr); +@@ -316,6 +320,12 @@ uint32_t cyw43_ll_read_backplane_reg(cyw43_ll_t *self_in, uint32_t addr); int cyw43_ll_write_backplane_mem(cyw43_ll_t *self_in, uint32_t addr, uint32_t len, const uint8_t *buf); int cyw43_ll_read_backplane_mem(cyw43_ll_t *self_in, uint32_t addr, uint32_t len, uint8_t *buf); +// Sming framework methods for accessing partition storage +int cyw43_storage_init(); ++uint32_t cyw43_storage_get_chunksize(); +uint32_t cyw43_storage_read(void *dest, uint32_t length); +void cyw43_storage_cleanup(void); + diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk index 263a6680aa..95ea6acad1 160000 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk @@ -1 +1 @@ -Subproject commit 263a6680aaf590b3c48f55645f30d1b96d168832 +Subproject commit 95ea6acad131124694cda1c162c52cd30e0aece0 diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch index f559e5fb88..c9373bb0ad 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch @@ -1,58 +1,26 @@ -diff --git a/src/common/pico_util/queue.c b/src/common/pico_util/queue.c -index a5c8e18..c3b8a91 100644 ---- a/src/common/pico_util/queue.c -+++ b/src/common/pico_util/queue.c -@@ -41,7 +41,7 @@ static inline uint16_t inc_index(queue_t *q, uint16_t index) { - return index; - } +diff --git a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +index 5125401..6ba0d2f 100644 +--- a/src/rp2_common/pico_crt0/rp2040/memmap_default.ld ++++ b/src/rp2_common/pico_crt0/rp2040/memmap_default.ld +@@ -255,7 +255,7 @@ SECTIONS --static bool queue_add_internal(queue_t *q, const void *data, bool block) { -+static bool __not_in_flash_func(queue_add_internal)(queue_t *q, const void *data, bool block) { - do { - uint32_t save = spin_lock_blocking(q->core.spin_lock); - if (queue_get_level_unsafe(q) != q->element_count) { -@@ -94,7 +94,7 @@ static bool queue_peek_internal(queue_t *q, void *data, bool block) { - } while (true); - } - --bool queue_try_add(queue_t *q, const void *data) { -+bool __not_in_flash_func(queue_try_add)(queue_t *q, const void *data) { - return queue_add_internal(q, data, false); - } - -diff --git a/src/rp2_common/hardware_base/include/hardware/address_mapped.h b/src/rp2_common/hardware_base/include/hardware/address_mapped.h -index 8e92d8b..da5feac 100644 ---- a/src/rp2_common/hardware_base/include/hardware/address_mapped.h -+++ b/src/rp2_common/hardware_base/include/hardware/address_mapped.h -@@ -105,12 +105,12 @@ __force_inline static uint32_t xip_alias_check_addr(const void *addr) { - #define xip_nocache_noalloc_alias_untyped(addr) ((void *)(XIP_NOCACHE_NOALLOC_BASE | xip_alias_check_addr(addr))) - - // Typed conversion alias pointer generation macros --#define hw_set_alias(p) ((typeof(p))hw_set_alias_untyped(p)) --#define hw_clear_alias(p) ((typeof(p))hw_clear_alias_untyped(p)) --#define hw_xor_alias(p) ((typeof(p))hw_xor_alias_untyped(p)) --#define xip_noalloc_alias(p) ((typeof(p))xip_noalloc_alias_untyped(p)) --#define xip_nocache_alias(p) ((typeof(p))xip_nocache_alias_untyped(p)) --#define xip_nocache_noalloc_alias(p) ((typeof(p))xip_nocache_noalloc_alias_untyped(p)) -+#define hw_set_alias(p) ((__typeof__(p))hw_set_alias_untyped(p)) -+#define hw_clear_alias(p) ((__typeof__(p))hw_clear_alias_untyped(p)) -+#define hw_xor_alias(p) ((__typeof__(p))hw_xor_alias_untyped(p)) -+#define xip_noalloc_alias(p) ((__typeof__(p))xip_noalloc_alias_untyped(p)) -+#define xip_nocache_alias(p) ((__typeof__(p))xip_nocache_alias_untyped(p)) -+#define xip_nocache_noalloc_alias(p) ((__typeof__(p))xip_nocache_noalloc_alias_untyped(p)) + .flash_end : { + KEEP(*(.embedded_end_block*)) +- PROVIDE(__flash_binary_end = .); ++ __flash_binary_end = .; + } > FLASH - /*! \brief Atomically set the specified bits to 1 in a HW register - * \ingroup hardware_base -diff --git a/src/rp2_common/pico_standard_link/memmap_default.ld b/src/rp2_common/pico_standard_link/memmap_default.ld -index e85b327..cf826c6 100644 ---- a/src/rp2_common/pico_standard_link/memmap_default.ld -+++ b/src/rp2_common/pico_standard_link/memmap_default.ld -@@ -231,7 +231,7 @@ SECTIONS - } > SCRATCH_Y + /* stack limit is poorly named, but historically is maximum heap ptr */ +diff --git a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +index bce316d..05c1beb 100644 +--- a/src/rp2_common/pico_crt0/rp2350/memmap_default.ld ++++ b/src/rp2_common/pico_crt0/rp2350/memmap_default.ld +@@ -269,7 +269,7 @@ SECTIONS .flash_end : { + KEEP(*(.embedded_end_block*)) - PROVIDE(__flash_binary_end = .); + __flash_binary_end = .; - } > FLASH + } > FLASH =0xaa /* stack limit is poorly named, but historically is maximum heap ptr */ diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt b/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt index 7081f49973..80bfa74b9e 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required(VERSION 3.12) -set(PICO_PLATFORM "rp2040") -set(PICO_COMPILER "pico_arm_gcc") +if (PICO_VARIANT STREQUAL "rp2350") + set(PICO_COMPILER "pico_arm_cortex_m33_gcc") + set(PICO_PLATFORM "rp2350-arm-s") +else() + set(PICO_COMPILER "pico_arm_cortex_m0plus_gcc") + set(PICO_PLATFORM "rp2040") +endif() set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) @@ -19,6 +24,8 @@ set(SKIP_PICO_STDIO_UART 1) set(SKIP_PICO_STDIO_USB 1) set(SKIP_TINYUSB 1) +set(PICO_NO_PICOTOOL 1) + # Initialize the SDK pico_sdk_init() @@ -31,6 +38,7 @@ target_compile_definitions(pico PUBLIC PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64 PICO_DIVIDER_IN_RAM=1 PICO_MEM_IN_RAM=1 + PICO_CXX_DISABLE_ALLOCATION_OVERRIDES=1 ) pico_set_program_name(pico "Sming") @@ -40,7 +48,7 @@ include_directories(BEFORE ${pico_lib_SOURCE_DIR}) target_link_libraries(pico hardware_adc - hardware_base + hardware_boot_lock hardware_claim hardware_clocks hardware_divider @@ -63,15 +71,21 @@ target_link_libraries(pico hardware_vreg hardware_watchdog hardware_xosc + pico_aon_timer pico_bit_ops pico_divider pico_double pico_fix + pico_flash pico_float pico_int64_ops pico_mem_ops pico_multicore + pico_platform_compiler + pico_platform_panic + pico_platform_sections pico_runtime + pico_runtime_init pico_standard_link pico_unique_id pico_audio_i2s diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk index a0ec0d43df..b25898865e 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_bit_ops.mk @@ -1,5 +1,6 @@ # pico_bit_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __clzsi2 \ __clzdi2 \ @@ -7,3 +8,4 @@ WRAPPED_FUNCTIONS += \ __ctzdi2 \ __popcountsi2 \ __popcountdi2 +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk index 8578a4ccf2..a8f3244744 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_divider.mk @@ -1,5 +1,6 @@ # pico_divider +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_idiv \ __aeabi_idivmod \ @@ -7,3 +8,4 @@ WRAPPED_FUNCTIONS += \ __aeabi_uidiv \ __aeabi_uidivmod \ __aeabi_uldivmod +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk index e45345f639..ef47c520ad 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_float.mk @@ -1,5 +1,6 @@ # pico_float +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_fadd \ __aeabi_fdiv \ @@ -24,7 +25,10 @@ WRAPPED_FUNCTIONS += \ __aeabi_f2uiz \ __aeabi_f2ulz \ __aeabi_f2d \ - sqrtf \ + sqrtf +endif + +WRAPPED_FUNCTIONS += \ cosf \ sinf \ tanf \ diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk index 83f39e1492..ce6c395606 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_int64_ops.mk @@ -1,4 +1,6 @@ # pico_int64_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ __aeabi_lmul +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk index 6244c18b5d..9815650161 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/pico_mem_ops.mk @@ -1,5 +1,6 @@ # pico_mem_ops +ifeq ($(SMING_SOC),rp2040) WRAPPED_FUNCTIONS += \ memcpy \ memset \ @@ -9,3 +10,4 @@ WRAPPED_FUNCTIONS += \ __aeabi_memset4 \ __aeabi_memcpy8 \ __aeabi_memset8 +endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c index 6abc297851..2724fd0393 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/clk.c +++ b/Sming/Arch/Rp2040/Components/rp2040/src/clk.c @@ -25,38 +25,6 @@ uint32_t IRAM_ATTR esp_get_ccount() return ((1 + ovf) << 24) - systick_hw->cvr; } -/*! \brief Check if a given system clock frequency is valid/attainable - * \ingroup pico_stdlib - * - * \param freq_khz Requested frequency - * \param vco_freq_out On success, the voltage controller oscillator frequeucny to be used by the SYS PLL - * \param post_div1_out On success, The first post divider for the SYS PLL - * \param post_div2_out On success, The second post divider for the SYS PLL. - * @return true if the frequency is possible and the output parameters have been written. - */ -static bool check_sys_clock_khz(uint32_t freq_khz, uint* vco_out, uint* postdiv1_out, uint* postdiv_out) -{ - uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000; - for(uint fbdiv = 320; fbdiv >= 16; fbdiv--) { - uint vco = fbdiv * crystal_freq_khz; - if(vco < 400000 || vco > 1600000) { - continue; - } - for(uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) { - for(uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) { - uint out = vco / (postdiv1 * postdiv2); - if(out == freq_khz && (vco % (postdiv1 * postdiv2)) == 0) { - *vco_out = vco * 1000; - *postdiv1_out = postdiv1; - *postdiv_out = postdiv2; - return true; - } - } - } - } - return false; -} - // Fix the peripheral clocks but allow system (CPU) to be varied independently using PLL void system_init_clocks() { @@ -85,10 +53,17 @@ void system_init_clocks() // Initialise systick for use by esp_get_ccount() exception_set_exclusive_handler(SYSTICK_EXCEPTION, systick_overflow_isr); +#ifdef SOC_RP2350 + systick_hw->csr = (1 << M33_SYST_CSR_CLKSOURCE_LSB) // Processor CLK source + | M33_SYST_CSR_TICKINT_BITS // Enable overflow ISR + | M33_SYST_CSR_ENABLE_BITS; // ENABLE + systick_hw->rvr = M33_SYST_RVR_BITS; // Reload value when counter hits 0 +#else systick_hw->csr = (1 << M0PLUS_SYST_CSR_CLKSOURCE_LSB) // Processor CLK source | M0PLUS_SYST_CSR_TICKINT_BITS // Enable overflow ISR | M0PLUS_SYST_CSR_ENABLE_BITS; // ENABLE systick_hw->rvr = M0PLUS_SYST_RVR_BITS; // Reload value when counter hits 0 +#endif } bool system_update_cpu_freq(uint8_t mhz) diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp index ab6e329416..77d50b6e13 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp @@ -57,8 +57,14 @@ bool __noinline IRAM_ATTR get_bootsel_button() // } - // Read input (low when BOOTSEL pressed) - bool button_state = !(sio_hw->gpio_hi_in & BIT(CS_PIN_INDEX)); + // The HI GPIO registers in SIO can observe and control the 6 QSPI pins. + // Note the button pulls the pin *low* when pressed. +#ifdef SOC_RP2040 +#define CS_BIT (1u << 1) +#else +#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS +#endif + bool button_state = !(sio_hw->gpio_hi_in & CS_BIT); // Re-enable chip select hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, @@ -88,15 +94,11 @@ void check_bootsel() } // namespace -extern void system_init_rtc(); - extern "C" int main(void) { extern void system_init_clocks(); system_init_clocks(); - system_init_rtc(); - system_soft_wdt_restart(); // Initialise hardware timers diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp index d048995da7..1615997c0f 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp @@ -122,6 +122,27 @@ uint32_t cyw43_storage_read(void* dest, uint32_t length) return length; } +uint32_t cyw43_storage_get_chunksize() +{ + const uint32_t chunkTag = 0x4b4e4843; // "CHNK" + struct chunk_t { + uint32_t tag; + uint32_t length; + }; + struct chunk_t chunk; + int res = cyw43_storage_read(&chunk, sizeof(chunk)); + if(res != sizeof(chunk)) { + debug_e("[CYW43] Bad chunk header %d\n", res); + return 0; + } + if(chunk.tag != chunkTag) { + debug_e("[CYW43] Bad chunk tag %08x\n", chunk.tag); + return 0; + } + debug_d("[CYW43] Chunk %u bytes\n", chunk.length); + return chunk.length; +} + void cyw43_storage_cleanup() { decompressor.reset(); diff --git a/Sming/Arch/Rp2040/Components/sming-arch/component.mk b/Sming/Arch/Rp2040/Components/sming-arch/component.mk index 95761ca116..1395bfdfa5 100644 --- a/Sming/Arch/Rp2040/Components/sming-arch/component.mk +++ b/Sming/Arch/Rp2040/Components/sming-arch/component.mk @@ -12,6 +12,7 @@ COMPONENT_DEPENDS := \ libc \ rp2040 \ uf2 \ + picotool \ driver \ gdbstub \ spi_flash diff --git a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp index 36917e6ffa..fe25a3566a 100644 --- a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp @@ -13,9 +13,15 @@ #include #include #include +#include + +#ifdef SOC_RP2350 +#include +#include +#else #include #include -#include +#endif #define FLASHCMD_READ_SFDP 0x5a #define FLASHCMD_READ_JEDEC_ID 0x9f @@ -305,11 +311,33 @@ bool flashmem_erase_sector(flash_sector_t sector_id) return true; } +/* + DOUT/DUAL, ///< Two bits per clock for Data, 1-bit for Command and Address + DIO, ///< Two bits per clock for Address and Data, 1-bit for Command + QOUT/QUAD, ///< Four bits per clock for Data, 1-bit for Command and Address + QIO, ///< Four bits per clock for Address and Data, 1-bit for Command +*/ SPIFlashInfo flashmem_get_info() { SPIFlashInfo info{}; info.size = flashmem_get_size_type(); +#ifdef SOC_RP2350 + uint32_t rfmt = qmi_hw->m[0].rfmt; + auto data_width = (rfmt & QMI_M0_RFMT_DATA_WIDTH_BITS) >> QMI_M0_RFMT_DATA_WIDTH_LSB; + auto addr_width = (rfmt & QMI_M0_RFMT_ADDR_WIDTH_BITS) >> QMI_M0_RFMT_ADDR_WIDTH_LSB; + + switch(data_width) { + case 2: + info.mode = (addr_width == QMI_M0_RFMT_ADDR_WIDTH_VALUE_D) ? MODE_DIO : MODE_DOUT; + break; + case 4: + info.mode = (addr_width == QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q) ? MODE_QIO : MODE_QOUT; + break; + default: + info.mode = MODE_SLOW_READ; + } +#else // Flash mode uint32_t ctrlr0 = ssi_hw->ctrlr0; auto ssi_frame_format = (ctrlr0 & SSI_CTRLR0_SPI_FRF_BITS) >> SSI_CTRLR0_SPI_FRF_LSB; @@ -326,6 +354,7 @@ SPIFlashInfo flashmem_get_info() default: info.mode = MODE_SLOW_READ; } +#endif return info; } @@ -376,11 +405,7 @@ uint32_t spi_flash_get_id(void) flash_addr_t flashmem_get_address(const void* memptr) { - auto addr = uint32_t(memptr); - if(addr < XIP_BASE || addr >= XIP_NOALLOC_BASE) { - return 0; - } - return addr - XIP_BASE; + return isFlashPtr(memptr) ? (uint32_t(memptr) - XIP_BASE) : 0; } void flashmem_sfdp_read(uint32_t addr, void* buffer, size_t count) diff --git a/Sming/Arch/Rp2040/Components/uf2/component.mk b/Sming/Arch/Rp2040/Components/uf2/component.mk index a2f33922a9..21d4d52ec4 100644 --- a/Sming/Arch/Rp2040/Components/uf2/component.mk +++ b/Sming/Arch/Rp2040/Components/uf2/component.mk @@ -8,6 +8,11 @@ COMPONENT_DOCFILES := \ DEBUG_VARS += UF2CONV_PY UF2CONV_PY := $(COMPONENT_PATH)/uf2conv.py +ifeq ($(SMING_SOC),rp2350) +UF2_FAMILY := "rp2xxx_absolute" +else +UF2_FAMILY := "rp2040" +endif # Invoke uf2conv utility # $1 -> Parameters @@ -17,19 +22,12 @@ else Uf2Conv = $(PYTHON) $(UF2CONV_PY) $(if $V,--verbose) $1 endif - -# Read flash manufacturer ID and determine actual size -define ReadFlashID - $(info Reading Flash ID) - $(call Uf2Conv,--list --verbose) -endef - # Write file contents to Flash # $1 -> List of `Offset=File` chunks define WriteFlash $(if $1,\ $(info WriteFlash $1) \ - $(call Uf2Conv,--upload $1 --output $(OUT_BASE)/flash.uf2) + $(call Uf2Conv,--family $(UF2_FAMILY) --upload $1 --output $(OUT_BASE)/flash.uf2) ) endef @@ -41,23 +39,3 @@ define VerifyFlash $(info ** NOT IMPLEMENTED **) ) endef - -# Read flash memory into file -# $1 -> `Offset,Size` chunk -# $2 -> Output filename -define ReadFlash - $(info ReadFlash $1,$2) - $(info ** NOT IMPLEMENTED **) -endef - -# Erase a region of Flash -# $1 -> Offset,Size -define EraseFlashRegion - $(info EraseFlashRegion $1) - $(info ** NOT IMPLEMENTED **) -endef - -# Erase flash memory contents -define EraseFlash - $(info ** NOT IMPLEMENTED **) -endef diff --git a/Sming/Arch/Rp2040/Components/uf2/uf2families.json b/Sming/Arch/Rp2040/Components/uf2/uf2families.json index 42b5bbc2a2..26812b97b8 100644 --- a/Sming/Arch/Rp2040/Components/uf2/uf2families.json +++ b/Sming/Arch/Rp2040/Components/uf2/uf2families.json @@ -34,6 +34,11 @@ "short_name": "STM32WL", "description": "ST STM32WLxx" }, + { + "id": "0x22e0d6fc", + "short_name": "RTL8710B", + "description": "Realtek AmebaZ RTL8710B" + }, { "id": "0x2abc77ec", "short_name": "LPC55", @@ -49,6 +54,11 @@ "short_name": "GD32F350", "description": "GD32F350" }, + { + "id": "0x3379CFE2", + "short_name": "RTL8720D", + "description": "Realtek AmebaD RTL8720D" + }, { "id": "0x04240bdf", "short_name": "STM32L5", @@ -64,6 +74,11 @@ "short_name": "MIMXRT10XX", "description": "NXP i.MX RT10XX" }, + { + "id": "0x51e903a8", + "short_name": "XR809", + "description": "Xradiotech 809" + }, { "id": "0x53b80f00", "short_name": "STM32F7", @@ -77,7 +92,7 @@ { "id": "0x57755a57", "short_name": "STM32F4", - "description": "ST STM32F401" + "description": "ST STM32F4xx" }, { "id": "0x5a18069b", @@ -94,16 +109,31 @@ "short_name": "STM32F1", "description": "ST STM32F103" }, + { + "id": "0x621e937a", + "short_name": "NRF52833", + "description": "Nordic NRF52833" + }, { "id": "0x647824b6", "short_name": "STM32F0", "description": "ST STM32F0xx" }, + { + "id": "0x675a40b0", + "short_name": "BK7231U", + "description": "Beken 7231U/7231T" + }, { "id": "0x68ed2b88", "short_name": "SAMD21", "description": "Microchip (Atmel) SAMD21" }, + { + "id": "0x6a82cc42", + "short_name": "BK7251", + "description": "Beken 7251/7252" + }, { "id": "0x6b846188", "short_name": "STM32F3", @@ -114,6 +144,11 @@ "short_name": "STM32F407", "description": "ST STM32F407" }, + { + "id": "0x4e8f1c5d", + "short_name": "STM32H5", + "description": "ST STM32H5xx" + }, { "id": "0x6db66082", "short_name": "STM32H7", @@ -124,6 +159,11 @@ "short_name": "STM32WB", "description": "ST STM32WBxx" }, + { + "id": "0x7b3ef230", + "short_name": "BK7231N", + "description": "Beken 7231N" + }, { "id": "0x7eab61ed", "short_name": "ESP8266", @@ -139,11 +179,21 @@ "short_name": "STM32F407VG", "description": "ST STM32F407VG" }, + { + "id": "0x9fffd543", + "short_name": "RTL8710A", + "description": "Realtek Ameba1 RTL8710A" + }, { "id": "0xada52840", "short_name": "NRF52840", "description": "Nordic NRF52840" }, + { + "id": "0x820d9a5f", + "short_name": "NRF52820", + "description": "Nordic NRF52820_xxAA" + }, { "id": "0xbfdd4eee", "short_name": "ESP32S2", @@ -159,14 +209,144 @@ "short_name": "ESP32C3", "description": "ESP32-C3" }, + { + "id": "0x2b88d29c", + "short_name": "ESP32C2", + "description": "ESP32-C2" + }, + { + "id": "0x332726f6", + "short_name": "ESP32H2", + "description": "ESP32-H2" + }, + { + "id": "0x540ddf62", + "short_name": "ESP32C6", + "description": "ESP32-C6" + }, + { + "id": "0x3d308e94", + "short_name": "ESP32P4", + "description": "ESP32-P4" + }, + { + "id": "0xf71c0343", + "short_name": "ESP32C5", + "description": "ESP32-C5" + }, + { + "id": "0x77d850c4", + "short_name": "ESP32C61", + "description": "ESP32-C61" + }, + { + "id": "0xde1270b7", + "short_name": "BL602", + "description": "Boufallo 602" + }, + { + "id": "0xe08f7564", + "short_name": "RTL8720C", + "description": "Realtek AmebaZ2 RTL8720C" + }, { "id": "0xe48bff56", "short_name": "RP2040", "description": "Raspberry Pi RP2040" }, + { + "id": "0xe48bff57", + "short_name": "RP2XXX_ABSOLUTE", + "description": "Raspberry Pi Microcontrollers: Absolute (unpartitioned) download" + }, + { + "id": "0xe48bff58", + "short_name": "RP2XXX_DATA", + "description": "Raspberry Pi Microcontrollers: Data partition download" + }, + { + "id": "0xe48bff59", + "short_name": "RP2350_ARM_S", + "description": "Raspberry Pi RP2350, Secure Arm image" + }, + { + "id": "0xe48bff5a", + "short_name": "RP2350_RISCV", + "description": "Raspberry Pi RP2350, RISC-V image" + }, + { + "id": "0xe48bff5b", + "short_name": "RP2350_ARM_NS", + "description": "Raspberry Pi RP2350, Non-secure Arm image" + }, { "id": "0x00ff6919", "short_name": "STM32L4", "description": "ST STM32L4xx" + }, + { + "id": "0x9af03e33", + "short_name": "GD32VF103", + "description": "GigaDevice GD32VF103" + }, + { + "id": "0x4f6ace52", + "short_name": "CSK4", + "description": "LISTENAI CSK300x/400x" + }, + { + "id": "0x6e7348a8", + "short_name": "CSK6", + "description": "LISTENAI CSK60xx" + }, + { + "id": "0x11de784a", + "short_name": "M0SENSE", + "description": "M0SENSE BL702" + }, + { + "id": "0x4b684d71", + "short_name": "MaixPlay-U4", + "description": "Sipeed MaixPlay-U4(BL618)" + }, + { + "id": "0x9517422f", + "short_name": "RZA1LU", + "description": "Renesas RZ/A1LU (R7S7210xx)" + }, + { + "id": "0x2dc309c5", + "short_name": "STM32F411xE", + "description": "ST STM32F411xE" + }, + { + "id": "0x06d1097b", + "short_name": "STM32F411xC", + "description": "ST STM32F411xC" + }, + { + "id": "0x72721d4e", + "short_name": "NRF52832xxAA", + "description": "Nordic NRF52832xxAA" + }, + { + "id": "0x6f752678", + "short_name": "NRF52832xxAB", + "description": "Nordic NRF52832xxAB" + }, + { + "id": "0xa0c97b8e", + "short_name": "AT32F415", + "description": "ArteryTek AT32F415" + }, + { + "id": "0x699b62ec", + "short_name": "CH32V", + "description": "WCH CH32V2xx and CH32V3xx" + }, + { + "id": "0x7be8976d", + "short_name": "RA4M1", + "description": "Renesas RA4M1" } -] \ No newline at end of file +] diff --git a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp new file mode 100644 index 0000000000..ba92f59be2 --- /dev/null +++ b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp @@ -0,0 +1,135 @@ +/**** + * 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. + * + * Rp2040/Core/HardwarePWM.cpp + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Note on use of divisor + * ---------------------- + * + * Divisor is 8:4 fractional value, so 1 <= int <= 255, 0 <= frac <= 15 + * Simplest way to use full range is to factor calculations by 16. + * + * Using default CSR_PH_CORRECT=0: + * + * F_PWM = 16 * F_SYS / (TOP + 1) / DIV + * + */ + +#define PWM_FREQ_DEFAULT 1000 + +HardwarePWM::HardwarePWM(const uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) +{ + assert(noOfPins > 0 && noOfPins <= PWM_CHANNEL_NUM_MAX); + noOfPins = std::min(uint8_t(PWM_CHANNEL_NUM_MAX), noOfPins); + std::copy_n(pins, noOfPins, channels); + setPeriod(1e6 / PWM_FREQ_DEFAULT); + + for(unsigned i = 0; i < noOfPins; ++i) { + auto pin = channels[i]; + gpio_set_function(pin, GPIO_FUNC_PWM); + gpio_set_dir(pin, GPIO_OUT); + } +} + +HardwarePWM::~HardwarePWM() +{ + for(unsigned i = 0; i < channel_count; ++i) { + auto slice_num = pwm_gpio_to_slice_num(channels[i]); + pwm_set_enabled(slice_num, false); + } +} + +uint32_t HardwarePWM::getDutyChan(uint8_t chan) const +{ + if(chan >= channel_count) { + return 0; + } + auto pin = channels[chan]; + auto slice_num = pwm_gpio_to_slice_num(pin); + auto value = pwm_hw->slice[slice_num].cc; + value >>= pwm_gpio_to_channel(pin) ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB; + return value & 0xffff; +} + +bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool) +{ + if(chan >= channel_count) { + return false; + } + auto pin = channels[chan]; + duty = std::min(duty, maxduty); + pwm_set_gpio_level(pin, duty); + return true; +} + +uint32_t HardwarePWM::getPeriod() const +{ + // All channels configured with same clock + auto slice_num = pwm_gpio_to_slice_num(channels[0]); + uint32_t top = pwm_hw->slice[slice_num].top; + uint32_t div = pwm_hw->slice[slice_num].div; + return muldiv(62500ULL, (top + 1) * div, clock_get_hz(clk_sys)); +} + +void HardwarePWM::setPeriod(uint32_t period) +{ + const uint32_t topMax{0xffff}; + const uint32_t divMin{0x10}; // 1.0 + const uint32_t divMax{0xfff}; // INT + FRAC + auto sysFreq = clock_get_hz(clk_sys); + // Calculate divisor assuming maximum value for TOP: ensure value is rounded UP + uint32_t div = ((uint64_t(period) * sysFreq / 62500) + topMax) / (topMax + 1); + uint32_t top; + if(div > divMax) { + // Period too big, set to maximum + top = topMax; + div = divMax; + } else { + if(div < divMin) { + // Period is very small, set div to minimum + div = divMin; + } + top = (uint64_t(period) * sysFreq / 62500 / div) - 1; + } + + debug_d("[PWM] %s(%u): div %u, top %u", __FUNCTION__, period, div, top); + + pwm_config cfg = pwm_get_default_config(); + cfg.div = div; + cfg.top = top; + + for(unsigned i = 0; i < channel_count; ++i) { + auto pin = channels[i]; + auto slice_num = pwm_gpio_to_slice_num(pin); + pwm_init(slice_num, &cfg, true); + } + + maxduty = top; +} + +void HardwarePWM::update() +{ + // Not implemented +} + +uint32_t HardwarePWM::getFrequency(uint8_t pin) const +{ + auto slice_num = pwm_gpio_to_slice_num(pin); + auto top = pwm_hw->slice[slice_num].top; + auto div = pwm_hw->slice[slice_num].div; + return 16UL * clock_get_hz(clk_sys) / (div * (top + 1)); +} diff --git a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo b/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo deleted file mode 100644 index 6def2d36fd..0000000000 --- a/Sming/Arch/Rp2040/Core/HardwarePWM.cpp.todo +++ /dev/null @@ -1,136 +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. - * - * HardwarePWM.cpp - * - * Original Author: https://github.com/hrsavla - * - * This HardwarePWM library enables Sming framework user to use ESP SDK PWM API - * Period of PWM is fixed to 1000us / Frequency = 1khz - * Duty at 100% = 22222. Duty at 0% = 0 - * You can use function setPeriod() to change frequency/period. - * Calculate the max duty as per the formulae give in ESP8266 SDK - * Max Duty = (Period * 1000) / 45 - * - * PWM can be generated on up to 8 pins (ie All pins except pin 16) - * Created on August 17, 2015, 2:27 PM - * - * See also ESP8266 Technical Reference, Chapter 12: - * http://espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf - * - */ - -#include -#include "ESP8266EX.h" - -#include - -#define PERIOD_TO_MAX_DUTY(x) (x * 25) - -HardwarePWM::HardwarePWM(uint8* pins, uint8 no_of_pins) : channel_count(no_of_pins) -{ - if(no_of_pins > 0) { - uint32 io_info[PWM_CHANNEL_NUM_MAX][3]; // pin information - uint32 pwm_duty_init[PWM_CHANNEL_NUM_MAX]; // pwm duty - for(uint8 i = 0; i < no_of_pins; i++) { - io_info[i][0] = EspDigitalPins[pins[i]].mux; - io_info[i][1] = EspDigitalPins[pins[i]].gpioFunc; - io_info[i][2] = EspDigitalPins[pins[i]].id; - pwm_duty_init[i] = 0; // Start with zero output - channels[i] = pins[i]; - } - const int initial_period = 1000; - pwm_init(initial_period, pwm_duty_init, no_of_pins, io_info); - update(); - maxduty = PERIOD_TO_MAX_DUTY(initial_period); // for period of 1000 - } -} - -HardwarePWM::~HardwarePWM() -{ - // There is no function in the SDK to stop PWM output, yet. -} - -/* Function Name: getChannel - * Description: This function is used to get channel number for given pin - * Parameters: pin - Esp8266 pin number - */ -uint8 HardwarePWM::getChannel(uint8 pin) -{ - for(uint8 i = 0; i < channel_count; i++) { - if(channels[i] == pin) { - //debugf("getChannel %d is %d", pin, i); - return i; - } - } - //debugf("getChannel: can't find pin %d", pin); - return PWM_BAD_CHANNEL; -} - -/* Function Name: getDutyChan - * Description: This function is used to get the duty cycle number for a given channel - * Parameters: chan -Esp8266 channel number - */ -uint32 HardwarePWM::getDutyChan(uint8 chan) -{ - if(chan == PWM_BAD_CHANNEL) { - return 0; - } else { - return pwm_get_duty(chan); - } -} - -/* Function Name: setDutyChan - * Description: This function is used to set the pwm duty cycle for a given channel. If parameter 'update' is false - * then you have to call update() later to update duties. - * Parameters: chan - channel number - * duty - duty cycle value - * update - update PWM output - */ -bool HardwarePWM::setDutyChan(uint8 chan, uint32 duty, bool update) -{ - if(chan == PWM_BAD_CHANNEL) { - return false; - } else if(duty <= maxduty) { - pwm_set_duty(duty, chan); - if(update) { - this->update(); - } - return true; - } else { - debugf("Duty cycle value too high for current period."); - return false; - } -} - -/* Function Name: getPeriod - * Description: This function is used to get Period of PWM. - * Period / frequency will remain same for all pins. - * - */ -uint32 HardwarePWM::getPeriod() -{ - return pwm_get_period(); -} - -/* Function Name: setPeriod - * Description: This function is used to set Period of PWM. - * Period / frequency will remain same for all pins. - */ -void HardwarePWM::setPeriod(uint32 period) -{ - maxduty = PERIOD_TO_MAX_DUTY(period); - pwm_set_period(period); - update(); -} - -/* Function Name: update - * Description: This function is used to actually update the PWM. - */ -void HardwarePWM::update() -{ - pwm_start(); -} diff --git a/Sming/Arch/Rp2040/Platform/RTC.cpp b/Sming/Arch/Rp2040/Platform/RTC.cpp index 07a317b173..07c14c7ed8 100644 --- a/Sming/Arch/Rp2040/Platform/RTC.cpp +++ b/Sming/Arch/Rp2040/Platform/RTC.cpp @@ -9,66 +9,62 @@ ****/ #include -#include -#include #include - -extern "C" int settimeofday(const struct timeval*, const struct timezone*); +#include RtcClass RTC; -#define NS_PER_SECOND 1000000000 +#define NS_PER_SECOND 1'000'000'000 +#define US_PER_SECOND 1'000'000 + +RtcClass::RtcClass() = default; -void system_init_rtc() +namespace { - rtc_init(); - datetime_t t{.year = 1970, .month = 1, .day = 1}; - rtc_set_datetime(&t); +int64_t epoch_sys_time_us; } -RtcClass::RtcClass() = default; - -uint64_t RtcClass::getRtcNanoseconds() +extern "C" int _gettimeofday(struct timeval* tv, void*) { - return uint64_t(getRtcSeconds()) * NS_PER_SECOND; + if(tv) { + auto us_since_epoch = epoch_sys_time_us + time_us_64(); + *tv = { + .tv_sec = time_t(us_since_epoch / US_PER_SECOND), + .tv_usec = suseconds_t(us_since_epoch % US_PER_SECOND), + }; + } + return 0; } -uint32_t RtcClass::getRtcSeconds() +extern "C" int settimeofday(const struct timeval* tv, const struct timezone*) { - datetime_t t; - if(!rtc_get_datetime(&t)) { - return 0; + if(tv) { + auto us_since_epoch = tv->tv_sec * US_PER_SECOND + tv->tv_usec; + epoch_sys_time_us = us_since_epoch - time_us_64(); } + return 0; +} - DateTime dt; - dt.setTime(t.sec, t.min, t.hour, t.day, t.month - 1, t.year); +uint64_t RtcClass::getRtcNanoseconds() +{ + return uint64_t(epoch_sys_time_us + time_us_64()) * 1000ULL; +} - return time_t(dt); +uint32_t RtcClass::getRtcSeconds() +{ + return (epoch_sys_time_us + time_us_64()) / US_PER_SECOND; } bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) { - return setRtcSeconds(nanoseconds / NS_PER_SECOND); + auto us_since_epoch = nanoseconds / 1000; + epoch_sys_time_us = us_since_epoch - get_absolute_time(); + return true; } bool RtcClass::setRtcSeconds(uint32_t seconds) { - struct timeval tv { - seconds - }; - settimeofday(&tv, nullptr); - - DateTime dt{seconds}; - - datetime_t t = { - .year = int16_t(dt.Year), - .month = int8_t(1 + dt.Month), - .day = int8_t(dt.Day), - .dotw = int8_t(dt.DayofWeek), - .hour = int8_t(dt.Hour), - .min = int8_t(dt.Minute), - .sec = int8_t(dt.Second), - }; - - return rtc_set_datetime(&t); + auto us_since_epoch = int64_t(seconds) * US_PER_SECOND; + epoch_sys_time_us = us_since_epoch - time_us_64(); + return true; } diff --git a/Sming/Arch/Rp2040/README.rst b/Sming/Arch/Rp2040/README.rst index 3897680c39..cf7fc1ae97 100644 --- a/Sming/Arch/Rp2040/README.rst +++ b/Sming/Arch/Rp2040/README.rst @@ -1,13 +1,15 @@ -Sming RP2040 Architecture -========================= +Sming Raspberry Pi Pico Architecture +==================================== .. highlight:: bash -Support building Sming for the `Raspberry Pi RP2040 SOC -`__. +Support building Sming for the `Raspberry Pi Pico-series Microcontrollers `__. +At time of writing this includes both RP2040 and RP2350 devices. -Testing so far has been limited to the Rasperry Pi Pico, but there are lots of other boards available. -Configure this using the :envvar:`PICO_BOARD` setting. The default is ``pico`` (or ``pico_w`` if networking is enabled). +Testing has been limited to the Rasperry Pi Pico development boards, but there are lots of others available. +Configure this using the :envvar:`PICO_BOARD` setting. +The default is ``pico`` (or ``pico_w`` if networking is enabled). +Support for the new ``pico2`` boards is provided using :envvar:`SMING_SOC=rp2350 `. You can find the `full list here `__. Special mention to the arduino-pico project https://github.com/earlephilhower/arduino-pico. @@ -41,7 +43,8 @@ The following features are tested and working: - USB supported using the :library:`USB` library, both host and device modes. - HardwareSPI via :library:`HardwareSPI` for fully asynchronous SPI communications (host mode only). -Not yet implemented: +Limited or no support is provided for the following items. +In many cases best use of the hardware is made using the Pico SDK API directly. PWM Hardware can drive up to 16 outputs and measure input frequency/duty cycle. @@ -51,13 +54,14 @@ I2C RTC Can wake from deep sleep but requires an external clock (e.g. 32kHz crystal) and appropriate API. (Setting and reading the time is implemented.) + Note that the RP2350 does not have an RTC. Sming uses the Always-On timer api to support both devices. Low-power modes Deep sleep / suspend / power-saving PIO (Programmable I/O) - A killer feature for the RP2040. + A killer feature for the RP2 series. Uses range from simple glue logic to I2S, etc. Crash/exception handling & serial debugging - RP2040 supports JTAG debugging but requires extra hardware. + RP2 devices support JTAG debugging but requires extra hardware. Serial debugging is often enough and easier to set up. Requires GDB stub plus implementing crash handler callbacks, etc. Multi-boot / OTA updates. @@ -66,8 +70,13 @@ Multi-boot / OTA updates. Adding RP2040 support to rBoot may work, however the Pico typically has only 2MByte flash which is quite restrictive. It is also necessary to compile images at different addresses as there is no windowed XIP (eXecute In Place) capability. See :library:`FlashIP` library for a basic method of OTA. + Note that the Pico2 boards have 4MByte flash and partition table support which requires integrating with Sming. Bluetooth - The SDK supports this but has not yet been integrated into Sming. + The SDK supports bluetooth for the CYW43439 BT/WiFi SoC which the Pico-W boards (and other) use. + This has not yet been integrated into Sming. +RISCV (RP2350) + Sming builds ARM code but these devices also support RISCV. + This will require an additional toolchain and compile options. Installation @@ -144,10 +153,7 @@ Once the file has finished sending the RP2040 reboots itself into normal operati The RP2040 can also be programmed via JTAG debugging but this requires additional hardware and setup. -.. note:: - - The RP2040 bootloader does not include support for reading flash memory via mass storage, - so commands such as ``make verifyflash`` won't work at present. +Commands such as ``make readmap`` use :component-rp2040:`picotool` and require the device to be in BOOT mode. Dual-core support diff --git a/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp b/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp index 80280f3547..1b226b3060 100644 --- a/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Rp2040/Services/Profiling/TaskStat.cpp @@ -15,7 +15,7 @@ namespace Profiling struct TaskStat::Info { }; -TaskStat::TaskStat(Print& out) : out(out) +TaskStat::TaskStat(Print& out) : out(&out) { } @@ -23,7 +23,7 @@ TaskStat::~TaskStat() = default; bool TaskStat::update() { - out.println("[TaskStat] Not Implemented"); + out->println("[TaskStat] Not Implemented"); return false; } diff --git a/Sming/Arch/Rp2040/app.mk b/Sming/Arch/Rp2040/app.mk index 97bd3ab590..e1c19d9882 100644 --- a/Sming/Arch/Rp2040/app.mk +++ b/Sming/Arch/Rp2040/app.mk @@ -8,9 +8,19 @@ LDFLAGS += \ -Wl,--build-id=none \ --specs=nosys.specs \ - -mcpu=cortex-m0plus \ -mthumb +ifeq ($(SMING_SOC),rp2350) +LDFLAGS += \ + -mcpu=cortex-m33 \ + -march=armv8-m.main+fp+dsp \ + -mfloat-abi=softfp +else +LDFLAGS += \ + -mcpu=cortex-m0plus \ + -march=armv6-m +endif + ifneq ($(COMPILER_VERSION_MAJOR),10) LDFLAGS += -Wl,--no-warn-rwx-segments endif diff --git a/Sming/Arch/Rp2040/build.mk b/Sming/Arch/Rp2040/build.mk index d3ccb6622f..08d421e887 100644 --- a/Sming/Arch/Rp2040/build.mk +++ b/Sming/Arch/Rp2040/build.mk @@ -7,11 +7,27 @@ CPPFLAGS += \ -DARCH_RP2040 \ -DARDUINO_ARCH_RP2040 \ - -march=armv6-m \ - -mcpu=cortex-m0plus \ + -DPICO_NO_HARDWARE=0 \ + -DPICO_ON_DEVICE=1 \ + -DPICO_32BIT=1 \ -mthumb \ -nostdlib +ifeq ($(SMING_SOC),rp2350) +RP_VARIANT = rp2350 +CPPFLAGS += \ + -mcpu=cortex-m33 \ + -march=armv8-m.main+fp+dsp \ + -mfloat-abi=softfp \ + -mcmse \ + -DPICO_RP2350 +else +RP_VARIANT = rp2040 +CPPFLAGS += \ + -mcpu=cortex-m0plus \ + -DPICO_RP2040 +endif + CXXFLAGS += \ -fno-threadsafe-statics \ -fno-use-cxa-atexit diff --git a/Sming/Arch/Rp2040/rp2350-pindefs.txt b/Sming/Arch/Rp2040/rp2350-pindefs.txt new file mode 100644 index 0000000000..e8940b933e --- /dev/null +++ b/Sming/Arch/Rp2040/rp2350-pindefs.txt @@ -0,0 +1,52 @@ +[io_mux] +gpio f0 f1 f2 f3 f4 ff5 ff6 ff7 ff8 f9 f10 f11 notes +0 - SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 PIO2 XIP_CS1n USB_OVCUR_DET - +1 - SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 PIO2 TRACECLK USB_VBUS_DET - +2 - SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 PIO2 TRACEDATA0 USB_VBUS_EN UART0_TX +3 - SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 PIO2 TRACEDATA1 USB_OVCUR_DET UART0_RX +4 - SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 PIO2 TRACEDATA2 USB_VBUS_DET - +5 - SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 PIO2 TRACEDATA3 USB_VBUS_EN - +6 - SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_TX +7 - SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_RX +8 - SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_EN - +9 - SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +10 - SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_TX +11 - SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_RX +12 HSTX SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN0 USB_OVCUR_DET - +13 HSTX SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT0 USB_VBUS_DET - +14 HSTX SPI1_SCK UART0_CTS I2C1_SDA PWM7_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN1 USB_VBUS_EN UART0_TX +15 HSTX SPI1_TX UART0_RTS I2C1_SCL PWM7_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT1 USB_OVCUR_DET UART0_RX +16 HSTX SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +17 HSTX SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +18 HSTX SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART0_TX +19 HSTX SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_DET UART0_RX +20 - SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN0 USB_VBUS_EN - +21 - SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT0 USB_OVCUR_DET - +22 - SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 PIO2 CLOCK_GPIN1 USB_VBUS_DET UART1_TX +23 - SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT1 USB_VBUS_EN UART1_RX +24 - SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 PIO2 CLOCK_GPOUT2 USB_OVCUR_DET - +25 - SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 PIO2 CLOCK_GPOUT3 USB_VBUS_DET - +26 - SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_TX +27 - SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_RX +28 - SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +29 - SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - + +# IOs 30 through 47 are QFN-80 only +30 - SPI1_SCK UART0_CTS I2C1_SDA PWM7_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART0_TX +31 - SPI1_TX UART0_RTS I2C1_SCL PWM7_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_RX +32 - SPI0_RX UART0_TX I2C0_SDA PWM8_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +33 - SPI0_CSn UART0_RX I2C0_SCL PWM8_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +34 - SPI0_SCK UART0_CTS I2C1_SDA PWM9_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_TX +35 - SPI0_TX UART0_RTS I2C1_SCL PWM9_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART0_RX +36 - SPI0_RX UART1_TX I2C0_SDA PWM10_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +37 - SPI0_CSn UART1_RX I2C0_SCL PWM10_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +38 - SPI0_SCK UART1_CTS I2C1_SDA PWM11_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN UART1_TX +39 - SPI0_TX UART1_RTS I2C1_SCL PWM11_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_RX +40 - SPI1_RX UART1_TX I2C0_SDA PWM8_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET - +41 - SPI1_CSn UART1_RX I2C0_SCL PWM8_B SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +42 - SPI1_SCK UART1_CTS I2C1_SDA PWM9_A SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET UART1_TX +43 - SPI1_TX UART1_RTS I2C1_SCL PWM9_B SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART1_RX +44 - SPI1_RX UART0_TX I2C0_SDA PWM10_A SIO PIO0 PIO1 PIO2 - USB_VBUS_EN - +45 - SPI1_CSn UART0_RX I2C0_SCL PWM10_B SIO PIO0 PIO1 PIO2 - USB_OVCUR_DET - +46 - SPI1_SCK UART0_CTS I2C1_SDA PWM11_A SIO PIO0 PIO1 PIO2 - USB_VBUS_DET UART0_TX +47 - SPI1_TX UART0_RTS I2C1_SCL PWM11_B SIO PIO0 PIO1 PIO2 XIP_CS1n USB_VBUS_EN UART0_RX diff --git a/Sming/Arch/Rp2040/rp2350-soc.json b/Sming/Arch/Rp2040/rp2350-soc.json new file mode 100644 index 0000000000..bbd9c6cfe8 --- /dev/null +++ b/Sming/Arch/Rp2040/rp2350-soc.json @@ -0,0 +1,62 @@ +{ + "variant": "rp2350", + "name": "RP2350", + "peripherals": { + "CLOCK": { + "sigmask": "{name}.+" + }, + "SPI[0-1]": { + "sigmask": "{name}.+" + }, + "UART0": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART0_TX", + 0 + ], + "RXD": [ + "UART0_RX", + 1 + ] + } + }, + "UART1": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART1_TX", + 4 + ], + "RXD": [ + "UART1_RX", + 5 + ] + } + }, + "I2C[0-1]": { + "sigmask": "{name}.+" + }, + "PIO[0-2]": { + "sigmask": "{name}.+" + }, + "PWM[0-9]": { + "sigmask": "{name}.+" + }, + "SIO": { + "sigmask": "{name}.+" + }, + "USB": { + "sigmask": "{name}.+" + }, + "HSTX": { + "sigmask": "{name}" + }, + "XIP": { + "sigmask": "{name}.+" + }, + "TRACE": { + "sigmask": "{name}.+" + } + } +} \ No newline at end of file diff --git a/Sming/Components/FlashString b/Sming/Components/FlashString index 79eb493406..ee011c39a8 160000 --- a/Sming/Components/FlashString +++ b/Sming/Components/FlashString @@ -1 +1 @@ -Subproject commit 79eb493406c3138cb20abf92d8afd5e357f4f715 +Subproject commit ee011c39a8aa75fefd6dd6f5eb48deb8d7feda4b diff --git a/Sming/Components/IFS b/Sming/Components/IFS index e57c5c9359..50bd7363e4 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit e57c5c93591fa062fa879bd61cfd13d2b104b529 +Subproject commit 50bd7363e4373a3c2a59f7dae695f6f93f5aa51b diff --git a/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp b/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp index 8ff964416b..7d23a2e85b 100644 --- a/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp +++ b/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp @@ -25,6 +25,7 @@ DM9051PhyFactory DM9051Service::dm9051PhyFactory; bool DM9051Service::begin(const Config& config) { esp_netif_init(); + esp_event_loop_create_default(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&netif_cfg); diff --git a/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp b/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp index 4410f52ade..3a5c719c66 100644 --- a/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp +++ b/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp @@ -25,6 +25,7 @@ W5500PhyFactory W5500Service::w5500PhyFactory; bool W5500Service::begin(const Config& config) { esp_netif_init(); + esp_event_loop_create_default(); esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&netif_cfg); diff --git a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp index 0ee9de2684..2b69133aaf 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/AccessPointImpl.cpp @@ -57,7 +57,7 @@ void AccessPointImpl::enable(bool enabled, bool save) } } ESP_ERROR_CHECK(esp_wifi_set_storage(save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); - ESP_ERROR_CHECK(esp_wifi_set_mode((wifi_mode_t)mode)); + ESP_ERROR_CHECK(esp_wifi_set_mode(mode)); } bool AccessPointImpl::isEnabled() const @@ -88,10 +88,13 @@ bool AccessPointImpl::config(const String& ssid, String password, WifiAuthMode m config.ap.authmode = (wifi_auth_mode_t)mode; config.ap.max_connection = 8; + bool enabled = isEnabled(); enable(true, false); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &config)); - ESP_ERROR_CHECK(esp_wifi_start()); + if(enabled) { + System.queueCallback(esp_wifi_start); + } return true; } @@ -192,9 +195,5 @@ std::unique_ptr 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 1c4af61451..10e1569164 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -75,47 +75,58 @@ 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) { wifi_mode_t mode; @@ -394,36 +405,34 @@ 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]; - uint16_t ap_count{0}; + memset(ap_info, 0, sizeof(ap_info)); ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); - ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count)); + // TODO: Handle hidden APs - for(unsigned i = 0; (i < event->number) && (i < ap_count); i++) { + for(unsigned i = 0; i < number; i++) { list.addElement(new BssInfoImpl(&ap_info[i])); } station.scanCompletedCallback(true, list); @@ -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/Network/src/Network/DnsServer.cpp b/Sming/Components/Network/src/Network/DnsServer.cpp index 5479e5e072..3e8c8e24ad 100644 --- a/Sming/Components/Network/src/Network/DnsServer.cpp +++ b/Sming/Components/Network/src/Network/DnsServer.cpp @@ -84,9 +84,6 @@ void DnsServer::onReceive(pbuf* buf, IpAddress remoteIP, uint16_t remotePort) } unsigned requestLen = pbuf_copy_partial(buf, buffer, buf->tot_len, 0); - if(requestLen != buf->tot_len) { - return; - } debug_hex(DBG, "< DNS", buffer, requestLen); @@ -97,8 +94,6 @@ void DnsServer::onReceive(pbuf* buf, IpAddress remoteIP, uint16_t remotePort) } delete[] buffer; - - UdpConnection::onReceive(buf, remoteIP, remotePort); } size_t DnsServer::processQuestion(char* buffer, size_t requestLen) diff --git a/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp b/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp index e5cd17aa1d..27923700a4 100644 --- a/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp +++ b/Sming/Components/Network/src/Network/Http/HttpBodyParser.cpp @@ -16,6 +16,7 @@ #include "HttpBodyParser.h" #include +#include /* * Content is received in chunks which we need to reassemble into name=value pairs. @@ -103,11 +104,11 @@ size_t formUrlParser(HttpRequest& request, const char* at, int length) size_t bodyToStringParser(HttpRequest& request, const char* at, int length) { - auto data = static_cast(request.args); + auto data = static_cast(request.args); if(length == PARSE_DATASTART) { delete data; - data = new String(); + data = new MemoryDataStream(); request.args = data; return 0; } @@ -118,15 +119,10 @@ size_t bodyToStringParser(HttpRequest& request, const char* at, int length) } if(length == PARSE_DATAEND || length < 0) { - request.setBody(std::move(*data)); - delete data; + request.setBody(data); request.args = nullptr; return 0; } - if(!data->concat(at, length)) { - return 0; - } - - return length; + return data->write(at, length); } diff --git a/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp b/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp index be7e8896a7..0d9bd1bc7b 100644 --- a/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp +++ b/Sming/Components/Network/src/Network/Mqtt/MqttClient.cpp @@ -199,11 +199,16 @@ bool MqttClient::setWill(const String& topic, const String& message, uint8_t fla bool MqttClient::connect(const Url& url, const String& clientName) { this->url = url; + bool useSsl{url.Scheme == URI_SCHEME_MQTT_SECURE}; if(!useSsl && url.Scheme != URI_SCHEME_MQTT) { debug_e("Only mqtt and mqtts protocols are allowed"); return false; } + if(clientName == "") { + debug_e("clientName cannot be empty"); + return false; + } if(getConnectionState() != eTCS_Ready) { close(); diff --git a/Sming/Components/Network/src/Network/SmtpClient.cpp b/Sming/Components/Network/src/Network/SmtpClient.cpp index 477436c6d5..0bad31c808 100644 --- a/Sming/Components/Network/src/Network/SmtpClient.cpp +++ b/Sming/Components/Network/src/Network/SmtpClient.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -296,6 +297,12 @@ void SmtpClient::sendMailHeaders(MailMessage* mail) mail->stream = std::make_unique(mail->stream.release()); } + if(!mail->headers.contains(F("Message-ID"))) { + Uuid uuid; + uuid.generate(); + mail->headers[F("Message-ID")] = "<" + uuid.toString() + "@" + url.Host + ">"; + } + if(!mail->attachments.isEmpty()) { MultipartStream* mStream = new MultipartStream(MultipartStream::Producer(&SmtpClient::multipartProducer, this)); MultipartStream::BodyPart text; 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/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 7069c55c78..98c6b9cf5a 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -281,7 +281,7 @@ class Partition bool read(storage_size_t offset, void* dst, size_t size); template - typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) + typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) { return read(offset, &value, sizeof(value)); } diff --git a/Sming/Components/malloc_count/component.mk b/Sming/Components/malloc_count/component.mk index 7089c0962f..abc46923f8 100644 --- a/Sming/Components/malloc_count/component.mk +++ b/Sming/Components/malloc_count/component.mk @@ -21,7 +21,6 @@ MC_WRAP_FUNCS := \ strdup ifeq ($(SMING_ARCH),Esp8266) MC_WRAP_FUNCS += \ - realloc \ pvPortMalloc \ pvPortCalloc \ pvPortRealloc \ @@ -29,6 +28,11 @@ MC_WRAP_FUNCS += \ pvPortZallocIram \ vPortFree endif +ifeq ($(SMING_ARCH)$(UNAME),HostWindows) +MC_WRAP_FUNCS += \ + __mingw_realloc \ + __mingw_free +endif EXTRA_LDFLAGS := $(call UndefWrap,$(MC_WRAP_FUNCS)) diff --git a/Sming/Components/malloc_count/malloc_count.cpp b/Sming/Components/malloc_count/malloc_count.cpp index 6766a8e46b..5f50e85b0a 100644 --- a/Sming/Components/malloc_count/malloc_count.cpp +++ b/Sming/Components/malloc_count/malloc_count.cpp @@ -364,6 +364,11 @@ extern "C" void WRAP(free)(void*) __attribute__((alias("mc_free"))); using namespace MallocCount; +#ifdef __WIN32 +extern "C" void* WRAP(__mingw_realloc)(void*, size_t) __attribute__((alias("mc_realloc"))); +extern "C" void WRAP(__mingw_free)(void*) __attribute__((alias("mc_free"))); +#endif + #ifdef ARCH_ESP8266 extern "C" void* WRAP(pvPortMalloc)(size_t) __attribute__((alias("mc_malloc"))); @@ -373,7 +378,7 @@ extern "C" void* WRAP(pvPortZalloc)(size_t) __attribute__((alias("mc_zalloc"))); extern "C" void* WRAP(pvPortZallocIram)(size_t) __attribute__((alias("mc_zalloc"))); extern "C" void WRAP(vPortFree)(void*) __attribute__((alias("mc_free"))); -#else +#elif !defined(ARCH_RP2040) void* operator new(size_t size) { diff --git a/Sming/Core/Data/Buffer/PrintBuffer.cpp b/Sming/Core/Data/Buffer/PrintBuffer.cpp new file mode 100644 index 0000000000..33b63a1e8f --- /dev/null +++ b/Sming/Core/Data/Buffer/PrintBuffer.cpp @@ -0,0 +1,43 @@ +/**** + * 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. + * + * PrintBuffer.cpp + * + ****/ + +#include "PrintBuffer.h" + +size_t BasePrintBuffer::write(uint8_t c) +{ + buffer[writeOffset++] = c; + if(writeOffset == bufferSize) { + flush(); + } + return 1; +} + +size_t BasePrintBuffer::write(const uint8_t* data, size_t size) +{ + size_t written{0}; + while(size != 0) { + auto copySize = std::min(bufferSize - writeOffset, size); + memcpy(&buffer[writeOffset], data, copySize); + writeOffset += copySize; + written += copySize; + data += copySize; + size -= copySize; + if(writeOffset == bufferSize) { + flush(); + } + } + return written; +} + +void BasePrintBuffer::flush() +{ + output.write(buffer, writeOffset); + writeOffset = 0; +} diff --git a/Sming/Core/Data/Buffer/PrintBuffer.h b/Sming/Core/Data/Buffer/PrintBuffer.h new file mode 100644 index 0000000000..09d683d1b9 --- /dev/null +++ b/Sming/Core/Data/Buffer/PrintBuffer.h @@ -0,0 +1,155 @@ +/**** + * 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. + * + * PrintBuffer.h + * + ****/ + +#pragma once + +#include +#include + +/** + * @brief Generic write-through buffer class + * @ingroup stream + * @note Call flush() at end of write operation to ensure all data is output + * This is done automatically when the buffer is destroyed. + */ +class BasePrintBuffer : public Print +{ +public: + /** + * @brief Create buffer + * @param output Destination stream + * @param buffer buffer to use + * @param size Size of buffer + */ + BasePrintBuffer(Print& output, uint8_t buffer[], size_t bufferSize) + : output(output), buffer(buffer), bufferSize(bufferSize) + { + } + + ~BasePrintBuffer() + { + flush(); + } + + size_t write(uint8_t c) override; + + size_t write(const uint8_t* data, size_t size) override; + + /** + * @brief Write any buffered content to output + */ + void flush(); + +private: + Print& output; + uint8_t* buffer; + size_t bufferSize; + size_t writeOffset{}; +}; + +/** + * @brief Write-through buffer using stack only + * @tparam size Size of buffer + * + * Example usage: + * + * FileStream stream("file.txt", File::ReadWrite); + * { + * StaticPrintBuffer<256> buffer(stream); + * writeSomeData(buffer); + * } // Buffer flushed and destroyed when it goes out of scope + */ +template class StaticPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination + */ + StaticPrintBuffer(Print& output) : BasePrintBuffer(output, buffer, size) + { + } + +private: + uint8_t buffer[size]; +}; + +/** + * @brief Write-through buffer using heap storage + * + * Example usage: + * + * FileStream stream("file.txt", File::ReadWrite); + * { + * HeapPrintBuffer buffer(stream, 512); + * writeSomeData(buffer); + * } // Buffer flushed and destroyed when it goes out of scope + */ +class HeapPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination + * @param size Buffer size + */ + HeapPrintBuffer(Print& output, size_t size) : HeapPrintBuffer(output, new uint8_t[size], size) + { + } + +private: + HeapPrintBuffer(Print& output, uint8_t* buffer, size_t size) : BasePrintBuffer(output, buffer, size), buffer(buffer) + { + } + + std::unique_ptr buffer; +}; + +/** + * @brief Write-through buffer using heap storage and owned stream pointer + * + * Example usage: + * + * auto stream = std::make_unique("file.txt", File::ReadWrite); + * auto bufferedStream = new DynamicPrintBuffer(std::move(stream), 512); + * + * // write to bufferedStream as required via callbacks, etc. + * ... + * + * // This destroys both buffer *and* the file stream + * delete bufferedStream; + */ +class DynamicPrintBuffer : public BasePrintBuffer +{ +public: + /** + * @brief Construct a stack-based buffer + * @param output Print destination, will take ownership of this + * @param size Buffer size + */ + DynamicPrintBuffer(std::unique_ptr&& output, size_t size) + : DynamicPrintBuffer(output.release(), new uint8_t[size], size) + { + } + + ~DynamicPrintBuffer() + { + flush(); + } + +private: + DynamicPrintBuffer(Print* output, uint8_t* buffer, size_t size) + : BasePrintBuffer(*output, buffer, size), output(output), buffer(buffer) + { + } + + std::unique_ptr output; + std::unique_ptr buffer; +}; diff --git a/Sming/Core/Data/Format/Formatter.cpp b/Sming/Core/Data/Format/Formatter.cpp new file mode 100644 index 0000000000..546900a25a --- /dev/null +++ b/Sming/Core/Data/Format/Formatter.cpp @@ -0,0 +1,110 @@ +/**** + * 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. + * + * Formatter.cpp + * + * @author mikee47 Aug 2024 + * + ****/ + +#include "Formatter.h" + +namespace Format +{ +/** + * @brief Get character used for standard escapes + * @param c Code to be escaped + * @param options + * @retval char Corresponding character, NUL if there isn't a standard escape + */ +char escapeChar(char c, Options options) +{ + switch(c) { + case '\0': + return options[Option::unicode] ? '\0' : '0'; + case '\"': + return options[Option::doublequote] ? c : '\0'; + case '\'': + return options[Option::singlequote] ? c : '\0'; + case '\\': + return options[Option::backslash] ? c : '\0'; + case '\a': + return 'a'; + case '\b': + return 'b'; + case '\f': + return 'f'; + case '\n': + return 'n'; + case '\r': + return 'r'; + case '\t': + return 't'; + case '\v': + return 'v'; + default: + return '\0'; + } +} + +unsigned escapeControls(String& value, Options options) +{ + // Count number of extra characters we'll need to insert + unsigned extra{0}; + for(auto& c : value) { + if(escapeChar(c, options)) { + extra += 1; // "\" + } else if(options[Option::unicode]) { + if(uint8_t(c) < 0x20 || (c & 0x80)) { + extra += 5; // "\uNNNN" + } + } else if(uint8_t(c) < 0x20) { + extra += 3; // "\xnn" + } else if((c & 0x80) && options[Option::utf8]) { + // Characters such as £ (0xa3) are escaped to 0xc2 0xa3 in UTF-8 + extra += 1; // 0xc2 + } + } + if(extra == 0) { + return 0; + } + auto len = value.length(); + if(!value.setLength(len + extra)) { + return 0; + } + char* out = value.begin(); + const char* in = out; + memmove(out + extra, in, len); + in += extra; + while(len--) { + uint8_t c = *in++; + auto esc = escapeChar(c, options); + if(esc) { + *out++ = '\\'; + c = esc; + } else if(options[Option::unicode]) { + if(uint8_t(c) < 0x20 || (c & 0x80)) { + *out++ = '\\'; + *out++ = 'u'; + *out++ = '0'; + *out++ = '0'; + *out++ = hexchar(uint8_t(c) >> 4); + c = hexchar(uint8_t(c) & 0x0f); + } + } else if(uint8_t(c) < 0x20) { + *out++ = '\\'; + *out++ = 'x'; + *out++ = hexchar(uint8_t(c) >> 4); + c = hexchar(uint8_t(c) & 0x0f); + } else if((c & 0x80) && options[Option::utf8]) { + *out++ = 0xc2; + } + *out++ = c; + } + return extra; +} + +} // namespace Format diff --git a/Sming/Core/Data/Format/Formatter.h b/Sming/Core/Data/Format/Formatter.h index 993e0dd61c..45e59aeb84 100644 --- a/Sming/Core/Data/Format/Formatter.h +++ b/Sming/Core/Data/Format/Formatter.h @@ -14,9 +14,27 @@ #include #include +#include namespace Format { +enum class Option { + unicode, //< Use unicode escapes \uNNNN, otherwise hex \xNN + utf8, ///< Convert extended ASCII to UTF8 + doublequote, + singlequote, + backslash, +}; +using Options = BitSet; + +/** + * @brief Escape standard control codes such as `\n` (below ASCII 0x20) + * @param value String to be modified + * @param options + * @retval unsigned Number of control characters found and replaced + */ +unsigned escapeControls(String& value, Options options); + /** * @brief Virtual class to perform format-specific String adjustments */ diff --git a/Sming/Core/Data/Format/Json.cpp b/Sming/Core/Data/Format/Json.cpp index d2f15f46ca..522e96757a 100644 --- a/Sming/Core/Data/Format/Json.cpp +++ b/Sming/Core/Data/Format/Json.cpp @@ -17,67 +17,28 @@ namespace Format { Json json; -namespace -{ -bool IsValidUtf8(const char* str, unsigned length) -{ - if(str == nullptr) { - return true; - } - - unsigned i = 0; - while(i < length) { - char c = str[i++]; - if((c & 0x80) == 0) { - continue; - } - - if(i >= length) { - return false; // incomplete multibyte char - } - - if(c & 0x20) { - c = str[i++]; - if((c & 0xC0) != 0x80) { - return false; // malformed trail byte or out of range char - } - if(i >= length) { - return false; // incomplete multibyte char - } - } - - c = str[i++]; - if((c & 0xC0) != 0x80) { - return false; // malformed trail byte - } - } - - return true; -} - -} // namespace - /* * Check for invalid characters and replace them - can break browser * operation otherwise. * * This can occur if filenames become corrupted, so here we just * substitute an underscore _ for anything which fails to match UTF8. - * - * TODO: Perform ANSI -> UTF8 conversion? */ void Json::escape(String& value) const { - if(!IsValidUtf8(value.c_str(), value.length())) { - debug_w("Invalid UTF8: %s", value.c_str()); - for(unsigned i = 0; i < value.length(); ++i) { - char& c = value[i]; - if(c < 0x20 || uint8_t(c) > 127) - c = '_'; - } - } + escapeControls(value, Option::unicode | Option::doublequote | Option::backslash); +} - value.replace("\"", "\\\""); +void Json::quote(String& value) const +{ + escape(value); + auto len = value.length(); + if(value.setLength(len + 2)) { + auto s = value.begin(); + memmove(s + 1, s, len); + s[0] = '"'; + s[len + 1] = '"'; + } } } // namespace Format diff --git a/Sming/Core/Data/Format/Json.h b/Sming/Core/Data/Format/Json.h index 2c7f35f983..4abd2a7ee4 100644 --- a/Sming/Core/Data/Format/Json.h +++ b/Sming/Core/Data/Format/Json.h @@ -20,6 +20,7 @@ class Json : public Standard { public: void escape(String& value) const override; + void quote(String& value) const override; MimeType mimeType() const override { diff --git a/Sming/Core/HardwarePWM.cpp b/Sming/Core/HardwarePWM.cpp new file mode 100644 index 0000000000..72603e2907 --- /dev/null +++ b/Sming/Core/HardwarePWM.cpp @@ -0,0 +1,26 @@ +/**** + * 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. + * + * HardwarePWM.cpp + * + * Common code for all architectures + * + */ + +#include "HardwarePWM.h" +#include + +uint8_t HardwarePWM::getChannel(uint8_t pin) const +{ + for(unsigned i = 0; i < channel_count; ++i) { + if(channels[i] == pin) { + return i; + } + } + + debug_d("[HWPWM] getChannel: can't find pin %u", pin); + return PWM_BAD_CHANNEL; +} diff --git a/Sming/Core/HardwarePWM.h b/Sming/Core/HardwarePWM.h index fe1d6d501d..77d7887c52 100644 --- a/Sming/Core/HardwarePWM.h +++ b/Sming/Core/HardwarePWM.h @@ -32,7 +32,30 @@ #define PWM_BAD_CHANNEL 0xff ///< Invalid PWM channel -/// Hardware pulse width modulation +/** + * @brief Basic pulse width modulation support. + * + * PERIOD: A full PWM cycle has a duration, measured in hardware timer counts + * DUTY: The 'ON' portion of a PWM cycle measured in hardware timer counts + * + * These values differ between architectures. + * + * DUTY is always <= PERIOD. + * If DUTY == 0 then output is OFF. + * If DUTY == PERIOD then output is ON. + * Intermediate values produce a proportional output, PERCENT = 100 * DUTY / PERIOD. + * + * Producing an analogue voltage from such a PWM output requires a suitable filter + * with characteristics tuned to the specific PWM frequency in use. + * A single-pole R/C filter with R*C = PERIOD (in seconds) is often sufficient. + * + * Note: Devices such as servo motors use the digital signal directly. + * + * Note: The Esp8266 has no PWM hardware and uses an interrupt-based approach (software PWM). + * + * Note: Esp32 and Rp2040 hardware offers more capability which requires use of SDK calls + * or direct hardware access. To avoid resource conflicts avoid using this class in those cases. + */ class HardwarePWM { public: @@ -40,7 +63,8 @@ class HardwarePWM * @param pins Pointer to array of pins to control * @param no_of_pins Quantity of elements in array of pins */ - HardwarePWM(uint8_t* pins, uint8_t no_of_pins); + HardwarePWM(const uint8_t* pins, uint8_t no_of_pins); + virtual ~HardwarePWM(); /** @brief Set PWM duty cycle @@ -64,7 +88,7 @@ class HardwarePWM /** @brief Set PWM duty cycle * @param pin GPIO to set - * @param duty Value of duty cycle to set pin to + * @param duty Value of duty cycle (timer ticks) to set pin to * @param update Update PWM output * @retval bool True on success * @note This function is used to set the pwm duty cycle for a given pin. If parameter 'update' is false @@ -78,13 +102,13 @@ class HardwarePWM /** @brief Get PWM duty cycle * @param chan Channel to get duty cycle for - * @retval uint32_t Value of PWM duty cycle + * @retval uint32_t Value of PWM duty cycle in timer ticks */ - uint32_t getDutyChan(uint8_t chan); + uint32_t getDutyChan(uint8_t chan) const; /** @brief Get PWM duty cycle * @param pin GPIO to get duty cycle for - * @retval uint32_t Value of PWM duty cycle + * @retval uint32_t Value of PWM duty cycle in timer ticks */ uint32_t getDuty(uint8_t pin) { @@ -93,27 +117,27 @@ class HardwarePWM } /** @brief Set PWM period - * @param period PWM period + * @param period PWM period in microseconds * @note All PWM pins share the same period */ void setPeriod(uint32_t period); /** @brief Get PWM period - * @retval uint32_t Value of PWM period + * @retval uint32_t Value of PWM period in microseconds */ - uint32_t getPeriod(); + uint32_t getPeriod() const; /** @brief Get channel number for a pin * @param pin GPIO to interrogate * @retval uint8_t Channel of GPIO */ - uint8_t getChannel(uint8_t pin); + uint8_t getChannel(uint8_t pin) const; /** @brief Get the maximum duty cycle value - * @retval uint32_t Maximum permissible duty cycle + * @retval uint32_t Maximum permissible duty cycle in timer ticks * @note Attempt to set duty of a pin above this value will fail */ - uint32_t getMaxDuty() + uint32_t getMaxDuty() const { return maxduty; } @@ -126,7 +150,7 @@ class HardwarePWM * @param pin GPIO to get frequency for * @retval uint32_t Value of Frequency */ - uint32_t getFrequency(uint8_t pin); + uint32_t getFrequency(uint8_t pin) const; private: uint8_t channel_count; diff --git a/Sming/Core/SmingVersion.h b/Sming/Core/SmingVersion.h index 6e6ad945c4..802c1a3e1d 100644 --- a/Sming/Core/SmingVersion.h +++ b/Sming/Core/SmingVersion.h @@ -5,8 +5,8 @@ * */ -#define SMING_MAJOR_VERSION 5 -#define SMING_MINOR_VERSION 2 +#define SMING_MAJOR_VERSION 6 +#define SMING_MINOR_VERSION 0 #define SMING_PATCH_VERSION 0 #define SMING_PRE_RELEASE "" diff --git a/Sming/Libraries/ConfigDB b/Sming/Libraries/ConfigDB new file mode 160000 index 0000000000..034ec0b691 --- /dev/null +++ b/Sming/Libraries/ConfigDB @@ -0,0 +1 @@ +Subproject commit 034ec0b69195c6e3ff5babb404786c8071edbd06 diff --git a/Sming/Libraries/JsonStreamingParser b/Sming/Libraries/JsonStreamingParser new file mode 160000 index 0000000000..46c8271829 --- /dev/null +++ b/Sming/Libraries/JsonStreamingParser @@ -0,0 +1 @@ +Subproject commit 46c8271829c685c912b8926a6630c676080f4f9e diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB index df65917eb6..6af107fbe2 160000 --- a/Sming/Libraries/USB +++ b/Sming/Libraries/USB @@ -1 +1 @@ -Subproject commit df65917eb6b796dbf1137f93ac0190d777403a7c +Subproject commit 6af107fbe25f7a8cb154ccea6ce9fb69e34dc60b 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/Sming/Services/Profiling/TaskStat.h b/Sming/Services/Profiling/TaskStat.h index 141435bf27..f0fe609671 100644 --- a/Sming/Services/Profiling/TaskStat.h +++ b/Sming/Services/Profiling/TaskStat.h @@ -47,8 +47,16 @@ class TaskStat */ bool update(); + /** + * @brief Change the output stream + */ + void setOutput(Print& out) + { + this->out = &out; + } + private: - Print& out; + Print* out; static constexpr size_t maxTasks{32}; struct Info; std::unique_ptr taskInfo; diff --git a/Sming/System/stringconversion.cpp b/Sming/System/stringconversion.cpp index 43cb89cb81..9432a46ee8 100644 --- a/Sming/System/stringconversion.cpp +++ b/Sming/System/stringconversion.cpp @@ -160,7 +160,7 @@ char *dtostrf_p(double floatVar, int minStringWidthIncDecimalPoint, int numDigit int_part = (unsigned long) floatVar; //print the int part into num - char* s = ltoa(int_part, buf, 10); + char* s = ultoa(int_part, buf, 10); //adjust end pointer buf += strlen(s); //go to end of string @@ -171,7 +171,7 @@ char *dtostrf_p(double floatVar, int minStringWidthIncDecimalPoint, int numDigit *buf++ = '.'; // print the decimal point //print the fraction part into temp - s = ltoa( ((floatVar - int_part) * mult), temp, 10); + s = ultoa( ((floatVar - int_part) * mult), temp, 10); i = processedFracLen - strlen(s) + 1; diff --git a/Sming/Wiring/FIFO.h b/Sming/Wiring/FIFO.h index ffd6df5728..8a2d6e53be 100644 --- a/Sming/Wiring/FIFO.h +++ b/Sming/Wiring/FIFO.h @@ -21,10 +21,10 @@ #include "Countable.h" -template class FIFO : public Countable +template class FIFO : public Countable { public: - const int size; // speculative feature, in case it's needed + const unsigned size; // speculative feature, in case it's needed FIFO(); @@ -60,18 +60,18 @@ template class FIFO : public Countable } protected: - volatile int numberOfElements; - int nextIn; - int nextOut; + unsigned numberOfElements; + unsigned nextIn; + unsigned nextOut; T raw[rawSize]; }; -template FIFO::FIFO() : size(rawSize) +template FIFO::FIFO() : size(rawSize) { flush(); } -template bool FIFO::enqueue(T element) +template bool FIFO::enqueue(T element) { if(full()) { return false; @@ -85,7 +85,7 @@ template bool FIFO::enqueue(T element) return true; } -template T FIFO::dequeue() +template T FIFO::dequeue() { T item; numberOfElements--; @@ -95,12 +95,12 @@ template T FIFO::dequeue() return item; } -template T FIFO::peek() const +template T FIFO::peek() const { return raw[nextOut]; } -template void FIFO::flush() +template void FIFO::flush() { nextIn = nextOut = numberOfElements = 0; } diff --git a/Sming/Wiring/FILO.h b/Sming/Wiring/FILO.h index 15253633a8..88d9e800a8 100644 --- a/Sming/Wiring/FILO.h +++ b/Sming/Wiring/FILO.h @@ -20,10 +20,10 @@ #include "Countable.h" -template class FILO : public Countable +template class FILO : public Countable { public: - const int size; // speculative feature, in case it's needed + const unsigned size; // speculative feature, in case it's needed FILO(); @@ -59,18 +59,18 @@ template class FILO : public Countable } private: - volatile int numberOfElements; - int nextIn; - int nextOut; + unsigned numberOfElements; + unsigned nextIn; + unsigned nextOut; T raw[rawSize]; }; -template FILO::FILO() : size(rawSize) +template FILO::FILO() : size(rawSize) { flush(); } -template bool FILO::push(T element) +template bool FILO::push(T element) { if(count() >= rawSize) { return false; @@ -79,7 +79,7 @@ template bool FILO::push(T element) return true; } -template T FILO::pop() +template T FILO::pop() { if(numberOfElements > 0) { return raw[--numberOfElements]; @@ -87,7 +87,7 @@ template T FILO::pop() return raw[0]; } -template T FILO::peek() const +template T FILO::peek() const { if(numberOfElements > 0) { return raw[numberOfElements - 1]; @@ -95,7 +95,7 @@ template T FILO::peek() const return raw[0]; } -template void FILO::flush() +template void FILO::flush() { nextIn = nextOut = numberOfElements = 0; } diff --git a/Sming/build.mk b/Sming/build.mk index 9b8d4c7c37..2dc96401f2 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -140,7 +140,7 @@ CMAKE ?= cmake # clang-format command DEBUG_VARS += CLANG_FORMAT -CLANG_FORMAT ?= clang-format +CLANG_FORMAT ?= clang-format-8 # more tools DEBUG_VARS += AWK @@ -239,6 +239,11 @@ COMPILER_VERSION_FULL := $(shell LANG=C $(CC) -v 2>&1 | $(AWK) -F " version " '/ COMPILER_NAME := $(word 1,$(COMPILER_VERSION_FULL)) COMPILER_VERSION := $(word 2,$(COMPILER_VERSION_FULL)) +# Use of bitwise assignment for volatile registers is deprecated in C++20 but de-deprecated in C++23 +ifeq ($(COMPILER_NAME)-$(SMING_CXX_STD),gcc-c++20) +CXXFLAGS += -Wno-volatile +endif + ifndef USE_CLANG # Required to access peripheral registers using structs # e.g. `uint32_t value: 8` sitting at a byte or word boundary will be 'optimised' to diff --git a/Tools/ci/scanlog.py b/Tools/ci/scanlog.py index 73821602b8..bdd196320a 100644 --- a/Tools/ci/scanlog.py +++ b/Tools/ci/scanlog.py @@ -327,7 +327,6 @@ def get_args(cmd: str): def print_diff(log1: Log, log2: Log): for job1 in log1.jobs: - job_printed = False try: job2 = next(job for job in log2.jobs if job.name == job1.name) except StopIteration: @@ -364,9 +363,7 @@ def print_diff(log1: Log, log2: Log): data[name] = f'{v2-v1:+}' diff_table.append(data) - if not job_printed: - print(f'{job1.name}:') - job_printed = True + print(f'{job1.name}: {target}') print_table(diff_table) if table2.rows: diff --git a/Tools/export.sh b/Tools/export.sh index 602bc4423a..3a6f885d06 100755 --- a/Tools/export.sh +++ b/Tools/export.sh @@ -30,17 +30,26 @@ if [ -z "$SMING_HOME" ]; then fi # Common + +# Python Virtual Environment +if [ -f ~/.venvs/Sming/bin/activate ]; then + source ~/.venvs/Sming/bin/activate +fi + export PYTHON=${PYTHON:=$(which python3)} +# Toolchain paths +export SMING_TOOLCHAINS=${SMING_TOOLCHAINS:=/opt} + # Esp8266 -export ESP_HOME=${ESP_HOME:=/opt/esp-quick-toolchain} +export ESP_HOME=${ESP_HOME:=$SMING_TOOLCHAINS/esp-quick-toolchain} # Esp32 -export IDF_PATH=${IDF_PATH:=/opt/esp-idf} -export IDF_TOOLS_PATH=${IDF_TOOLS_PATH:=/opt/esp32} +export IDF_PATH=${IDF_PATH:=$SMING_TOOLCHAINS/esp-idf} +export IDF_TOOLS_PATH=${IDF_TOOLS_PATH:=$SMING_TOOLCHAINS/esp32} # Rp2040 -export PICO_TOOLCHAIN_PATH=${PICO_TOOLCHAIN_PATH:=/opt/rp2040} +export PICO_TOOLCHAIN_PATH=${PICO_TOOLCHAIN_PATH:=$SMING_TOOLCHAINS/rp2040} # Provide non-apple CLANG (e.g. for rbpf library) if [ -n "$GITHUB_ACTIONS" ] && [ "$(uname)" = "Darwin" ]; then diff --git a/Tools/ide/common/sming.py b/Tools/ide/common/sming.py index c86f48354b..ac666a0482 100644 --- a/Tools/ide/common/sming.py +++ b/Tools/ide/common/sming.py @@ -49,7 +49,6 @@ def subst_path(self, path, prefix=''): path = self.replace(path, 'SMING_HOME', prefix) path = self.replace(path, 'ESP_HOME', prefix) path = self.replace(path, 'IDF_PATH', prefix) - path = self.replace(path, 'IDF_TOOLS_PATH', prefix) return path def isWsl(self): diff --git a/Tools/install.sh b/Tools/install.sh index 4b85fd5dd1..94136ed286 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -84,6 +84,56 @@ source "$(dirname "${BASH_SOURCE[0]}")/export.sh" export WGET="wget --no-verbose" +# Scripts for checking for required resources + +abort () { + echo "ABORTING" + if [ $sourced = 1 ]; then + return 1 + else + exit 1 + fi +} + +check_for_installed_tools() { + REQUIRED_TOOLS=( "$@" ) + echo -e "Checking for installed tools.\nRequired tools: ${REQUIRED_TOOLS[*]}" + TOOLS_MISSING=0 + for TOOL in "${REQUIRED_TOOLS[@]}"; do + if ! command -v "$TOOL" > /dev/null ; then + TOOLS_MISSING=1 + echo "Install required tool $TOOL" + fi + done + if [ $TOOLS_MISSING != 0 ]; then + abort + fi +} + +check_for_installed_files() { + REQUIRED_FILES=( "$@" ) + echo -e "Checking for installed files.\nRequired files: ${REQUIRED_FILES[*]}" + FILES_MISSING=0 + for FILE in "${REQUIRED_FILES[@]}"; do + if ! [ -f "$FILE" ]; then + FILES_MISSING=1 + echo "Install required FILE $FILE" + fi + done + if [ $FILES_MISSING != 0 ]; then + abort + fi +} + +install_venv() { + echo + echo "!!! Trying to install Python Virtual Environment !!!" + mkdir -p ~/.venvs/ + python3 -m venv ~/.venvs/Sming + source ~/.venvs/Sming/bin/activate + eval "$1" +} + # Installers put downloaded archives here DOWNLOADS="downloads" mkdir -p $DOWNLOADS @@ -100,11 +150,18 @@ elif [ -n "$(command -v dnf)" ]; then PKG_INSTALL="sudo dnf install -y" else echo "Unsupported distribution" - if [ $sourced = 1 ]; then - return 1 - else - exit 1 - fi + check_for_installed_tools \ + ccache \ + cmake \ + curl \ + git \ + make \ + ninja \ + unzip \ + g++ \ + python3 \ + pip3 \ + wget fi # Common install @@ -183,9 +240,11 @@ case $DIST in esac +if [ "$(/usr/bin/python -c 'import sys;print(sys.version_info[0])')" != 3 ]; then if [ "$DIST" != "darwin" ]; then sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100 fi +fi set -e @@ -193,7 +252,9 @@ if [ -f "/usr/bin/clang-format-8" ]; then sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-8 100 fi -python3 -m pip install --upgrade pip protobuf -r "$SMING_HOME/../Tools/requirements.txt" +PYTHON_INSTALL_CMD="python3 -m pip install --upgrade pip -r \"$SMING_HOME/../Tools/requirements.txt\"" + +eval "$PYTHON_INSTALL_CMD" || $PKG_INSTALL python3-venv && install_venv "$PYTHON_INSTALL_CMD" install() { diff --git a/Tools/requirements.txt b/Tools/requirements.txt index 2dacbee54b..018c3fc615 100644 --- a/Tools/requirements.txt +++ b/Tools/requirements.txt @@ -1,3 +1,4 @@ +protobuf pyserial jsonschema kconfiglib diff --git a/docs/source/framework/core/data/buffering.rst b/docs/source/framework/core/data/buffering.rst new file mode 100644 index 0000000000..fe5d1054d8 --- /dev/null +++ b/docs/source/framework/core/data/buffering.rst @@ -0,0 +1,15 @@ +Buffering +========= + +In general, writing efficiently to files is best done in chunks, such as by building a line of data in a :cpp:class:`String` and writing it in one go. + +Sming offers a simple write-through buffering mechanism which can be used where necessary. The :library:`ArduinoJson` can benefit greatly from this. + +.. doxygenclass:: StaticPrintBuffer + :members: + +.. doxygenclass:: HeapPrintBuffer + :members: + +.. doxygenclass:: DynamicPrintBuffer + :members: diff --git a/docs/source/getting-started/config.rst b/docs/source/getting-started/config.rst index 28b4089475..7157afc439 100644 --- a/docs/source/getting-started/config.rst +++ b/docs/source/getting-started/config.rst @@ -11,11 +11,21 @@ and integrated development environments (IDEs) work correctly. You can find a list of these in :source:`Tools/export.sh`. -For Linux and WSL2, append values to your ``~/.bashrc`` file:: +For Linux and WSL2, append :envvar:`SMING_HOME` to your ``~/.bashrc`` file:: # All architectures export SMING_HOME=/opt/sming/Sming - + +:envvar:`SMING_HOME` is the only mandatory environmental variable. + +If you want to change the location where the toolchain will be downloaded and installed you can append the values below:: + + # Specifies a common toolchains directory + export SMING_TOOLCHAINS=/opt + +The :envvar:`SMING_TOOLCHAINS` is optional. As are the ones below. You can append them to your ``~/.bashrc`` file only +if you need to change the location of the installed toolchains:: + # Esp8266 export ESP_HOME=/opt/esp-quick-toolchain diff --git a/docs/source/index.rst b/docs/source/index.rst index 20ca4cb497..f9936d2f39 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,7 +9,7 @@ Sming is an asynchronous embedded C++ framework with superb performance and mult Sming is open source, modular and supports :doc:`multiple architectures `: :doc:`ESP8266 `, :doc:`ESP32 `, -:doc:`RP2040 `, +:doc:`Raspberry Pi Pico-series (both RP2040 and RP2350) `, and :doc:`Host Emulation `. |samples|_ diff --git a/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index 1a0b1350f6..e10ef07edf 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -97,7 +97,7 @@ To evaluate how much would be removed run this command (it's safe):: python clean-tools.py scan -To perform 'dry-run' of a clean operation, without actually deleteing anything:: +To perform 'dry-run' of a clean operation, without actually deleting anything:: python clean-tools.py clean diff --git a/docs/source/information/develop/clang-tools.rst b/docs/source/information/develop/clang-tools.rst index 683a89bfc5..41e5606794 100644 --- a/docs/source/information/develop/clang-tools.rst +++ b/docs/source/information/develop/clang-tools.rst @@ -15,16 +15,25 @@ Note that *clang-format* is part of the main **Clang** project, whilst *clang-ti found in **clang-tools-extra**. -Installation +clang-format ------------ -In Ubuntu you should be able to install them using the following command:: +Installation +~~~~~~~~~~~~ - sudo apt-get install clang-format clang-tidy +Sming requires version 8 which is generally no longer available in the standard repositories for recent GNU/Linux distributions. +You can find standalone builds at https://github.com/muttleyxd/clang-tools-static-binaries/releases. + +For example: + +``` +export CLANG_FORMAT=/opt/clang-format-8 +wget https://github.com/muttleyxd/clang-tools-static-binaries/releases/download/master-32d3ac78/clang-format-8_linux-amd64 -O /opt/clang-format-8 +chmod +x $CLANG_FORMAT +``` + +You should persist the definition for :envvar:`CLANG_FORMAT` as Sming uses this when running the ``make cs`` commands (see below). -See the the `download `__ page -of the Clang project for installation instructions for other operating -systems. .. important:: @@ -37,10 +46,6 @@ systems. You should install the same version on your development computer. - -clang-format ------------- - Rules ~~~~~ @@ -57,6 +62,8 @@ IDE integration There are multiple existing integrations for IDEs. You can find details in the `ClangFormat documentation `__. +For VS Code/Codium install the **clang-format** extension and configure the path with the location of the **clang-format-8** executable. + For the Eclipse IDE we recommend installing the `CppStyle plugin `__. You can configure your IDE to auto-format the code on "Save" using the @@ -114,12 +121,23 @@ C, C++ or header file or a selection in it and run the ``Format`` command clang-tidy ---------- -Configuration -~~~~~~~~~~~~~ +Installation +~~~~~~~~~~~~ No specific version is required but generally you should aim to use the most recent version available in your distribution. Version 17.0.6 was used at time of writing these notes. +In Ubuntu you should be able install using the following command:: + + sudo apt-get install clang-tidy + +See the the `download `__ page +of the Clang project for installation instructions for other operating +systems. + +Configuration +~~~~~~~~~~~~~ + The default tool configuration is defined in the `.clang-tidy `__ file, located in the root directory of the framework. diff --git a/docs/source/upgrading/5.1-5.2.rst b/docs/source/upgrading/5.1-5.2.rst index 55cbc7a831..523fb5177c 100644 --- a/docs/source/upgrading/5.1-5.2.rst +++ b/docs/source/upgrading/5.1-5.2.rst @@ -18,7 +18,7 @@ The procedure has therefore been revised to use installation scripts instead of The initial installation step to bootstrap the installation remains unchanged: The ``choco-install.cmd`` script is fetched from the Sming ``develop`` branch and executed. The custom choco scripts have been replaced with scripted logic. -Installation of toolchains is done as a separate step as it does not require administrative priviledges. +Installation of toolchains is done as a separate step as it does not require administrative privileges. The documentation at https://sming.readthedocs.io/en/latest/getting-started/windows/index.html has been updated to reflect these changes. 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. diff --git a/samples/Basic_HwPWM/app/application.cpp b/samples/Basic_HwPWM/app/application.cpp index b1c29c4784..2ac094036a 100644 --- a/samples/Basic_HwPWM/app/application.cpp +++ b/samples/Basic_HwPWM/app/application.cpp @@ -18,26 +18,38 @@ #include #include -#define LED_PIN 2 - namespace { // List of pins that you want to connect to pwm -uint8_t pins[]{ +const uint8_t pins[] +{ +#if defined(ARCH_ESP32) +#define LED_PIN 3 + LED_PIN, 4, 5, 18, 19, 4, +#elif defined(ARCH_RP2040) +#define LED_PIN PICO_DEFAULT_LED_PIN + LED_PIN, 2, 3, 4, 5, 6, 7, 8, +#else +#define LED_PIN 2 LED_PIN, 4, 5, 0, 15, 13, 12, 14, +#endif }; -HardwarePWM HW_pwm(pins, ARRAY_SIZE(pins)); -SimpleTimer procTimer; +const uint8_t defaultDutyPercent[]{ + 50, 95, 50, 85, 10, 30, 60, 80, +}; -const int maxDuty = HW_pwm.getMaxDuty(); +HardwarePWM pwm(pins, ARRAY_SIZE(pins)); +uint32_t maxDuty; + +SimpleTimer procTimer; void doPWM() { static bool countUp = true; - static int duty; + static uint32_t duty; - const int increment = maxDuty / 50; + const uint32_t increment = maxDuty / 50; if(countUp) { duty += increment; @@ -45,15 +57,14 @@ void doPWM() duty = maxDuty; countUp = false; } + } else if(duty <= increment) { + duty = 0; + countUp = true; } else { duty -= increment; - if(duty <= 0) { - duty = 0; - countUp = true; - } } - HW_pwm.analogWrite(LED_PIN, duty); + pwm.analogWrite(LED_PIN, duty); } } // namespace @@ -69,17 +80,21 @@ void init() WifiAccessPoint.enable(false); #endif - // Setting PWM values on 8 different pins - HW_pwm.analogWrite(4, maxDuty); - HW_pwm.analogWrite(5, maxDuty / 2); - HW_pwm.analogWrite(0, maxDuty); - HW_pwm.analogWrite(2, maxDuty / 2); - HW_pwm.analogWrite(15, 0); - HW_pwm.analogWrite(13, maxDuty / 3); - HW_pwm.analogWrite(12, 2 * maxDuty / 3); - HW_pwm.analogWrite(14, maxDuty); - - Serial.println(_F("PWM output set on all 8 Pins. Kindly check...\r\n" - "Now LED_PIN will go from 0 to VCC to 0 in cycles.")); + // Change PWM frequency if required: period is in microseconds + // pwm.setPeriod(100); + + maxDuty = pwm.getMaxDuty(); + auto period = pwm.getPeriod(); + auto freq = pwm.getFrequency(LED_PIN); + + Serial << _F("PWM period = ") << period << _F("us, freq = ") << freq << _F(", max. duty = ") << maxDuty << endl; + + // Set default PWM values + for(unsigned i = 0; i < ARRAY_SIZE(pins); ++i) { + pwm.analogWrite(pins[i], maxDuty * defaultDutyPercent[i] / 100); + } + + Serial << _F("PWM output set on all ") << ARRAY_SIZE(pins) << _F(" Pins. Kindly check...") << endl + << _F("Now LED (pin ") << LED_PIN << _F(") will go from 0 to VCC to 0 in cycles.") << endl; procTimer.initializeMs<100>(doPWM).start(); } diff --git a/samples/Basic_HwPWM/component.mk b/samples/Basic_HwPWM/component.mk index be6ff9c63a..99a419fcc1 100644 --- a/samples/Basic_HwPWM/component.mk +++ b/samples/Basic_HwPWM/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp8266 DISABLE_NETWORK := 1 # Uncomment the line below if you want to use Espressif's PWM library. diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 7f8b01064f..acaf936a8f 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -246,7 +246,7 @@ bool initFileSystem() #endif #ifdef ENABLE_USB_STORAGE - USB::begin(); + USB::begin(true); USB::MSC::onMount([](auto inst) { usbStorage.begin(inst); usbStorage.enumerate([](auto& unit, const USB::MSC::Inquiry& inquiry) { @@ -284,7 +284,7 @@ bool initFileSystem() for(auto part : unit.partitions()) { Serial << part << endl; } - auto part = *unit.partitions().begin(); + auto part = Storage::findDefaultPartition(Storage::Partition::SubType::Data::fat); auto fatfs = IFS::createFatFilesystem(part); if(fatfs && fatfs->mount() == FS_OK) { getFileSystem()->setVolume(3, fatfs); diff --git a/samples/Basic_IFS/basic_ifs_Rp2040.hw b/samples/Basic_IFS/basic_ifs_Rp2040.hw index 004bc45534..53b0f9bde0 100644 --- a/samples/Basic_IFS/basic_ifs_Rp2040.hw +++ b/samples/Basic_IFS/basic_ifs_Rp2040.hw @@ -8,7 +8,7 @@ ], "partitions": { "rom0": { - "size": "320K" + "size": "428K" }, "lfs1": { "size": "932K", diff --git a/samples/Basic_Serial/.gitignore b/samples/Basic_Serial/.gitignore new file mode 100644 index 0000000000..bb97907eef --- /dev/null +++ b/samples/Basic_Serial/.gitignore @@ -0,0 +1 @@ +/files/ diff --git a/samples/HttpServer_WebSockets/app/application.cpp b/samples/HttpServer_WebSockets/app/application.cpp index 2d0a059c4c..056973520c 100644 --- a/samples/HttpServer_WebSockets/app/application.cpp +++ b/samples/HttpServer_WebSockets/app/application.cpp @@ -66,8 +66,8 @@ void wsMessageReceived(WebsocketConnection& socket, const String& message) Serial.println(message); if(message == _F("shutdown")) { - String message(F("The server is shutting down...")); - socket.broadcast(message); + String reply(F("The server is shutting down...")); + socket.broadcast(reply); shutdownServer(); return; } diff --git a/tests/HostTests/include/modules.h b/tests/HostTests/include/modules.h index d29f54e112..037dedb112 100644 --- a/tests/HostTests/include/modules.h +++ b/tests/HostTests/include/modules.h @@ -29,6 +29,7 @@ XX(CStringArray) \ XX(Stream) \ XX(TemplateStream) \ + XX(Formatter) \ XX(Serial) \ XX(ObjectMap) \ XX_NET(Base64) \ diff --git a/tests/HostTests/modules/Formatter.cpp b/tests/HostTests/modules/Formatter.cpp new file mode 100644 index 0000000000..0e0593f4e7 --- /dev/null +++ b/tests/HostTests/modules/Formatter.cpp @@ -0,0 +1,54 @@ +#include +#include + +class FormatterTest : public TestGroup +{ +public: + FormatterTest() : TestGroup(_F("Formatter")) + { + } + + void execute() override + { + // Note: \xa3 is unicode for £ + DEFINE_FSTR_LOCAL(text1, "A JSON\ntest string\twith escapes\x12\0\n" + "Worth \"maybe\" \xa3 0.53. Yen \xa5 5bn.") + + TEST_CASE("JSON") + { + DEFINE_FSTR_LOCAL(text1b, "A JSON\\ntest string\\twith escapes\\u0012\\u0000\\n" + "Worth \\\"maybe\\\" \\u00a3 0.53. Yen \\u00a5 5bn.") + + Serial << text1 << endl; + String s(text1); + Format::json.escape(s); + REQUIRE_EQ(s, text1b); + + s = text1; + Format::json.quote(s); + String quoted = String('"') + text1b + '"'; + REQUIRE_EQ(s, quoted); + } + + TEST_CASE("C++") + { + DEFINE_FSTR_LOCAL( + text1a, "A JSON\\ntest string\\twith escapes\\x12\\0\\nWorth \\\"maybe\\\" \xa3 0.53. Yen \xa5 5bn.") + String s(text1); + Format::escapeControls(s, Format::Option::doublequote | Format::Option::backslash); + REQUIRE_EQ(s, text1a); + + DEFINE_FSTR_LOCAL( + text1b, + "A JSON\\ntest string\\twith escapes\\x12\\0\\nWorth \\\"maybe\\\" \xc2\xa3 0.53. Yen \xc2\xa5 5bn.") + s = text1; + Format::escapeControls(s, Format::Option::utf8 | Format::Option::doublequote | Format::Option::backslash); + REQUIRE_EQ(s, text1b); + } + } +}; + +void REGISTER_TEST(Formatter) +{ + registerGroup(); +}