diff --git a/.github/workflows/ci-esp32.yml b/.github/workflows/ci-esp32.yml new file mode 100644 index 0000000000..4036e42932 --- /dev/null +++ b/.github/workflows/ci-esp32.yml @@ -0,0 +1,71 @@ +name: Continuous Integration (CI) for Esp32 + +on: + push: + + pull_request: + branches: [ develop ] + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, windows-latest] + variant: [esp32, esp32s2, esp32c3, esp32s3, esp32c2] + idf_version: ["4.3", "4.4", "5.0"] + exclude: + - variant: esp32s3 + idf_version: "4.3" + - variant: esp32c2 + idf_version: "4.3" + - variant: esp32c2 + idf_version: "4.4" + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} + cancel-in-progress: true + + runs-on: ${{ matrix.os }} + + env: + SMING_ARCH: Esp32 + SMING_SOC: ${{ matrix.variant }} + INSTALL_IDF_VER: ${{ matrix.idf_version }} + + steps: + - name: Fix autocrlf setting + run: | + git config --global --add core.autocrlf input + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Configure environment + shell: pwsh + run: | + "CI_BUILD_DIR=" + (Resolve-Path ".").path >> $env:GITHUB_ENV + "SMING_HOME=" + (Resolve-Path "Sming").path >> $env:GITHUB_ENV + + - name: Install build tools for Ubuntu + if: ${{ matrix.os == 'ubuntu-20.04' }} + run: | + Tools/ci/install.sh + + - name: Install build tools for Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + . Tools/ci/setenv.ps1 + Tools/ci/install.cmd + + - name: Build and test for ${{matrix.variant}} with IDF v${{matrix.idf_version}} on Ubuntu + if: ${{ matrix.os == 'ubuntu-20.04' }} + run: | + source $SMING_HOME/../Tools/export.sh + Tools/ci/build.sh + + - name: Build and test for ${{matrix.variant}} with IDF v${{matrix.idf_version}} on Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + . Tools/ci/setenv.ps1 + Tools/ci/build.cmd diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 128a33f77b..7173fb515d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,18 +12,12 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04, windows-latest] - variant: [esp8266, host, esp32, esp32s2, esp32c3, rp2040] + variant: [esp8266, host, rp2040] include: - variant: esp8266 arch: Esp8266 - variant: host arch: Host - - variant: esp32 - arch: Esp32 - - variant: esp32s2 - arch: Esp32 - - variant: esp32c3 - arch: Esp32 - variant: rp2040 arch: Rp2040 @@ -33,6 +27,10 @@ jobs: runs-on: ${{ matrix.os }} + env: + SMING_ARCH: ${{ matrix.arch }} + SMING_SOC: ${{ matrix.variant }} + steps: - name: Fix autocrlf setting run: | @@ -46,21 +44,19 @@ jobs: run: | "CI_BUILD_DIR=" + (Resolve-Path ".").path >> $env:GITHUB_ENV "SMING_HOME=" + (Resolve-Path "Sming").path >> $env:GITHUB_ENV - "SMING_ARCH=${{ matrix.arch }}" >> $env:GITHUB_ENV - "SMING_SOC=${{ matrix.variant }}" >> $env:GITHUB_ENV - name: Install build tools for Ubuntu - if: ${{ matrix.os == 'ubuntu-20.04' }} + if: ${{ matrix.os == 'ubuntu-20.04' }} run: | Tools/ci/install.sh - name: Install build tools for Windows - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.os == 'windows-latest' }} run: | . Tools/ci/setenv.ps1 Tools/ci/install.cmd - - name: Build and test for ${{matrix.arch}} on Ubuntu + - name: Build and test for ${{matrix.variant}} on Ubuntu env: CLANG_FORMAT: clang-format-8 if: ${{ matrix.os == 'ubuntu-20.04' }} @@ -69,7 +65,7 @@ jobs: $CLANG_FORMAT --version Tools/ci/build.sh - - name: Build and test for ${{matrix.arch}} on Windows + - name: Build and test for ${{matrix.variant}} on Windows if: ${{ matrix.os == 'windows-latest' }} run: | . Tools/ci/setenv.ps1 diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index cb247ad98d..531b04f0a6 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-20.04, windows-latest] variant: [esp8266, host, esp32, esp32s2, esp32c3, rp2040] include: - variant: esp8266 @@ -71,7 +71,7 @@ jobs: "SMING_SOC=${{ matrix.variant }}" >> $env:GITHUB_ENV - name: Install build tools for Ubuntu - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-20.04' }} run: | . $SMING_HOME/../Tools/export.sh $SMING_HOME/../Tools/ci/install.sh $SMING_ARCH @@ -85,7 +85,7 @@ jobs: - name: Build and Test for ${{matrix.arch}} on Ubuntu env: CLANG_FORMAT: clang-format-8 - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-20.04' }} run: | . $SMING_HOME/../Tools/export.sh make -j$(nproc) -f $CI_MAKEFILE diff --git a/.gitmodules b/.gitmodules index c4ac5e4caf..67d22b225b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -69,6 +69,10 @@ path = Sming/Components/rboot/rboot url = https://github.com/mikee47/rboot ignore = dirty +[submodule "uzlib"] + path = Sming/Components/uzlib/uzlib + url = https://github.com/pfalcon/uzlib.git + ignore = dirty [submodule "ws_parser"] path = Sming/Components/ws_parser url = https://github.com/charliesome/ws_parser.git @@ -233,6 +237,10 @@ path = Sming/Libraries/FatIFS url = https://github.com/mikee47/FatIFS ignore = dirty +[submodule "Libraries.FlashIP"] + path = Sming/Libraries/FlashIP + url = https://github.com/mikee47/FlashIP + ignore = dirty [submodule "Libraries.flatbuffers"] path = Sming/Libraries/flatbuffers/src url = https://github.com/google/flatbuffers.git @@ -369,10 +377,14 @@ path = Sming/Libraries/UPnP url = https://github.com/mikee47/Sming-UPnP ignore = dirty -[submodule "Sming/Libraries/UPnP-Schema"] +[submodule "Libraries.UPnP-Schema"] path = Sming/Libraries/UPnP-Schema url = https://github.com/mikee47/UPnP-Schema ignore = dirty +[submodule "Libraries.USB"] + path = Sming/Libraries/USB + url = https://github.com/mikee47/Sming-USB + ignore = dirty [submodule "Libraries.VT100"] path = Sming/Libraries/VT100 url = https://github.com/mikee47/VT100 diff --git a/README.md b/README.md index d0de9ab4bb..11d70852ce 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Sming Sming is an asynchronous embedded C/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 and ESP32. +Sming is [open source](LICENSE), modular and supports [multiple architectures](https://sming.readthedocs.io/en/latest/features.html) including ESP8266, ESP32 and RP2040. [![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 4.7.0**](https://sming.readthedocs.io/en/stable) - current stable version. +- [**Documentation for version 5.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 V4.7.0](https://github.com/SmingHub/Sming/releases/tag/4.7.0) - great new features, performance and stability improvements. +- [Sming V5.0.0](https://github.com/SmingHub/Sming/releases/tag/5.0.0) - great new features, performance and stability improvements. ### Development diff --git a/Sming/Arch/Esp32/Components/driver/hw_timer.cpp b/Sming/Arch/Esp32/Components/driver/hw_timer.cpp index 63af06d45f..9b5cc202dc 100644 --- a/Sming/Arch/Esp32/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Esp32/Components/driver/hw_timer.cpp @@ -10,104 +10,215 @@ #include #include -#include +#include #include +#include namespace { -struct TimerConfig { - timer_group_t group; - timer_idx_t index; - timer_hal_context_t hal; - intr_handle_t isr_handle; - hw_timer_callback_t callback; - void* arg; - bool autoload; -}; +#if ESP_IDF_VERSION_MAJOR >= 5 +using timer_group_t = unsigned int; +using timer_idx_t = unsigned int; +#endif -TimerConfig timer; - -void IRAM_ATTR timerIsr(void* arg) +class TimerConfig { - auto& timer = *static_cast(arg); +public: + TimerConfig(unsigned group, unsigned index) + : group(timer_group_t(group)), index(timer_idx_t(index)), dev(TIMER_LL_GET_HW(group)) + { + } - if(timer.callback != nullptr) { - timer.callback(arg); + void begin() + { + periph_module_enable(timer_group_periph_signals.groups[group].module); + enable_counter(false); + enable_alarm(true); + set_alarm_value(0); +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_counter_increase(dev, index, false); +#else + timer_ll_set_count_direction(dev, index, GPTIMER_COUNT_DOWN); + timer_ll_set_clock_source(dev, index, GPTIMER_CLK_SRC_DEFAULT); +#endif } - timer_hal_clear_intr_status(&timer.hal); + void IRAM_ATTR attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) + { + if(isr_handle != nullptr) { + detach_interrupt(); + } + + if(callback == nullptr) { + return; + } + + this->callback = callback; + + uint32_t status_reg = reinterpret_cast(timer_ll_get_intr_status_reg(dev)); + uint32_t mask = 1 << index; +#if ESP_IDF_VERSION_MAJOR < 5 + int source = timer_group_periph_signals.groups[group].t0_irq_id + index; +#else + int source = timer_group_periph_signals.groups[group].timer_irq_id[index]; +#endif + esp_intr_alloc_intrstatus(source, ESP_INTR_FLAG_IRAM, status_reg, mask, timerIsr, this, &isr_handle); + clear_intr_status(); + enable_intr(true); + } - if(!timer.autoload) { - timer_hal_set_counter_enable(&timer.hal, false); + void __forceinline detach_interrupt() + { + enable_intr(false); + esp_intr_free(isr_handle); + isr_handle = nullptr; } - timer_hal_set_alarm_enable(&timer.hal, true); -} + void __forceinline enable_intr(bool state) + { +#if ESP_IDF_VERSION_MAJOR < 5 + if(state) { + timer_ll_intr_enable(dev, index); + } else { + timer_ll_intr_disable(dev, index); + } +#else + timer_ll_enable_intr(dev, index, state); +#endif + } -} // namespace + void __forceinline clear_intr_status() + { + timer_ll_clear_intr_status(dev, index); + } -void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) -{ - if(timer.isr_handle != nullptr) { - hw_timer1_detach_interrupt(); + void __forceinline set_alarm_value(uint64_t value) + { + timer_ll_set_alarm_value(dev, index, value); + } + + void __forceinline enable_alarm(bool state) + { +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_alarm_enable(dev, index, state); +#else + timer_ll_enable_alarm(dev, index, state); +#endif + } + + void __forceinline enable_auto_reload(bool state) + { +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_auto_reload(dev, index, state); +#else + timer_ll_enable_auto_reload(dev, index, state); +#endif + autoload = state; + } + + void __forceinline set_prescale(uint32_t divider) + { +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_divider(dev, index, divider); +#else + timer_ll_set_clock_prescale(dev, index, divider); +#endif } - if(callback == nullptr) { - return; + void __forceinline set_counter_value(uint64_t value) + { +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_counter_value(dev, index, value); +#else + timer_ll_set_reload_value(dev, index, value); + timer_ll_trigger_soft_reload(dev, index); +#endif } - timer.callback = callback; + uint64_t __forceinline get_counter_value() + { +#if ESP_IDF_VERSION_MAJOR < 5 + uint64_t val{0}; + timer_ll_get_counter_value(dev, index, &val); + return val; +#else + return timer_ll_get_counter_value(dev, index); +#endif + } + + void __forceinline enable_counter(bool state) + { +#if ESP_IDF_VERSION_MAJOR < 5 + timer_ll_set_counter_enable(dev, index, state); +#else + timer_ll_enable_counter(dev, index, state); +#endif + } + +private: + static void IRAM_ATTR timerIsr(void* arg) + { + auto& timer = *static_cast(arg); + + if(timer.callback != nullptr) { + timer.callback(arg); + } + + timer.clear_intr_status(); + + if(!timer.autoload) { + timer.enable_counter(false); + } + + timer.enable_alarm(true); + } - uint32_t status_reg{0}; - uint32_t mask{0}; - timer_hal_get_status_reg_mask_bit(&timer.hal, &status_reg, &mask); - esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[timer.group].t0_irq_id + timer.index, - ESP_INTR_FLAG_IRAM, status_reg, mask, timerIsr, &timer, &timer.isr_handle); - timer_hal_clear_intr_status(&timer.hal); - timer_hal_intr_enable(&timer.hal); + timer_group_t group; + timer_idx_t index; + timg_dev_t* dev; + intr_handle_t isr_handle{}; + hw_timer_callback_t callback{nullptr}; + void* arg{nullptr}; + bool autoload{false}; +}; + +TimerConfig timer(HW_TIMER1_GROUP, HW_TIMER1_INDEX); + +} // namespace + +void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) +{ + timer.attach_interrupt(source_type, callback, arg); } -void hw_timer1_detach_interrupt(void) +void IRAM_ATTR hw_timer1_detach_interrupt(void) { - timer_hal_intr_disable(&timer.hal); - esp_intr_free(timer.isr_handle); - timer.isr_handle = nullptr; + timer.detach_interrupt(); } -void hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) +void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) { - timer_hal_set_auto_reload(&timer.hal, auto_load); - timer_hal_set_divider(&timer.hal, 1 << div); - timer.autoload = auto_load; + timer.enable_auto_reload(auto_load); + timer.set_prescale(1 << div); } void IRAM_ATTR hw_timer1_write(uint32_t ticks) { - timer_hal_set_counter_value(&timer.hal, ticks); - timer_hal_set_counter_enable(&timer.hal, true); + timer.set_counter_value(ticks); + timer.enable_counter(true); } void IRAM_ATTR hw_timer1_disable(void) { - timer_hal_set_counter_enable(&timer.hal, false); + timer.enable_counter(false); } uint32_t hw_timer1_read(void) { - uint64_t val{0}; - timer_hal_get_counter_value(&timer.hal, &val); - return val; + return timer.get_counter_value(); } void hw_timer_init(void) { - timer.group = HW_TIMER1_GROUP; - timer.index = HW_TIMER1_INDEX; - periph_module_enable(timer_group_periph_signals.groups[timer.group].module); - timer_hal_init(&timer.hal, timer.group, timer.index); - timer_hal_set_counter_enable(&timer.hal, false); - timer_hal_set_alarm_enable(&timer.hal, true); - timer_hal_set_alarm_value(&timer.hal, 0); - timer_hal_set_level_int_enable(&timer.hal, true); - timer_hal_set_counter_increase(&timer.hal, false); + timer.begin(); } diff --git a/Sming/Arch/Esp32/Components/driver/i2s.rst b/Sming/Arch/Esp32/Components/driver/i2s.rst index b4c5e11759..fc56ee73d7 100644 --- a/Sming/Arch/Esp32/Components/driver/i2s.rst +++ b/Sming/Arch/Esp32/Components/driver/i2s.rst @@ -1,5 +1,5 @@ -I2S: Inter-IC Serial communcations -================================== +I2S: Inter-IC Serial communications +=================================== Introduction ------------ diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/adc.h b/Sming/Arch/Esp32/Components/driver/include/driver/adc.h new file mode 100644 index 0000000000..351964ffc7 --- /dev/null +++ b/Sming/Arch/Esp32/Components/driver/include/driver/adc.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#if ESP_IDF_VERSION_MAJOR < 5 +#include_next +#else +#include +#include +#endif diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/gpio.h b/Sming/Arch/Esp32/Components/driver/include/driver/gpio.h new file mode 100644 index 0000000000..25c3429394 --- /dev/null +++ b/Sming/Arch/Esp32/Components/driver/include/driver/gpio.h @@ -0,0 +1,4 @@ +#pragma once + +#include_next +#include 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 49de03e797..8f2a7e2ccd 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h @@ -13,8 +13,9 @@ #include #include #include +#include -#ifdef CONFIG_ESP_TIMER_IMPL_TG0_LAC +#if CONFIG_ESP_TIMER_IMPL_TG0_LAC #include #else #include @@ -41,8 +42,8 @@ extern "C" { *************************************/ // Timer group/index to use: available on all ESP32 variants -#define HW_TIMER1_GROUP TIMER_GROUP_0 -#define HW_TIMER1_INDEX TIMER_0 +#define HW_TIMER1_GROUP 0 +#define HW_TIMER1_INDEX 0 /** * @brief Maximum timer interval in ticks @@ -89,7 +90,7 @@ typedef enum { * @param callback Callback function invoked via timer interrupt * @param arg Passed to callback function */ -void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg); +void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg); /** * @brief Enable the timer @@ -97,23 +98,23 @@ void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw * @param intr_type Ignored, always level-triggered * @param auto_load */ -void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load); +void hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load); /** * @brief Set the timer interval * @param ticks */ -void IRAM_ATTR hw_timer1_write(uint32_t ticks); +void hw_timer1_write(uint32_t ticks); /** * @brief Disable the timer */ -void IRAM_ATTR hw_timer1_disable(void); +void hw_timer1_disable(void); /** * @brief Detach interrupt from the timer */ -void IRAM_ATTR hw_timer1_detach_interrupt(void); +void hw_timer1_detach_interrupt(void); /** * @brief Get timer1 count @@ -129,18 +130,14 @@ uint32_t hw_timer1_read(void); #if CONFIG_ESP_TIMER_IMPL_TG0_LAC #define HW_TIMER2_CLK 2000000U -#define HW_TIMER2_INDEX 0 #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define HW_TIMER2_CLK 80000000U -#define HW_TIMER2_INDEX #elif defined(CONFIG_IDF_TARGET_ESP32C3) #define HW_TIMER2_CLK 16000000U -#define HW_TIMER2_INDEX 0 #elif defined(CONFIG_IDF_TARGET_ESP32S3) #define HW_TIMER2_CLK 16000000U -#define HW_TIMER2_INDEX 0 -#else -_Static_assert(false, "ESP32 Unsupported timer"); +#elif defined(CONFIG_IDF_TARGET_ESP32C2) +#define HW_TIMER2_CLK 40000000U #endif /** @@ -150,10 +147,16 @@ _Static_assert(false, "ESP32 Unsupported timer"); __forceinline static uint32_t hw_timer2_read(void) { #if CONFIG_ESP_TIMER_IMPL_TG0_LAC - return REG_READ(TIMG_LACTLO_REG(HW_TIMER2_INDEX)); + return REG_READ(TIMG_LACTLO_REG(0)); +#elif ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) + systimer_ll_counter_snapshot(&SYSTIMER, 0); + return systimer_ll_get_counter_value_low(&SYSTIMER, 0); +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + systimer_ll_counter_snapshot(); + return systimer_ll_get_counter_value_low(); #else - systimer_ll_counter_snapshot(HW_TIMER2_INDEX); - return systimer_ll_get_counter_value_low(HW_TIMER2_INDEX); + systimer_ll_counter_snapshot(0); + return systimer_ll_get_counter_value_low(0); #endif } diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/periph_ctrl.h b/Sming/Arch/Esp32/Components/driver/include/driver/periph_ctrl.h new file mode 100644 index 0000000000..c1dad911ec --- /dev/null +++ b/Sming/Arch/Esp32/Components/driver/include/driver/periph_ctrl.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#if ESP_IDF_VERSION_MAJOR < 5 +#include_next +#else +#include +#endif diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h index b003ec121a..570369049a 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/pwm.h @@ -1,65 +1,18 @@ -/* - * ESPRESSIF MIT License +/**** + * 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. * - * Copyright (c) 2016 + * pwm.h * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __PWM_H__ -#define __PWM_H__ + ****/ #pragma once -#if defined(__cplusplus) -extern "C" { -#endif - -/*pwm.h: function and macro definition of PWM API , driver level */ -/*user_light.h: user interface for light API, user level*/ -/*user_light_adj: API for color changing and lighting effects, user level*/ - -/*NOTE!! : DO NOT CHANGE THIS FILE*/ - -/*SUPPORT UP TO 8 PWM CHANNEL*/ +#ifdef SOC_LEDC_CHANNEL_NUM +#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 - -//struct pwm_param { -// uint32_t period; -// uint32_t freq; -// uint32_t duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8 -//}; -// -///* pwm_init should be called only once, for now */ -//void pwm_init(uint32_t period, uint32_t* duty, uint32_t pwm_channel_num, uint32_t (*pin_info_list)[3]); -//void pwm_start(void); -// -//void pwm_set_duty(uint32_t duty, uint8_t channel); -//uint32_t pwm_get_duty(uint8_t channel); -//void pwm_set_period(uint32_t period); -//uint32_t pwm_get_period(void); -// -//uint32_t get_pwm_version(void); -//void set_pwm_debug_en(uint8_t print_en); - -#if defined(__cplusplus) -} -#endif - #endif diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/spi_master.h b/Sming/Arch/Esp32/Components/driver/include/driver/spi_master.h new file mode 100644 index 0000000000..0d18f8d13e --- /dev/null +++ b/Sming/Arch/Esp32/Components/driver/include/driver/spi_master.h @@ -0,0 +1,13 @@ +#pragma once + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include_next + +#include +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif + +#pragma GCC diagnostic pop diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index 0015310cc3..3e03b60339 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -2,8 +2,6 @@ uart.cpp - esp32 UART HAL */ -// #define typeof(x) std::remove_volatile::type -#define typeof(x) decltype(x) // These conflict with enumerated types defined in IDF #define UART_PARITY_NONE IDF_UART_PARITY_NONE #define UART_PARITY_EVEN IDF_UART_PARITY_EVEN @@ -24,6 +22,20 @@ namespace { +// Ensure global values correspond to hardware values (may break when new variants added) +#define CHECK_STATUS_BIT(smg_name, idf_name) \ + static_assert(int(smg_name) == int(idf_name), "Esp32 value mismatch for " #smg_name); +CHECK_STATUS_BIT(UART_STATUS_TX_DONE, UART_INTR_TX_DONE) +CHECK_STATUS_BIT(UART_STATUS_RXFIFO_TOUT, UART_INTR_RXFIFO_TOUT) +CHECK_STATUS_BIT(UART_STATUS_BRK_DET, UART_INTR_BRK_DET) +CHECK_STATUS_BIT(UART_STATUS_CTS_CHG, UART_INTR_CTS_CHG) +CHECK_STATUS_BIT(UART_STATUS_DSR_CHG, UART_INTR_DSR_CHG) +CHECK_STATUS_BIT(UART_STATUS_RXFIFO_OVF, UART_INTR_RXFIFO_OVF) +CHECK_STATUS_BIT(UART_STATUS_FRM_ERR, UART_INTR_FRAM_ERR) +CHECK_STATUS_BIT(UART_STATUS_PARITY_ERR, UART_INTR_PARITY_ERR) +CHECK_STATUS_BIT(UART_STATUS_TXFIFO_EMPTY, UART_INTR_TXFIFO_EMPTY) +CHECK_STATUS_BIT(UART_STATUS_RXFIFO_FULL, UART_INTR_RXFIFO_FULL) + /* * Parameters relating to RX FIFO and buffer thresholds * @@ -65,7 +77,10 @@ struct smg_uart_pins_t { #elif defined(SOC_ESP32S3) #define UART0_PIN_DEFAULT 43, 44 #define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM -#define UART2_PIN_DEFAULT UART_NUM_2_TXD_DIRECT_GPIO_NUM, UART_NUM_2_RXD_DIRECT_GPIO_NUM +#define UART2_PIN_DEFAULT 17, 16 +#elif defined(SOC_ESP32C2) +#define UART0_PIN_DEFAULT UART_NUM_0_TXD_DIRECT_GPIO_NUM, UART_NUM_0_RXD_DIRECT_GPIO_NUM +#define UART1_PIN_DEFAULT 10, 9 #else static_assert(false, "Must define default UART pins for selected ESP_VARIANT"); #endif @@ -165,11 +180,10 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) auto uart = inst->uart; auto dev = getDevice(uart->uart_nr); - decltype(uart_dev_t::int_st) usis; - usis.val = dev->int_st.val; + auto usis = dev->int_st.val; // If status is clear there's no interrupt to service on this UART - if(usis.val == 0) { + if(usis == 0) { return; } @@ -179,7 +193,7 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) // Deal with the event, unless we're in raw mode if(!bitRead(uart->options, UART_OPT_CALLBACK_RAW)) { // Rx FIFO full or timeout - if(usis.rxfifo_full || usis.rxfifo_tout || usis.rxfifo_ovf) { + if(usis & (UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF)) { size_t read = 0; // Read as much data as possible from the RX FIFO into buffer @@ -197,7 +211,7 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) // Don't call back until buffer is (almost) full if(space > uart->rx_headroom) { - status.rxfifo_full = false; + status &= ~UART_INTR_RXFIFO_FULL; } } @@ -205,7 +219,7 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) * If the FIFO is full and we didn't read any of the data then need to mask the interrupt out or it'll recur. * The interrupt gets re-enabled by a call to uart_read() or uart_flush() */ - if(usis.rxfifo_ovf) { + if(usis & UART_INTR_RXFIFO_OVF) { uart_ll_disable_intr_mask(dev, UART_INTR_RXFIFO_OVF); } else if(read == 0) { uart_ll_disable_intr_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT); @@ -213,7 +227,7 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) } // Unless we replenish TX FIFO, disable after handling interrupt - if(usis.txfifo_empty) { + if(usis & UART_INTR_TXFIFO_EMPTY) { // Dump as much data as we can from buffer into the TX FIFO if(uart->tx_buffer != nullptr) { size_t space = uart_txfifo_free(dev); @@ -232,20 +246,20 @@ void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) uart_ll_disable_intr_mask(dev, UART_INTR_TXFIFO_EMPTY); } else { // We've topped up TX FIFO so defer callback until next time - status.txfifo_empty = false; + status &= ~UART_INTR_TXFIFO_EMPTY; } } } // Keep a note of persistent flags - cleared via uart_get_status() - uart->status |= status.val; + uart->status |= status; - if(status.val != 0 && uart->callback != nullptr) { - uart->callback(uart, status.val); + if(status != 0 && uart->callback != nullptr) { + uart->callback(uart, status); } // Final step is to clear status flags - dev->int_clr.val = usis.val; + dev->int_clr.val = usis; } } // namespace @@ -346,7 +360,7 @@ void smg_uart_start_isr(smg_uart_t* uart) return; } - decltype(uart_dev_t::int_ena) int_ena{}; + uint32_t int_ena{0}; auto dev = getDevice(uart->uart_nr); dev->conf1.val = 0; @@ -360,10 +374,7 @@ void smg_uart_start_isr(smg_uart_t* uart) * should be cleared at the start of a transaction and checked at the end. * See uart_get_status(). */ - int_ena.rxfifo_full = true; - int_ena.rxfifo_tout = true; - int_ena.brk_det = true; - int_ena.rxfifo_ovf = true; + int_ena |= UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_BRK_DET | UART_INTR_RXFIFO_OVF; } if(smg_uart_tx_enabled(uart)) { @@ -380,7 +391,7 @@ void smg_uart_start_isr(smg_uart_t* uart) } dev->int_clr.val = 0x0007ffff; - dev->int_ena.val = int_ena.val; + dev->int_ena.val = int_ena; smg_uart_disable_interrupts(); auto& inst = uartInstances[uart->uart_nr]; @@ -483,32 +494,25 @@ void smg_uart_set_break(smg_uart_t* uart, bool state) uint8_t smg_uart_get_status(smg_uart_t* uart) { - decltype(uart_dev_t::int_st) status{}; + uint32_t status{0}; if(uart != nullptr) { smg_uart_disable_interrupts(); // Get break/overflow flags from actual uart (physical or otherwise) - decltype(uart_dev_t::int_st) uart_status; - uart_status.val = uart->status; - status.brk_det = uart_status.brk_det; - status.rxfifo_ovf = uart_status.rxfifo_ovf; + status = uart->status & (UART_INTR_BRK_DET | UART_INTR_RXFIFO_OVF); uart->status = 0; // Read raw status register directly from real uart, masking out non-error bits uart = get_physical(uart); if(uart != nullptr) { auto dev = getDevice(uart->uart_nr); - decltype(uart_dev_t::int_raw) int_raw; - int_raw.val = dev->int_raw.val; - status.brk_det |= int_raw.brk_det; - status.rxfifo_ovf |= int_raw.rxfifo_ovf; - status.frm_err |= int_raw.frm_err; - status.parity_err |= int_raw.parity_err; + status |= dev->int_raw.val & + (UART_INTR_BRK_DET | UART_INTR_RXFIFO_OVF | UART_INTR_FRAM_ERR | UART_INTR_PARITY_ERR); // Clear errors - dev->int_clr.val = status.val; + uart_ll_clr_intsts_mask(dev, status); } smg_uart_restore_interrupts(); } - return status.val; + return status; } void smg_uart_flush(smg_uart_t* uart, smg_uart_mode_t mode) @@ -541,12 +545,7 @@ void smg_uart_flush(smg_uart_t* uart, smg_uart_mode_t mode) // If receive overflow occurred then these interrupts will be masked if(flushRx) { uart_ll_rxfifo_rst(dev); - - decltype(uart_dev_t::int_clr) int_clr; - int_clr.val = 0x0007ffff; - int_clr.txfifo_empty = false; // Leave this one - dev->int_clr.val = int_clr.val; - + dev->int_clr.val = 0x0007ffff & ~UART_INTR_TXFIFO_EMPTY; uart_ll_ena_intr_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF); } } @@ -562,11 +561,16 @@ uint32_t smg_uart_set_baudrate_reg(int uart_nr, uint32_t baud_rate) auto dev = getDevice(uart_nr); + // Return the actual baud rate in use +#if ESP_IDF_VERSION_MAJOR < 5 uart_ll_set_sclk(dev, UART_SCLK_APB); uart_ll_set_baudrate(dev, baud_rate); - - // Return the actual baud rate in use return uart_ll_get_baudrate(dev); +#else + uart_ll_set_sclk(dev, UART_SCLK_DEFAULT); + uart_ll_set_baudrate(dev, baud_rate, APB_CLK_FREQ); + return uart_ll_get_baudrate(dev, APB_CLK_FREQ); +#endif } uint32_t smg_uart_set_baudrate(smg_uart_t* uart, uint32_t baud_rate) @@ -716,16 +720,17 @@ bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config uint8_t full_threshold; if(uart->rx_buffer == nullptr) { // Setting this to 0 results in lockup as the interrupt never clears - full_threshold = TRange(1, UART_RXFIFO_FULL_THRHD).clip(config->rxfifo_full_thresh); + full_threshold = TRange(1U, unsigned(UART_RXFIFO_FULL_THRHD)).clip(config->rxfifo_full_thresh); } else { full_threshold = RX_FIFO_FULL_THRESHOLD; } uart_ll_set_rxfifo_full_thr(dev, full_threshold); - uart_ll_set_rx_tout(dev, TRange(0, UART_RX_TOUT_THRHD).clip(config->rx_timeout_thresh)); + uart_ll_set_rx_tout(dev, TRange(0U, unsigned(UART_RX_TOUT_THRHD)).clip(config->rx_timeout_thresh)); } if(smg_uart_tx_enabled(uart)) { - uart_ll_set_txfifo_empty_thr(dev, TRange(0, UART_TXFIFO_EMPTY_THRHD).clip(config->txfifo_empty_intr_thresh)); + uart_ll_set_txfifo_empty_thr( + dev, TRange(0U, unsigned(UART_TXFIFO_EMPTY_THRHD)).clip(config->txfifo_empty_intr_thresh)); } dev->int_clr.val = config->intr_mask; @@ -763,7 +768,11 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) if(tx_pin != UART_PIN_NO_CHANGE) { gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[tx_pin], PIN_FUNC_GPIO); gpio_set_level(gpio_num_t(tx_pin), true); +#ifdef SOC_UART_TX_PIN_IDX + gpio_matrix_out(tx_pin, conn.pins[SOC_UART_TX_PIN_IDX].signal, false, false); +#else gpio_matrix_out(tx_pin, conn.tx_sig, false, false); +#endif uart->tx_pin = tx_pin; } @@ -771,7 +780,11 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[rx_pin], PIN_FUNC_GPIO); gpio_set_pull_mode(gpio_num_t(rx_pin), GPIO_PULLUP_ONLY); gpio_set_direction(gpio_num_t(rx_pin), GPIO_MODE_INPUT); +#ifdef SOC_UART_RX_PIN_IDX + gpio_matrix_in(rx_pin, conn.pins[SOC_UART_RX_PIN_IDX].signal, false); +#else gpio_matrix_in(rx_pin, conn.rx_sig, false); +#endif } return true; diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index 119f993c10..5a83cd1aa1 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -14,6 +14,17 @@ ifeq ($(CREATE_EVENT_TASK),1) COMPONENT_CPPFLAGS += -DCREATE_EVENT_TASK endif +IDF_VERSION := $(firstword $(subst -, ,$(IDF_VER))) +IDF_VERSION_4 := $(filter v4%,$(IDF_VERSION)) + +ifneq (,$(filter esp32s3-v4.3%,$(ESP_VARIANT)-$(IDF_VER))) +$(error esp32s3 requires ESP IDF v4.4 or later) +endif + +ifneq (,$(filter esp32c2-v4%,$(ESP_VARIANT)-$(IDF_VER))) +$(error esp32c2 requires ESP IDF v5.0 or later) +endif + SDK_BUILD_BASE := $(COMPONENT_BUILD_BASE)/sdk SDK_COMPONENT_LIBDIR := $(COMPONENT_BUILD_BASE)/lib @@ -21,9 +32,10 @@ SDKCONFIG_H := $(SDK_BUILD_BASE)/config/sdkconfig.h SDK_LIBDIRS := \ esp_wifi/lib/$(ESP_VARIANT) \ + esp_phy/lib/$(ESP_VARIANT) \ xtensa/$(ESP_VARIANT) \ hal/$(ESP_VARIANT) \ - $(ESP_VARIANT)/ld \ + soc/$(ESP_VARIANT)/ld \ esp_rom/$(ESP_VARIANT)/ld # BLUETOOTH @@ -45,7 +57,9 @@ LIBDIRS += \ $(SDK_BUILD_BASE)/esp-idf/mbedtls/mbedtls/library \ $(SDK_BUILD_BASE)/esp-idf/$(ESP_VARIANT) \ $(SDK_BUILD_BASE)/esp-idf/$(ESP_VARIANT)/ld \ + $(SDK_BUILD_BASE)/esp-idf/esp_system/ld \ $(ESP32_COMPONENT_PATH)/ld \ + $(SDK_COMPONENTS_PATH)/$(ESP_VARIANT)/ld \ $(addprefix $(SDK_COMPONENTS_PATH)/,$(SDK_LIBDIRS)) SDK_INCDIRS := \ @@ -54,7 +68,6 @@ SDK_INCDIRS := \ bootloader_support/include_bootloader \ driver/$(ESP_VARIANT)/include \ driver/include \ - esp_ipc/include \ esp_pm/include \ esp_rom/include/$(ESP_VARIANT) \ esp_rom/include \ @@ -63,10 +76,10 @@ SDK_INCDIRS := \ esp_timer/include \ soc/include \ soc/$(ESP_VARIANT)/include \ + soc/include/soc \ heap/include \ log/include \ nvs_flash/include \ - freertos/include \ esp_event/include \ lwip/lwip/src/include \ lwip/port/esp32/include \ @@ -75,11 +88,12 @@ SDK_INCDIRS := \ wpa_supplicant/include \ wpa_supplicant/port/include \ esp_hw_support/include \ + esp_hw_support/include/soc \ hal/include \ + hal/platform_port/include \ hal/$(ESP_VARIANT)/include \ esp_system/include \ esp_common/include \ - esp_adc_cal/include \ esp_netif/include \ esp_eth/include \ esp_wifi/include \ @@ -87,6 +101,28 @@ SDK_INCDIRS := \ lwip/include/apps/sntp \ wpa_supplicant/include/esp_supplicant +ifdef IDF_VERSION_4 +SDK_INCDIRS += \ + esp_adc_cal/include \ + esp_ipc/include \ + freertos/include \ + freertos/include/esp_additions \ + freertos/include/esp_additions/freertos +FREERTOS_PORTABLE := freertos/port +else +SDK_INCDIRS += \ + esp_adc/include \ + esp_app_format/include \ + esp_partition/include \ + freertos/FreeRTOS-Kernel/include \ + freertos/esp_additions/include \ + freertos/esp_additions/include/freertos \ + driver/deprecated +FREERTOS_PORTABLE := freertos/FreeRTOS-Kernel/portable +endif + + + ifeq ($(ENABLE_BLUETOOTH),1) SDK_INCDIRS += \ bt/include/$(ESP_VARIANT)/include \ @@ -116,13 +152,13 @@ endif ifdef IDF_TARGET_ARCH_RISCV SDK_INCDIRS += \ - freertos/port/riscv/include \ + $(FREERTOS_PORTABLE)/riscv/include \ riscv/include else SDK_INCDIRS += \ xtensa/include \ xtensa/$(ESP_VARIANT)/include \ - freertos/port/xtensa/include + $(FREERTOS_PORTABLE)/xtensa/include endif @@ -137,12 +173,10 @@ SDK_COMPONENTS := \ cxx \ driver \ efuse \ - $(ESP_VARIANT) \ esp_common \ esp_event \ esp_gdbstub \ esp_hw_support \ - esp_ipc \ esp_pm \ esp_rom \ esp_ringbuf \ @@ -159,14 +193,31 @@ SDK_COMPONENTS := \ soc \ spi_flash +ifneq (,$(filter v4.3%,$(IDF_VERSION))) +SDK_COMPONENTS += $(ESP_VARIANT) +else +SDK_COMPONENTS += esp_phy +endif + +ifdef IDF_VERSION_4 +SDK_COMPONENTS += \ + esp_ipc \ + esp_adc_cal +else +SDK_COMPONENTS += \ + esp_adc \ + esp_app_format \ + esp_partition +endif + + ifneq ($(DISABLE_NETWORK),1) SDK_COMPONENTS += \ esp_wifi \ esp_eth \ lwip \ mbedcrypto \ - esp_netif \ - openssl + esp_netif ifneq ($(DISABLE_WIFI),1) SDK_COMPONENTS += \ wifi_provisioning \ @@ -174,10 +225,6 @@ SDK_COMPONENTS += \ endif endif -ifneq ($(ESP_VARIANT),esp32s3) -SDK_COMPONENTS += esp_adc_cal -endif - ifdef IDF_TARGET_ARCH_RISCV SDK_COMPONENTS += riscv else @@ -188,12 +235,15 @@ SDK_ESP_WIFI_LIBS := \ coexist \ core \ espnow \ - mesh \ net80211 \ phy \ pp \ smartconfig +ifneq ($(ESP_VARIANT),esp32c2) +SDK_ESP_WIFI_LIBS += mesh +endif + ifeq ($(ENABLE_BLUETOOTH),1) SDK_ESP_BLUETOOTH_LIBS := bt btdm_app ifneq (,$(filter $(ESP_VARIANT),esp32c3 esp32s3)) @@ -236,7 +286,8 @@ LDFLAGS_esp32 := \ LDFLAGS_esp32s2 := \ $(call LinkerScript,rom.newlib-funcs) \ $(call LinkerScript,rom.newlib-data) \ - $(call LinkerScript,rom.spiflash) + $(call LinkerScript,rom.spiflash) \ + $(call LinkerScript,rom.newlib-time) \ LDFLAGS_esp32c3 := \ $(call LinkerScript,rom.newlib) \ @@ -244,9 +295,16 @@ LDFLAGS_esp32c3 := \ $(call LinkerScript,rom.eco3) LDFLAGS_esp32s3 := \ - $(call LinkerScript,rom.newlib-funcs) \ - $(call LinkerScript,rom.newlib-data) \ - $(call LinkerScript,rom.spiflash) + $(call LinkerScript,rom.newlib) \ + $(call LinkerScript,rom.version) \ + $(call LinkerScript,rom.newlib-time) + +LDFLAGS_esp32c2 := \ + $(call LinkerScript,rom.newlib) \ + $(call LinkerScript,rom.version) \ + $(call LinkerScript,rom.newlib-time) \ + $(call LinkerScript,rom.heap) \ + $(call LinkerScript,rom.mbedtls) SDK_WRAP_SYMBOLS := SDK_UNDEF_SYMBOLS := @@ -254,12 +312,11 @@ SDK_UNDEF_SYMBOLS := $(foreach c,$(wildcard $(SDK_DEFAULT_PATH)/*.mk),$(eval include $c)) EXTRA_LDFLAGS := \ - -T $(ESP_VARIANT)_out.ld \ - $(call LinkerScript,project) \ $(call LinkerScript,peripherals) \ $(call LinkerScript,rom) \ $(call LinkerScript,rom.api) \ $(call LinkerScript,rom.libgcc) \ + $(call LinkerScript,rom.newlib-nano) \ $(call Wrap,\ esp_event_loop_create_default \ esp_event_handler_register \ @@ -272,6 +329,15 @@ EXTRA_LDFLAGS := \ $(call Undef,$(SDK_UNDEF_SYMBOLS)) \ $(call Wrap,$(SDK_WRAP_SYMBOLS)) +ifneq (,$(filter v4.3%,$(IDF_VERSION))) +EXTRA_LDFLAGS += \ + -T $(ESP_VARIANT)_out.ld \ + $(call LinkerScript,project) +else +EXTRA_LDFLAGS += \ + -T memory.ld \ + -T sections.ld +endif SDK_PROJECT_PATH := $(ESP32_COMPONENT_PATH)/project/$(ESP_VARIANT)/$(BUILD_TYPE) SDK_CONFIG_DEFAULTS := $(SDK_PROJECT_PATH)/sdkconfig.defaults @@ -342,6 +408,13 @@ $(SDK_CONFIG_DEFAULTS): $(SDK_CUSTOM_CONFIG_PATH) $(Q) $(foreach f,$(SDK_CONFIG_FILES),\ $(if $(wildcard $f),cat $f >> $@;) \ ) + $(Q) printf "\n# Auto-generated settings\n" >> $@ + $(Q) echo "CONFIG_ESPTOOLPY_FLASHMODE_$(SPI_MODE)=y" >> $@ + $(Q) echo "CONFIG_ESPTOOLPY_FLASHFREQ_$(SPI_SPEED)M=y" >> $@ + $(Q) echo "CONFIG_ESPTOOLPY_FLASHSIZE_$(SPI_SIZE)B=y" >> $@ +ifeq ($(ENABLE_GDB), 1) + $(Q) echo "CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=$(if $(ENABLE_GDB),y,n)" >> $@ +endif ##@Configuration diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index a4caeb16e7..c893597df9 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -50,5 +50,8 @@ CONFIG_VFS_SUPPORT_TERMIOS=n # Not used CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n -# Debugging -CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=y +# 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 diff --git a/Sming/Arch/Esp32/Components/esp32/src/clk.c b/Sming/Arch/Esp32/Components/esp32/src/clk.c index ca0bd2fee6..724f3def0e 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/clk.c +++ b/Sming/Arch/Esp32/Components/esp32/src/clk.c @@ -2,15 +2,10 @@ #include #include -#if CONFIG_IDF_TARGET_ESP32 -typedef esp_pm_config_esp32_t pm_config_t; -#elif CONFIG_IDF_TARGET_ESP32C3 -typedef esp_pm_config_esp32c3_t pm_config_t; -#elif CONFIG_IDF_TARGET_ESP32S2 -typedef esp_pm_config_esp32s2_t pm_config_t; -#elif CONFIG_IDF_TARGET_ESP32S3 -typedef esp_pm_config_esp32s3_t pm_config_t; -#endif +#define EXPAND(a) a +#define CONCAT3a(a, b, c) a##b##c +#define CONCAT3(a, b, c) CONCAT3a(a, b, c) +typedef CONCAT3(esp_pm_config_, SMING_SOC, _t) pm_config_t; int esp_clk_cpu_freq(void); @@ -56,5 +51,5 @@ bool system_update_cpu_freq(uint32_t freq) uint32_t system_get_cpu_freq(void) { - return esp_clk_cpu_freq() / MHZ; + return esp_clk_cpu_freq() / 1000000U; } diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h index e34c31504a..8579d2d67e 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -19,7 +20,11 @@ uint32_t system_get_cpu_freq(void); __forceinline static uint32_t esp_get_ccount() { +#if ESP_IDF_VERSION_MAJOR < 5 return cpu_hal_get_cycle_count(); +#else + return esp_cpu_get_cycle_count(); +#endif } #ifdef __cplusplus diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_system.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_system.h index 9d0704944f..9531516ba2 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_system.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_system.h @@ -1,16 +1,20 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" #include_next -#include +#include -#ifdef __cplusplus -extern "C" { +#if ESP_IDF_VERSION_MAJOR >= 5 +#include #endif -#include +#pragma GCC diagnostic pop uint32_t system_get_time(void); void system_restart(void); @@ -50,8 +54,10 @@ const char* system_get_sdk_version(void); uint32_t system_get_chip_id(void); +unsigned long os_random(void); + +int os_get_random(unsigned char* buf, size_t len); + #ifdef __cplusplus } #endif - -#pragma GCC diagnostic pop diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h index 6077b68105..3637e3074a 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h @@ -23,7 +23,7 @@ #include "esp_tasks.h" #include #include -#include +#include #include #include #include @@ -39,7 +39,7 @@ /** @brief Disable interrupts * @retval Current interrupt level */ -#define noInterrupts() portENTER_CRITICAL_NESTED() +#define noInterrupts() portSET_INTERRUPT_MASK_FROM_ISR() /** @brief Enable interrupts */ @@ -47,4 +47,4 @@ /** @brief Restore interrupts to level saved from previous noInterrupts() call */ -#define restoreInterrupts(state) portEXIT_CRITICAL_NESTED(state) +#define restoreInterrupts(state) portCLEAR_INTERRUPT_MASK_FROM_ISR(state) diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/ets_sys.h b/Sming/Arch/Esp32/Components/esp32/src/include/ets_sys.h deleted file mode 100644 index e6555b6f82..0000000000 --- a/Sming/Arch/Esp32/Components/esp32/src/include/ets_sys.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index ed8f54c9f4..47ea3f00f2 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -27,13 +27,21 @@ namespace { void main(void*) { - auto err = esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true); + 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); - err = esp_task_wdt_status(nullptr); - assert(err == ESP_OK); hw_timer_init(); @@ -73,6 +81,8 @@ extern "C" void app_main(void) constexpr unsigned core_id{0}; #endif +#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); } diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index e9a573e1c2..a3d3607e0b 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -2,7 +2,10 @@ #include #include #include -#include +#include +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif extern "C" int64_t esp_system_get_time(); @@ -53,8 +56,18 @@ void system_restart(void) * Doing so causes a deadlock and a task watchdog timeout. * * Delegating this call to any other task fixes the issue. + * + * We can use the timer task to handle the call. + * This method does not free the allocated timer resources but as the system + * is restarting this doesn't matter. */ - esp_ipc_call(0, esp_ipc_func_t(esp_restart), nullptr); + const esp_timer_create_args_t create_args = { + .callback = esp_timer_cb_t(esp_restart), + .dispatch_method = ESP_TIMER_TASK, + }; + esp_timer_handle_t handle{nullptr}; + esp_timer_create(&create_args, &handle); + esp_timer_start_once(handle, 100); } /* Watchdog */ diff --git a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp index a44ffb7480..0ae47b5c9c 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp @@ -18,9 +18,7 @@ uint32_t flashmem_write(const void* from, uint32_t toaddr, uint32_t size) { - esp_task_wdt_reset(); - - esp_err_t r = spi_flash_write(toaddr, from, size); + esp_err_t r = esp_flash_write(esp_flash_default_chip, from, toaddr, size); if(r != ESP_OK) { SYSTEM_ERROR("ERROR in flash_write: r=%d at %08X\n", r, toaddr); size = 0; @@ -31,9 +29,7 @@ uint32_t flashmem_write(const void* from, uint32_t toaddr, uint32_t size) uint32_t flashmem_read(void* to, uint32_t fromaddr, uint32_t size) { - esp_task_wdt_reset(); - - esp_err_t r = spi_flash_read(fromaddr, to, size); + esp_err_t r = esp_flash_read(esp_flash_default_chip, to, fromaddr, size); if(r != ESP_OK) { SYSTEM_ERROR("ERROR in flash_read: r=%d at %08X\n", r, fromaddr); size = 0; @@ -48,7 +44,7 @@ bool flashmem_erase_sector(uint32_t sector_id) debug_d("flashmem_erase_sector(0x%08x)", sector_id); - return spi_flash_erase_sector(sector_id) == SPI_FLASH_RESULT_OK; + return esp_flash_erase_region(esp_flash_default_chip, sector_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE) == ESP_OK; } SPIFlashInfo flashmem_get_info() diff --git a/Sming/Arch/Esp32/Components/spi_flash/include/esp_spi_flash.h b/Sming/Arch/Esp32/Components/spi_flash/include/esp_spi_flash.h index 3e4a03dff7..439bd344ee 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/include/esp_spi_flash.h +++ b/Sming/Arch/Esp32/Components/spi_flash/include/esp_spi_flash.h @@ -11,7 +11,12 @@ #pragma once +#include +#if ESP_IDF_VERSION_MAJOR < 5 #include_next +#else +#include +#endif #include #include @@ -26,8 +31,6 @@ extern "C" { * @{ */ -#define SPI_FLASH_RESULT_OK 0 - /// Flash memory access must be aligned and in multiples of 4-byte words #define INTERNAL_FLASH_WRITE_UNIT_SIZE 4 #define INTERNAL_FLASH_READ_UNIT_SIZE 4 @@ -51,10 +54,10 @@ typedef enum { } SPIFlashMode; typedef enum { - SPEED_40MHZ = ESP_IMAGE_SPI_SPEED_40M, - SPEED_26MHZ = ESP_IMAGE_SPI_SPEED_26M, - SPEED_20MHZ = ESP_IMAGE_SPI_SPEED_20M, - SPEED_80MHZ = ESP_IMAGE_SPI_SPEED_80M, + SPEED_40MHZ = 0, // ESP_IMAGE_SPI_SPEED_40M + SPEED_26MHZ = 1, // ESP_IMAGE_SPI_SPEED_26M + SPEED_20MHZ = 2, // ESP_IMAGE_SPI_SPEED_20M + SPEED_80MHZ = 0x0f, // ESP_IMAGE_SPI_SPEED_80M } SPIFlashSpeed; typedef enum { diff --git a/Sming/Arch/Esp32/Core/Digital.cpp b/Sming/Arch/Esp32/Core/Digital.cpp index 92028643f4..b5c694018f 100644 --- a/Sming/Arch/Esp32/Core/Digital.cpp +++ b/Sming/Arch/Esp32/Core/Digital.cpp @@ -103,7 +103,7 @@ void digitalWrite(uint16_t pin, uint8_t val) gpio_ll_set_level(&GPIO, gpio_num_t(pin), val); } -uint8_t IRAM_ATTR digitalRead(uint16_t pin) +uint8_t digitalRead(uint16_t pin) { return gpio_ll_get_level(&GPIO, gpio_num_t(pin)); } diff --git a/Sming/Arch/Esp32/Core/HardwarePWM.cpp b/Sming/Arch/Esp32/Core/HardwarePWM.cpp new file mode 100644 index 0000000000..fcc387dc34 --- /dev/null +++ b/Sming/Arch/Esp32/Core/HardwarePWM.cpp @@ -0,0 +1,275 @@ +/**** + * 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 + * Esp32 version: https://github.com/pljakobs + * + * This HardwarePWM library enables Sming framework uses to use the ESP32 ledc PWM api + * + * the ESP32 PWM Hardware is much more powerful than the ESP8266, allowing wider PWM timers (up to 20 bit) + * as well as much higher PWM frequencies (up to 40MHz for a 1 Bit wide PWM) + * + * Overview: + * +------------------------------------------------------------------------------------------------+ + * | LED_PWM | + * | +-------------------------------------------+ +-------------------------------------------+ | + * | | High_Speed_Channels¹ | | Low_Speed_Channels | | + * | | +-----+ +--------+ | | +-----+ +--------+ | | + * | | | | --> | h_ch 0 | | | | | --> | l_ch 0 | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | h_timer 0 | --> | | | | | l_timer 0 | --> | | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | | --> | h_ch 1 | | | | | --> | l_ch 1 | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | | | | | | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | | --> | h_ch 2 | | | | | --> | l_ch 2 | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | h_timer 1 | --> | | | | | l_timer 1 | --> | | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | | --> | h_ch 3 | | | | | --> | l_ch 3 | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | MUX | | | | MUX | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | | --> | h_ch 4 | | | | | --> | l_ch 4 | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | h_timer 2 | --> | | | | | l_timer 2 | --> | | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | | --> | h_ch 5 | | | | | --> | l_ch 5 | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | | | | | | | | + * | | | | +--------+ | | | | +--------+ | | + * | | | | --> | h_ch 6 | | | | | --> | l_ch 6²| | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | h_timer 3 | --> | | | | | l_timer 3 | --> | | | | + * | | +-----------+ | | +--------+ | | +-----------+ | | +--------+ | | + * | | | | --> | h_ch 7 | | | | | --> | l_ch 7²| | | + * | | | | +--------+ | | | | +--------+ | | + * | | +-----+ | | +-----+ | | + * | +-------------------------------------------+ +-------------------------------------------+ | + * +------------------------------------------------------------------------------------------------+ + * ¹ High speed channels are only available when SOC_LEDC_SUPPORT_HS_MODE is defined as 1 + * ² The ESP32C3 does only support six channels, so 6 and 7 are not available on that SoC + * + * The nomenclature of timers in the high speed / low speed blocks is a bit misleading as the idf api + * speaks of "speed mode", which, to me, implies that this would be a mode configurable in a specific timer + * while in reality, it does select a block of timers. + * + * Maximum Timer width for PWM: + * ============================ + * esp32 SOC_LEDC_TIMER_BIT_WIDE_NUM (20) + * esp32c3 SOC_LEDC_TIMER_BIT_WIDE_NUM (14) + * esp32s2 SOC_LEDC_TIMER_BIT_WIDE_NUM (14) + * esp32s3 SOC_LEDC_TIMER_BIT_WIDE_NUM (14) + * + * Number of Channels: + * =================== + * esp32 SOC_LEDC_CHANNEL_NUM (8) + * esp32c3 SOC_LEDC_CHANNEL_NUM (6) + * esp32s2 SOC_LEDC_CHANNEL_NUM (8) + * esp32s3 SOC_LEDC_CHANNEL_NUM (8) + * + * Some SoSs support a mode called HIGHSPEED_MODE which is essentially another full block of PWM hardware + * that adds SOC_LEDC_CHANNEL_NUM channels. + * Those Architectures have SOC_LEDC_SUPPORT_HS_MODE defined as 1. + * In esp-idf-4.3 that's currently only the esp32 SOC + * + * Supports highspeed mode: + * ======================== + * esp32 SOC_LEDC_SUPPORT_HS_MODE (1) + * + * hardware technical reference: + * ============================= + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#ledpwm + * + * Overview of the whole ledc-system here: + * https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html + * + * the ledc interface also exposes some advanced functions such as fades that are then done in hardware. + * ToDo: implement a Sming interface for fades + * + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_RESOLUTION ledc_timer_bit_t(10) +#define DEFAULT_PERIOD 200 +namespace +{ +ledc_channel_t pinToChannel(uint8_t pin) +{ + return ledc_channel_t(pin % 8); +} + +ledc_mode_t pinToGroup(uint8_t pin) +{ + return ledc_mode_t(pin / 8); +} + +ledc_timer_t pinToTimer(uint8_t pin) +{ + return ledc_timer_t((pin / 2) % 4); +} + +uint32_t periodToFrequency(uint32_t period) +{ + return (period == 0) ? 0 : (1000000 / period); +} + +uint32_t frequencyToPeriod(uint32_t freq) +{ + return (freq == 0) ? 0 : (1000000 / freq); +} + +uint32_t maxDuty(ledc_timer_bit_t bits) +{ + return (1U << bits) - 1; +} + +} //namespace + +HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +{ + debug_d("starting HardwarePWM init"); + 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]; + + /* + * Prepare and then apply the LEDC PWM timer configuration. + * This may configure the same timer more than once (in fact up to 8 times) + * which should not be an issue, though, since the values should be the same for all timers + */ + // The two groups (if available) are operating in different speed modes, hence speed mode is an alias for group or vice versa + ledc_timer_config_t ledc_timer{ + .speed_mode = pinToGroup(i), + .duty_resolution = LEDC_TIMER_10_BIT, // todo: make configurable later + .timer_num = pinToTimer(i), + .freq_hz = periodToFrequency(DEFAULT_PERIOD), // todo: make configurable later + .clk_cfg = LEDC_AUTO_CLK, + }; + + debug_d("ledc_timer.\r\n" + "\tspeed_mode: %i\r\n" + "\ttimer_num: %i\r\n" + "\tduty_resolution: %i\r\n" + "\tfreq: %i\n\tclk_cfg: %i\r\n\n", + ledc_timer.speed_mode, ledc_timer.timer_num, ledc_timer.duty_resolution, ledc_timer.freq_hz, + ledc_timer.clk_cfg); + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + /* + * Prepare and then apply the LEDC PWM channel configuration + */ + ledc_channel_config_t ledc_channel{ + .gpio_num = pins[i], + .speed_mode = pinToGroup(i), + .channel = pinToChannel(i), + .intr_type = LEDC_INTR_DISABLE, + .timer_sel = pinToTimer(i), + .duty = 0, + .hpoint = 0, + }; + debug_d("ledc_channel\n" + "\tspeed_mode: %i\r\n" + "\tchannel: %i\r\n" + "\ttimer_sel %i\r\n" + "\tintr_type: %i\r\n" + "\tgpio_num: %i\r\n" + "\tduty: %i\r\n" + "\thpoint: %i\r\n\n", + pinToGroup(i), pinToChannel(i), pinToTimer(i), ledc_channel.intr_type, pins[i], 0, 0); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + ledc_bind_channel_timer(pinToGroup(i), pinToChannel(i), pinToTimer(i)); + } + maxduty = maxDuty(DEFAULT_RESOLUTION); +} + +HardwarePWM::~HardwarePWM() +{ + // Stop pwm for all pins and set idle level to 0 + for(uint8_t i = 0; i < channel_count; i++) { + ledc_stop(pinToGroup(i), pinToChannel(i), 0); + } +} + +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) +{ + // esp32 defines the frequency / period per timer + return (chan == PWM_BAD_CHANNEL) ? 0 : ledc_get_duty(pinToGroup(chan), pinToChannel(chan)); +} + +bool HardwarePWM::setDutyChan(uint8_t chan, uint32_t duty, bool update) +{ + if(chan == PWM_BAD_CHANNEL) { + return false; + } + + if(duty <= maxduty) { + ESP_ERROR_CHECK(ledc_set_duty(pinToGroup(chan), pinToChannel(chan), duty)); + /* + * ignoring the update flag in this release, ToDo: implement a synchronized update mechanism + * if(update) { + * ESP_ERROR_CHECK(ledc_update_duty(pinToGroup(chan), pinToChannel(chan))); + * //update(); + * } + */ + ESP_ERROR_CHECK(ledc_update_duty(pinToGroup(chan), pinToChannel(chan))); + return true; + } + + debug_d("Duty cycle value too high for current period, max duty cycle is %d", maxduty); + return false; +} + +uint32_t HardwarePWM::getPeriod() +{ + // 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. + return frequencyToPeriod(ledc_get_freq(ledc_mode_t(0), ledc_timer_t(0))); +} + +void HardwarePWM::setPeriod(uint32_t period) +{ + // Set the frequency globally, will add per timer functions later. + // Also, this can be done smarter. + for(uint8_t i = 0; i < channel_count; i++) { + ESP_ERROR_CHECK(ledc_set_freq(pinToGroup(i), pinToTimer(i), periodToFrequency(period))); + } + // ledc_update_duty(); + update(); +} + +void HardwarePWM::update() +{ + // ledc_update_duty(); +} + +uint32_t HardwarePWM::getFrequency(uint8_t pin) +{ + return ledc_get_freq(pinToGroup(pin), pinToTimer(pin)); +} diff --git a/Sming/Arch/Esp32/Core/adc.cpp b/Sming/Arch/Esp32/Core/adc.cpp index 6e81de448a..a2dce4f220 100644 --- a/Sming/Arch/Esp32/Core/adc.cpp +++ b/Sming/Arch/Esp32/Core/adc.cpp @@ -1,6 +1,8 @@ #include #include +#if ESP_IDF_VERSION_MAJOR < 5 #include +#endif #include #include @@ -10,7 +12,7 @@ namespace { struct AdcInfo { adc_unit_t adc; - uint8_t channel; + adc_channel_t channel; }; bool lookupAdc(uint16_t pin, AdcInfo& info) @@ -19,7 +21,7 @@ bool lookupAdc(uint16_t pin, AdcInfo& info) for(unsigned ch = 0; ch < SOC_ADC_MAX_CHANNEL_NUM; ++ch) { if(adc_channel_io_map[adc][ch] == pin) { info.adc = adc_unit_t(adc + 1); - info.channel = ch; + info.channel = adc_channel_t(ch); return true; } } @@ -40,6 +42,8 @@ uint16_t analogRead(uint16_t pin) pinMode(pin, ANALOG); +#if ESP_IDF_VERSION_MAJOR < 5 + constexpr adc_atten_t attenuation{ADC_ATTEN_DB_0}; esp_adc_cal_characteristics_t adcChars{}; @@ -74,4 +78,36 @@ uint16_t analogRead(uint16_t pin) } return adc1_get_raw(adc1_channel_t(info.channel)); + +#else + + // Initialise unit + adc_oneshot_unit_init_cfg_t init_config{ + .unit_id = info.adc, + }; + adc_oneshot_unit_handle_t adc_handle; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle)); + + // Initialise channel + adc_oneshot_chan_cfg_t channel_config{ + .atten = ADC_ATTEN_DB_0, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, info.channel, &channel_config)); + + // Calibration + // adc_cali_handle_t adc1_cali_handle = NULL; + // bool do_calibration1 = example_adc_calibration_init(ADC_UNIT_1, ADC_ATTEN_DB_11, &adc1_cali_handle); + + int rawSampleValue{0}; + ESP_ERROR_CHECK(adc_oneshot_read(adc_handle, info.channel, &rawSampleValue)); + + // ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_handle, adc_raw[0][0], &voltage[0][0])); + // ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]); + + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle)); + + return rawSampleValue; + +#endif } diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index 4afaa24ac8..f40f35557f 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -88,6 +88,7 @@ This is still at an early stage of development however basic applications should - esp32s2 - esp32c3 - esp32s3 +- esp32c2 You can change variants like this: @@ -100,6 +101,29 @@ Each variant uses a different build directory, e.g. ``out/Esp32/esp32c3/...`` to See :component-esp32:`esp32` for further details. +IDF versions +============ + +Sming currently supports IDF versions 4.3, 4.4 and 5.0. + +The default installed IDF version is 4.4. This can be changed as follows:: + + INSTALL_IDF_VER=5.0 $SMING_HOME/../Tools/install.sh + +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. + +After switching versions, run `make clean components-clean` before re-compiling. + +.. note:: + + Currently, switching from version 4.x to 5.0 or vice-versa requires an additional step + as they use different versions of the 'pyparsing' Python library. + + If moving from IDF 4.x to 5.0: `python -m pip install --upgrade pyparsing` + Moving from IDF 5.0 to 4.x: `python -m pip install pyparsing\<2.4` + + Components ---------- diff --git a/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp b/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp index 03754e121e..97a69e98db 100644 --- a/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp +++ b/Sming/Arch/Esp32/Services/Profiling/TaskStat.cpp @@ -84,8 +84,8 @@ bool TaskStat::update() std::bitset startMatched, endMatched; - PSTR_ARRAY(hdrfmt, "# | Core | Prio | Run Time | % Time | Name"); - PSTR_ARRAY(datfmt, "%-3u | %c | %4u | %8u | %3u%% | %s\r\n"); + 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); // Match each task in startInfo.status to those in the endInfo.status @@ -108,7 +108,7 @@ bool TaskStat::update() coreId = status.xCoreID; #endif out.printf(datfmt, status.xTaskNumber, (coreId == CONFIG_FREERTOS_NO_AFFINITY) ? '-' : ('0' + coreId), - status.uxCurrentPriority, taskElapsedTime, percentageTime, status.pcTaskName); + status.uxCurrentPriority, status.xHandle, taskElapsedTime, percentageTime, status.pcTaskName); } } diff --git a/Sming/Arch/Esp32/Tools/idf_tools.py b/Sming/Arch/Esp32/Tools/idf_tools.py new file mode 100644 index 0000000000..8001e98652 --- /dev/null +++ b/Sming/Arch/Esp32/Tools/idf_tools.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import os, argparse, json + +def get_tool_info(soc): + path = os.path.expandvars('${IDF_PATH}/tools/tools.json') + with open(path, 'r') as f: # type: ignore + tools_info = json.load(f) + + compiler_prefix = None + compiler_version = None + for tool in tools_info['tools']: + if soc in tool['supported_targets']: + desc = tool['description'] + if desc.startswith('Toolchain'): + compiler_prefix = tool['name'] + compiler_version = tool['versions'][0]['name'] + break + print(f"{compiler_prefix} {compiler_version}") + + # ESP32_COMPILER_PREFIX=compiler_prefix + # IDF_TARGET_ARCH_RISCV=is_riscv + + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='IDF Tools Parser') + parser.add_argument('soc', help='Target SOC') + args = parser.parse_args() + get_tool_info(args.soc) diff --git a/Sming/Arch/Esp32/Tools/install.cmd b/Sming/Arch/Esp32/Tools/install.cmd index ae5388a47e..9f0122949b 100644 --- a/Sming/Arch/Esp32/Tools/install.cmd +++ b/Sming/Arch/Esp32/Tools/install.cmd @@ -4,11 +4,16 @@ if "%IDF_PATH%"=="" goto :EOF if "%IDF_TOOLS_PATH%"=="" goto :EOF if "%IDF_REPO%"=="" set IDF_REPO="https://github.com/mikee47/esp-idf.git" -if "%IDF_BRANCH%"=="" set IDF_BRANCH="sming/release/v4.3" +if "%INSTALL_IDF_VER%"=="" set INSTALL_IDF_VER=4.4 +set IDF_BRANCH="sming/release/v%INSTALL_IDF_VER%" git clone -b %IDF_BRANCH% %IDF_REPO% %IDF_PATH% REM Install IDF tools and packages python "%IDF_PATH%\tools\idf_tools.py" --non-interactive install python -m pip install %SMINGTOOLS%/gevent-1.5.0-cp39-cp39-win_amd64.whl -python -m pip install -r %IDF_PATH%\requirements.txt +set IDF_REQUIREMENTS="%IDF_PATH%\requirements.txt" +if not exist "%IDF_REQUIREMENTS%" set IDF_REQUIREMENTS="%IDF_PATH%\tools\requirements\requirements.core.txt" +python -m pip install -r "%IDF_REQUIREMENTS%" + +if "%INSTALL_IDF_VER%"=="5.0" python "%IDF_PATH%\tools\idf_tools.py" --non-interactive install-python-env diff --git a/Sming/Arch/Esp32/Tools/install.sh b/Sming/Arch/Esp32/Tools/install.sh index ccf85289f8..0667e28704 100755 --- a/Sming/Arch/Esp32/Tools/install.sh +++ b/Sming/Arch/Esp32/Tools/install.sh @@ -36,13 +36,15 @@ if [ ! -L "$IDF_PATH" ] && [ -d "$IDF_PATH" ]; then mv "$IDF_PATH" "$IDF_PATH-old" fi -IDF_CLONE_PATH="$(readlink -m "$IDF_PATH/..")/esp-idf-4.3" +INSTALL_IDF_VER="${INSTALL_IDF_VER:=4.4}" +IDF_CLONE_PATH="$(readlink -m "$IDF_PATH/..")/esp-idf-${INSTALL_IDF_VER}" IDF_REPO="${IDF_REPO:=https://github.com/mikee47/esp-idf.git}" -IDF_BRANCH="${IDF_BRANCH:=sming/release/v4.3}" +IDF_BRANCH="sming/release/v${INSTALL_IDF_VER}" if [ -d "$IDF_CLONE_PATH" ]; then printf "\n\n** Skipping ESP-IDF clone: '$IDF_CLONE_PATH' exists\n\n" else + echo "git clone -b $IDF_BRANCH $IDF_REPO $IDF_CLONE_PATH" git clone -b "$IDF_BRANCH" "$IDF_REPO" "$IDF_CLONE_PATH" fi @@ -52,7 +54,12 @@ ln -s "$IDF_CLONE_PATH" "$IDF_PATH" # Install IDF tools and packages python3 "$IDF_PATH/tools/idf_tools.py" --non-interactive install -python3 -m pip install -r "$IDF_PATH/requirements.txt" +python3 "$IDF_PATH/tools/idf_tools.py" --non-interactive install-python-env +IDF_REQUIREMENTS="$IDF_PATH/requirements.txt" +if [ ! -f "$IDF_REQUIREMENTS" ]; then + IDF_REQUIREMENTS="$IDF_PATH/tools/requirements/requirements.core.txt" +fi +python3 -m pip install --no-input -r "$IDF_REQUIREMENTS" if [ -z "$KEEP_DOWNLOADS" ]; then rm -rf "$IDF_TOOLS_PATH/dist" diff --git a/Sming/Arch/Esp32/Tools/memanalyzer.py b/Sming/Arch/Esp32/Tools/memanalyzer.py index 04d052f2e5..372972d00d 100644 --- a/Sming/Arch/Esp32/Tools/memanalyzer.py +++ b/Sming/Arch/Esp32/Tools/memanalyzer.py @@ -17,7 +17,7 @@ import esptool # Get expected memory sizes from loader tables -loader = esptool._chip_to_rom_loader(os.environ['ESP_VARIANT']) +loader = esptool.CHIP_DEFS[os.environ['ESP_VARIANT']] TOTAL_DRAM = sum(end - start for (start, end, n) in loader.MEMORY_MAP if n in ['DRAM']) TOTAL_IRAM = sum(end - start for (start, end, n) in loader.MEMORY_MAP if n in ['IRAM']) diff --git a/Sming/Arch/Esp32/app.mk b/Sming/Arch/Esp32/app.mk index a2ffcaa001..42271785d1 100644 --- a/Sming/Arch/Esp32/app.mk +++ b/Sming/Arch/Esp32/app.mk @@ -24,5 +24,11 @@ ifeq ($(CHIP_REV_MIN),) CHIP_REV_MIN := 0 endif +ifeq ($(SMING_SOC),esp32c2) +ESPTOOL_EXTRA_ARGS := --flash-mmu-page-size $(CONFIG_MMU_PAGE_MODE) +else +ESPTOOL_EXTRA_ARGS := +endif + $(TARGET_BIN): $(TARGET_OUT) - $(Q) $(ESPTOOL_CMDLINE) elf2image --min-rev $(CHIP_REV_MIN) --elf-sha256-offset 0xb0 $(flashimageoptions) -o $@ $< + $(Q) $(ESPTOOL_CMDLINE) elf2image --min-rev $(CHIP_REV_MIN) --elf-sha256-offset 0xb0 $(ESPTOOL_EXTRA_ARGS) $(flashimageoptions) -o $@ $< diff --git a/Sming/Arch/Esp32/build.mk b/Sming/Arch/Esp32/build.mk index 9e102d8088..32d9b6b38a 100644 --- a/Sming/Arch/Esp32/build.mk +++ b/Sming/Arch/Esp32/build.mk @@ -26,12 +26,10 @@ export IDF_TOOLS_PATH := $(call FixPath,$(IDF_TOOLS_PATH)) ESP_VARIANT := $(SMING_SOC) export ESP_VARIANT -ifeq ($(ESP_VARIANT),esp32c3) -ESP32_COMPILER_PREFIX := riscv32-esp-elf -IDF_TARGET_ARCH_RISCV := 1 -else -ESP32_COMPILER_PREFIX := xtensa-$(ESP_VARIANT)-elf -endif +IDF_TOOL_INFO := $(shell $(PYTHON) $(ARCH_TOOLS)/idf_tools.py $(SMING_SOC)) +ESP32_COMPILER_PREFIX := $(word 1,$(IDF_TOOL_INFO)) +ESP32_COMPILER_VERSION := $(word 2,$(IDF_TOOL_INFO)) +IDF_TARGET_ARCH_RISCV := $(findstring riscv,$(ESP32_COMPILER_PREFIX)) # $1 => Root directory # $2 => Sub-directory @@ -42,8 +40,7 @@ endef DEBUG_VARS += ESP32_COMPILER_PATH ESP32_ULP_PATH ESP32_OPENOCD_PATH ESP32_PYTHON_PATH ifndef ESP32_COMPILER_PATH -include $(IDF_PATH)/tools/toolchain_versions.mk -ESP32_COMPILER_PATH := $(IDF_TOOLS_PATH)/tools/$(ESP32_COMPILER_PREFIX)/$(CURRENT_TOOLCHAIN_COMMIT_DESC)-$(CURRENT_TOOLCHAIN_GCC_VERSION)/$(ESP32_COMPILER_PREFIX) +ESP32_COMPILER_PATH := $(IDF_TOOLS_PATH)/tools/$(ESP32_COMPILER_PREFIX)/$(ESP32_COMPILER_VERSION)/$(ESP32_COMPILER_PREFIX) endif ifndef ESP32_ULP_PATH @@ -117,17 +114,8 @@ OBJDUMP := $(TOOLSPEC)-objdump GDB := $(TOOLSPEC)-gdb SIZE := $(TOOLSPEC)-size -# Get version variables -include $(IDF_PATH)/make/version.mk -include $(IDF_PATH)/make/ldgen.mk - -# If we have `version.txt` then prefer that for extracting IDF version -ifeq ("$(wildcard ${IDF_PATH}/version.txt)","") -IDF_VER_T := $(shell cd ${IDF_PATH} && git describe --always --tags --dirty) -else -IDF_VER_T := $(shell cat ${IDF_PATH}/version.txt) -endif -IDF_VER := $(shell echo "$(IDF_VER_T)" | cut -c 1-31) +# Extracting IDF version +IDF_VER := $(shell (cd $$IDF_PATH && git describe --always --tags --dirty) | cut -c 1-31) # [ Sming specific flags ] DEBUG_VARS += IDF_PATH IDF_VER @@ -145,7 +133,8 @@ CPPFLAGS += \ -D__ets__ \ -D_GNU_SOURCE \ -DCONFIG_NONE_OS \ - -Dasm=__asm__ + -Dasm=__asm__ \ + -Dtypeof=__typeof__ PROJECT_VER ?= export IDF_VER diff --git a/Sming/Arch/Esp32/esp32c2-pindefs.txt b/Sming/Arch/Esp32/esp32c2-pindefs.txt new file mode 100644 index 0000000000..12da455040 --- /dev/null +++ b/Sming/Arch/Esp32/esp32c2-pindefs.txt @@ -0,0 +1,163 @@ +[io_mux] +gpio pad f0 f1 f2 f3 drv reset notes +0 GPIO0 GPIO0 GPIO0 - - 2 0 R +1 GPIO1 GPIO1 GPIO1 - - 2 0 R +2 GPIO2 GPIO2 GPIO2 FSPIQ - 2 1 R +3 GPIO3 GPIO3 GPIO3 - - 2 1 R +4 MTMS MTMS GPIO4 FSPIHD - 2 1 R +5 MTDI MTDI GPIO5 FSPIWP - 2 1 R +6 MTCK MTCK GPIO6 FSPICLK - 2 1* - +7 MTDO MTDO GPIO7 FSPID - 2 1 - +8 GPIO8 GPIO8 GPIO8 - - 2 1 - +9 GPIO9 GPIO9 GPIO9 - - 2 3 - +10 GPIO10 GPIO10 GPIO10 FSPICS0 - 2 1 - +11 VDD_SPI GPIO11 GPIO11 - - 2 0 S +12 SPIHD SPIHD GPIO12 - - 2 3 S +13 SPIWP SPIWP GPIO13 - - 2 3 S +14 SPICS0 SPICS0 GPIO14 - - 2 3 S +15 SPICLK SPICLK GPIO15 - - 2 3 S +16 SPID SPID GPIO16 - - 2 3 S +17 SPIQ SPIQ GPIO17 - - 2 3 S +18 GPIO18 GPIO18 GPIO18 - - 2 0 - +19 U0RXD U0RXD GPIO19 - - 2 3 - +20 U0TXD U0TXD GPIO20 - - 2 4 - + +[rtc_mux] +rtc gpio pad a0 +0 0 GPIO0 ADC1_CH0 +1 1 GPIO1 ADC1_CH1 +2 2 GPIO2 ADC1_CH2 +3 3 GPIO3 ADC1_CH3 +4 4 MTMS ADC1_CH4 +5 5 MTDI ADC2_CH0 + +[gpio_matrix] +signal input default direct_in output enable direct_out +0 SPIQ_in 0 yes SPIQ_out SPIQ_oe yes +1 SPID_in 0 yes SPID_out SPID_oe yes +2 SPIHD_in 0 yes SPIHD_out SPIHD_oe yes +3 SPIWP_in 0 yes SPIWP_out SPIWP_oe yes +4 - - - SPICLK_out_mux SPICLK_oe yes +5 - - - SPICS0_out SPICS0_oe yes +6 U0RXD_in 0 yes U0TXD_out 1’d1 yes +7 U0CTS_in 0 no U0RTS_out 1’d1 no +8 U0DSR_in 0 no U0DTR_out 1’d1 no +9 U1RXD_in 0 no U1TXD_out 1’d1 no +10 U1CTS_in 0 no U1RTS_out 1’d1 no +11 U1DSR_in 0 no U1DTR_out 1’d1 no +12 - - - - - - +13 - - - - - - +14 - - - - - - +15 - - - SPIQ_monitor 1’d1 no +16 - - - SPID_monitor 1’d1 no +17 - - - SPIHD_monitor 1’d1 no +18 - - - SPIWP_monitor 1’d1 no +19 - - - SPICS1_out SPICS1_oe no +20 - - - - - - +21 - - - - - - +22 - - - - - - +23 - - - - - - +24 - - - - - - +25 - - - - - - +26 - - - - - - +27 - - - - - - +28 cpu_gpio_in0 0 no cpu_gpio_out0 cpu_gpio_out_oen0 no +29 cpu_gpio_in1 0 no cpu_gpio_out1 cpu_gpio_out_oen1 no +30 cpu_gpio_in2 0 no cpu_gpio_out2 cpu_gpio_out_oen2 no +31 cpu_gpio_in3 0 no cpu_gpio_out3 cpu_gpio_out_oen3 no +32 cpu_gpio_in4 0 no cpu_gpio_out4 cpu_gpio_out_oen4 no +33 cpu_gpio_in5 0 no cpu_gpio_out5 cpu_gpio_out_oen5 no +34 cpu_gpio_in6 0 no cpu_gpio_out6 cpu_gpio_out_oen6 no +35 cpu_gpio_in7 0 no cpu_gpio_out7 cpu_gpio_out_oen7 no +36 - - - - - - +37 - - - - - - +38 - - - - - - +39 - - - - - - +40 - - - - - - +41 - - - - - - +42 - - - - - - +43 - - - - - - +44 - - - - - - +45 ext_adc_start 0 no ledc_ls_sig_out0 1’d1 no +46 - - - ledc_ls_sig_out1 1’d1 no +47 - - - ledc_ls_sig_out2 1’d1 no +48 - - - ledc_ls_sig_out3 1’d1 no +49 - - - ledc_ls_sig_out4 1’d1 no +50 - - - ledc_ls_sig_out5 1’d1 no +51 - - - - - - +52 - - - - - - +53 I2CEXT0_SCL_in 1 no I2CEXT0_SCL_out I2CEXT0_SCL_oe no +54 I2CEXT0_SDA_in 1 no I2CEXT0_SDA_out I2CEXT0_SDA_oe no +55 - - - - - - +56 - - - - - - +57 - - - - - - +58 - - - - - - +59 - - - - - - +60 - - - - - - +61 - - - - - - +62 - - - - - - +63 FSPICLK_in 0 yes FSPICLK_out_mux FSPICLK_oe yes +64 FSPIQ_in 0 yes FSPIQ_out FSPIQ_oe yes +65 FSPID_in 0 yes FSPID_out FSPID_oe yes +66 FSPIHD_in 0 yes FSPIHD_out FSPIHD_oe yes +67 FSPIWP_in 0 yes FSPIWP_out FSPIWP_oe yes +68 FSPICS0_in 0 yes FSPICS0_out FSPICS0_oe yes +69 - - - FSPICS1_out FSPICS1_oe no +70 - - - FSPICS2_out FSPICS2_oe no +71 - - - FSPICS3_out FSPICS3_oe no +72 - - - FSPICS4_out FSPICS4_oe no +73 - - - FSPICS5_out FSPICS5_oe no +74 - - - - - - +75 - - - - - - +76 - - - - - - +77 - - - - - - +78 - - - - - - +79 - - - - - - +80 - - - - - - +81 - - - - - - +82 - - - - - - +83 - - - - - - +84 - - - - - - +85 - - - - - - +86 - - - - - - +87 - - - - - - +88 - - - - - - +89 - - - ant_sel0 1’d1 no +90 - - - ant_sel1 1’d1 no +91 - - - ant_sel2 1’d1 no +92 - - - ant_sel3 1’d1 no +93 - - - ant_sel4 1’d1 no +94 - - - ant_sel5 1’d1 no +95 - - - ant_sel6 1’d1 no +96 - - - ant_sel7 1’d1 no +97 sig_in_func_97 0 no sig_in_func97 1’d1 no +98 sig_in_func_98 0 no sig_in_func98 1’d1 no +99 sig_in_func_99 0 no sig_in_func99 1’d1 no +100 sig_in_func_100 0 no sig_in_func100 1’d1 no +101 - - - - - - +102 - - - - - - +103 - - - - - - +104 - - - - - - +105 - - - - - - +106 - - - - - - +107 - - - - - - +108 - - - - - - +109 - - - - - - +110 - - - - - - +111 - - - - - - +112 - - - - - - +113 - - - - - - +114 - - - - - - +115 - - - - - - +116 - - - - - - +117 - - - - - - +118 - - - - - - +119 - - - - - - +120 - - - - - - +121 - - - - - - +122 - - - - - - +123 - - - CLK_OUT_out1 1’d1 no +124 - - - CLK_OUT_out2 1’d1 no +125 - - - CLK_OUT_out3 1’d1 no +126 - - - - - - +127 - - - - - - diff --git a/Sming/Arch/Esp32/esp32c2-soc.json b/Sming/Arch/Esp32/esp32c2-soc.json new file mode 100644 index 0000000000..724e8dbf66 --- /dev/null +++ b/Sming/Arch/Esp32/esp32c2-soc.json @@ -0,0 +1,56 @@ +{ + "variant": "esp32c2", + "name": "ESP32-C2", + "peripherals": { + "ADC": { + "sigmask": "ADC.+|ext_adc_start" + }, + "CLOCKS": { + "sigmask": "CLK_.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "GPIO": { + "sigmask": "GPIO.+" + }, + "I2C0": { + "sigmask": "I2CEXT0.+" + }, + "LEDC": { + "sigmask": "ledc_.+" + }, + "SPI1": { + "sigmask": "SPI[^3]+" + }, + "SPI2": { + "sigmask": "FSPI.+" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 43 + ], + "RXD": [ + "U0RXD", + 44 + ] + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD_out", + 10 + ], + "RXD": [ + "U1RXD_in", + 9 + ] + } + } + } +} \ No newline at end of file diff --git a/Sming/Arch/Esp32/standard.hw b/Sming/Arch/Esp32/standard.hw index f648416ce8..035880da41 100644 --- a/Sming/Arch/Esp32/standard.hw +++ b/Sming/Arch/Esp32/standard.hw @@ -9,7 +9,7 @@ "type": "flash", "size": "4M", "mode": "dio", - "speed": 40 + "speed": "60 if SMING_SOC=='esp32c2' else 40" } }, "partitions": { diff --git a/Sming/Arch/Esp8266/Components/driver/i2s.rst b/Sming/Arch/Esp8266/Components/driver/i2s.rst index de64454103..87d2f41efc 100644 --- a/Sming/Arch/Esp8266/Components/driver/i2s.rst +++ b/Sming/Arch/Esp8266/Components/driver/i2s.rst @@ -1,5 +1,5 @@ -I2S: Inter-IC Serial communcations -================================== +I2S: Inter-IC Serial communications +=================================== Introduction ------------ diff --git a/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h b/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h index e47435fa3a..2424ae320a 100644 --- a/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h +++ b/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h @@ -23,13 +23,13 @@ extern "C" { * * Example: * - * uint32 io_info[][3] = { + * uint32 ioInfo[][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); + * pwm_init(light_param.pwm_period, light_param.pwm_duty, 3, ioInfo); * */ diff --git a/Sming/Arch/Esp8266/Components/driver/new-pwm/README.md b/Sming/Arch/Esp8266/Components/driver/new-pwm/README.md index d9391a597e..8881d1f3c0 100644 --- a/Sming/Arch/Esp8266/Components/driver/new-pwm/README.md +++ b/Sming/Arch/Esp8266/Components/driver/new-pwm/README.md @@ -37,7 +37,7 @@ Example usage: const uint32_t period = 5000; // * 200ns ^= 1 kHz // PWM setup - uint32 io_info[PWM_CHANNELS][3] = { + uint32 ioInfo[PWM_CHANNELS][3] = { // MUX, FUNC, PIN {PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12}, {PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15, 15}, @@ -47,9 +47,9 @@ Example usage: }; // initial duty: all off - uint32 pwm_duty_init[PWM_CHANNELS] = {0, 0, 0, 0, 0}; + uint32 pwmDutyInit[PWM_CHANNELS] = {0, 0, 0, 0, 0}; - pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info); + pwm_init(period, pwmDutyInit, PWM_CHANNELS, ioInfo); pwm_start(); // do something like this whenever you want to change duty diff --git a/Sming/Arch/Esp8266/Components/esp8266/include/espconn.h b/Sming/Arch/Esp8266/Components/esp8266/include/espconn.h index acfc4f67d0..697cedf5fd 100644 --- a/Sming/Arch/Esp8266/Components/esp8266/include/espconn.h +++ b/Sming/Arch/Esp8266/Components/esp8266/include/espconn.h @@ -205,7 +205,7 @@ sint8 espconn_create(struct espconn *espconn); /****************************************************************************** * FunctionName : espconn_tcp_get_max_con - * Description : get the number of simulatenously active TCP connections + * Description : get the number of simultaneously active TCP connections * Parameters : none * Returns : none *******************************************************************************/ @@ -214,7 +214,7 @@ uint8 espconn_tcp_get_max_con(void); /****************************************************************************** * FunctionName : espconn_tcp_set_max_con - * Description : set the number of simulatenously active TCP connections + * Description : set the number of simultaneously active TCP connections * Parameters : num -- total number * Returns : none *******************************************************************************/ @@ -223,7 +223,7 @@ sint8 espconn_tcp_set_max_con(uint8 num); /****************************************************************************** * FunctionName : espconn_tcp_get_max_con_allow - * Description : get the count of simulatenously active connections on the server + * Description : get the count of simultaneously active connections on the server * Parameters : espconn -- espconn to get the count * Returns : result *******************************************************************************/ @@ -232,7 +232,7 @@ sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn); /****************************************************************************** * FunctionName : espconn_tcp_set_max_con_allow - * Description : set the count of simulatenously active connections on the server + * Description : set the count of simultaneously active connections on the server * Parameters : espconn -- espconn to set the count * num -- support the connection number * Returns : result diff --git a/Sming/Arch/Esp8266/Components/spi_flash/flashmem.c b/Sming/Arch/Esp8266/Components/spi_flash/flashmem.c index 2c4c54de01..75f33ec622 100644 --- a/Sming/Arch/Esp8266/Components/spi_flash/flashmem.c +++ b/Sming/Arch/Esp8266/Components/spi_flash/flashmem.c @@ -267,8 +267,6 @@ uint32_t flashmem_write_internal( const void *from, uint32_t toaddr, uint32_t si { assert(IS_ALIGNED(from) && IS_ALIGNED(toaddr) && IS_ALIGNED(size)); - WDT_FEED(); - SpiFlashOpResult r = spi_flash_write(toaddr, (uint32*)from, size); if(SPI_FLASH_RESULT_OK == r) return size; @@ -282,8 +280,6 @@ uint32_t flashmem_read_internal( void *to, uint32_t fromaddr, uint32_t size ) { assert(IS_ALIGNED(to) && IS_ALIGNED(fromaddr) && IS_ALIGNED(size)); - WDT_FEED(); - SpiFlashOpResult r = spi_flash_read(fromaddr, (uint32*)to, size); if(SPI_FLASH_RESULT_OK == r) return size; diff --git a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp index a1cbb10689..585f5b813e 100644 --- a/Sming/Arch/Esp8266/Core/HardwarePWM.cpp +++ b/Sming/Arch/Esp8266/Core/HardwarePWM.cpp @@ -23,31 +23,32 @@ * */ +#include #include #include "ESP8266EX.h" #include -#include - #define PERIOD_TO_MAX_DUTY(x) (x * 25) -HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t no_of_pins) : channel_count(no_of_pins) +HardwarePWM::HardwarePWM(uint8_t* pins, uint8_t noOfPins) : channel_count(noOfPins) { - if(no_of_pins > 0) { - uint32_t io_info[PWM_CHANNEL_NUM_MAX][3]; // pin information - uint32_t pwm_duty_init[PWM_CHANNEL_NUM_MAX]; // pwm duty - for(uint8_t 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 + if(noOfPins == 0) { + return; + } + + uint32_t ioInfo[PWM_CHANNEL_NUM_MAX][3]; // pin information + uint32_t pwmDutyInit[PWM_CHANNEL_NUM_MAX]; // pwm duty + for(uint8_t i = 0; i < noOfPins; i++) { + ioInfo[i][0] = EspDigitalPins[pins[i]].mux; + ioInfo[i][1] = EspDigitalPins[pins[i]].gpioFunc; + ioInfo[i][2] = EspDigitalPins[pins[i]].id; + pwmDutyInit[i] = 0; // Start with zero output + channels[i] = pins[i]; } + const int initialPeriod = 1000; + pwm_init(initialPeriod, pwmDutyInit, noOfPins, ioInfo); + update(); + maxduty = PERIOD_TO_MAX_DUTY(initialPeriod); // for period of 1000 } HardwarePWM::~HardwarePWM() @@ -55,72 +56,46 @@ 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_t HardwarePWM::getChannel(uint8_t pin) { for(uint8_t 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); + + debug_d("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_t HardwarePWM::getDutyChan(uint8_t chan) { - if(chan == PWM_BAD_CHANNEL) { - return 0; - } else { - return pwm_get_duty(chan); - } + return (chan == PWM_BAD_CHANNEL) ? 0 : 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_t chan, uint32_t duty, bool update) { if(chan == PWM_BAD_CHANNEL) { return false; - } else if(duty <= maxduty) { + } + + 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; } + + debug_e("Duty cycle value too high for current period. max duty is %d.", maxduty); + return false; } -/* Function Name: getPeriod - * Description: This function is used to get Period of PWM. - * Period / frequency will remain same for all pins. - * - */ uint32_t 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_t period) { maxduty = PERIOD_TO_MAX_DUTY(period); @@ -128,10 +103,14 @@ void HardwarePWM::setPeriod(uint32_t period) update(); } -/* Function Name: update - * Description: This function is used to actually update the PWM. - */ void HardwarePWM::update() { pwm_start(); } + +uint32_t HardwarePWM::getFrequency(uint8_t pin) +{ + (void)pin; + auto period = pwm_get_period(); + return (period == 0) ? 0 : 1000000U / period; +} diff --git a/Sming/Arch/Esp8266/Tools/install.sh b/Sming/Arch/Esp8266/Tools/install.sh index 3d84d83659..29c1cb3fce 100755 --- a/Sming/Arch/Esp8266/Tools/install.sh +++ b/Sming/Arch/Esp8266/Tools/install.sh @@ -2,11 +2,13 @@ # # Esp8266 install.sh +EQT_REPO=https://github.com/earlephilhower/esp-quick-toolchain/releases/download/3.0.0-newlib4.0.0-gnu20 + if [ -d "$ESP_HOME" ]; then printf "\n\n** Skipping Esp8266 tools installation: '$ESP_HOME' exists\n\n" else - TOOLCHAIN=x86_64-linux-gnu.xtensa-lx106-elf-e6a192b.201211.tar.gz - $WGET "$SMINGTOOLS/$TOOLCHAIN" -O "$DOWNLOADS/$TOOLCHAIN" + TOOLCHAIN="$(uname -m)-linux-gnu.xtensa-lx106-elf-e6a192b.201211.tar.gz" + $WGET "$EQT_REPO/$TOOLCHAIN" -O "$DOWNLOADS/$TOOLCHAIN" mkdir -p "$ESP_HOME" tar -zxf "$DOWNLOADS/$TOOLCHAIN" -C "$ESP_HOME" --totals fi diff --git a/Sming/Arch/Host/Components/hostlib/README.rst b/Sming/Arch/Host/Components/hostlib/README.rst index 673def58fe..55716d30db 100644 --- a/Sming/Arch/Host/Components/hostlib/README.rst +++ b/Sming/Arch/Host/Components/hostlib/README.rst @@ -1,7 +1,7 @@ Host Library ============ -This Components provides the core funcionality for the Host Emulator: +This Components provides the core functionality for the Host Emulator: Sockets ------- diff --git a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp index aa1dad346f..0c8f44c741 100644 --- a/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/hw_timer.cpp @@ -30,7 +30,7 @@ void IRAM_ATTR timer1_isr() } // namespace -void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg) +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& p = hw_timer_private; 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 f8cc61272b..b94d5b4e34 100644 --- a/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Rp2040/Components/driver/include/driver/hw_timer.h @@ -93,7 +93,7 @@ extern struct hw_timer_private_t hw_timer_private; * @param callback Callback function invoked via timer interrupt * @param arg Passed to callback function */ -void IRAM_ATTR hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg); +void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg); /** * @brief Detach interrupt from the timer @@ -106,7 +106,7 @@ void hw_timer1_detach_interrupt(); * @param intr_type * @param auto_load */ -void IRAM_ATTR hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load); +void hw_timer1_enable(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load); /** * @brief Set the timer interval and arm diff --git a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp index f1d4d31e8b..ee8312357a 100644 --- a/Sming/Arch/Rp2040/Components/driver/os_timer.cpp +++ b/Sming/Arch/Rp2040/Components/driver/os_timer.cpp @@ -24,12 +24,12 @@ os_timer_t* timer_list; class CriticalLock { public: - CriticalLock() + __forceinline CriticalLock() { level = save_and_disable_interrupts(); } - ~CriticalLock() + __forceinline ~CriticalLock() { restore_interrupts(level); } @@ -38,7 +38,7 @@ class CriticalLock uint32_t level; }; -static void IRAM_ATTR timer_insert(uint32_t expire, os_timer_t* ptimer) +void IRAM_ATTR timer_insert(uint32_t expire, os_timer_t* ptimer) { debug_tmr("insert %p %u", ptimer, expire); diff --git a/Sming/Arch/Rp2040/Components/driver/uart.cpp b/Sming/Arch/Rp2040/Components/driver/uart.cpp index 7bcf300c17..06503f3624 100644 --- a/Sming/Arch/Rp2040/Components/driver/uart.cpp +++ b/Sming/Arch/Rp2040/Components/driver/uart.cpp @@ -138,8 +138,8 @@ void IRAM_ATTR handleInterrupt(smg_uart_t* uart, uart_dev_t* dev) */ if(rxfifo_ovf) { hw_clear_bits(&dev->imsc, UART_UARTIMSC_OEIM_BITS); - } else if(read == 0) { - hw_set_bits(&dev->imsc, UART_UARTIMSC_RXIM_BITS | UART_UARTIMSC_RTIM_BITS); + } else if(!read) { + hw_clear_bits(&dev->imsc, UART_UARTIMSC_RXIM_BITS | UART_UARTIMSC_RTIM_BITS); } } @@ -396,7 +396,7 @@ void smg_uart_wait_tx_empty(smg_uart_t* uart) } auto dev = getDevice(uart->uart_nr); - while((dev->fr & UART_UARTFR_TXFE_BITS) != 0) { + while((dev->fr & UART_UARTFR_BUSY_BITS) != 0) { } } diff --git a/Sming/Arch/Rp2040/Components/rp2040/README.rst b/Sming/Arch/Rp2040/Components/rp2040/README.rst index 727ddc2862..c8cef9ede9 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/README.rst +++ b/Sming/Arch/Rp2040/Components/rp2040/README.rst @@ -28,3 +28,27 @@ Configuration variables This setting is provided to make it easy to re-program RP2040 boards during development. When enabled, Sming monitors the BOOTSEL button and restartS in boot mode if pressed. + + +.. envvar:: LINK_CYW43_FIRMWARE + + default: 1 + + The Pico-W board requires a ~140K (compressed) firmware BLOB which by default is linked into the application image. + + This can be wasteful when using OTA as the firmware must be contained in all application images. + + Setting this value to '0' will omit firmware from the image, and instead load it from a partition called 'cyw43_fw'. + This partition can be added to the standard map using the 'cyw43_fw' :envvar:`HWCONFIG_OPT` setting:: + + make LINK_CYW43_FIRMWARE=0 HWCONFIG_OPT=cyw43_fw + + This is not the default setting since the additional partition must be managed by the end application. + + +.. envvar:: PICO_DEBUG + + default: 0 + + Set to 1 to enable additional debug output from compiled Pico SDK library. + Shows things like WiFi firmware version. diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index 670b13ba31..4c18fef8e6 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -6,16 +6,28 @@ else export PICO_SDK_PATH := $(COMPONENT_PATH)/pico-sdk endif -COMPONENT_RELINK_VARS += PICO_BOARD -ifndef PICO_BOARD -export PICO_BOARD=pico +ifeq ($(DISABLE_WIFI),1) +export PICO_BOARD ?= pico +else +export PICO_BOARD ?= pico_w +COMPONENT_DEPENDS += uzlib endif +COMPONENT_RELINK_VARS += PICO_DEBUG +PICO_DEBUG ?= 0 + +COMPONENT_VARS := PICO_BOARD DISABLE_WIFI DISABLE_NETWORK + +PICO_SDK_VARS := PICO_BOARD=$(PICO_BOARD) +PICO_SDK_LIBHASH := $(call CalculateVariantHash,PICO_SDK_VARS) + GLOBAL_CFLAGS += \ - -DPICO_ON_DEVICE=1 + -DPICO_ON_DEVICE=1 \ + -DCYW43_LWIP=1 \ + -DPICO_CYW43_ARCH_POLL=1 # Press BOOTSEL to reboot into programming mode -COMPONENT_RELINK_VARS := ENABLE_BOOTSEL +COMPONENT_RELINK_VARS += ENABLE_BOOTSEL ifndef SMING_RELEASE ENABLE_BOOTSEL ?= 1 endif @@ -42,6 +54,7 @@ SDK_INTERFACES := \ common/pico_util \ rp2040/hardware_regs \ rp2040/hardware_structs \ + rp2_common/hardware_adc \ rp2_common/hardware_gpio \ rp2_common/pico_platform \ rp2_common/hardware_base \ @@ -54,6 +67,7 @@ SDK_INTERFACES := \ rp2_common/hardware_flash \ rp2_common/hardware_irq \ rp2_common/hardware_pio \ + rp2_common/hardware_pwm \ rp2_common/hardware_resets \ rp2_common/hardware_rosc \ rp2_common/hardware_rtc \ @@ -62,12 +76,17 @@ SDK_INTERFACES := \ rp2_common/hardware_vreg \ rp2_common/hardware_watchdog \ rp2_common/hardware_xosc \ + 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_multicore \ + rp2_common/pico_rand \ rp2_common/pico_runtime \ - rp2_common/pico_unique_id + rp2_common/pico_unique_id \ + rp2_common/pico_cyw43_arch \ + rp2_common/pico_cyw43_driver COMPONENT_INCDIRS := \ src/include \ @@ -77,7 +96,7 @@ COMPONENT_INCDIRS := \ COMPONENT_SRCDIRS := src RP2040_COMPONENT_DIR := $(COMPONENT_PATH) -PICO_BUILD_DIR := $(COMPONENT_BUILD_BASE)/sdk +PICO_BUILD_DIR := $(COMPONENT_BUILD_BASE)/sdk-$(PICO_SDK_LIBHASH) PICO_BASE_DIR := $(PICO_BUILD_DIR)/generated/pico_base PICO_CONFIG := $(PICO_BASE_DIR)/pico/config_autogen.h PICO_LIB := $(PICO_BUILD_DIR)/libpico.a @@ -96,21 +115,40 @@ EXTRA_LIBS += \ RP2040_CMAKE_OPTIONS := \ -G Ninja \ - -DCMAKE_MAKE_PROGRAM=$(NINJA) + -DCMAKE_MAKE_PROGRAM=$(NINJA) \ + -DCMAKE_BUILD_TYPE=$(if $(subst 1,,$(PICO_DEBUG)),RelWithDebInfo,Debug) COMPONENT_PREREQUISITES := $(PICO_CONFIG) BOOTLOADER := $(PICO_BUILD_DIR)/pico-sdk/src/rp2_common/boot_stage2/bs2_default_padded_checksummed.S +DEBUG_VARS += CYW43_FIRMWARE +CYW43_FIRMWARE := $(COMPONENT_BUILD_BASE)/cyw43-fw.gz + +COMPONENT_RELINK_VARS += LINK_CYW43_FIRMWARE +LINK_CYW43_FIRMWARE ?= 1 +ifeq ($(LINK_CYW43_FIRMWARE),1) +COMPONENT_CPPFLAGS += -DCYW43_FIRMWARE=\"$(CYW43_FIRMWARE)\" +endif + COMPONENT_TARGETS := \ - $(PICO_LIB) + $(PICO_LIB) \ + $(CYW43_FIRMWARE) -$(PICO_CONFIG): $(PICO_BUILD_DIR) +$(PICO_CONFIG): $(PICO_BUILD_DIR) $(PICO_SDK_PATH)/lib/cyw43-driver.patch $(PICO_SDK_PATH)/lib/cyw43-driver/.submodule $(PICO_SDK_PATH)/lib/lwip/.submodule $(Q) cd $(PICO_BUILD_DIR) && $(CMAKE) $(RP2040_CMAKE_OPTIONS) $(RP2040_COMPONENT_DIR)/sdk $(COMPONENT_RULE)$(PICO_LIB): $(Q) cd $(@D) && $(NINJA) +$(PICO_SDK_PATH)/lib/cyw43-driver.patch: $(RP2040_COMPONENT_DIR)/cyw43-driver.patch + cp $< $@ + +$(COMPONENT_RULE)$(CYW43_FIRMWARE): + @echo ">>> Creating CYW43 Firmware BLOB ..." + $(Q) cd "$(RP2040_COMPONENT_DIR)/firmware" && ./build.sh $@ + @echo "Created $@" + ifdef COMPONENT_RULE $(PICO_BUILD_DIR): $(Q) mkdir -p $@ diff --git a/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch new file mode 100644 index 0000000000..216cf19f0c --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/cyw43-driver.patch @@ -0,0 +1,262 @@ +diff --git a/src/cyw43_ctrl.c b/src/cyw43_ctrl.c +index c6c2df6..753bfa8 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] = { + [CYW43_EV_SET_SSID] = "SET_SSID", + [CYW43_EV_JOIN] = "JOIN", + [CYW43_EV_AUTH] = "AUTH", ++ [CYW43_EV_AUTH_IND] = "AUTH_IND", + [CYW43_EV_DEAUTH_IND] = "DEAUTH_IND", + [CYW43_EV_ASSOC] = "ASSOC", ++ [CYW43_EV_ASSOC_IND] = "ASSOC_IND", + [CYW43_EV_DISASSOC] = "DISASSOC", + [CYW43_EV_DISASSOC_IND] = "DISASSOC_IND", + [CYW43_EV_LINK] = "LINK", ++ [CYW43_EV_PROBREQ_MSG] = "PROBREQ_MSG", + [CYW43_EV_PSK_SUP] = "PSK_SUP", + [CYW43_EV_ESCAN_RESULT] = "ESCAN_RESULT", ++ [CYW43_EV_P2P_PROBREQ_MSG] = "P2P_PROBREQ_MSG", + [CYW43_EV_CSA_COMPLETE_IND] = "CSA_COMPLETE_IND", + [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 7f4229b..f3bc641 100644 +--- a/src/cyw43_ll.c ++++ b/src/cyw43_ll.c +@@ -55,9 +55,6 @@ int sdio_transfer(uint32_t cmd, uint32_t arg, uint32_t *resp); + void sdio_enable_high_speed_4bit(void); + #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); + +@@ -69,10 +66,6 @@ extern bool enable_spi_packet_dumping; + + #define CYW43_RAM_SIZE (512 * 1024) + +-// Include the file containing the WiFi+CLM firmware blob as a C array. +-#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)) +@@ -377,58 +370,31 @@ static int cyw43_read_backplane_mem(cyw43_int_t *self, uint32_t addr, uint32_t l + } + #endif + +-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; +- +- CYW43_VDEBUG("writing %lu bytes to 0x%lx\n", (uint32_t)len, (uint32_t)addr); +- +- 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", (uint)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; ++} + +- if (addr == 0) { +- // check that firmware is actually there +- +- // 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; +- } +- +- // 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 (found == -1) { +- CYW43_WARN("could not find valid firmware\n"); +- 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(); +@@ -446,7 +412,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; +@@ -459,6 +425,10 @@ static int cyw43_download_resource(cyw43_int_t *self, uint32_t addr, size_t raw_ + } + + #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", (uint)dt, (uint)(len * 1000 / dt)); +@@ -480,7 +450,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; +@@ -1383,8 +1353,8 @@ 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 + uint8_t *buf = &self->spid_buf[SDPCM_HEADER_LEN + 16]; + + const size_t clm_dload_chunk_len = CLM_CHUNK_LEN; +@@ -1409,7 +1379,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); + +@@ -1665,12 +1635,9 @@ 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); +- */ ++ 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; +@@ -1787,9 +1754,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_VDEBUG("cyw43_clm_load done\n"); + ++ cyw43_storage_cleanup(); ++ + 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 + +@@ -1893,6 +1862,10 @@ 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); + // Get and print CLM version + memcpy(buf, "clmver\x00", 7); + cyw43_do_ioctl(self, SDPCM_GET, WLC_GET_VAR, 128, buf, WWD_STA_INTERFACE); +@@ -1922,8 +1895,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 +- CLR_EV(buf, 44); // probe request + CLR_EV(buf, 54); // interface change ++ CLR_EV(buf, 67); // WAI stations event (whatever that is) + CLR_EV(buf, 71); // probe response + #undef CLR_EV + memcpy(buf, "bsscfg:event_msgs", 18); +diff --git a/src/cyw43_ll.h b/src/cyw43_ll.h +index cf442db..a7ad227 100644 +--- a/src/cyw43_ll.h ++++ b/src/cyw43_ll.h +@@ -65,15 +65,19 @@ + #define CYW43_EV_SET_SSID (0) + #define CYW43_EV_JOIN (1) + #define CYW43_EV_AUTH (3) ++#define CYW43_EV_AUTH_IND (4) + #define CYW43_EV_DEAUTH (5) + #define CYW43_EV_DEAUTH_IND (6) + #define CYW43_EV_ASSOC (7) ++#define CYW43_EV_ASSOC_IND (8) + #define CYW43_EV_DISASSOC (11) + #define CYW43_EV_DISASSOC_IND (12) + #define CYW43_EV_LINK (16) + #define CYW43_EV_PRUNE (23) ++#define CYW43_EV_PROBREQ_MSG (44) + #define CYW43_EV_PSK_SUP (46) + #define CYW43_EV_ESCAN_RESULT (69) ++#define CYW43_EV_P2P_PROBREQ_MSG (72) + #define CYW43_EV_CSA_COMPLETE_IND (80) + #define CYW43_EV_ASSOC_REQ_IE (87) + #define CYW43_EV_ASSOC_RESP_IE (88) +@@ -312,6 +316,11 @@ 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_read(void *dest, uint32_t length); ++void cyw43_storage_cleanup(void); ++ + //!\} + + #endif // CYW43_INCLUDED_CYW43_LL_H diff --git a/Sming/Arch/Rp2040/Components/rp2040/firmware/43439A0-7.95.49.00.bin b/Sming/Arch/Rp2040/Components/rp2040/firmware/43439A0-7.95.49.00.bin new file mode 100644 index 0000000000..e61689d762 Binary files /dev/null and b/Sming/Arch/Rp2040/Components/rp2040/firmware/43439A0-7.95.49.00.bin differ diff --git a/Sming/Arch/Rp2040/Components/rp2040/firmware/README.txt b/Sming/Arch/Rp2040/Components/rp2040/firmware/README.txt new file mode 100644 index 0000000000..394cdff4e4 --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/firmware/README.txt @@ -0,0 +1,25 @@ +Pico-W Firmware +=============== + +This directory contains firmware for RP2040 devices. +Files are combined and compressed during build. + +Version information can be found by inspecting binary files or building with PICO_DEBUG=1. + +43439A0-7.95.49.00.bin + Nov 29 2021 22:49:09 version 7.95.49 (2271bb6 CY) FWID 01-c51d9400 + +clm_blob.bin + API: 12.2 + Data: RaspberryPi.PicoW + Compiler: 1.29.4 + ClmImport: 1.47.1 + Customization: v5 22/06/24 + Creation: 2022-06-24 06:55:08 + + +Files extracted from pico-sdk/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined:: + + SRCFILE='../pico-sdk/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined' + dd if="$SRCFILE" of=43439A0-7.95.49.00.bin bs=1 count=224190 + dd if="$SRCFILE" of=clm_blob.bin bs=1 iseek=224256 diff --git a/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh b/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh new file mode 100755 index 0000000000..520ae4275c --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/firmware/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# +# Combines firmware BLOBs into a single file with headers indicating size. +# No padding is necessary. +# A simple chunk header is written which avoids need to hard-code sizes into driver. +# + +set -e + +write_chunk() { + sz=$(printf "%08x" $(du -b "$1" | cut -f1)) + # Output 8-byte header containing chunk tag plus length in little-endian format + printf "CHNK\x${sz:6:2}\x${sz:4:2}\x${sz:2:2}\x${sz:0:2}" >> $2 + # Append chunk data + cat "$1" >> $2 +} + +OUTFILE="${1/.gz/}" +rm -f "$OUTFILE" +write_chunk "43439A0-7.95.49.00.bin" "$OUTFILE" +write_chunk "clm_blob.bin" "$OUTFILE" +gzip --best "$OUTFILE" diff --git a/Sming/Arch/Rp2040/Components/rp2040/firmware/clm_blob.bin b/Sming/Arch/Rp2040/Components/rp2040/firmware/clm_blob.bin new file mode 100644 index 0000000000..dc4ee02523 Binary files /dev/null and b/Sming/Arch/Rp2040/Components/rp2040/firmware/clm_blob.bin differ diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk index 0f67a6c00c..e87f11bd2b 160000 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk @@ -1 +1 @@ -Subproject commit 0f67a6c00c05e60c34fe1f35a835a133d3e12872 +Subproject commit e87f11bd2b54654a251d088193fe3b3c5247baa1 diff --git a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch index dcc9f8dde5..a707d793c6 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch +++ b/Sming/Arch/Rp2040/Components/rp2040/pico-sdk.patch @@ -1,13 +1,64 @@ -diff --git a/src/rp2_common/pico_platform/include/pico/platform.h b/src/rp2_common/pico_platform/include/pico/platform.h -index 596b0db..0fb309f 100644 ---- a/src/rp2_common/pico_platform/include/pico/platform.h -+++ b/src/rp2_common/pico_platform/include/pico/platform.h -@@ -357,7 +357,7 @@ static __force_inline void tight_loop_contents(void) {} - * \return a * b - */ - __force_inline static int32_t __mul_instruction(int32_t a, int32_t b) { -- asm ("mul %0, %1" : "+l" (a) : "l" (b) : ); -+ __asm__ ("mul %0, %1" : "+l" (a) : "l" (b) : ); - return a; +diff --git a/lib/cyw43-driver b/lib/cyw43-driver +--- a/lib/cyw43-driver ++++ b/lib/cyw43-driver +@@ -1 +1 @@ +-Subproject commit 9bfca61173a94432839cd39210f1d1afdf602c42 ++Subproject commit 9bfca61173a94432839cd39210f1d1afdf602c42-dirty +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; } +-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)) + + /*! \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 638e994..3fb53cd 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 + + .flash_end : { +- PROVIDE(__flash_binary_end = .); ++ __flash_binary_end = .; + } > FLASH + + /* 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 739b172780..7081f49973 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/CMakeLists.txt @@ -5,7 +5,6 @@ set(PICO_COMPILER "pico_arm_gcc") set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_BUILD_TYPE RelWithDebInfo) include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) # include(pico_extras_import.cmake) @@ -30,6 +29,8 @@ target_compile_definitions(pico PUBLIC PICO_PRINTF_ALWAYS_INCLUDED=1 PICO_FLASH_SIZE_BYTES=16777216 PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64 + PICO_DIVIDER_IN_RAM=1 + PICO_MEM_IN_RAM=1 ) pico_set_program_name(pico "Sming") @@ -69,8 +70,10 @@ target_link_libraries(pico pico_float pico_int64_ops pico_mem_ops + pico_multicore pico_runtime pico_standard_link pico_unique_id pico_audio_i2s + pico_cyw43_arch_lwip_poll ) diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/cyw43_ctrl.mk b/Sming/Arch/Rp2040/Components/rp2040/sdk/cyw43_ctrl.mk new file mode 100644 index 0000000000..bd527444e8 --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/cyw43_ctrl.mk @@ -0,0 +1,4 @@ +# cyw43_ctrl + +WRAPPED_FUNCTIONS += \ + cyw43_cb_process_async_event diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/lwipopts.h b/Sming/Arch/Rp2040/Components/rp2040/sdk/lwipopts.h new file mode 100644 index 0000000000..adf87b0276 --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/sdk/lwipopts.h @@ -0,0 +1,91 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// Common settings used in most of the pico_w examples +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) + +// allow override in some examples +#ifndef NO_SYS +#define NO_SYS 1 +#endif +// allow override in some examples +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif +#if PICO_CYW43_ARCH_POLL +#define MEM_LIBC_MALLOC 1 +#else +// MEM_LIBC_MALLOC is incompatible with non polling versions +#define MEM_LIBC_MALLOC 0 +#endif +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 16000 +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define MEMP_NUM_UDP_PCB 8 +#define PBUF_POOL_SIZE 24 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define TCP_WND (8 * TCP_MSS) +#define TCP_MSS 1460 +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETCONN 0 +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 +// #define ETH_PAD_SIZE 2 +#define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_IGMP 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 1 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#ifndef NDEBUG +#define LWIP_DEBUG 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 +#endif + +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define PPP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF + +#endif /* __LWIPOPTS_H__ */ diff --git a/Sming/Arch/Rp2040/Components/rp2040/sdk/tusb_config.h b/Sming/Arch/Rp2040/Components/rp2040/sdk/tusb_config.h deleted file mode 100644 index 0c98598d40..0000000000 --- a/Sming/Arch/Rp2040/Components/rp2040/sdk/tusb_config.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#ifndef _TUSB_CONFIG_H_ -#define _TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUSB_MCU - #define CFG_TUSB_MCU OPT_MCU_RP2040 -#endif - -#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE -#define CFG_TUSB_OS OPT_OS_PICO - -// CFG_TUSB_DEBUG is defined by compiler in DEBUG build -#ifndef CFG_TUSB_DEBUG -#define CFG_TUSB_DEBUG 0 -#endif - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_HID (2) -#define CFG_TUD_CDC (1) -#define CFG_TUD_MSC (0) -#define CFG_TUD_MIDI (1) -#define CFG_TUD_VENDOR (0) - -#define CFG_TUD_CDC_RX_BUFSIZE (256) -#define CFG_TUD_CDC_TX_BUFSIZE (256) - -#define CFG_TUD_MIDI_RX_BUFSIZE (64) -#define CFG_TUD_MIDI_TX_BUFSIZE (64) - -// HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE (64) - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CONFIG_H_ */ diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h b/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h index cda67e0fa1..bb28e5009a 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h +++ b/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -15,6 +16,20 @@ enum sleep_type { bool system_deep_sleep(uint32_t time_in_us); bool system_deep_sleep_set_option(uint8_t option); +enum sleep_level { + MIN_SLEEP_T, + MAX_SLEEP_T, +}; + +void wifi_enable_gpio_wakeup(uint32_t i, enum GPIO_INT_TYPE intr_status); +void wifi_disable_gpio_wakeup(void); +bool wifi_set_sleep_type(enum sleep_type type); +enum sleep_type wifi_get_sleep_type(void); +bool wifi_set_sleep_level(enum sleep_level level); +enum sleep_level wifi_get_sleep_level(void); +bool wifi_set_listen_interval(uint8_t interval); +uint8_t wifi_get_listen_interval(void); + #ifdef __cplusplus } #endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_tasks.h b/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_tasks.h index a279b483d2..50bfdd4364 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_tasks.h +++ b/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_tasks.h @@ -29,15 +29,3 @@ bool system_os_post(os_task_priority_t prio, os_signal_t sig, os_param_t par); #ifdef __cplusplus } #endif - -#ifdef DRIVER_CODE_INIT -// Setup default task queues -void system_init_tasks(); - -// Hook function to process task queues -void system_service_tasks(); - -typedef void (*system_task_callback_t)(os_param_t param); - -bool system_queue_callback(system_task_callback_t callback, os_param_t param); -#endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c b/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c index 9599aba2a9..f2a9b2004a 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c +++ b/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c @@ -9,3 +9,45 @@ bool system_deep_sleep_set_option(uint8_t option) { return false; } + +/* GPIO */ + +void wifi_enable_gpio_wakeup(uint32_t i, enum GPIO_INT_TYPE intr_status) +{ +} + +void wifi_disable_gpio_wakeup(void) +{ +} + +/* WiFi */ + +bool wifi_set_sleep_type(enum sleep_type type) +{ + return type == NONE_SLEEP_T; +} + +enum sleep_type wifi_get_sleep_type(void) +{ + return NONE_SLEEP_T; +} + +bool wifi_set_sleep_level(enum sleep_level level) +{ + return false; +} + +enum sleep_level wifi_get_sleep_level(void) +{ + return MIN_SLEEP_T; +} + +bool wifi_set_listen_interval(uint8_t interval) +{ + return false; +} + +uint8_t wifi_get_listen_interval(void) +{ + return 0; +} diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp index cf41746032..ab6e329416 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/startup.cpp @@ -21,9 +21,17 @@ extern void init(); extern void hw_timer_init(); extern void system_init_timers(); extern void system_service_timers(); +extern void rp2040_network_initialise(); +extern void rp2040_network_service(); namespace { +#ifdef PICO_DEFAULT_LED_PIN +#define PICO_HDD_ACTIVITY_LED_PINMASK BIT(PICO_DEFAULT_LED_PIN) +#else +#define PICO_HDD_ACTIVITY_LED_PINMASK 0 +#endif + #ifdef ENABLE_BOOTSEL uint32_t last_bootsel_check; @@ -72,7 +80,7 @@ void check_bootsel() last_bootsel_check = ticks; if(get_bootsel_button()) { - reset_usb_boot(BIT(PICO_DEFAULT_LED_PIN), 0); + reset_usb_boot(PICO_HDD_ACTIVITY_LED_PINMASK, 0); } } @@ -80,11 +88,15 @@ void check_bootsel() } // namespace +extern void system_init_rtc(); + extern "C" int main(void) { - extern void system_init_clocks(void); + extern void system_init_clocks(); system_init_clocks(); + system_init_rtc(); + system_soft_wdt_restart(); // Initialise hardware timers @@ -110,12 +122,19 @@ extern "C" int main(void) Storage::initialize(); +#ifndef DISABLE_NETWORK + rp2040_network_initialise(); +#endif + init(); // User code init while(true) { system_soft_wdt_feed(); system_service_tasks(); system_service_timers(); +#ifndef DISABLE_NETWORK + rp2040_network_service(); +#endif #ifdef ENABLE_BOOTSEL check_bootsel(); #endif diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/tasks.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/tasks.cpp index df1ddaa000..cabd0903fe 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/tasks.cpp +++ b/Sming/Arch/Rp2040/Components/rp2040/src/tasks.cpp @@ -1,55 +1,66 @@ #include "include/esp_tasks_ll.h" #include #include -#include +#include +#include + +namespace { class TaskQueue { public: - TaskQueue(os_task_t callback, os_event_t* events, uint8_t length) + static void init() { - this->callback = callback; - this->events = events; - this->length = length; - read = count = 0; + spinlock = spin_lock_claim_unused(true); } - bool IRAM_ATTR post(os_signal_t sig, os_param_t par) + TaskQueue(os_task_t callback, uint8_t length): callback(callback) { - auto level = save_and_disable_interrupts(); + queue_init_with_spinlock(&queue, sizeof(os_event_t), length, spinlock); + } - bool full = (count == length); - if(!full) { - events[(read + count) % length] = os_event_t{sig, par}; - ++count; - } + ~TaskQueue() + { + queue_free(&queue); + } - restore_interrupts(level); - return !full; + bool __forceinline post(os_signal_t sig, os_param_t par) + { + os_event_t event {sig, par}; + return queue_try_add(&queue, &event); } void process() { // Don't service any newly queued events - for(unsigned n = count; n != 0; --n) { - auto evt = events[read]; - read = (read + 1) % length; - --count; - callback(&evt); + unsigned count = queue_get_level(&queue); + while(count--) { + os_event_t event; + if(queue_try_remove(&queue, &event)) { + callback(&event); + } } } + explicit operator bool() const + { + return callback && queue.data; + } + private: + static uint8_t spinlock; os_task_t callback; - os_event_t* events; - uint8_t read; - uint8_t count; - uint8_t length; + queue_t queue; }; -static TaskQueue* task_queues[USER_TASK_PRIO_MAX + 1]; +uint8_t TaskQueue::spinlock; const uint8_t SYSTEM_TASK_PRIO = USER_TASK_PRIO_MAX; +const uint8_t SYSTEM_TASK_QUEUE_LENGTH = 8; + +TaskQueue* task_queues[SYSTEM_TASK_PRIO + 1]; + +}; bool system_os_task(os_task_t callback, os_task_priority_t prio, os_event_t* events, uint8_t qlen) { @@ -63,8 +74,8 @@ bool system_os_task(os_task_t callback, os_task_priority_t prio, os_event_t* eve return false; } - queue = new TaskQueue(callback, events, qlen); - return queue != nullptr; + queue = new TaskQueue(callback, qlen); + return queue && *queue; } bool IRAM_ATTR system_os_post(os_task_priority_t prio, os_signal_t sig, os_param_t par) @@ -82,7 +93,7 @@ bool IRAM_ATTR system_os_post(os_task_priority_t prio, os_signal_t sig, os_param void system_init_tasks() { - static os_event_t events[8]; + TaskQueue::init(); auto systemTaskCallback = [](os_event_t* event) { auto callback = system_task_callback_t(event->sig); @@ -91,7 +102,7 @@ void system_init_tasks() } }; - task_queues[SYSTEM_TASK_PRIO] = new TaskQueue(systemTaskCallback, events, ARRAY_SIZE(events)); + task_queues[SYSTEM_TASK_PRIO] = new TaskQueue(systemTaskCallback, SYSTEM_TASK_QUEUE_LENGTH); } void system_service_tasks() diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp new file mode 100644 index 0000000000..4c87e488a7 --- /dev/null +++ b/Sming/Arch/Rp2040/Components/rp2040/src/wifi.cpp @@ -0,0 +1,130 @@ +/* + * Contains code based on https://github.com/raspberrypi/pico-sdk/issues/909 + * NB. Future driver updates may simplify this process. + */ + +#ifndef DISABLE_WIFI + +#include +#include +#include +#include +#include +extern "C" { +#include +} + +#ifdef CYW43_FIRMWARE +#include +IMPORT_FSTR_ARRAY_LOCAL(cyw43_firmware, uint8_t, CYW43_FIRMWARE) +#endif + +namespace { + +#define BUFFER_SIZE 16384 +#define DICT_SIZE 32767 + +class Decompressor { +public: + explicit Decompressor(const FSTR::ObjectBase& data) + { + stream.reset(new FlashMemoryStream(data)); + } + + explicit Decompressor(Storage::Partition part) + { + stream.reset(new Storage::PartitionStream(part)); + } + + bool init() + { + uzlib_init(); + uzlib_uncompress_init(&state, dict, DICT_SIZE); + state.source_read_cb = read_source; + int res = uzlib_gzip_parse_header(&state); + if (res != TINF_OK) { + debug_e("[CYW] bad GZIP header %d", res); + return false; + } + return true; + } + + bool read(void* dest, size_t length) + { + state.dest = static_cast(dest); + state.dest_limit = state.dest + length; + int res = uzlib_uncompress_chksum(&state); + if(res != TINF_OK) { + debug_e("[CYW] Decompress error %d", res); + return false; + } + return true; + } + +private: + // Return -1 when finished + static int read_source(struct uzlib_uncomp* uncomp) + { + auto self = reinterpret_cast(uncomp); + size_t len = self->stream->readBytes(self->src_buffer, BUFFER_SIZE); + if(len == 0) { + return -1; + } + + uncomp->source = self->src_buffer; + uncomp->source_limit = &self->src_buffer[len]; + + return *self->state.source++; + } + + struct uzlib_uncomp state{}; + uint8_t src_buffer[BUFFER_SIZE]{}; + uint8_t dict[DICT_SIZE]; + std::unique_ptr stream; +}; + +std::unique_ptr decompressor; + +} + +int cyw43_storage_init() +{ +#ifdef CYW43_FIRMWARE + decompressor.reset(new Decompressor(cyw43_firmware)); +#else + auto part = Storage::findPartition("cyw43_fw"); + if(!part) { + debug_e("Failed to find CYW43 firmware partition"); + } else { + decompressor.reset(new Decompressor(part)); + } +#endif + + if (!decompressor || !decompressor->init()) { + decompressor.reset(); + return -1; + } + + return 0; +} + +uint32_t cyw43_storage_read(void* dest, uint32_t length) +{ + if(!decompressor) { + return 0; + } + + if(!decompressor->read(dest, length)) { + decompressor.reset(); + return 0; + } + + return length; +} + +void cyw43_storage_cleanup() +{ + decompressor.reset(); +} + +#endif // ifndef DISABLE_WIFI diff --git a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp index 54d7f4a599..54f9fdcedd 100644 --- a/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Rp2040/Components/spi_flash/flashmem.cpp @@ -131,7 +131,7 @@ uint32_t readAligned(void* to, uint32_t fromaddr, uint32_t size) (void)xip_ctrl_hw->stream_fifo; } - xip_ctrl_hw->stream_addr = flashaddr; + xip_ctrl_hw->stream_addr = XIP_NOCACHE_NOALLOC_BASE + fromaddr; xip_ctrl_hw->stream_ctr = transfer_count; /* @@ -300,6 +300,7 @@ uint32_t flashmem_read(void* to, uint32_t fromaddr, uint32_t size) bool flashmem_erase_sector(uint32_t sector_id) { debug_d("flashmem_erase_sector(0x%08x)", sector_id); + system_soft_wdt_feed(); flash_range_erase(sector_id * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE); return true; } diff --git a/Sming/Arch/Rp2040/Components/uf2/uf2conv.py b/Sming/Arch/Rp2040/Components/uf2/uf2conv.py index e51f4b7437..06beeb27f2 100644 --- a/Sming/Arch/Rp2040/Components/uf2/uf2conv.py +++ b/Sming/Arch/Rp2040/Components/uf2/uf2conv.py @@ -180,15 +180,9 @@ def get_drives(): if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: - rootpath = "/media" - if sys.platform == "darwin": - rootpath = "/Volumes" - elif sys.platform == "linux": - tmp = rootpath + "/" + os.environ["USER"] - if os.path.isdir(tmp): - rootpath = tmp - for d in os.listdir(rootpath): - drives.append(os.path.join(rootpath, d)) + r = subprocess.check_output(["findmnt", "-o", "TARGET", "-t", "vfat", "-ln"]) + for dev in r.decode().split('\n'): + drives.append(dev) def has_info(d): try: diff --git a/Sming/Arch/Rp2040/Core/adc.cpp b/Sming/Arch/Rp2040/Core/adc.cpp new file mode 100644 index 0000000000..5ac4fe8419 --- /dev/null +++ b/Sming/Arch/Rp2040/Core/adc.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +#define PIN_ADC0 26 +#define PIN_ADC1 27 +#define PIN_ADC2 28 +#define PIN_ADC3 29 +#define PIN_TEMP 30 // Not a GPIO +#define ADC_TEMP 4 + +namespace +{ +std::bitset initflags; +} + +uint16_t analogRead(uint16_t pin) +{ + if(pin < PIN_ADC0 || pin > PIN_TEMP) { + // Not an analogue pin + return 0; + } + + uint8_t channel = pin - PIN_ADC0; + if((adc_hw->cs & ADC_CS_EN_BITS) == 0) { + adc_init(); + } + if(!initflags[channel]) { + if(channel == ADC_TEMP) { + adc_set_temp_sensor_enabled(true); + } else { + adc_gpio_init(pin); + } + initflags[channel] = true; + } + + adc_select_input(channel); + return adc_read(); +} diff --git a/Sming/Arch/Rp2040/Core/adc.cpp.todo b/Sming/Arch/Rp2040/Core/adc.cpp.todo deleted file mode 100644 index 6ab92823ff..0000000000 --- a/Sming/Arch/Rp2040/Core/adc.cpp.todo +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -uint16_t analogRead(uint16_t pin) -{ - if(pin == A0) - return system_adc_read(); - else - return -1; // Not supported -} diff --git a/Sming/Arch/Rp2040/Core/pins_arduino.h b/Sming/Arch/Rp2040/Core/pins_arduino.h index c5fe1e9421..cbad241ecb 100644 --- a/Sming/Arch/Rp2040/Core/pins_arduino.h +++ b/Sming/Arch/Rp2040/Core/pins_arduino.h @@ -12,7 +12,7 @@ #pragma once -const uint8_t A0{0}; // TODO main ADC input +const uint8_t A0{26}; #define NOT_A_PIN 0 #define NOT_A_PORT 0 diff --git a/Sming/Arch/Rp2040/Platform/RTC.cpp b/Sming/Arch/Rp2040/Platform/RTC.cpp index 6d211744e4..fef78b61d5 100644 --- a/Sming/Arch/Rp2040/Platform/RTC.cpp +++ b/Sming/Arch/Rp2040/Platform/RTC.cpp @@ -16,24 +16,15 @@ RtcClass RTC; #define NS_PER_SECOND 1000000000 -namespace +void system_init_rtc() { -bool initialised; - -void checkInit() -{ - if(initialised) { - return; - } rtc_init(); - initialised = true; + datetime_t t{.year = 1970, .month = 1, .day = 1}; + rtc_set_datetime(&t); } -} // namespace - RtcClass::RtcClass() { - rtc_init(); } uint64_t RtcClass::getRtcNanoseconds() @@ -43,13 +34,13 @@ uint64_t RtcClass::getRtcNanoseconds() uint32_t RtcClass::getRtcSeconds() { - checkInit(); - datetime_t t; - rtc_get_datetime(&t); + if(!rtc_get_datetime(&t)) { + return 0; + } DateTime dt; - dt.setTime(t.sec, t.min, t.hour, t.day, t.month, t.year); + dt.setTime(t.sec, t.min, t.hour, t.day, t.month - 1, t.year); return time_t(dt); } @@ -61,13 +52,11 @@ bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) bool RtcClass::setRtcSeconds(uint32_t seconds) { - checkInit(); - DateTime dt{seconds}; datetime_t t = { .year = int16_t(dt.Year), - .month = int8_t(dt.Month), + .month = int8_t(1 + dt.Month), .day = int8_t(dt.Day), .dotw = int8_t(dt.DayofWeek), .hour = int8_t(dt.Hour), diff --git a/Sming/Arch/Rp2040/README.rst b/Sming/Arch/Rp2040/README.rst index 40eda7363b..473fb85079 100644 --- a/Sming/Arch/Rp2040/README.rst +++ b/Sming/Arch/Rp2040/README.rst @@ -22,7 +22,7 @@ Tested and working: - CPU frequency adjustment :cpp:func:`system_get_cpu_freq`, :cpp:func:`system_update_cpu_freq` - Timers working: hardware, software and CPU cycle counter - Hardware serial ports (UART driver) -- Task queue +- Task queue (also supports queuing tasks from code running on core #1) - Flash memory routines - :cpp:func:`os_random` and :cpp:func:`os_get_random` implemented using ring oscillator. This is the best the hardware is capable of, but not crypto grade. @@ -36,14 +36,10 @@ Tested and working: - System functions :cpp:func:`system_get_chip_id`, :cpp:func:`system_get_sdk_version`. - Partitions and file systems (except SD cards and FAT) - SPIClass tested with Radio_nRF24L01 sample only +- WiFi networking support for the Pico-W +- Standard analogue I/O via analogRead. More advanced hardware capabilities require use of the SDK directly. +- Dual-core support. See below for details. -In progress: - -Networking - A skeleton WiFi/lwip2 support framework is provided sufficient to build samples with Networking enabled, - but it is currently non-functional. - The goal is to allow use of networking adapters such as Ethernet over SPI, similar to how ESP32. - USB offers the possibility of CDMA networking for mobile applications. Yet to be implemented: @@ -53,8 +49,6 @@ USB Arduino-Pico overrides ``HardwareSerial`` to support serial devices, we can do something similar. HardwareSPI To support DMA, etc. -Analogue I/O - Has 4 channels + temperature. PWM Hardware can drive up to 16 outputs and measure input frequency/duty cycle. I2C @@ -64,8 +58,6 @@ RTC (Setting and reading the time is implemented.) Low-power modes Deep sleep / suspend / power-saving -Dual-core support - RP2040 is a dual-core processor! PIO (Programmable I/O) A killer feature for the RP2040. Uses range from simple glue logic to I2S, etc. @@ -76,7 +68,9 @@ Crash/exception handling & serial debugging Multi-boot / OTA updates. If you run ``make map`` you'll see there is no bootloader! It's part of the firmware image at present. - Adding RP2040 support to rBoot would probably be simplest. + 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. Requirements @@ -167,6 +161,68 @@ The RP2040 can also be programmed via JTAG debugging but this requires additiona so commands such as ``make verifyflash`` won't work at present. +Dual-core support +----------------- + +Sming is a strictly non-threaded framework, and all code runs on core #0. +The SDK *multicore* API may still be used to run code on core #1, but this requires some care to ensure smooth operation. + +The task queue (:cpp:func:`System::queueTask`, etc.) may be used to send messages to Sming from Core #1 code. + +Passing messages the other way, from Sming code to core #1, could be done using a separate SDK task queue. + + +Flash access +~~~~~~~~~~~~ + +Core 1 code may run directly from flash memory (via XIP) without any special considerations. +However, during flash erase/write operations (e.g. file writes) XIP is disabled. +If core 1 code attempts to access flash during these periods the system will hard fault. + +.. note:: + + Floating-point support requires use of routines in flash memory. + Integer operations should all be safe to use. + + If unexplained crashes are occuring then check the build output files (in out/Rp2040/debug/build) + or use a debugger to identify any errant code running from flash. + +A typical use for core #1 might be to perform processing of some kind, such as processing data sampled +via analogue inputs. If all code is run from RAM then it can continue uninterrupted even during filing system +operations. + +Alternatively some kind of synchronisation mechanism may be used to ensure that core 1 is suspended or running from RAM +during any flash erase/write operations. + + + +Networking +---------- + +The Pico-W variant includes an Infineon CYW43439 bluetooth/WiFi SoC. + +Raspberry Pi use the ... driver. The SDK also includes an LWIP implementation. + +The physical interface is SPI using a custom (PIO) implementation. +This requires the use of GPIOxx which can no longer be accessed directly, +but instead via xxxxx. + +The CYW43 chip is initialised (via `cyw43_ensure_up`) when application code +makes the first call into the networking API, for example by enabling station +or AP access. Part of the hardware configuration here is to download firmware +to the CYW43 chip (about 240KB) plus the CLM BLOB (< 1KB). + +.. note: + + CLM stands for ``Country Locale Matrix``. The data defines regulatory configuration (target power outputs). + Currently a 'global' setting is used to initialise WiFi, but there may be advantages in changing this to the + specific country where the device is being deployed. + +Sming contains patches which compresses this data (based on https://github.com/raspberrypi/pico-sdk/issues/909) +to about 145KB. +By default, it is linked into the application image, but can also be read from a separate partition. + + Source code ----------- diff --git a/Sming/Arch/Rp2040/Tools/install.sh b/Sming/Arch/Rp2040/Tools/install.sh index 24f6b27359..03451153e5 100755 --- a/Sming/Arch/Rp2040/Tools/install.sh +++ b/Sming/Arch/Rp2040/Tools/install.sh @@ -7,10 +7,10 @@ $PKG_INSTALL ninja-build if [ -d "$PICO_TOOLCHAIN_PATH/arm-none-eabi" ]; then printf "\n\n** Skipping Rp2040 tools installation: '$PICO_TOOLCHAIN_PATH' exists\n\n" else - TOOLCHAIN_VERSION="10.3-2021.07" + TOOLCHAIN_VERSION="10.3-2021.10" TOOLCHAIN_BASE_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm" TOOLCHAIN_NAME="gcc-arm-none-eabi-$TOOLCHAIN_VERSION" - TOOLCHAIN_FILE="$TOOLCHAIN_NAME-x86_64-linux.tar.bz2" + TOOLCHAIN_FILE="$TOOLCHAIN_NAME-$(uname -m)-linux.tar.bz2" TOOLCHAIN_URL="$TOOLCHAIN_BASE_URL/$TOOLCHAIN_VERSION/$TOOLCHAIN_FILE" $WGET "$TOOLCHAIN_URL" -O "$DOWNLOADS/$TOOLCHAIN_FILE" mkdir -p "$PICO_TOOLCHAIN_PATH" diff --git a/Sming/Arch/Rp2040/options.json b/Sming/Arch/Rp2040/options.json new file mode 100644 index 0000000000..f155970376 --- /dev/null +++ b/Sming/Arch/Rp2040/options.json @@ -0,0 +1,15 @@ +{ + "cyw43_fw": { + "description": "Pico-W CYW43439 WiFi transceiver firmware", + "partitions": { + "cyw43_fw": { + "address": "self.device.size - 0x1000 - self.size", + "size": "0x24000", + "type": "data", + "subtype": "phy", + "readonly": true, + "filename": "$(CYW43_FIRMWARE)" + } + } + } +} \ No newline at end of file diff --git a/Sming/Components/FlashString b/Sming/Components/FlashString index 0045c67179..1025908632 160000 --- a/Sming/Components/FlashString +++ b/Sming/Components/FlashString @@ -1 +1 @@ -Subproject commit 0045c67179833555256e2c3e0e3b82eaca3dc851 +Subproject commit 10259086321ebeceb6b7106b4697c9caef9956e6 diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h index d6cb1a5dca..4ab6e1c9ac 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h @@ -16,6 +16,7 @@ #include #include "TcpTransport.h" #include "TcpClientStream.h" +#include namespace Hosted { @@ -27,12 +28,7 @@ class TcpClientTransport : public TcpTransport TcpClientTransport(TcpClient& client) { client.setReceiveDelegate(TcpClientDataDelegate(&TcpClientTransport::process, this)); - stream = new TcpClientStream(client); - } - - ~TcpClientTransport() - { - delete stream; + stream.reset(new TcpClientStream(client)); } protected: @@ -46,7 +42,7 @@ class TcpClientTransport : public TcpTransport } private: - TcpClientStream* stream = nullptr; + std::unique_ptr stream; }; } // namespace Transport diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 1767d7020e..b6fdbabb50 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 1767d7020e18c8ffa0c58b31a5650a5275ee47c6 +Subproject commit b6fdbabb506af5722da9395d65b70c6a7f31d6c9 diff --git a/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp b/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp index a64eb2d094..8ff964416b 100644 --- a/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp +++ b/Sming/Components/Network/Arch/Esp32/Network/DM9051.cpp @@ -9,6 +9,7 @@ ****/ #include +#include #include #include "spi_config.h" @@ -28,8 +29,10 @@ bool DM9051Service::begin(const Config& config) esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&netif_cfg); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) // Set default handlers to process TCP/IP stuffs CHECK_RET(esp_eth_set_default_handlers(netif)); +#endif // And register our own event handlers enableEventCallback(true); @@ -48,10 +51,13 @@ bool DM9051Service::begin(const Config& config) .spics_io_num = getPin(config.chipSelectPin, DEFAULT_PIN_CS), .queue_size = 20, }; +#if ESP_IDF_VERSION_MAJOR < 5 spi_device_handle_t spi_handle{nullptr}; CHECK_RET(spi_bus_add_device(spiHost, &devcfg, &spi_handle)); - eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle); +#else + eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spiHost, &devcfg); +#endif dm9051_config.int_gpio_num = getPin(config.interruptPin, DEFAULT_PIN_INT); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config); @@ -69,7 +75,7 @@ bool DM9051Service::begin(const Config& config) setMacAddress(MacAddress({0x02, 0x00, 0x00, 0x12, 0x34, 0x56})); - netif_glue = esp_eth_new_netif_glue(handle); + netif_glue = static_cast(esp_eth_new_netif_glue(handle)); CHECK_RET(esp_netif_attach(netif, netif_glue)); CHECK_RET(esp_eth_start(handle)); diff --git a/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp b/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp index f888613859..4410f52ade 100644 --- a/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp +++ b/Sming/Components/Network/Arch/Esp32/Network/W5500.cpp @@ -9,6 +9,7 @@ ****/ #include +#include #include #include "spi_config.h" @@ -28,8 +29,10 @@ bool W5500Service::begin(const Config& config) esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&netif_cfg); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) // Set default handlers to process TCP/IP stuffs CHECK_RET(esp_eth_set_default_handlers(netif)); +#endif // And register our own event handlers enableEventCallback(true); @@ -48,10 +51,13 @@ bool W5500Service::begin(const Config& config) .spics_io_num = getPin(config.chipSelectPin, DEFAULT_PIN_CS), .queue_size = 20, }; +#if ESP_IDF_VERSION_MAJOR < 5 spi_device_handle_t spi_handle{nullptr}; CHECK_RET(spi_bus_add_device(spiHost, &devcfg, &spi_handle)); - eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle); +#else + eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spiHost, &devcfg); +#endif w5500_config.int_gpio_num = getPin(config.interruptPin, DEFAULT_PIN_INT); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); @@ -69,7 +75,7 @@ bool W5500Service::begin(const Config& config) setMacAddress(MacAddress({0x02, 0x00, 0x00, 0x12, 0x34, 0x56})); - netif_glue = esp_eth_new_netif_glue(handle); + netif_glue = static_cast(esp_eth_new_netif_glue(handle)); CHECK_RET(esp_netif_attach(netif, netif_glue)); CHECK_RET(esp_eth_start(handle)); diff --git a/Sming/Components/Network/Arch/Esp32/Network/spi_config.h b/Sming/Components/Network/Arch/Esp32/Network/spi_config.h index 6fcc0f87ba..b1499c834d 100644 --- a/Sming/Components/Network/Arch/Esp32/Network/spi_config.h +++ b/Sming/Components/Network/Arch/Esp32/Network/spi_config.h @@ -35,6 +35,11 @@ #define DEFAULT_PIN_CS 10 #define DEFAULT_PIN_INT 19 #define DEFAULT_PIN_RESET 18 +#elif defined(SOC_ESP32C2) +#define DEFAULT_HOST SPI2_HOST +#define DEFAULT_PIN_CS 10 +#define DEFAULT_PIN_INT 19 +#define DEFAULT_PIN_RESET 18 #endif #define CHECK_RET(err) \ diff --git a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp index ec6b028dbf..6923567084 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/EmbeddedEthernet.cpp @@ -29,14 +29,17 @@ bool EmbeddedEthernet::begin(const Config& config) esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); netif = esp_netif_new(&cfg); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) // Set default handlers to process TCP/IP stuffs ESP_ERROR_CHECK(esp_eth_set_default_handlers(netif)); +#endif // And register our own event handlers enableEventCallback(true); enableGotIpCallback(true); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); +#if ESP_IDF_VERSION_MAJOR < 5 if(config.smiMdcPin != PIN_DEFAULT) { mac_config.smi_mdc_gpio_num = config.smiMdcPin; } @@ -44,6 +47,16 @@ bool EmbeddedEthernet::begin(const Config& config) mac_config.smi_mdio_gpio_num = config.smiMdioPin; } mac = esp_eth_mac_new_esp32(&mac_config); +#else + eth_esp32_emac_config_t emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); + if(config.smiMdcPin != PIN_DEFAULT) { + emac_config.smi_mdc_gpio_num = config.smiMdcPin; + } + if(config.smiMdioPin != PIN_DEFAULT) { + emac_config.smi_mdio_gpio_num = config.smiMdioPin; + } + mac = esp_eth_mac_new_esp32(&emac_config, &mac_config); +#endif if(mac == nullptr) { debug_e("[ETH] Failed to construct MAC"); return false; @@ -57,7 +70,7 @@ bool EmbeddedEthernet::begin(const Config& config) esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); ESP_ERROR_CHECK(esp_eth_driver_install(ð_config, &handle)); - netif_glue = esp_eth_new_netif_glue(handle); + netif_glue = static_cast(esp_eth_new_netif_glue(handle)); ESP_ERROR_CHECK(esp_netif_attach(netif, netif_glue)); ESP_ERROR_CHECK(esp_eth_start(handle)); diff --git a/Sming/Components/Network/Arch/Esp32/Platform/EthernetPhy.cpp b/Sming/Components/Network/Arch/Esp32/Platform/EthernetPhy.cpp index 596dff13e5..41d03bdf05 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/EthernetPhy.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/EthernetPhy.cpp @@ -59,9 +59,14 @@ namespace Ethernet { PHY_IMPL(Ip101, ip101) PHY_IMPL(Rtl8201, rtl8201) -PHY_IMPL(Lan8720, lan8720) PHY_IMPL(Dp83848, dp83848) +#if ESP_IDF_VERSION_MAJOR < 5 +PHY_IMPL(Lan8720, lan8720) PHY_IMPL(Ksz8041, ksz8041) +#else +PHY_IMPL(Lan8720, lan87xx) +PHY_IMPL(Ksz8041, ksz80xx) +#endif // For internal use PHY_IMPL(W5500PhyFactory, w5500) diff --git a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp index c96171f05a..3d74fb1e27 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/IdfService.cpp @@ -10,9 +10,14 @@ #include #include +#include #include #include +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) +using esp_eth_netif_glue_handle_t = void*; +#endif + namespace Ethernet { void IdfService::end() @@ -22,9 +27,11 @@ void IdfService::end() } ESP_ERROR_CHECK(esp_eth_stop(handle)); - ESP_ERROR_CHECK(esp_eth_del_netif_glue(netif_glue)); + ESP_ERROR_CHECK(esp_eth_del_netif_glue(static_cast(netif_glue))); netif_glue = nullptr; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) ESP_ERROR_CHECK(esp_eth_clear_default_handlers(netif)); +#endif ESP_ERROR_CHECK(esp_eth_driver_uninstall(handle)); handle = nullptr; diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index 4609bed48c..73921ae8e7 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -127,7 +127,7 @@ void StationImpl::enable(bool enabled, bool save) switch(mode) { case WIFI_MODE_STA: case WIFI_MODE_APSTA: - return; // No change required + break; case WIFI_MODE_AP: mode = WIFI_MODE_APSTA; break; @@ -155,7 +155,9 @@ void StationImpl::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(mode)); - ESP_ERROR_CHECK(esp_wifi_start()); + if(enabled) { + ESP_ERROR_CHECK(esp_wifi_start()); + } } bool StationImpl::isEnabled() const @@ -220,7 +222,7 @@ bool StationImpl::isEnabledDHCP() const return false; } esp_netif_dhcp_status_t status; - if(esp_netif_dhcps_get_status(stationNetworkInterface, &status) != ESP_OK) { + if(esp_netif_dhcpc_get_status(stationNetworkInterface, &status) != ESP_OK) { return false; } diff --git a/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.cpp index 2a897c13c9..775dc07f70 100644 --- a/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.cpp +++ b/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.cpp @@ -82,11 +82,7 @@ bool AccessPointImpl::config(const String& ssid, String password, AUTH_MODE mode debugf("AP configuration was updated"); } else { debugf("Set AP configuration in background"); - if(runConfig != nullptr) { - delete runConfig; - } - runConfig = new softap_config(); - memcpy(runConfig, &config, sizeof(softap_config)); + runConfig.reset(new softap_config(config)); } } else { debugf("AP configuration loaded"); @@ -190,22 +186,23 @@ std::unique_ptr AccessPointImpl::getStations() const void AccessPointImpl::onSystemReady() { - if(runConfig != nullptr) { - noInterrupts(); - bool enabled = isEnabled(); - enable(true, false); - wifi_softap_dhcps_stop(); - - if(!wifi_softap_set_config(runConfig)) { - debugf("Can't set AP config on system ready event!"); - } else { - debugf("AP configuration was updated on system ready event"); - } - delete runConfig; - runConfig = nullptr; + if(!runConfig) { + return; + } + + noInterrupts(); + bool enabled = isEnabled(); + enable(true, false); + wifi_softap_dhcps_stop(); - wifi_softap_dhcps_start(); - enable(enabled, false); - interrupts(); + if(!wifi_softap_set_config(runConfig.get())) { + debugf("Can't set AP config on system ready event!"); + } else { + debugf("AP configuration was updated on system ready event"); } + runConfig.reset(); + + wifi_softap_dhcps_start(); + enable(enabled, false); + interrupts(); } diff --git a/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.h index 8ce64e886e..a470795ca3 100644 --- a/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.h +++ b/Sming/Components/Network/Arch/Esp8266/Platform/AccessPointImpl.h @@ -40,5 +40,5 @@ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler void onSystemReady() override; private: - softap_config* runConfig = nullptr; + std::unique_ptr runConfig; }; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp index 32a3b7eca3..d156751977 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp +++ b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.cpp @@ -11,67 +11,132 @@ #include "AccessPointImpl.h" #include "StationListImpl.h" -static AccessPointImpl accessPoint; -AccessPointClass& WifiAccessPoint = accessPoint; +AccessPointClass& WifiAccessPoint{SmingInternal::Network::accessPoint}; + +namespace SmingInternal::Network +{ +AccessPointImpl accessPoint; void AccessPointImpl::enable(bool enabled, bool save) { + if(enabled != this->enabled) { + cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, enabled, cyw43_arch_get_country_code()); + if(enabled) { + dhcps_start(); + } else { + dhcps_stop(); + } + this->enabled = enabled; + } } bool AccessPointImpl::isEnabled() const { - return false; + return enabled; +} + +static unsigned translateAuthMode(WifiAuthMode mode) +{ + // See cyw43_ll.h and whd_types.h for more details + switch(mode) { + case AUTH_OPEN: + return CYW43_AUTH_OPEN; + case AUTH_WPA_PSK: + return CYW43_AUTH_WPA_TKIP_PSK; + case AUTH_WPA_WPA2_PSK: + return CYW43_AUTH_WPA2_MIXED_PSK; + case AUTH_WEP: + case AUTH_WPA2_PSK: + default: + return CYW43_AUTH_WPA2_AES_PSK; + } } bool AccessPointImpl::config(const String& ssid, String password, WifiAuthMode mode, bool hidden, int channel, int beaconInterval) { - return false; + unsigned auth = translateAuthMode(mode); + cyw43_wifi_ap_set_ssid(&cyw43_state, ssid.length(), reinterpret_cast(ssid.c_str())); + if(password) { + cyw43_wifi_ap_set_password(&cyw43_state, password.length(), reinterpret_cast(password.c_str())); + cyw43_wifi_ap_set_auth(&cyw43_state, auth); + } else { + cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_OPEN); + } + if(enabled) { + cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, cyw43_arch_get_country_code()); + dhcps_start(); + } + return true; } IpAddress AccessPointImpl::getIP() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + return *netif_ip_addr4(netif); } IpAddress AccessPointImpl::getNetworkBroadcast() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + return netif_ip_addr4(netif)->addr | ~netif_ip_netmask4(netif)->addr; } IpAddress AccessPointImpl::getNetworkMask() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + return *netif_ip_netmask4(netif); } IpAddress AccessPointImpl::getNetworkGateway() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + return *netif_ip_gw4(netif); } bool AccessPointImpl::setIP(IpAddress address) { - return false; + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + netif_set_ipaddr(netif, address); + dhcps_start(); + return true; +} + +void AccessPointImpl::dhcps_start() +{ + auto netif = &cyw43_state.netif[CYW43_ITF_AP]; + ip4_addr_t gw = *netif_ip_addr4(netif); + ip4_addr_t mask; + IP4_ADDR(&mask, 255, 255, 255, 0); + dhcp_server_init(&dhcp_server, &gw, &mask); +} + +void AccessPointImpl::dhcps_stop() +{ + dhcp_server_deinit(&dhcp_server); } MacAddress AccessPointImpl::getMacAddress() const { - return MacAddress{}; + MacAddress mac; + cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_AP, &mac[0]); + return mac; } bool AccessPointImpl::setMacAddress(const MacAddress& addr) const { + // Not implemented return false; } String AccessPointImpl::getSSID() const { - return nullptr; + return String(reinterpret_cast(cyw43_state.ap_ssid), cyw43_state.ap_ssid_len); } String AccessPointImpl::getPassword() const { - return nullptr; + return String(reinterpret_cast(cyw43_state.ap_key), cyw43_state.ap_key_len); } std::unique_ptr AccessPointImpl::getStations() const @@ -82,3 +147,9 @@ std::unique_ptr AccessPointImpl::getStations() const void AccessPointImpl::onSystemReady() { } + +void AccessPointImpl::eventHandler(EventInfo& info) +{ +} + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h index 9ad1964628..65a94656b1 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h +++ b/Sming/Components/Network/Arch/Rp2040/Platform/AccessPointImpl.h @@ -4,15 +4,19 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * AccessPointImpl.h - Esp8266 WiFi Access Point + * AccessPointImpl.h * ****/ #pragma once #include +#include "WifiEventsImpl.h" +#include "dhcpserver.h" #include +namespace SmingInternal::Network +{ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler { public: @@ -36,6 +40,19 @@ class AccessPointImpl : public AccessPointClass, protected ISystemReadyHandler String getPassword() const override; std::unique_ptr getStations() const override; + void eventHandler(EventInfo& info); + protected: void onSystemReady() override; + +private: + void dhcps_start(); + void dhcps_stop(); + + dhcp_server_t dhcp_server{}; + bool enabled{false}; }; + +extern AccessPointImpl accessPoint; + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp index 3004fc2201..c799f0be1b 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp @@ -10,120 +10,315 @@ #include "StationImpl.h" #include "WifiEventsImpl.h" +#include "whd.h" +#include -static StationImpl station; -StationClass& WifiStation = station; +#include + +#define SCAN_TIMEOUT_MS 30000 + +StationClass& WifiStation{SmingInternal::Network::station}; + +namespace SmingInternal::Network +{ +BssList StationImpl::scanResults; +SimpleTimer StationImpl::scanTimer; + +StationImpl station; void StationImpl::enable(bool enabled, bool save) { + debug_d("%s", __PRETTY_FUNCTION__); + if(enabled != this->enabled) { + cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, enabled, cyw43_arch_get_country_code()); + this->enabled = enabled; + } } bool StationImpl::isEnabled() const { - return false; + return this->enabled; } bool StationImpl::config(const Config& cfg) { - return false; + this->cfg = cfg; + return enabled ? internalConnect() : true; } bool StationImpl::connect() { - return false; + if(cfg.ssid.length() == 0) { + return false; + } + + int link_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA); + debug_d("link_status %d", link_status); + switch(link_status) { + case CYW43_LINK_JOIN: + return true; + case CYW43_LINK_NOIP: + cyw43_cb_tcpip_set_link_up(&cyw43_state, CYW43_ITF_STA); + return true; + case CYW43_LINK_UP: + return true; + case CYW43_LINK_FAIL: + case CYW43_LINK_NONET: + case CYW43_LINK_BADAUTH: + case CYW43_LINK_DOWN: + return internalConnect(); + default: + return false; + } +} + +bool StationImpl::internalConnect() +{ + unsigned auth = cfg.password.length() ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN; + // Note: `channel` is ignored if `bssid` is not set. Leave it at 0 and see what happens + const uint8_t* bssid = cfg.bssid ? &cfg.bssid[0] : nullptr; + unsigned channel{0}; + int res = cyw43_wifi_join(&cyw43_state, cfg.ssid.length(), reinterpret_cast(cfg.ssid.c_str()), + cfg.password.length(), reinterpret_cast(cfg.password.c_str()), auth, + bssid, channel); + return res == 0; } bool StationImpl::disconnect() { - return false; + int res = cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA); + return res == 0; } bool StationImpl::isEnabledDHCP() const { - return false; + return cyw43_state.dhcp_client.state != DHCP_STATE_OFF; } void StationImpl::enableDHCP(bool enable) { + debug_w("%s NOT IMPLEMENTED", __PRETTY_FUNCTION__); } void StationImpl::setHostname(const String& hostname) { + this->hostname = hostname; + netif_set_hostname(&cyw43_state.netif[CYW43_ITF_STA], this->hostname.c_str()); } String StationImpl::getHostname() const { - return nullptr; + return netif_get_hostname(&cyw43_state.netif[CYW43_ITF_STA]); } IpAddress StationImpl::getIP() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_STA]; + return *netif_ip_addr4(netif); } MacAddress StationImpl::getMacAddress() const { - return MacAddress{}; + MacAddress mac; + cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, &mac[0]); + return mac; } bool StationImpl::setMacAddress(const MacAddress& addr) const { - return false; + // `cyw43_poll` gets set by cyw43_ensure_up(), after which point MAC cannot be changed + if(cyw43_poll != nullptr) { + debug_e("Set STA MAC failed, already initialised"); + return false; + } + + addr.getOctets(cyw43_state.mac); + return true; } IpAddress StationImpl::getNetworkBroadcast() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_STA]; + return netif_ip_addr4(netif)->addr | ~netif_ip_netmask4(netif)->addr; } IpAddress StationImpl::getNetworkMask() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_STA]; + return *netif_ip_netmask4(netif); } IpAddress StationImpl::getNetworkGateway() const { - return IpAddress{}; + auto netif = &cyw43_state.netif[CYW43_ITF_STA]; + return *netif_ip_gw4(netif); } bool StationImpl::setIP(IpAddress address, IpAddress netmask, IpAddress gateway) { - return false; + auto netif = &cyw43_state.netif[CYW43_ITF_STA]; + netif_set_ipaddr(netif, address); + netif_set_netmask(netif, netmask); + netif_set_gw(netif, gateway); + return true; } String StationImpl::getSSID() const { - return nullptr; + return cfg.ssid; } MacAddress StationImpl::getBSSID() const { - return {}; + return whd_get_bssid(CYW43_ITF_STA); } int8_t StationImpl::getRssi() const { - return 0; + int32_t rssi{0}; + int res = cyw43_wifi_get_rssi(&cyw43_state, &rssi); + return (res == 0) ? rssi : 0; } uint8_t StationImpl::getChannel() const { - return 0; + return whd_get_channel(CYW43_ITF_STA); } String StationImpl::getPassword() const { - return nullptr; + return cfg.password; } StationConnectionStatus StationImpl::getConnectionStatus() const { - return eSCS_Idle; + int link_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA); + switch(link_status) { + case CYW43_LINK_JOIN: + case CYW43_LINK_NOIP: + return eSCS_Connecting; + case CYW43_LINK_UP: + return eSCS_GotIP; + case CYW43_LINK_FAIL: + return eSCS_ConnectionFailed; + case CYW43_LINK_NONET: + return eSCS_AccessPointNotFound; + case CYW43_LINK_BADAUTH: + return eSCS_WrongPassword; + case CYW43_LINK_DOWN: + default: + return enabled ? eSCS_ConnectionFailed : eSCS_Idle; + } +} + +static WifiAuthMode translateAuthMode(uint32_t auth_mode) +{ + // Docs are wrong... + switch(auth_mode) { + case 0: + return AUTH_OPEN; // 0 + case 2: + return AUTH_WPA_PSK; // 2? + case 5: + return AUTH_WPA2_PSK; // 5 + case 7: + return AUTH_WPA_WPA2_PSK; // 7 + default: + return AUTH_MAX; + } +} + +void StationImpl::eventHandler(EventInfo& info) +{ + switch(info.ev.event_type) { + case CYW43_EV_ESCAN_RESULT: + if(info.self.wifi_scan_state == 1 && info.ev.status == CYW43_STATUS_SUCCESS) { + station.scanCompleted(true); + } + break; + + case CYW43_EV_SET_SSID: + if(info.ev.status == CYW43_STATUS_SUCCESS) { + debug_d("[WiFi] Linked with '%s'", String((const char*)info.ev.data, info.ev.datalen).c_str()); + } + break; + + case CYW43_EV_DISASSOC_IND: + case CYW43_EV_DEAUTH_IND: + break; + } +} + +void StationImpl::scanCompleted(bool result) +{ + debug_d("scanCompleted(), result %u", result); + scanTimer.stop(); + if(scanCompletedCallback) { + scanCompletedCallback(result, scanResults); + scanCompletedCallback = nullptr; + } + scanResults.clear(); } bool StationImpl::startScan(ScanCompletedDelegate scanCompleted) { - return false; + if(scanCompletedCallback) { + debug_e("[STA] Scan in progress"); + return false; + } + + int link_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA); + switch(link_status) { + case CYW43_LINK_JOIN: + case CYW43_LINK_NOIP: + debug_e("[STA] Invalid WiFi state for scan"); + return false; + } + + scanResults.clear(); + scanCompletedCallback = scanCompleted; + if(!scanCompleted) { + return false; + } + + auto scan_result = [](void* env, const cyw43_ev_scan_result_t* result) -> int { + if(!result || !station.scanCompletedCallback) { + return 0; + } + + MacAddress bssid{result->bssid}; + for(auto& r : scanResults) { + if(r.bssid == bssid) { + return 0; // Already got + } + } + + auto r = new BssInfo{ + .bssid = bssid, + .authorization = translateAuthMode(result->auth_mode), + .channel = uint8_t(result->channel), + .rssi = result->rssi, + }; + if(result->ssid_len == 0 || result->ssid[0] == 0) { + r->hidden = true; + } else { + r->ssid.setString(reinterpret_cast(result->ssid), result->ssid_len); + } + scanResults.addElement(r); + return 0; + }; + + cyw43_wifi_scan_options_t scan_options{}; + int err = cyw43_wifi_scan(&cyw43_state, &scan_options, nullptr, scan_result); + if(err != 0) { + debug_e("startScan failed %d", err); + return false; + } + + scanTimer.initializeMs([]() { station.scanCompleted(false); }); + scanTimer.startOnce(); + + return true; } void StationImpl::onSystemReady() @@ -164,3 +359,5 @@ void StationImpl::wpsConfigStop() } #endif // ENABLE_WPS + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h index d886a2ea46..7ea4b4305f 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * StationImpl.h - Esp8266 WiFi Station + * StationImpl.h * ****/ @@ -12,6 +12,13 @@ #include #include +#include +#include +#include + +namespace SmingInternal::Network +{ +struct EventInfo; class StationImpl : public StationClass, protected ISystemReadyHandler { @@ -55,6 +62,22 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void wpsConfigStop() override; #endif + void eventHandler(EventInfo& info); + protected: void onSystemReady() override; + +private: + bool internalConnect(); + void scanCompleted(bool result); + + static BssList scanResults; + static SimpleTimer scanTimer; + Config cfg{}; + CString hostname; + bool enabled{false}; }; + +extern StationImpl station; + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h index 7ff39dc230..c515038784 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationListImpl.h @@ -17,20 +17,25 @@ class StationListImpl : public StationList public: StationListImpl() { - add(new Info{}); + int num_sta{0}; + MacAddress maclist[16]; + cyw43_wifi_ap_get_stas(&cyw43_state, &num_sta, &maclist[0][0]); + for(int i = 0; i < num_sta; ++i) { + add(new Info{maclist[i]}); + } } private: class Info : public StationInfo { public: - Info() + Info(MacAddress mac) : macaddr(mac) { } MacAddress mac() const override { - return MacAddress{}; + return this->macaddr; } int8_t rssi() const override @@ -42,5 +47,8 @@ class StationListImpl : public StationList { return IpAddress{}; } + + private: + MacAddress macaddr; }; }; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp index cfe7636320..5214a702f1 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp +++ b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.cpp @@ -5,17 +5,203 @@ * All files of the Sming Core are provided under the LGPL v3 license. * * WifiEventsImpl.cpp - * - * Created on: 19 февр. 2016 г. - * Author: shurik */ #include "WifiEventsImpl.h" -#include +#include "StationImpl.h" +#include "AccessPointImpl.h" +#include "whd.h" + +#include + +WifiEventsClass& WifiEvents{SmingInternal::Network::events}; + +// #define WIFI_DEBUG_PROBE +// #define WIFI_DEBUG_SCAN + +namespace +{ +// Information Elements +void print_eid(const uint8_t* data, size_t datalen) +{ +#ifdef ENABLE_WIFI_DEBUG + for(unsigned i = 0; i < datalen;) { + auto id = data[i++]; + auto len = data[i++]; + m_printHex(String(id).padLeft(3).c_str(), &data[i], len); + i += len; + } +#endif +} -static WifiEventsImpl events; -WifiEventsClass& WifiEvents = events; +} // namespace + +namespace SmingInternal::Network +{ +WifiEventsImpl events; WifiEventsImpl::WifiEventsImpl() { } + +void WifiEventsImpl::stationChanged(struct netif* netif) +{ + const ip_addr_t* ip = netif_ip_addr4(netif); + const ip_addr_t* netmask = netif_ip_netmask4(netif); + const ip_addr_t* gw = netif_ip_gw4(netif); + + debug_i("Got ip %s\n", ip4addr_ntoa(ip)); + + if(onSTAGotIP) { + if(ip && gw && netmask) { + onSTAGotIP(*ip, *gw, *netmask); + } + } +} + +/* + flags event_type status reason interface + 0000 ASSOC_REQ_IE 0 0 0 + 0000 AUTH 0 0 0 + 0000 ASSOC_RESP_IE 0 0 0 + 0000 ASSOC 0 0 0 + 0001 LINK 0 0 0 + 0000 PSK_SUP 6 0 0 + 0000 JOIN 0 0 0 + 0000 SET_SSID 0 0 0 +*/ +void WifiEventsImpl::eventHandler(EventInfo& info) +{ +#ifdef ENABLE_WIFI_DEBUG + bool debug{true}; + +#ifndef WIFI_DEBUG_PROBE + debug &= (info.ev.event_type != CYW43_EV_PROBREQ_MSG); + debug &= (info.ev.event_type != CYW43_EV_P2P_PROBREQ_MSG); +#endif + +#ifndef WIFI_DEBUG_SCAN + debug &= (info.ev.event_type != CYW43_EV_ESCAN_RESULT); +#endif + + if(debug) { + debug_i("EV.version = 0x%04x", __builtin_bswap16(info.ev.version)); + debug_i("EV.flags = %u", info.ev.flags); + debug_i("EV.event_type = %u", info.ev.event_type); + debug_i("EV.status = %u", info.ev.status); + debug_i("EV.reason = %u", info.ev.reason); + debug_i("EV.auth_type = %u", info.ev.auth_type); + debug_i("EV.datalen = %u", info.ev.datalen); + debug_i("EV.addr = %s", MacAddress(info.ev.addr).toString().c_str()); + debug_i("EV.ifname = %s", String(info.ev.ifname, 16).c_str()); + debug_i("EV.ifidx = %u", info.ev.ifidx); + debug_i("EV.bsscfgidx = %u", info.ev.bsscfgidx); + // debug_hex(INFO, "DATA", info.ev.data, info.ev.datalen); + } +#endif + + unsigned off{0}; + int rssi{0}; + MacAddress addr(info.ev.addr); + + switch(info.ev.event_type) { + case CYW43_EV_SET_SSID: +#ifdef ENABLE_WIFI_DEBUG + debug_hex(INFO, "SSID", info.ev.data, info.ev.datalen); +#endif + break; + + case CYW43_EV_LINK: + if(info.ev.status == CYW43_STATUS_SUCCESS && info.ev.ifidx == CYW43_ITF_STA) { + auto callback = [](struct netif* netif) -> void { events.stationChanged(netif); }; + netif_set_status_callback(&cyw43_state.netif[CYW43_ITF_STA], callback); + if(onSTAConnect) { + System.queueCallback([addr]() { + if(events.onSTAConnect) { + events.onSTAConnect(station.getSSID(), addr, station.getChannel()); + } + }); + } + } + break; + + case CYW43_EV_DISASSOC_IND: + if(info.ev.ifidx == CYW43_ITF_STA && onSTADisconnect) { + String ssid = WifiStation.getSSID(); + auto reason = WifiDisconnectReason(info.ev.reason); + System.queueCallback([ssid, addr, reason]() { + if(events.onSTADisconnect) { + events.onSTADisconnect(ssid, addr, reason); + } + }); + } + break; + + case CYW43_EV_ASSOC_IND: + print_eid(info.ev.data, info.ev.datalen); + if(info.ev.ifidx == CYW43_ITF_AP && onSOFTAPConnect) { + System.queueCallback([addr]() { + if(events.onSOFTAPConnect) { + unsigned aid{0}; + events.onSOFTAPConnect(addr, aid); + } + }); + } + break; + + case CYW43_EV_DEAUTH_IND: + if(info.ev.ifidx == CYW43_ITF_AP) { + if(info.ev.reason == CYW43_REASON_DISASSOC && onSOFTAPDisconnect) { + System.queueCallback([addr]() { + if(events.onSOFTAPDisconnect) { + unsigned aid{0}; + events.onSOFTAPDisconnect(addr, aid); + } + }); + } + } else if(info.ev.ifidx == CYW43_ITF_STA) { + if(onSTADisconnect) { + String ssid = WifiStation.getSSID(); + System.queueCallback([ssid, addr]() { + if(events.onSTADisconnect) { + events.onSTADisconnect(ssid, addr, WIFI_DISCONNECT_REASON_AUTH_FAIL); + } + }); + } + } + break; + + case CYW43_EV_P2P_PROBREQ_MSG: { + auto rxm = reinterpret_cast(info.ev.data); + off = sizeof(*rxm); +#ifdef WIFI_DEBUG_PROBE + debug_i("[PB] ver %u, channel 0x%04x, rssi %d, mactime 0x%08x, rate 0x%08x", __builtin_bswap16(rxm->version), + __builtin_bswap16(rxm->channel), __builtin_bswap32(rxm->rssi), __builtin_bswap32(rxm->mactime), + __builtin_bswap32(rxm->rate)); +#endif + rssi = rxm->rssi; + [[fallthrough]]; + } + + case CYW43_EV_PROBREQ_MSG: { + auto m = reinterpret_cast(&info.ev.data[off]); +#ifdef WIFI_DEBUG_PROBE + debug_i("[PB] fc 0x%04x, dur 0x%04x, da %s, sa %s, bssid %s, seq 0x%04x", m->frame_control, m->duration, + MacAddress(m->da).toString().c_str(), MacAddress(m->sa).toString().c_str(), + MacAddress(m->bssid).toString().c_str(), m->seq_ctrl); + off += 24; + print_eid(&msg->data[off], datalen - off); +#endif + if(onSOFTAPProbeReqRecved) { + System.queueCallback([rssi, addr]() { + if(events.onSOFTAPProbeReqRecved) { + events.onSOFTAPProbeReqRecved(rssi, addr); + } + }); + } + break; + } + } +} + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h index 2d13fa756d..5c810091ca 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h +++ b/Sming/Components/Network/Arch/Rp2040/Platform/WifiEventsImpl.h @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * WifiEventsImpl.h - Esp8266 WiFi events + * WifiEventsImpl.h * ****/ @@ -12,6 +12,28 @@ #include #include +#include + +namespace SmingInternal::Network +{ +struct whd_event_msg { + uint16_t version; + uint16_t flags; /* see flags below */ + uint32_t event_type; /* Message (see below) */ + uint32_t status; /* Status code (see below) */ + uint32_t reason; /* Reason code (if applicable) */ + uint32_t auth_type; /* WLC_E_AUTH */ + uint32_t datalen; /* data buf */ + uint8_t addr[6]; /* Station address (if applicable) */ + char ifname[16]; /* name of the packet incoming interface */ + uint8_t ifidx; /* destination OS i/f index */ + uint8_t bsscfgidx; /* source bsscfg index */ + uint8_t data[]; +}; +struct EventInfo { + cyw43_t& self; + const struct whd_event_msg& ev; +}; class WifiEventsImpl : public WifiEventsClass { @@ -20,4 +42,12 @@ class WifiEventsImpl : public WifiEventsClass public: WifiEventsImpl(); + + void stationChanged(struct netif* netif); + + void eventHandler(EventInfo& info); }; + +extern WifiEventsImpl events; + +} // namespace SmingInternal::Network diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.c b/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.c new file mode 100644 index 0000000000..01c6bf3e24 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.c @@ -0,0 +1,301 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// For DHCP specs see: +// https://www.ietf.org/rfc/rfc2131.txt +// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions + +#include +#include +#include + +#include "cyw43_config.h" +#include "dhcpserver.h" +#include "lwip/udp.h" + +#define DHCPDISCOVER (1) +#define DHCPOFFER (2) +#define DHCPREQUEST (3) +#define DHCPDECLINE (4) +#define DHCPACK (5) +#define DHCPNACK (6) +#define DHCPRELEASE (7) +#define DHCPINFORM (8) + +#define DHCP_OPT_PAD (0) +#define DHCP_OPT_SUBNET_MASK (1) +#define DHCP_OPT_ROUTER (3) +#define DHCP_OPT_DNS (6) +#define DHCP_OPT_HOST_NAME (12) +#define DHCP_OPT_REQUESTED_IP (50) +#define DHCP_OPT_IP_LEASE_TIME (51) +#define DHCP_OPT_MSG_TYPE (53) +#define DHCP_OPT_SERVER_ID (54) +#define DHCP_OPT_PARAM_REQUEST_LIST (55) +#define DHCP_OPT_MAX_MSG_SIZE (57) +#define DHCP_OPT_VENDOR_CLASS_ID (60) +#define DHCP_OPT_CLIENT_ID (61) +#define DHCP_OPT_END (255) + +#define PORT_DHCP_SERVER (67) +#define PORT_DHCP_CLIENT (68) + +#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8) +#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds + +#define MAC_LEN (6) +#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +typedef struct { + uint8_t op; // message opcode + uint8_t yiaddr[4]; // your IP address + uint8_t chaddr[16]; // client hardware address + uint8_t options[312]; // optional parameters, variable, starts with magic +} dhcp_msg_t; + +static int dhcp_socket_new_dgram(struct udp_pcb** udp, void* cb_data, udp_recv_fn cb_udp_recv) +{ + // family is AF_INET + // type is SOCK_DGRAM + + *udp = udp_new(); + if(*udp == NULL) { + return -ENOMEM; + } + + // Register callback + udp_recv(*udp, cb_udp_recv, (void*)cb_data); + + return 0; // success +} + +static void dhcp_socket_free(struct udp_pcb** udp) +{ + if(*udp != NULL) { + udp_remove(*udp); + *udp = NULL; + } +} + +static int dhcp_socket_bind(struct udp_pcb** udp, uint32_t ip, uint16_t port) +{ + ip_addr_t addr; + IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + // TODO convert lwIP errors to errno + return udp_bind(*udp, &addr, port); +} + +static int dhcp_socket_sendto(struct udp_pcb** udp, const void* buf, size_t len, uint32_t ip, uint16_t port) +{ + if(len > 0xffff) { + len = 0xffff; + } + + struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if(p == NULL) { + return -ENOMEM; + } + + memcpy(p->payload, buf, len); + + ip_addr_t dest; + IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + err_t err = udp_sendto(*udp, p, &dest, port); + + pbuf_free(p); + + if(err != ERR_OK) { + return err; + } + + return len; +} + +static uint8_t* opt_find(uint8_t* opt, uint8_t cmd) +{ + for(int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { + if(opt[i] == cmd) { + return &opt[i]; + } + i += 2 + opt[i + 1]; + } + return NULL; +} + +static void opt_write_n(uint8_t** opt, uint8_t cmd, size_t n, void* data) +{ + uint8_t* o = *opt; + *o++ = cmd; + *o++ = n; + memcpy(o, data, n); + *opt = o + n; +} + +static void opt_write_u8(uint8_t** opt, uint8_t cmd, uint8_t val) +{ + uint8_t* o = *opt; + *o++ = cmd; + *o++ = 1; + *o++ = val; + *opt = o; +} + +static void opt_write_u32(uint8_t** opt, uint8_t cmd, uint32_t val) +{ + uint8_t* o = *opt; + *o++ = cmd; + *o++ = 4; + *o++ = val >> 24; + *o++ = val >> 16; + *o++ = val >> 8; + *o++ = val; + *opt = o; +} + +static void dhcp_server_process(void* arg, struct udp_pcb* upcb, struct pbuf* p, const ip_addr_t* src_addr, + u16_t src_port) +{ + dhcp_server_t* d = arg; + (void)upcb; + (void)src_addr; + (void)src_port; + + // This is around 548 bytes + dhcp_msg_t dhcp_msg; + +#define DHCP_MIN_SIZE (240 + 3) + if(p->tot_len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0); + if(len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + dhcp_msg.op = DHCPOFFER; + memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4); + + uint8_t* opt = (uint8_t*)&dhcp_msg.options; + opt += 4; // assume magic cookie: 99, 130, 83, 99 + + switch(opt[2]) { + case DHCPDISCOVER: { + int yi = DHCPS_MAX_IP; + for(int i = 0; i < DHCPS_MAX_IP; ++i) { + if(memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, use this IP address + yi = i; + break; + } + if(yi == DHCPS_MAX_IP) { + // Look for a free IP address + if(memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP available + yi = i; + } + uint32_t expiry = d->lease[i].expiry << 16 | 0xffff; + if((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) { + // IP expired, reuse it + memset(d->lease[i].mac, 0, MAC_LEN); + yi = i; + } + } + } + if(yi == DHCPS_MAX_IP) { + // No more IP addresses left + goto ignore_request; + } + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER); + break; + } + + case DHCPREQUEST: { + uint8_t* o = opt_find(opt, DHCP_OPT_REQUESTED_IP); + if(o == NULL) { + // Should be NACK + goto ignore_request; + } + if(memcmp(o + 2, &d->ip.addr, 3) != 0) { + // Should be NACK + goto ignore_request; + } + uint8_t yi = o[5] - DHCPS_BASE_IP; + if(yi >= DHCPS_MAX_IP) { + // Should be NACK + goto ignore_request; + } + if(memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, ok to use this IP address + } else if(memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP unused, ok to use this IP address + memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN); + } else { + // IP already in use + // Should be NACK + goto ignore_request; + } + d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16; + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK); + printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n", dhcp_msg.chaddr[0], + dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5], + dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]); + break; + } + + default: + goto ignore_request; + } + + opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr); + opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr); + opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have multiple addresses + opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses + opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); + *opt++ = DHCP_OPT_END; + dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t*)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT); + +ignore_request: + pbuf_free(p); +} + +void dhcp_server_init(dhcp_server_t* d, ip_addr_t* ip, ip_addr_t* nm) +{ + ip_addr_copy(d->ip, *ip); + ip_addr_copy(d->nm, *nm); + memset(d->lease, 0, sizeof(d->lease)); + if(dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { + return; + } + dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER); +} + +void dhcp_server_deinit(dhcp_server_t* d) +{ + dhcp_socket_free(&d->udp); +} diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.h b/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.h new file mode 100644 index 0000000000..1fc9963088 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/dhcpserver.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwip/ip_addr.h" + +#define DHCPS_BASE_IP (16) +#define DHCPS_MAX_IP (8) + +typedef struct _dhcp_server_lease_t { + uint8_t mac[6]; + uint16_t expiry; +} dhcp_server_lease_t; + +typedef struct _dhcp_server_t { + ip_addr_t ip; + ip_addr_t nm; + dhcp_server_lease_t lease[DHCPS_MAX_IP]; + struct udp_pcb* udp; +} dhcp_server_t; + +void dhcp_server_init(dhcp_server_t* d, ip_addr_t* ip, ip_addr_t* nm); +void dhcp_server_deinit(dhcp_server_t* d); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/init.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/init.cpp new file mode 100644 index 0000000000..1530928f30 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/init.cpp @@ -0,0 +1,67 @@ +/**** + * 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. + * + * init.cpp + */ + +#include "StationImpl.h" +#include "AccessPointImpl.h" +#include "WifiEventsImpl.h" +#include +#include + +#ifdef DISABLE_WIFI + +void rp2040_network_initialise() +{ +} + +void rp2040_network_service() +{ +} + +#else + +// Called from startup +void rp2040_network_initialise() +{ + int err = cyw43_arch_init(); + if(err != 0) { + return; + } + +#ifdef ENABLE_WIFI_DEBUG + cyw43_state.trace_flags = 0xff; +#endif +} + +void rp2040_network_service() +{ + cyw43_arch_poll(); +} + +extern "C" void __wrap_cyw43_cb_process_async_event(cyw43_t* self, const cyw43_async_event_t* ev) +{ + using namespace SmingInternal::Network; + + auto& msg = *reinterpret_cast(ev); + const_cast(msg).datalen = __builtin_bswap32(msg.datalen); + + EventInfo info{*self, msg}; + if(msg.ifidx == CYW43_ITF_STA) { + station.eventHandler(info); + } else if(msg.ifidx == CYW43_ITF_AP) { + accessPoint.eventHandler(info); + } + events.eventHandler(info); + + const_cast(msg).datalen = __builtin_bswap32(msg.datalen); + + extern void __real_cyw43_cb_process_async_event(void*, const void*); + __real_cyw43_cb_process_async_event(self, ev); +} + +#endif diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/whd.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/whd.cpp new file mode 100644 index 0000000000..3da1cd3585 --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/whd.cpp @@ -0,0 +1,33 @@ +/**** + * 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. + * + * whd.cpp + * + ****/ + +#include "whd.h" +#include + +String whd_get_ssid(int itf) +{ + wlc_ssid_t ssid; + int err = cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_SSID, sizeof(ssid), reinterpret_cast(&ssid), itf); + return err ? nullptr : String(reinterpret_cast(ssid.SSID), ssid.SSID_len); +} + +MacAddress whd_get_bssid(int itf) +{ + MacAddress addr; + cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_BSSID, sizeof(addr), &addr[0], itf); + return addr; +} + +uint8_t whd_get_channel(int itf) +{ + channel_info_t info{}; + cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_CHANNEL, sizeof(info), reinterpret_cast(&info), itf); + return info.hw_channel; +} diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/whd.h b/Sming/Components/Network/Arch/Rp2040/Platform/whd.h new file mode 100644 index 0000000000..5b4ca3df9f --- /dev/null +++ b/Sming/Components/Network/Arch/Rp2040/Platform/whd.h @@ -0,0 +1,100 @@ +/**** + * 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. + * + * whd.h - Infineon WiFi Host Driver definitions + * + * See https://github.com/infineon/wifi-host-driver + * + ****/ + +#pragma once + +#include +#include + +#ifndef CYW43_IOCTL_GET_BSSID +#define CYW43_IOCTL_GET_BSSID 0x2E +#endif + +struct wlc_ssid_t { + uint32_t SSID_len; + uint8_t SSID[32]; +}; + +struct channel_info_t { + int32_t hw_channel; + int32_t target_channel; + int32_t scan_channel; +}; + +using whd_mac_t = MacAddress::Octets; + +struct wl_rx_mgmt_data_t { + uint16_t version; + uint16_t channel; + int32_t rssi; + uint32_t mactime; + uint32_t rate; +}; + +// From linux kernel hostap_80211.h +struct hostap_ieee80211_mgmt_t { + uint16_t frame_control; + uint16_t duration; + whd_mac_t da[6]; + whd_mac_t sa[6]; + whd_mac_t bssid[6]; + uint16_t seq_ctrl; + union { + struct { + uint16_t auth_alg; + uint16_t auth_transaction; + uint16_t status_code; + /* possibly followed by Challenge text */ + uint8_t variable[0]; + } __packed auth; + struct { + uint16_t reason_code; + } __packed deauth; + struct { + uint16_t capab_info; + uint16_t listen_interval; + /* followed by SSID and Supported rates */ + uint8_t variable[0]; + } __packed assoc_req; + struct { + uint16_t capab_info; + uint16_t status_code; + uint16_t aid; + /* followed by Supported rates */ + uint8_t variable[0]; + } __packed assoc_resp, reassoc_resp; + struct { + uint16_t capab_info; + uint16_t listen_interval; + whd_mac_t current_ap[6]; + /* followed by SSID and Supported rates */ + uint8_t variable[0]; + } __packed reassoc_req; + struct { + uint16_t reason_code; + } __packed disassoc; + struct { + } __packed probe_req; + struct { + uint8_t timestamp[8]; + uint16_t beacon_int; + uint16_t capab_info; + /* followed by some of SSID, Supported rates, + * FH Params, DS Params, CF Params, IBSS Params, TIM */ + uint8_t variable[0]; + } __packed beacon, probe_resp; + } u; +} __packed; + +String whd_get_ssid(int itf); +MacAddress whd_get_bssid(int itf); +uint8_t whd_get_channel(int itf); diff --git a/Sming/Components/Network/README.rst b/Sming/Components/Network/README.rst index 00a41b8857..e9192ec3ed 100644 --- a/Sming/Components/Network/README.rst +++ b/Sming/Components/Network/README.rst @@ -17,3 +17,15 @@ Other networking libraries: - :component:`ssl` - :library:`UPnP` - :library:`UPnP-Schema` + + +Configuration variables +----------------------- + +.. envvar:: ENABLE_WIFI_DEBUG + + default: 0 (disabled) + + *RP2040 only* + + Set to 1 to enable additional debugging output for processing WiFi events. diff --git a/Sming/Components/Network/component.mk b/Sming/Components/Network/component.mk index 893ea752f2..1bcda900fb 100644 --- a/Sming/Components/Network/component.mk +++ b/Sming/Components/Network/component.mk @@ -71,7 +71,25 @@ COMPONENT_DEPENDS += \ else ifeq ($(SMING_ARCH),Rp2040) -COMPONENT_DEPENDS += \ - lwip +COMPONENT_RELINK_VARS += DISABLE_WIFI PICO_DEBUG ENABLE_WIFI_DEBUG +ifeq ($(PICO_DEBUG),1) +COMPONENT_CPPFLAGS += -DPICO_DEBUG=1 +endif +ifeq ($(ENABLE_WIFI_DEBUG),1) +COMPONENT_CPPFLAGS += -DENABLE_WIFI_DEBUG=1 +endif + +PICO_SDK_PATH := $(ARCH_COMPONENTS)/rp2040/pico-sdk + +COMPONENT_INCDIRS += \ + $(ARCH_COMPONENTS)/rp2040/sdk + +ifneq ($(DISABLE_NETWORK),1) +COMPONENT_INCDIRS += \ + $(PICO_SDK_PATH)/lib/cyw43-driver \ + $(PICO_SDK_PATH)/lib/cyw43-driver/src \ + $(PICO_SDK_PATH)/lib/lwip/src/include \ + $(PICO_SDK_PATH)/src/rp2_common/pico_lwip/include +endif endif diff --git a/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.h b/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.h index fc6ddb6105..4c3224f853 100644 --- a/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.h +++ b/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.h @@ -18,7 +18,7 @@ #include "WString.h" /** - * @brief Class associated with an open websocket to handle communcations + * @brief Class associated with an open websocket to handle communications * @ingroup http */ class WebsocketResource : public HttpResource diff --git a/Sming/Components/Network/src/Network/NtpClient.cpp b/Sming/Components/Network/src/Network/NtpClient.cpp index ec75165867..e6d7b7dc6f 100644 --- a/Sming/Components/Network/src/Network/NtpClient.cpp +++ b/Sming/Components/Network/src/Network/NtpClient.cpp @@ -63,7 +63,7 @@ void NtpClient::requestTime() // an ip address in dotted decimal form or if the host is found in dns cache. // however I'm not sure if the dns cache is working since this never seems to // be called for a host lookup other than an ip address. - // Doesn't really matter since the loockup will be fast anyways, the host + // Doesn't really matter since the lookup will be fast anyways, the host // is most likely found in the dns cache of the next node the query is sent to. internalRequestTime(resolvedIp); break; diff --git a/Sming/Components/Storage/Tools/hwconfig/storage.py b/Sming/Components/Storage/Tools/hwconfig/storage.py index 410e51486b..785a25de9b 100644 --- a/Sming/Components/Storage/Tools/hwconfig/storage.py +++ b/Sming/Components/Storage/Tools/hwconfig/storage.py @@ -84,7 +84,8 @@ def parse_dict(self, data): elif k == 'mode': self.mode = v elif k == 'speed': - self.speed = v + SMING_SOC = os.environ['SMING_SOC'] + self.speed = eval(str(v)) else: raise InputError("Unknown storage field '%s'" % k) diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index 13b96ee8f1..eb711a1054 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -112,7 +112,7 @@ endif .PHONY: hwconfig-list hwconfig-list: ##List available hardware configurations - @echo "Available configurations: $(foreach c,$(ALL_HWCONFIG),\n $(if $(subst $c,,$(HWCONFIG)), ,*) $(shell printf "%-25s" "$c") $(filter %/$c.hw,$(ALL_HWCONFIG_PATHS)))" + @printf "Available configurations: $(foreach c,$(ALL_HWCONFIG),\n $(if $(subst $c,,$(HWCONFIG)), ,*) $(shell printf "%-25s" "$c") $(filter %/$c.hw,$(ALL_HWCONFIG_PATHS)))" @echo .PHONY: hwconfig-options diff --git a/Sming/Components/Storage/src/include/Storage/Iterator.h b/Sming/Components/Storage/src/include/Storage/Iterator.h index c17662693c..eef88b9501 100644 --- a/Sming/Components/Storage/src/include/Storage/Iterator.h +++ b/Sming/Components/Storage/src/include/Storage/Iterator.h @@ -15,9 +15,15 @@ namespace Storage { class Device; -class Iterator : public std::iterator +class Iterator { public: + using iterator_category = std::forward_iterator_tag; + using value_type = Partition; + using difference_type = std::ptrdiff_t; + using pointer = Partition*; + using reference = Partition&; + Iterator(Device& device) : mSearch{&device, Partition::Type::any, Partition::SubType::any}, mDevice(&device) { next(); diff --git a/Sming/Components/Storage/src/include/Storage/Types.h b/Sming/Components/Storage/src/include/Storage/Types.h index 846ce55b59..a66ab0c9a3 100644 --- a/Sming/Components/Storage/src/include/Storage/Types.h +++ b/Sming/Components/Storage/src/include/Storage/Types.h @@ -10,6 +10,8 @@ #pragma once #include +#include +#include #ifdef ENABLE_STORAGE_SIZE64 using storage_size_t = uint64_t; diff --git a/Sming/Components/esptool/esptool b/Sming/Components/esptool/esptool index c04d0f42db..b1fce755be 160000 --- a/Sming/Components/esptool/esptool +++ b/Sming/Components/esptool/esptool @@ -1 +1 @@ -Subproject commit c04d0f42db9e85b73171a2030bc2e9842ec476ac +Subproject commit b1fce755be2f2c66161e309649aefa4b21604de9 diff --git a/Sming/Components/lwip/lwipopts.h b/Sming/Components/lwip/lwipopts.h index f700e25a03..1aead91e35 100644 --- a/Sming/Components/lwip/lwipopts.h +++ b/Sming/Components/lwip/lwipopts.h @@ -109,7 +109,7 @@ #define MEMP_NUM_UDP_PCB 4 /** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_PCB 4 diff --git a/Sming/Components/lwip/src/Arch/Host/arch.mk b/Sming/Components/lwip/src/Arch/Host/arch.mk index 5f0080a0a4..06334b16f2 100644 --- a/Sming/Components/lwip/src/Arch/Host/arch.mk +++ b/Sming/Components/lwip/src/Arch/Host/arch.mk @@ -20,7 +20,7 @@ $(NPCAP_SRCDIR)/.ok: mkdir -p $(@D) && \ cd $(@D) && \ powershell -Command "Set-Variable ProgressPreference SilentlyContinue; \ - Invoke-WebRequest https://nmap.org/npcap/dist/$(PCAP_SRC) -OutFile $(PCAP_SRC); \ + Invoke-WebRequest https://npcap.com/dist/$(PCAP_SRC) -OutFile $(PCAP_SRC); \ Expand-Archive $(PCAP_SRC) ." && \ $(call ApplyPatch,$(LWIP_ARCH_SRCDIR)/npcap.patch) && \ touch $@ diff --git a/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt b/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt deleted file mode 100644 index f8b25ad0fd..0000000000 --- a/Sming/Components/lwip/src/Arch/Rp2040/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -cmake_minimum_required(VERSION 3.12) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_BUILD_TYPE RelWithDebInfo) - -set(DCMAKE_C_COMPILER $ENV{CC}) -set(CMAKE_C_COMPILER_FORCED TRUE) - -project(lwip C) - -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") -include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) - -set (LWIP_INCLUDE_DIRS - "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${LWIP_DIR}/.." - "${LWIP_DIR}/src/include" - "${CMAKE_CURRENT_SOURCE_DIR}/" -) - -include(${LWIP_DIR}/src/Filelists.cmake) - -add_library(lwip - sys.c - ${LWIP_DIR}/src/api/err.c - ${lwipcore_SRCS} - ${lwipcore4_SRCS} - ${lwipcore6_SRCS} - ${lwipnetif_SRCS} -) - -set_target_properties(lwip - PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} OUTPUT_NAME "${LWIP_LIBNAME}" -) - -target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) -target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/Sming/Components/lwip/src/Arch/Rp2040/arch.mk b/Sming/Components/lwip/src/Arch/Rp2040/arch.mk deleted file mode 100644 index 7ce92fc25e..0000000000 --- a/Sming/Components/lwip/src/Arch/Rp2040/arch.mk +++ /dev/null @@ -1,3 +0,0 @@ -# -# Rp2040 lwip -# diff --git a/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h b/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h deleted file mode 100644 index 55b39cc36f..0000000000 --- a/Sming/Components/lwip/src/Arch/Rp2040/include/arch/cc.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2001-2003 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __CC_H__ -#define __CC_H__ - -#include - -typedef int sys_prot_t; - -/* define compiler specific symbols */ -#if defined(__ICCARM__) - -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_STRUCT -#define PACK_STRUCT_END -#define PACK_STRUCT_FIELD(x) x -#define PACK_STRUCT_USE_INCLUDES - -#elif defined(__CC_ARM) - -#define PACK_STRUCT_BEGIN __packed -#define PACK_STRUCT_STRUCT -#define PACK_STRUCT_END -#define PACK_STRUCT_FIELD(x) x - -#elif defined(__GNUC__) - -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_STRUCT __attribute__((__packed__)) -#define PACK_STRUCT_END -#define PACK_STRUCT_FIELD(x) x - -#elif defined(__TASKING__) - -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_STRUCT -#define PACK_STRUCT_END -#define PACK_STRUCT_FIELD(x) x - -#endif - -#define LWIP_PLATFORM_ASSERT(x) \ - do { \ - if(!(x)) \ - while(1) \ - ; \ - } while(0) - -#ifdef __cplusplus -extern "C" { -#endif - -// Sming -uint32_t os_random(void); -#define LWIP_RAND() os_random() - -#ifdef __cplusplus -} -#endif - -#endif /* __CC_H__ */ diff --git a/Sming/Components/lwip/src/Arch/Rp2040/sys.c b/Sming/Components/lwip/src/Arch/Rp2040/sys.c deleted file mode 100644 index 2b69358e9e..0000000000 --- a/Sming/Components/lwip/src/Arch/Rp2040/sys.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -/* lwip has provision for using a mutex, when applicable */ -sys_prot_t sys_arch_protect(void) -{ - return 0; -} - -void sys_arch_unprotect(sys_prot_t pval) -{ - (void)pval; -} - -/* lwip needs a millisecond time source */ -uint32_t sys_now(void) -{ - extern uint32_t millis(void); - return millis(); -} diff --git a/Sming/Components/rboot/include/Network/RbootHttpUpdater.h b/Sming/Components/rboot/include/Network/RbootHttpUpdater.h index 3816d914b7..c17ba2db7b 100644 --- a/Sming/Components/rboot/include/Network/RbootHttpUpdater.h +++ b/Sming/Components/rboot/include/Network/RbootHttpUpdater.h @@ -33,25 +33,21 @@ class RbootHttpUpdater : protected HttpClient struct Item { String url; uint32_t targetOffset; - size_t size; // << max allowed size - RbootOutputStream* stream{nullptr}; // (optional) output stream to use. + size_t size; // << max allowed size + std::unique_ptr stream; // (optional) output stream to use. Item(String url, uint32_t targetOffset, size_t size, RbootOutputStream* stream) - : url(url), targetOffset(targetOffset), size(size), stream(stream) + : url(url), targetOffset(targetOffset), size(size) { - } - - ~Item() - { - delete stream; + this->stream.reset(stream); } RbootOutputStream* getStream() { - if(stream == nullptr) { - stream = new RbootOutputStream(targetOffset, size); + if(!stream) { + stream.reset(new RbootOutputStream(targetOffset, size)); } - return stream; + return stream.get(); } }; diff --git a/Sming/Components/ssl/Axtls/AxConnection.h b/Sming/Components/ssl/Axtls/AxConnection.h index d3cf7ef279..a73b7aedea 100644 --- a/Sming/Components/ssl/Axtls/AxConnection.h +++ b/Sming/Components/ssl/Axtls/AxConnection.h @@ -16,6 +16,7 @@ #include #include "AxCertificate.h" #include "AxError.h" +#include namespace Ssl { @@ -26,7 +27,6 @@ class AxConnection : public Connection ~AxConnection() { - delete certificate; // Typically sends out closing message ssl_free(ssl); } @@ -60,17 +60,16 @@ class AxConnection : public Connection const Certificate* getCertificate() const override { - if(certificate == nullptr && ssl->x509_ctx != nullptr) { - certificate = new AxCertificate(ssl); + if(!certificate && ssl->x509_ctx != nullptr) { + certificate.reset(new AxCertificate(ssl)); } - return certificate; + return certificate.get(); } void freeCertificate() override { - delete certificate; - certificate = nullptr; + certificate.reset(); } int read(InputBuffer& input, uint8_t*& output) override; @@ -93,7 +92,7 @@ class AxConnection : public Connection private: SSL* ssl{nullptr}; - mutable AxCertificate* certificate{nullptr}; + mutable std::unique_ptr certificate; InputBuffer* input{nullptr}; }; diff --git a/Sming/Components/ssl/include/Network/Ssl/Session.h b/Sming/Components/ssl/include/Network/Ssl/Session.h index efb5c01f8b..4f59127eb8 100644 --- a/Sming/Components/ssl/include/Network/Ssl/Session.h +++ b/Sming/Components/ssl/include/Network/Ssl/Session.h @@ -14,6 +14,7 @@ #include "KeyCertPair.h" #include "ValidatorList.h" #include +#include class TcpConnection; @@ -121,7 +122,6 @@ class Session ~Session() { close(); - delete sessionId; } /** @@ -130,7 +130,7 @@ class Session */ const SessionId* getSessionId() const { - return sessionId; + return sessionId.get(); } /** @@ -147,8 +147,8 @@ class Session */ void setConnection(Connection* connection) { - assert(this->connection == nullptr); - this->connection = connection; + assert(!this->connection); + this->connection.reset(connection); } /** @@ -157,7 +157,7 @@ class Session */ Connection* getConnection() { - return connection; + return connection.get(); } /** @@ -223,9 +223,9 @@ class Session void endHandshake(); private: - Context* context = nullptr; - Connection* connection = nullptr; - SessionId* sessionId = nullptr; + std::unique_ptr context; + std::unique_ptr connection; + std::unique_ptr sessionId; CpuFrequency curFreq = CpuFrequency(0); }; diff --git a/Sming/Components/ssl/src/Session.cpp b/Sming/Components/ssl/src/Session.cpp index aed3f1d1a4..c896799ce5 100644 --- a/Sming/Components/ssl/src/Session.cpp +++ b/Sming/Components/ssl/src/Session.cpp @@ -48,10 +48,10 @@ bool Session::onAccept(TcpConnection* client, tcp_pcb* tcp) return false; } - if(context == nullptr) { + if(!context) { assert(factory != nullptr); - context = factory->createContext(*this); - if(context == nullptr) { + context.reset(factory->createContext(*this)); + if(!context) { return false; } @@ -73,14 +73,14 @@ bool Session::onConnect(tcp_pcb* tcp) { debug_d("SSL %p: Starting connection...", this); - assert(connection == nullptr); - assert(context == nullptr); + assert(!connection); + assert(!context); // Client Session - delete context; + context.reset(); assert(factory != nullptr); - context = factory->createContext(*this); - if(context == nullptr) { + context.reset(factory->createContext(*this)); + if(!context) { return false; } @@ -90,7 +90,7 @@ bool Session::onConnect(tcp_pcb* tcp) return false; } - if(sessionId != nullptr && sessionId->isValid()) { + if(sessionId && sessionId->isValid()) { debug_d("-----BEGIN SSL SESSION PARAMETERS-----"); debug_d("SessionId: %s", toString(*sessionId).c_str()); debug_d("------END SSL SESSION PARAMETERS------"); @@ -98,8 +98,8 @@ bool Session::onConnect(tcp_pcb* tcp) beginHandshake(); - connection = context->createClient(tcp); - if(connection == nullptr) { + connection.reset(context->createClient(tcp)); + if(!connection) { endHandshake(); return false; } @@ -134,11 +134,8 @@ void Session::close() { debug_d("SSL %p: closing ...", this); - delete connection; - connection = nullptr; - - delete context; - context = nullptr; + connection.reset(); + context.reset(); hostName = nullptr; maxBufferSize = MaxBufferSize::Default; @@ -146,7 +143,7 @@ void Session::close() int Session::read(InputBuffer& input, uint8_t*& output) { - if(connection == nullptr) { + if(!connection) { debug_w("SSL: no connection"); return -1; } @@ -165,7 +162,7 @@ int Session::read(InputBuffer& input, uint8_t*& output) int Session::write(const uint8_t* data, size_t length) { - if(connection == nullptr) { + if(!connection) { debug_e("!! SSL Session connection is NULL"); return ERR_CONN; } @@ -181,7 +178,7 @@ int Session::write(const uint8_t* data, size_t length) bool Session::validateCertificate() { - if(connection == nullptr) { + if(!connection) { debug_w("SSL: connection not set, assuming cert. is OK"); return true; } @@ -202,8 +199,8 @@ void Session::handshakeComplete(bool success) if(success) { // If requested, take a copy of the session ID for later re-use if(options.sessionResume) { - if(sessionId == nullptr) { - sessionId = new SessionId; + if(!sessionId) { + sessionId.reset(new SessionId); } *sessionId = connection->getSessionId(); } @@ -211,7 +208,7 @@ void Session::handshakeComplete(bool success) debug_w("SSL Handshake failed"); } - if(options.freeKeyCertAfterHandshake && connection != nullptr) { + if(options.freeKeyCertAfterHandshake && connection) { connection->freeCertificate(); } } @@ -235,7 +232,7 @@ size_t Session::printTo(Print& p) const n += p.println(keyCert.getCertificateLength()); n += p.print(_F(" Cert PK Length: ")); n += p.println(keyCert.getKeyLength()); - if(connection != nullptr) { + if(connection) { n += connection->printTo(p); } diff --git a/Sming/Components/uzlib/README.rst b/Sming/Components/uzlib/README.rst new file mode 100644 index 0000000000..8f602baaae --- /dev/null +++ b/Sming/Components/uzlib/README.rst @@ -0,0 +1,4 @@ +uzlib +===== + +Deflate/Zlib-compatible LZ77 compression/decompression library diff --git a/Sming/Components/uzlib/component.mk b/Sming/Components/uzlib/component.mk new file mode 100644 index 0000000000..76648f7a33 --- /dev/null +++ b/Sming/Components/uzlib/component.mk @@ -0,0 +1,3 @@ +COMPONENT_SUBMODULES := uzlib +COMPONENT_INCDIRS := uzlib/src +COMPONENT_SRCDIRS := uzlib/src diff --git a/Sming/Components/uzlib/uzlib b/Sming/Components/uzlib/uzlib new file mode 160000 index 0000000000..6d60d651a4 --- /dev/null +++ b/Sming/Components/uzlib/uzlib @@ -0,0 +1 @@ +Subproject commit 6d60d651a4499a64f2e5b21b4cc08d98cb84b5c1 diff --git a/Sming/Core/CallbackTimer.h b/Sming/Core/CallbackTimer.h index 463b30d1ff..e8ef1989ac 100644 --- a/Sming/Core/CallbackTimer.h +++ b/Sming/Core/CallbackTimer.h @@ -410,7 +410,7 @@ template class CallbackTimer : protected TimerApi bool started = false; ///< Timer is active, or has fired }; -template IRAM_ATTR bool CallbackTimer::start(bool repeating) +template bool CallbackTimer::start(bool repeating) { stop(); if(!callbackSet || !intervalSet) { diff --git a/Sming/Core/Data/LinkedObject.h b/Sming/Core/Data/LinkedObject.h index 14d58d8cd0..7d8b25f781 100644 --- a/Sming/Core/Data/LinkedObject.h +++ b/Sming/Core/Data/LinkedObject.h @@ -61,10 +61,15 @@ class LinkedObject template class LinkedObjectTemplate : public LinkedObject { public: - template - class IteratorTemplate : public std::iterator + template class IteratorTemplate { public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + IteratorTemplate(TPtr x) : mObject(x) { } diff --git a/Sming/Core/Data/ObjectMap.h b/Sming/Core/Data/ObjectMap.h index f3f6839575..af75a16870 100644 --- a/Sming/Core/Data/ObjectMap.h +++ b/Sming/Core/Data/ObjectMap.h @@ -13,6 +13,7 @@ #pragma once #include "WVector.h" +#include /** * @brief Implementation of a HashMap for owned objects, i.e. anything created with new(). @@ -209,8 +210,7 @@ template class ObjectMap { int i = indexOf(key); if(i >= 0) { - delete entries[i].value; - entries[i].value = value; + entries[i].value.reset(value); } else { entries.addElement(new Entry(key, value)); } @@ -225,7 +225,7 @@ template class ObjectMap V* find(const K& key) const { int index = indexOf(key); - return (index < 0) ? nullptr : entries[index].value; + return (index < 0) ? nullptr : entries[index].value.get(); } /** @@ -298,13 +298,12 @@ template class ObjectMap */ V* extractAt(unsigned index) { - V* value = nullptr; + std::unique_ptr value; if(index < entries.count()) { - value = entries[index].value; - entries[index].value = nullptr; + entries[index].value.swap(value); entries.remove(index); } - return value; + return value.release(); } /** @@ -321,15 +320,11 @@ template class ObjectMap */ struct Entry { K key; - V* value = nullptr; + std::unique_ptr value; - Entry(const K& key, V* value) : key(key), value(value) + Entry(const K& key, V* value) : key(key) { - } - - ~Entry() - { - delete value; + this->value.reset(value); } }; diff --git a/Sming/Core/Data/Stream/EndlessMemoryStream.cpp b/Sming/Core/Data/Stream/EndlessMemoryStream.cpp index bf1b83f693..50eb5e7f8a 100644 --- a/Sming/Core/Data/Stream/EndlessMemoryStream.cpp +++ b/Sming/Core/Data/Stream/EndlessMemoryStream.cpp @@ -12,14 +12,13 @@ bool EndlessMemoryStream::seek(int len) { - if(stream == nullptr) { + if(!stream) { return false; } int res = stream->seek(len); if(stream->isFinished()) { - delete stream; - stream = nullptr; + stream.reset(); } return res; @@ -27,8 +26,8 @@ bool EndlessMemoryStream::seek(int len) size_t EndlessMemoryStream::write(const uint8_t* buffer, size_t size) { - if(stream == nullptr) { - stream = new MemoryDataStream(); + if(!stream) { + stream.reset(new MemoryDataStream()); } return stream->write(buffer, size); diff --git a/Sming/Core/Data/Stream/EndlessMemoryStream.h b/Sming/Core/Data/Stream/EndlessMemoryStream.h index 99443673f3..e0c490c382 100644 --- a/Sming/Core/Data/Stream/EndlessMemoryStream.h +++ b/Sming/Core/Data/Stream/EndlessMemoryStream.h @@ -11,6 +11,7 @@ #pragma once #include "MemoryDataStream.h" +#include /** * @brief Memory stream that stores unlimited number of bytes. @@ -24,11 +25,6 @@ class EndlessMemoryStream : public ReadWriteStream { public: - ~EndlessMemoryStream() - { - delete stream; - } - StreamType getStreamType() const override { return eSST_Memory; @@ -54,5 +50,5 @@ class EndlessMemoryStream : public ReadWriteStream } private: - MemoryDataStream* stream = nullptr; + std::unique_ptr stream; }; diff --git a/Sming/Core/Data/Stream/IFS/DirectoryTemplate.h b/Sming/Core/Data/Stream/IFS/DirectoryTemplate.h index 287c70b422..7786233178 100644 --- a/Sming/Core/Data/Stream/IFS/DirectoryTemplate.h +++ b/Sming/Core/Data/Stream/IFS/DirectoryTemplate.h @@ -49,13 +49,9 @@ class DirectoryTemplate : public SectionTemplate #undef XX }; - DirectoryTemplate(IDataSourceStream* source, Directory* dir) : SectionTemplate(source), directory(dir) + DirectoryTemplate(IDataSourceStream* source, Directory* dir) : SectionTemplate(source) { - } - - ~DirectoryTemplate() - { - delete directory; + directory.reset(dir); } Directory& dir() @@ -76,7 +72,7 @@ class DirectoryTemplate : public SectionTemplate String getValue(const char* name) override; private: - Directory* directory; + std::unique_ptr directory; }; } // namespace IFS diff --git a/Sming/Core/Data/StreamTransformer.cpp b/Sming/Core/Data/StreamTransformer.cpp index 81f1ca1f2a..8014cbfd7c 100644 --- a/Sming/Core/Data/StreamTransformer.cpp +++ b/Sming/Core/Data/StreamTransformer.cpp @@ -21,7 +21,7 @@ uint16_t StreamTransformer::readMemoryBlock(char* data, int bufSize) } if(tempStream == nullptr) { - tempStream = new CircularBuffer(NETWORK_SEND_BUFFER_SIZE + 10); + tempStream.reset(new CircularBuffer(NETWORK_SEND_BUFFER_SIZE + 10)); } // Use provided buffer as a temporary store for this operation @@ -41,13 +41,13 @@ void StreamTransformer::fillTempStream(char* buffer, size_t bufSize) } saveState(); - size_t outLength = transform(reinterpret_cast(buffer), chunkSize, result, resultSize); + size_t outLength = transform(reinterpret_cast(buffer), chunkSize, result.get(), resultSize); if(outLength > room) { restoreState(); return; } - auto written = tempStream->write(result, outLength); + auto written = tempStream->write(result.get(), outLength); (void)written; assert(written == outLength); @@ -55,8 +55,8 @@ void StreamTransformer::fillTempStream(char* buffer, size_t bufSize) } if(sourceStream->isFinished()) { - auto outLength = transform(nullptr, 0, result, resultSize); - auto written = tempStream->write(result, outLength); + auto outLength = transform(nullptr, 0, result.get(), resultSize); + auto written = tempStream->write(result.get(), outLength); (void)written; assert(written == outLength); } diff --git a/Sming/Core/Data/StreamTransformer.h b/Sming/Core/Data/StreamTransformer.h index d8f1178660..48050577ee 100644 --- a/Sming/Core/Data/StreamTransformer.h +++ b/Sming/Core/Data/StreamTransformer.h @@ -13,6 +13,7 @@ #pragma once #include "Buffer/CircularBuffer.h" +#include /** * @brief Class that can be used to transform streams of data on the fly @@ -21,15 +22,10 @@ class StreamTransformer : public IDataSourceStream { public: StreamTransformer(IDataSourceStream* stream, size_t resultSize = 256, size_t blockSize = 64) - : sourceStream(stream), result(new uint8_t[resultSize]), resultSize(resultSize), blockSize(blockSize) + : resultSize(resultSize), blockSize(blockSize) { - } - - ~StreamTransformer() - { - delete[] result; - delete tempStream; - delete sourceStream; + sourceStream.reset(stream); + result.reset(new uint8_t[resultSize]); } //Use base class documentation @@ -49,7 +45,7 @@ class StreamTransformer : public IDataSourceStream bool isValid() const { - return sourceStream != nullptr && sourceStream->isValid(); + return sourceStream && sourceStream->isValid(); } uint16_t readMemoryBlock(char* data, int bufSize) override; @@ -60,7 +56,7 @@ class StreamTransformer : public IDataSourceStream String getName() const override { - return (sourceStream == nullptr) ? nullptr : sourceStream->getName(); + return sourceStream ? sourceStream->getName() : String::nullstr; } /** @@ -89,9 +85,9 @@ class StreamTransformer : public IDataSourceStream private: void fillTempStream(char* buffer, size_t bufSize); - IDataSourceStream* sourceStream{nullptr}; - CircularBuffer* tempStream{nullptr}; - uint8_t* result{nullptr}; + std::unique_ptr sourceStream; + std::unique_ptr tempStream; + std::unique_ptr result; size_t resultSize; size_t blockSize; }; diff --git a/Sming/Core/HardwarePWM.h b/Sming/Core/HardwarePWM.h index 78b27476fb..101f692899 100644 --- a/Sming/Core/HardwarePWM.h +++ b/Sming/Core/HardwarePWM.h @@ -122,6 +122,12 @@ class HardwarePWM */ void update(); + /** @brief Get PWM Frequency + * @param pin GPIO to get frequency for + * @retval uint32_t Value of Frequency + */ + uint32_t getFrequency(uint8_t pin); + private: uint8_t channel_count; uint8_t channels[PWM_CHANNEL_NUM_MAX]; diff --git a/Sming/Core/SmingVersion.h b/Sming/Core/SmingVersion.h index 80d5d95189..a8f33c4779 100644 --- a/Sming/Core/SmingVersion.h +++ b/Sming/Core/SmingVersion.h @@ -5,8 +5,8 @@ * */ -#define SMING_MAJOR_VERSION 4 -#define SMING_MINOR_VERSION 7 +#define SMING_MAJOR_VERSION 5 +#define SMING_MINOR_VERSION 0 #define SMING_PATCH_VERSION 0 #define SMING_PRE_RELEASE "" diff --git a/Sming/Core/SystemClock.cpp b/Sming/Core/SystemClock.cpp index a86c157925..e109a3aa43 100644 --- a/Sming/Core/SystemClock.cpp +++ b/Sming/Core/SystemClock.cpp @@ -46,7 +46,7 @@ String SystemClockClass::getSystemTimeString(TimeZone timeType) const bool SystemClockClass::setTimeZoneOffset(int seconds) { - if((unsigned)abs(seconds) < (12 * SECS_PER_HOUR)) { + if((unsigned)abs(seconds) <= (12 * SECS_PER_HOUR)) { timeZoneOffsetSecs = seconds; return true; } diff --git a/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk b/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk index f534f71c7a..e9a9da107c 100644 --- a/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk +++ b/Sming/Libraries/.patches/Adafruit_NeoPixel/component.mk @@ -1 +1 @@ -COMPONENT_SOC := $(filter-out host,$(AVAILABLE_SOCS)) +COMPONENT_SOC := $(filter-out host esp32c2,$(AVAILABLE_SOCS)) diff --git a/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad index 544dc65029..f74c1a521e 160000 --- a/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad +++ b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad @@ -1 +1 @@ -Subproject commit 544dc650296f4a4b9a22995b996458c2c66fa4e5 +Subproject commit f74c1a521e3d27c39099579db603ae477b26a400 diff --git a/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad.patch b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad.patch new file mode 100644 index 0000000000..07a2e489eb --- /dev/null +++ b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad.patch @@ -0,0 +1,14 @@ +diff --git a/BleGamepad.cpp b/BleGamepad.cpp +index 212e6d7..f7fc502 100644 +--- a/BleGamepad.cpp ++++ b/BleGamepad.cpp +@@ -834,8 +834,7 @@ void BleGamepad::release(uint8_t b) + + uint8_t BleGamepad::specialButtonBitPosition(uint8_t b) + { +- if (b >= POSSIBLESPECIALBUTTONS) +- throw std::invalid_argument("Index out of range"); ++ assert(b < POSSIBLESPECIALBUTTONS); + uint8_t bit = 0; + for (int i = 0; i < b; i++) + { diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp index 7e10dbbfd7..6fa4659ec5 100644 --- a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp +++ b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp @@ -16,13 +16,15 @@ void loop() Serial.println("Press buttons 5 and 16. Move all enabled axes to max. Set DPAD (hat 1) to down right."); bleGamepad.press(BUTTON_5); bleGamepad.press(BUTTON_16); - bleGamepad.setAxes(32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, DPAD_DOWN_RIGHT); + bleGamepad.setAxes(32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767); + bleGamepad.setHat1(DPAD_DOWN_RIGHT); // All axes, sliders, hats etc can also be set independently. See the IndividualAxes.ino example delay(500); Serial.println("Release button 5. Move all axes to min. Set DPAD (hat 1) to centred."); bleGamepad.release(BUTTON_5); - bleGamepad.setAxes(-32767, -32767, -32767, -32767, -32767, -32767, -32767, -32767, DPAD_CENTERED); + bleGamepad.setAxes(-32767, -32767, -32767, -32767, -32767, -32767, -32767, -32767); + bleGamepad.setHat1(DPAD_CENTERED); delay(500); } diff --git a/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch index 2f7cee53ce..78efa2e1f8 100644 --- a/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch +++ b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch @@ -1,7 +1,34 @@ diff --git a/BleKeyboard.cpp b/BleKeyboard.cpp -index 0d043f4..3c2677c 100644 +index 0d043f4..d317e83 100644 --- a/BleKeyboard.cpp +++ b/BleKeyboard.cpp +@@ -499,7 +499,7 @@ size_t BleKeyboard::write(const uint8_t *buffer, size_t size) { + return n; + } + +-void BleKeyboard::onConnect(BLEServer* pServer) { ++void BleKeyboard::onConnect(BLEServer* pServer, BLEConnInfo& connInfo) { + this->connected = true; + + #if !defined(USE_NIMBLE) +@@ -513,7 +513,7 @@ void BleKeyboard::onConnect(BLEServer* pServer) { + + } + +-void BleKeyboard::onDisconnect(BLEServer* pServer) { ++void BleKeyboard::onDisconnect(BLEServer* pServer, BLEConnInfo& connInfo, int reason) { + this->connected = false; + + #if !defined(USE_NIMBLE) +@@ -528,7 +528,7 @@ void BleKeyboard::onDisconnect(BLEServer* pServer) { + #endif // !USE_NIMBLE + } + +-void BleKeyboard::onWrite(BLECharacteristic* me) { ++void BleKeyboard::onWrite(BLECharacteristic* me, BLEConnInfo& connInfo) { + uint8_t* value = (uint8_t*)(me->getValue().c_str()); + (void)value; + ESP_LOGI(LOG_TAG, "special keys: %d", *value); @@ -539,8 +539,8 @@ void BleKeyboard::delay_ms(uint64_t ms) { if(ms){ uint64_t e = (m + (ms * 1000)); @@ -14,3 +41,28 @@ index 0d043f4..3c2677c 100644 } } \ No newline at end of file +diff --git a/BleKeyboard.h b/BleKeyboard.h +index 0736a02..e72216d 100644 +--- a/BleKeyboard.h ++++ b/BleKeyboard.h +@@ -11,6 +11,7 @@ + #include "NimBLECharacteristic.h" + #include "NimBLEHIDDevice.h" + ++#define BLEConnInfo NimBLEConnInfo + #define BLEDevice NimBLEDevice + #define BLEServerCallbacks NimBLEServerCallbacks + #define BLECharacteristicCallbacks NimBLECharacteristicCallbacks +@@ -173,9 +174,9 @@ public: + void set_version(uint16_t version); + protected: + virtual void onStarted(BLEServer *pServer) { }; +- virtual void onConnect(BLEServer* pServer) override; +- virtual void onDisconnect(BLEServer* pServer) override; +- virtual void onWrite(BLECharacteristic* me) override; ++ virtual void onConnect(BLEServer* pServer, BLEConnInfo& connInfo) override; ++ virtual void onDisconnect(BLEServer* pServer, BLEConnInfo& connInfo, int reason) override; ++ virtual void onWrite(BLECharacteristic* me, BLEConnInfo& connInfo) override; + + }; + diff --git a/Sming/Libraries/FlashIP b/Sming/Libraries/FlashIP new file mode 160000 index 0000000000..5f6d552d7d --- /dev/null +++ b/Sming/Libraries/FlashIP @@ -0,0 +1 @@ +Subproject commit 5f6d552d7d18f80bbbce7cd891fdce9026802953 diff --git a/Sming/Libraries/Graphics b/Sming/Libraries/Graphics index 999ebaeb17..15696087bc 160000 --- a/Sming/Libraries/Graphics +++ b/Sming/Libraries/Graphics @@ -1 +1 @@ -Subproject commit 999ebaeb177e14a2a592fb1fd70bcfe421c2019f +Subproject commit 15696087bc9a1cbc8e3ba3e5f36cb18d096d0f48 diff --git a/Sming/Libraries/HardwareSPI b/Sming/Libraries/HardwareSPI index 09b9327dba..7f6516c7eb 160000 --- a/Sming/Libraries/HardwareSPI +++ b/Sming/Libraries/HardwareSPI @@ -1 +1 @@ -Subproject commit 09b9327dba3dc40ca276b0c3612e1e48602cab4a +Subproject commit 7f6516c7eb24a3b3bf92e5f64c1722a268b0d553 diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index f5fc23fbb3..21578a4816 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit f5fc23fbb3112460dbd595ddf03b7ec2d45c8cb0 +Subproject commit 21578a4816c5a8e17fa8aa091d149a53b9182631 diff --git a/Sming/Libraries/NimBLE/esp-nimble-cpp b/Sming/Libraries/NimBLE/esp-nimble-cpp index 9e5db157f8..05ac9deaea 160000 --- a/Sming/Libraries/NimBLE/esp-nimble-cpp +++ b/Sming/Libraries/NimBLE/esp-nimble-cpp @@ -1 +1 @@ -Subproject commit 9e5db157f88444bb95415e08a92c7eb817ff533d +Subproject commit 05ac9deaead7e05865fd7aaca5f9f8747d00a99a diff --git a/Sming/Libraries/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h b/Sming/Libraries/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h index 9a93aa114f..957a19f148 100644 --- a/Sming/Libraries/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h +++ b/Sming/Libraries/OtaNetwork/src/include/Ota/Network/HttpUpgrader.h @@ -35,25 +35,20 @@ class HttpUpgrader : protected HttpClient struct Item { String url; - Partition partition; // << partition to write the data to - size_t size{0}; // << actual size of written bytes - ReadWriteStream* stream{nullptr}; // (optional) output stream to use. + Partition partition; // << partition to write the data to + size_t size{0}; // << actual size of written bytes + std::unique_ptr stream; // (optional) output stream to use. Item(String url, Partition partition, ReadWriteStream* stream) : url(url), partition(partition), stream(stream) { } - ~Item() - { - delete stream; - } - ReadWriteStream* getStream() { - if(stream == nullptr) { - stream = new Ota::UpgradeOutputStream(partition); + if(!stream) { + stream.reset(new Ota::UpgradeOutputStream(partition)); } - return stream; + return stream.get(); } }; diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/PayloadParser.cpp b/Sming/Libraries/OtaUpgradeMqtt/src/PayloadParser.cpp index 34b695b76b..a88c5cd439 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/PayloadParser.cpp +++ b/Sming/Libraries/OtaUpgradeMqtt/src/PayloadParser.cpp @@ -35,7 +35,7 @@ int PayloadParser::parse(MqttPayloadParserState& state, mqtt_message_t* message, } if(length == MQTT_PAYLOAD_PARSER_END) { - bool skip = (updateState->stream == nullptr); + bool skip = !updateState->stream; if(!skip) { bool success = switchRom(*updateState); if(success) { @@ -78,11 +78,11 @@ int PayloadParser::parse(MqttPayloadParserState& state, mqtt_message_t* message, length -= offset; buffer += offset; - updateState->stream = getStorageStream(message->common.length - offset); + updateState->stream.reset(getStorageStream(message->common.length - offset)); } - auto stream = updateState->stream; - if(stream == nullptr) { + auto& stream = updateState->stream; + if(!stream) { return 0; } diff --git a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/PayloadParser.h b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/PayloadParser.h index f246e43292..be3b93e8a7 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/PayloadParser.h +++ b/Sming/Libraries/OtaUpgradeMqtt/src/include/OtaUpgrade/Mqtt/PayloadParser.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace OtaUpgrade { @@ -30,14 +31,9 @@ class PayloadParser { public: struct UpdateState { - ReadWriteStream* stream{nullptr}; + std::unique_ptr stream; bool started{false}; size_t version{0}; - - ~UpdateState() - { - delete stream; - } }; /** diff --git a/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp b/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp index 3317529ca7..e09e6b918a 100644 --- a/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp +++ b/Sming/Libraries/SPI/src/Arch/Esp32/SPI.cpp @@ -18,7 +18,6 @@ #include #undef FLAG_ATTR #define FLAG_ATTR(TYPE) -#define typeof decltype #include #include #include diff --git a/Sming/Libraries/Spiffs/spiffs b/Sming/Libraries/Spiffs/spiffs index ec68ba8208..0e3104cde5 160000 --- a/Sming/Libraries/Spiffs/spiffs +++ b/Sming/Libraries/Spiffs/spiffs @@ -1 +1 @@ -Subproject commit ec68ba8208d7550860e4e78299d58a529b88bf85 +Subproject commit 0e3104cde5db4b9d4db579296b44761930ef7501 diff --git a/Sming/Libraries/Spiffs/spiffs.patch b/Sming/Libraries/Spiffs/spiffs.patch index a1f816129c..fb6b53a2f2 100644 --- a/Sming/Libraries/Spiffs/spiffs.patch +++ b/Sming/Libraries/Spiffs/spiffs.patch @@ -1,80 +1,8 @@ -diff --git a/src/spiffs.h b/src/spiffs.h -index 534c3df..eddeb7d 100644 ---- a/src/spiffs.h -+++ b/src/spiffs.h -@@ -496,6 +496,15 @@ s32_t SPIFFS_remove(spiffs *fs, const char *path); - */ - s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh); - -+/** -+ * Truncates a file at given size -+ * @param fs the file system struct -+ * @param fh the filehandle of the file to truncate -+ * @param new_size the new size, must be less than existing file size -+ * @retval s32_t error code -+ */ -+s32_t SPIFFS_ftruncate(spiffs* fs, spiffs_file fh, u32_t new_size); -+ - /** - * Gets file status by path - * @param fs the file system struct - -diff --git a/src/spiffs_hydrogen.c b/src/spiffs_hydrogen.c -index 235aaaa..4df4b4e 100644 ---- a/src/spiffs_hydrogen.c -+++ b/src/spiffs_hydrogen.c -@@ -724,6 +724,45 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { - #endif // SPIFFS_READ_ONLY - } - -+s32_t SPIFFS_ftruncate(spiffs* fs, spiffs_file fh, u32_t new_size) { -+#if SPIFFS_READ_ONLY -+ (void)fs; (void)fh; (void)new_size; -+ return SPIFFS_ERR_RO_NOT_IMPL; -+#else -+ SPIFFS_API_CHECK_CFG(fs); -+ SPIFFS_API_CHECK_MOUNT(fs); -+ SPIFFS_LOCK(fs); -+ -+ spiffs_fd* fd; -+ -+ fh = SPIFFS_FH_UNOFFS(fs, fh); -+ s32_t res = spiffs_fd_get(fs, fh, &fd); -+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res); -+ -+ if ((fd->flags & SPIFFS_O_WRONLY) == 0) { -+ res = SPIFFS_ERR_NOT_WRITABLE; -+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res); -+ } -+ -+#if SPIFFS_CACHE_WR -+ spiffs_fflush_cache(fs, fh); -+#endif -+ -+ s32_t file_size = (fd->size == SPIFFS_UNDEFINED_LEN) ? 0 : fd->size; -+ if (new_size == file_size) { -+ res = SPIFFS_OK; -+ } else if (new_size > file_size) { -+ res = SPIFFS_ERR_END_OF_OBJECT; // Same error we'd get from SPIFFS_lseek -+ } else { -+ res = spiffs_object_truncate(fd, new_size, 0); -+ } -+ SPIFFS_API_CHECK_RES_UNLOCK(fs, res); -+ -+ SPIFFS_UNLOCK(fs); -+ return SPIFFS_OK; -+#endif -+} -+ - static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) { - (void)fh; - spiffs_page_object_ix_header objix_hdr; - diff --git a/src/spiffs_nucleus.c b/src/spiffs_nucleus.c -index f811d93..781c52f 100644 +index ab5cde1..69af230 100644 --- a/src/spiffs_nucleus.c +++ b/src/spiffs_nucleus.c -@@ -939,12 +939,14 @@ s32_t spiffs_object_create( +@@ -949,6 +949,7 @@ s32_t spiffs_object_create( fs->stats_p_allocated++; // write empty object index page @@ -82,18 +10,3 @@ index f811d93..781c52f 100644 oix_hdr.p_hdr.obj_id = obj_id; oix_hdr.p_hdr.span_ix = 0; oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED); - oix_hdr.type = type; - oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page - strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN); -+ oix_hdr.name[SPIFFS_OBJ_NAME_LEN - 1] = '\0'; - #if SPIFFS_OBJ_META_LEN - if (meta) { - _SPIFFS_MEMCPY(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN); -@@ -1008,6 +1010,7 @@ s32_t spiffs_object_update_index_hdr( - // change name - if (name) { - strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN); -+ objix_hdr->name[SPIFFS_OBJ_NAME_LEN - 1] = '\0'; - } - #if SPIFFS_OBJ_META_LEN - if (meta) { diff --git a/Sming/Libraries/Spiffs/src/.cs b/Sming/Libraries/Spiffs/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/Spiffs/src/FileSystem.cpp b/Sming/Libraries/Spiffs/src/FileSystem.cpp index 267e961800..7bc5f373cb 100644 --- a/Sming/Libraries/Spiffs/src/FileSystem.cpp +++ b/Sming/Libraries/Spiffs/src/FileSystem.cpp @@ -32,6 +32,11 @@ namespace SPIFFS return Error::NotMounted; \ } +#define CHECK_RES(res) \ + if((res) < 0) { \ + return translateSpiffsError(res); \ + } + struct FileDir { char path[SPIFFS_OBJ_NAME_LEN]; ///< Filter for readdir() unsigned pathlen; @@ -372,9 +377,7 @@ int FileSystem::read(FileHandle file, void* data, size_t size) int FileSystem::write(FileHandle file, const void* data, size_t size) { int res = SPIFFS_write(handle(), file, const_cast(data), size); - if(res < 0) { - return translateSpiffsError(res); - } + CHECK_RES(res) touch(file); return res; @@ -465,9 +468,7 @@ int FileSystem::stat(const char* path, Stat* stat) spiffs_stat ss; int err = SPIFFS_stat(handle(), path ?: "", &ss); - if(err < 0) { - return translateSpiffsError(err); - } + CHECK_RES(err) if(stat != nullptr) { *stat = Stat{}; @@ -492,9 +493,7 @@ int FileSystem::fstat(FileHandle file, Stat* stat) { spiffs_stat ss; int err = SPIFFS_fstat(handle(), file, &ss); - if(err < 0) { - return translateSpiffsError(err); - } + CHECK_RES(err) auto smb = getMetaBuffer(file); if(smb == nullptr) { @@ -518,6 +517,75 @@ int FileSystem::fstat(FileHandle file, Stat* stat) return FS_OK; } +int FileSystem::fgetextents(FileHandle file, Storage::Partition* part, Extent* list, uint16_t extcount) +{ + CHECK_MOUNTED() + + if(part) { + *part = partition; + } + + // This implementation is based on the `spiffs_object_read` function in spiffs_nuceleus.c. + + auto fs = handle(); + auto fh = SPIFFS_FH_UNOFFS(fs, file); + spiffs_fd* fd; + int res = spiffs_fd_get(fs, fh, &fd); + CHECK_RES(res) + uint32_t fileSize = (fd->size == SPIFFS_UNDEFINED_LEN) ? 0 : fd->size; + uint32_t dataPageSize = SPIFFS_DATA_PAGE_SIZE(fs); + auto objix_pix = spiffs_page_ix(-1); + auto prev_objix_spix = spiffs_span_ix(-1); + unsigned extIndex{0}; + uint32_t nextExtOffset{0}; + spiffs_span_ix data_spix{0}; + for(uint32_t offset = 0; offset < fileSize; ++data_spix, offset += dataPageSize) { + auto cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); + if(prev_objix_spix != cur_objix_spix) { + // load current object index (header) page + if(cur_objix_spix == 0) { + objix_pix = fd->objix_hdr_pix; + } else { + res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, + &objix_pix); + CHECK_RES(res); + } + + res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, + SPIFFS_PAGE_TO_PADDR(fs, objix_pix), LOG_PAGE_SIZE, workBuffer); + CHECK_RES(res) + + prev_objix_spix = cur_objix_spix; + } + + spiffs_page_ix data_pix; + if(cur_objix_spix == 0) { + data_pix = ((spiffs_page_ix*)(workBuffer + sizeof(spiffs_page_object_ix_header)))[data_spix]; + } else { + data_pix = + ((spiffs_page_ix*)(workBuffer + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)]; + } + + Extent ext{ + .offset = SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header), + .length = std::min(dataPageSize, fileSize - offset), + .skip = uint16_t(LOG_PAGE_SIZE - dataPageSize), + }; + if(ext.offset == nextExtOffset && ext.length == dataPageSize) { + --extIndex; + if(list) { + ++list[extIndex].repeat; + } + } else if(list && extIndex < extcount) { + list[extIndex] = ext; + } + nextExtOffset = ext.offset + LOG_PAGE_SIZE; + ++extIndex; + } + + return extIndex; +} + int FileSystem::fsetxattr(FileHandle file, AttributeTag tag, const void* data, size_t size) { CHECK_MOUNTED() @@ -558,9 +626,7 @@ int FileSystem::setxattr(const char* path, AttributeTag tag, const void* data, s FS_CHECK_PATH(path) spiffs_stat ss; int err = SPIFFS_stat(handle(), path ?: "", &ss); - if(err < 0) { - return translateSpiffsError(err); - } + CHECK_RES(err) SpiffsMetaBuffer smb; smb.assign(ss.meta); err = smb.setxattr(tag, data, size); @@ -584,9 +650,7 @@ int FileSystem::getxattr(const char* path, AttributeTag tag, void* buffer, size_ FS_CHECK_PATH(path) spiffs_stat ss; int err = SPIFFS_stat(handle(), path, &ss); - if(err < 0) { - return translateSpiffsError(err); - } + CHECK_RES(err) SpiffsMetaBuffer smb; smb.assign(ss.meta); return smb.getxattr(tag, buffer, size); @@ -649,11 +713,12 @@ int FileSystem::readdir(DirHandle dir, Stat& stat) { GET_FILEDIR() + SPIFFS_clearerr(handle()); spiffs_dirent e; for(;;) { if(SPIFFS_readdir(&d->d, &e) == nullptr) { int err = SPIFFS_errno(handle()); - if(err == SPIFFS_VIS_END) { + if(err == SPIFFS_OK) { return Error::NoMoreFiles; } diff --git a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h index 8afa6305fe..9ebbd156bf 100644 --- a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h +++ b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h @@ -89,6 +89,7 @@ class FileSystem : public IFileSystem file_offset_t tell(FileHandle file) override; int ftruncate(FileHandle file, file_size_t new_size) override; int flush(FileHandle file) override; + int fgetextents(FileHandle file, Storage::Partition* part, Extent* list, uint16_t extcount) override; int rename(const char* oldpath, const char* newpath) override; int remove(const char* path) override; int fremove(FileHandle file) override; @@ -137,7 +138,7 @@ class FileSystem : public IFileSystem IProfiler* profiler{nullptr}; SpiffsMetaBuffer metaCache[SPIFF_FILEDESC_COUNT]; spiffs fs; - uint16_t workBuffer[LOG_PAGE_SIZE]; + uint8_t workBuffer[LOG_PAGE_SIZE * 2]; spiffs_fd fileDescriptors[SPIFF_FILEDESC_COUNT]; uint8_t cache[CACHE_SIZE]; }; diff --git a/Sming/Libraries/Spiffs/src/include/spiffs_config.h b/Sming/Libraries/Spiffs/src/include/spiffs_config.h index 18771a6799..ac7a6245bf 100644 --- a/Sming/Libraries/Spiffs/src/include/spiffs_config.h +++ b/Sming/Libraries/Spiffs/src/include/spiffs_config.h @@ -40,40 +40,40 @@ // for filedescriptor and cache buffers. Once decided for a configuration, // this can be disabled to reduce flash. #ifndef SPIFFS_BUFFER_HELP -#define SPIFFS_BUFFER_HELP 0 +#define SPIFFS_BUFFER_HELP 0 #endif // Enables/disable memory read caching of nucleus file system operations. // If enabled, memory area must be provided for cache in SPIFFS_mount. -#ifndef SPIFFS_CACHE -#define SPIFFS_CACHE 1 +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 #endif #if SPIFFS_CACHE // Enables memory write caching for file descriptors in hydrogen -#ifndef SPIFFS_CACHE_WR -#define SPIFFS_CACHE_WR 1 +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 #endif // Enable/disable statistics on caching. Debug/test purpose only. -#ifndef SPIFFS_CACHE_STATS -#define SPIFFS_CACHE_STATS 0 +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 0 #endif #endif // Always check header of each accessed page to ensure consistent state. // If enabled it will increase number of reads, will increase flash. #ifndef SPIFFS_PAGE_CHECK -#define SPIFFS_PAGE_CHECK 1 +#define SPIFFS_PAGE_CHECK 1 #endif // Define maximum number of gc runs to perform to reach desired free pages. #ifndef SPIFFS_GC_MAX_RUNS -#define SPIFFS_GC_MAX_RUNS 3 +#define SPIFFS_GC_MAX_RUNS 3 #endif // Enable/disable statistics on gc. Debug/test purpose only. #ifndef SPIFFS_GC_STATS -#define SPIFFS_GC_STATS 0 +#define SPIFFS_GC_STATS 0 #endif // Garbage collecting examines all pages in a block which and sums up @@ -86,21 +86,21 @@ // Garbage collecting heuristics - weight used for deleted pages. #ifndef SPIFFS_GC_HEUR_W_DELET -#define SPIFFS_GC_HEUR_W_DELET (5) +#define SPIFFS_GC_HEUR_W_DELET (5) #endif // Garbage collecting heuristics - weight used for used pages. #ifndef SPIFFS_GC_HEUR_W_USED -#define SPIFFS_GC_HEUR_W_USED (-1) +#define SPIFFS_GC_HEUR_W_USED (-1) #endif // Garbage collecting heuristics - weight used for time between // last erased and erase of this block. #ifndef SPIFFS_GC_HEUR_W_ERASE_AGE -#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) #endif // Object name maximum length. #ifndef SPIFFS_OBJ_NAME_LEN -#define SPIFFS_OBJ_NAME_LEN (32) +#define SPIFFS_OBJ_NAME_LEN (32) #endif // Maximum length of the metadata associated with an object. @@ -114,14 +114,14 @@ // logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + // spiffs_object_ix_header fields + at least some LUT entries) #ifndef SPIFFS_OBJ_META_LEN -#define SPIFFS_OBJ_META_LEN (16) +#define SPIFFS_OBJ_META_LEN (16) #endif // Size of buffer allocated on stack used when copying data. // Lower value generates more read/writes. No meaning having it bigger // than logical page size. #ifndef SPIFFS_COPY_BUFFER_STACK -#define SPIFFS_COPY_BUFFER_STACK (64) +#define SPIFFS_COPY_BUFFER_STACK (64) #endif // Enable this to have an identifiable spiffs filesystem. This will look for @@ -129,7 +129,7 @@ // not on mount point. If not, SPIFFS_format must be called prior to mounting // again. #ifndef SPIFFS_USE_MAGIC -#define SPIFFS_USE_MAGIC (0) +#define SPIFFS_USE_MAGIC (0) #endif // SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level @@ -144,7 +144,6 @@ #define SPIFFS_UNLOCK(fs) #endif - // Enable if only one spiffs instance with constant configuration will exist // on the target. This will reduce calculations, flash and memory accesses. // Parts of configuration must be defined below instead of at time of mount. @@ -156,29 +155,29 @@ // Instead of giving parameters in config struct, singleton build must // give parameters in defines below. #ifndef SPIFFS_CFG_PHYS_SZ -#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2) +#define SPIFFS_CFG_PHYS_SZ(ignore) (1024 * 1024 * 2) #endif #ifndef SPIFFS_CFG_PHYS_ERASE_SZ -#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) #endif #ifndef SPIFFS_CFG_PHYS_ADDR -#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) #endif #ifndef SPIFFS_CFG_LOG_PAGE_SZ -#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) #endif #ifndef SPIFFS_CFG_LOG_BLOCK_SZ -#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) #endif #endif // Enable this if your target needs aligned data for index tables #ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES -#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 #endif // Enable this if you want the HAL callbacks to be called with the spiffs struct -#define SPIFFS_HAL_CALLBACK_EXTRA 1 +#define SPIFFS_HAL_CALLBACK_EXTRA 1 // Enable this if you want to add an integer offset to all file handles // (spiffs_file). This is useful if running multiple instances of spiffs on @@ -187,7 +186,7 @@ // NB: This adds config field fh_ix_offset in the configuration struct when // mounting, which must be defined. #ifndef SPIFFS_FILEHDL_OFFSET -#define SPIFFS_FILEHDL_OFFSET 0 +#define SPIFFS_FILEHDL_OFFSET 0 #endif // Enable this to compile a read only version of spiffs. @@ -201,7 +200,7 @@ // returned. // Might be useful for e.g. bootloaders and such. #ifndef SPIFFS_READ_ONLY -#define SPIFFS_READ_ONLY 0 +#define SPIFFS_READ_ONLY 0 #endif // Enable this to add a temporal file cache using the fd buffer. @@ -223,7 +222,7 @@ // directly. If all available descriptors become opened, all cache memory is // lost. #ifndef SPIFFS_TEMPORAL_FD_CACHE -#define SPIFFS_TEMPORAL_FD_CACHE 1 +#define SPIFFS_TEMPORAL_FD_CACHE 1 #endif // Temporal file cache hit score. Each time a file is opened, all cached files @@ -232,7 +231,7 @@ // value for the specific access patterns of the application. However, it must // be between 1 (no gain for hitting a cached entry often) and 255. #ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE -#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4 +#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4 #endif // Enable to be able to map object indices to memory. @@ -248,7 +247,7 @@ // file is modified in some way. The index buffer is tied to the file // descriptor. #ifndef SPIFFS_IX_MAP -#define SPIFFS_IX_MAP 1 +#define SPIFFS_IX_MAP 1 #endif // By default SPIFFS in some cases relies on the property of NOR flash that bits @@ -259,34 +258,34 @@ // use this technique. If your controller is one of the rare ones that don't, // turn this option on and SPIFFS will perform a read-modify-write instead. #ifndef SPIFFS_NO_BLIND_WRITES -#define SPIFFS_NO_BLIND_WRITES 0 +#define SPIFFS_NO_BLIND_WRITES 0 #endif // Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function // in the api. This function will visualize all filesystem using given printf // function. #ifndef SPIFFS_TEST_VISUALISATION -#define SPIFFS_TEST_VISUALISATION 0 +#define SPIFFS_TEST_VISUALISATION 0 #endif #if SPIFFS_TEST_VISUALISATION #ifndef spiffs_printf -#define spiffs_printf(...) c_printf(__VA_ARGS__) +#define spiffs_printf(...) c_printf(__VA_ARGS__) #endif // spiffs_printf argument for a free page #ifndef SPIFFS_TEST_VIS_FREE_STR -#define SPIFFS_TEST_VIS_FREE_STR "_" +#define SPIFFS_TEST_VIS_FREE_STR "_" #endif // spiffs_printf argument for a deleted page #ifndef SPIFFS_TEST_VIS_DELE_STR -#define SPIFFS_TEST_VIS_DELE_STR "/" +#define SPIFFS_TEST_VIS_DELE_STR "/" #endif // spiffs_printf argument for an index page for given object id #ifndef SPIFFS_TEST_VIS_INDX_STR -#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" #endif // spiffs_printf argument for a data page for given object id #ifndef SPIFFS_TEST_VIS_DATA_STR -#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" #endif #endif diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB new file mode 160000 index 0000000000..9055f1b444 --- /dev/null +++ b/Sming/Libraries/USB @@ -0,0 +1 @@ +Subproject commit 9055f1b4443d3bd5fbdd08147c74a6f0528a6a8a diff --git a/Sming/Libraries/USB.no-recursive b/Sming/Libraries/USB.no-recursive new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/WebCam/src/Camera/FakeCamera.h b/Sming/Libraries/WebCam/src/Camera/FakeCamera.h index 2f656398af..eff18f6873 100644 --- a/Sming/Libraries/WebCam/src/Camera/FakeCamera.h +++ b/Sming/Libraries/WebCam/src/Camera/FakeCamera.h @@ -27,15 +27,9 @@ class FakeCamera: public CameraInterface this->files = files; } - ~FakeCamera() - { - delete file; - file = nullptr; - } - const String getMimeType() const override { - return "image/jpeg"; + return toString(MIME_JPEG); } /** @@ -66,14 +60,11 @@ class FakeCamera: public CameraInterface } // go to the next picture. - delete file; - file = new FileStream(files[index++]); + auto& filename = files[index++]; if(index == files.count()) { index = 0; } - if(!file->isValid()) { - delete file; - file = nullptr; + if(!file.open(filename)) { return false; } state = eWCS_HAS_PICTURE; @@ -86,11 +77,7 @@ class FakeCamera: public CameraInterface */ size_t getSize() override { - if(file == nullptr) { - return 0; - } - - return file->getSize(); + return file.getSize(); } /** @@ -103,17 +90,13 @@ class FakeCamera: public CameraInterface */ size_t read(char* buffer, size_t size, size_t offset = 0) { - if(file == nullptr) { - return 0; - } - // get the current picture and read the desired data from it. - file->seekFrom(offset, SeekOrigin::Start); - return file->readMemoryBlock(buffer, size); + file.seekFrom(offset, SeekOrigin::Start); + return file.readMemoryBlock(buffer, size); } private: - size_t index = 0; - FileStream* file = nullptr; + size_t index{0}; + FileStream file; Vector files; }; diff --git a/Sming/Libraries/Yeelight/.cs b/Sming/Libraries/Yeelight/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/Yeelight/YeelightBulb.cpp b/Sming/Libraries/Yeelight/YeelightBulb.cpp index f7aad50860..b7d23e77a0 100644 --- a/Sming/Libraries/Yeelight/YeelightBulb.cpp +++ b/Sming/Libraries/Yeelight/YeelightBulb.cpp @@ -11,40 +11,34 @@ #include #include "WCharacter.h" +namespace +{ +bool isNumeric(const String& str) +{ + for(auto c : str) { + if(!isDigit(c)) + return false; + } + return true; +} + +} // namespace + YeelightBulb::~YeelightBulb() { - if (connection != nullptr) - delete connection; - connection = nullptr; } bool YeelightBulb::connect() { - if (connection != nullptr) - { - if (connection->isProcessing()) - return true; - - //connection->close(); - delete connection; + if(connection && connection->isProcessing()) { + return true; } - connection = new TcpClient(TcpClientDataDelegate(&YeelightBulb::onResponse, this)); + connection.reset(new TcpClient(TcpClientDataDelegate(&YeelightBulb::onResponse, this))); connection->setTimeOut(USHRT_MAX); // Stay connected forever - bool result = connection->connect(lamp, port); - //if (result) updateState(); - return result; -} -bool isNumeric(String str) -{ - for (unsigned i = 0; i < str.length(); i++) - { - if (!isDigit(str[i])) - return false; - } - return true; + return connection->connect(lamp, port); } void YeelightBulb::sendCommand(const String& method, const Vector& params) @@ -55,12 +49,12 @@ void YeelightBulb::sendCommand(const String& method, const Vector& param doc["id"] = requestId++; doc["method"] = method; auto arr = doc.createNestedArray("params"); - for (unsigned i = 0; i < params.count(); i++) - { - if (isNumeric(params[i])) + for(unsigned i = 0; i < params.count(); i++) { + if(isNumeric(params[i])) { arr.add(params[i].toInt()); - else + } else { arr.add(params[i]); + } } String request = Json::serialize(doc); request += "\r\n"; @@ -87,10 +81,11 @@ void YeelightBulb::off() void YeelightBulb::setState(bool isOn) { - if (isOn) + if(isOn) { on(); - else + } else { off(); + } } void YeelightBulb::updateState() @@ -114,7 +109,7 @@ void YeelightBulb::setRGB(byte r, byte g, byte b) { ensureOn(); Vector params; - long val = (long)r*65536 + (long)g*256 + b; + uint32_t val = (r << 16) | (g << 8) | b; params.add(String(val)); sendCommand("set_rgb", params); } @@ -130,16 +125,18 @@ void YeelightBulb::setHSV(int hue, int sat) void YeelightBulb::ensureOn() { - if (state <= 0) + if(state <= 0) { on(); + } } void YeelightBulb::parsePower(const String& value) { - if (value == "on") + if(value == "on") { state = eYBS_On; - else if (value == "off") + } else if(value == "off") { state = eYBS_Off; + } debugf("LED state: %s", value.c_str()); } @@ -150,19 +147,17 @@ bool YeelightBulb::onResponse(TcpClient& client, char* data, int size) debugf("LED > %s", source.c_str()); unsigned p = 0; - while (p < source.length()) - { + while(p < source.length()) { int p2 = source.indexOf("\r\n", p); - if (p2 < 0) + if(p2 < 0) { p2 = source.length(); + } String buf = source.substring(p, p2); p = unsigned(p2) + 2; DynamicJsonDocument doc(1024); - if(Json::deserialize(doc, buf)) - { + if(Json::deserialize(doc, buf)) { long id = doc["id"] | -1; - if (id == propsId) - { + if(id == propsId) { JsonArray result = doc["result"]; const char* value = result[0]; if(value != nullptr) { @@ -172,8 +167,7 @@ bool YeelightBulb::onResponse(TcpClient& client, char* data, int size) const char* method = doc["method"]; debugf("LED method %s received", method); - if (strcmp(method,"props") == 0) - { + if(strcmp(method, "props") == 0) { JsonObject result = doc["params"]; const char* value = result["power"]; if(value != nullptr) { diff --git a/Sming/Libraries/Yeelight/include/YeelightBulb.h b/Sming/Libraries/Yeelight/include/YeelightBulb.h index 11fff0095b..99a2064809 100644 --- a/Sming/Libraries/Yeelight/include/YeelightBulb.h +++ b/Sming/Libraries/Yeelight/include/YeelightBulb.h @@ -6,16 +6,17 @@ ****/ #pragma once -#include "WVector.h" -#include "WString.h" -#include "IpAddress.h" +#include +#include +#include +#include + class TcpClient; -enum YeelightBulbState -{ +enum YeelightBulbState { eYBS_Unknown = -1, eYBS_Off = 0, - eYBS_On = 1 + eYBS_On = 1, }; /** @brief Yeelight wifi bulb controller class @@ -46,7 +47,10 @@ class YeelightBulb void updateState(); /** @brief Get current lamp state (should be called only after updateState) */ - YeelightBulbState currentState() { return state; } + YeelightBulbState currentState() + { + return state; + } void setBrightness(int percent); void setRGB(byte r, byte g, byte b); @@ -54,14 +58,14 @@ class YeelightBulb protected: void ensureOn(); - bool onResponse(TcpClient& client, char *data, int size); + bool onResponse(TcpClient& client, char* data, int size); void parsePower(const String& resp); private: IpAddress lamp; uint16_t port = 55443; - TcpClient* connection = nullptr; + std::unique_ptr connection; long requestId = 0; long propsId = 0; YeelightBulbState state = eYBS_Unknown; diff --git a/Sming/Makefile b/Sming/Makefile index b42993d4a1..e506f608ff 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -209,13 +209,14 @@ endef # Files that should follow our coding standards # Root directories to search -CS_ROOT_DIRS ?= $(abspath $(SMING_HOME)/..) +CS_ROOT_DIRS ?= $(abspath $(SMING_HOME)/.. $(COMPONENT_SEARCH_DIRS)) # List of single directories to search CS_SEARCH_DIRS ?= $(call ListAllSubDirs,$(CS_ROOT_DIRS)) # Resultant set of directories whose contents to apply coding style to CS_DIRS ?= $(patsubst %/.cs,%,$(wildcard $(foreach d,$(CS_SEARCH_DIRS),$d/.cs))) # Files to apply coding style to -CS_FILES = $(if $(CS_DIRS),$(sort $(call rwildcard,$(CS_DIRS:=/*),%.cpp %.hpp %.h %.c))) +CS_ALL_FILES = $(if $(CS_DIRS),$(sort $(call rwildcard,$(CS_DIRS:=/*),%.cpp %.hpp %.h %.c))) +CS_FILES = $(foreach f,$(CS_ALL_FILES),$(if $(findstring /out/,$f),,$f)) .PHONY: cs cs: ##Apply coding style to all core files diff --git a/Sming/Services/CommandProcessing/CommandExecutor.cpp b/Sming/Services/CommandProcessing/CommandExecutor.cpp index c42dae5e45..4cb49e78ce 100644 --- a/Sming/Services/CommandProcessing/CommandExecutor.cpp +++ b/Sming/Services/CommandProcessing/CommandExecutor.cpp @@ -16,7 +16,7 @@ CommandExecutor::CommandExecutor() CommandExecutor::CommandExecutor(Stream* reqStream) : CommandExecutor() { - commandOutput = new CommandOutput(reqStream); + commandOutput.reset(new CommandOutput(reqStream)); if(commandHandler.getVerboseMode() != SILENT) { commandOutput->println(_F("Welcome to the Stream Command executor")); } @@ -25,7 +25,7 @@ CommandExecutor::CommandExecutor(Stream* reqStream) : CommandExecutor() #ifndef DISABLE_NETWORK CommandExecutor::CommandExecutor(TcpClient* cmdClient) : CommandExecutor() { - commandOutput = new CommandOutput(cmdClient); + commandOutput.reset(new CommandOutput(cmdClient)); if(commandHandler.getVerboseMode() != SILENT) { commandOutput->println(_F("Welcome to the Tcp Command executor")); } @@ -33,18 +33,13 @@ CommandExecutor::CommandExecutor(TcpClient* cmdClient) : CommandExecutor() CommandExecutor::CommandExecutor(WebsocketConnection* reqSocket) { - commandOutput = new CommandOutput(reqSocket); + commandOutput.reset(new CommandOutput(reqSocket)); if(commandHandler.getVerboseMode() != SILENT) { reqSocket->sendString(_F("Welcome to the Websocket Command Executor")); } } #endif -CommandExecutor::~CommandExecutor() -{ - delete commandOutput; -} - int CommandExecutor::executorReceive(char* recvData, int recvSize) { int receiveReturn = 0; @@ -117,7 +112,7 @@ void CommandExecutor::processCommandLine(const String& cmdString) commandOutput->print(cmdCommand); commandOutput->println('\''); } else { - cmdDelegate.commandFunction(cmdString, commandOutput); + cmdDelegate.commandFunction(cmdString, commandOutput.get()); } } diff --git a/Sming/Services/CommandProcessing/CommandExecutor.h b/Sming/Services/CommandProcessing/CommandExecutor.h index 2e74f548ba..a04ac0e6c4 100644 --- a/Sming/Services/CommandProcessing/CommandExecutor.h +++ b/Sming/Services/CommandProcessing/CommandExecutor.h @@ -10,6 +10,7 @@ #include "CommandHandler.h" #include "CommandOutput.h" #include +#include #ifndef DISABLE_NETWORK #include @@ -28,7 +29,6 @@ class CommandExecutor CommandExecutor(WebsocketConnection* reqSocket); #endif CommandExecutor(Stream* reqStream); - ~CommandExecutor(); int executorReceive(char* recvData, int recvSize); int executorReceive(char recvChar); @@ -39,5 +39,5 @@ class CommandExecutor CommandExecutor(); void processCommandLine(const String& cmdString); LineBuffer commandBuf; - CommandOutput* commandOutput = nullptr; + std::unique_ptr commandOutput; }; diff --git a/Sming/Services/CommandProcessing/CommandOutput.cpp b/Sming/Services/CommandProcessing/CommandOutput.cpp index 604ce4a3ed..a8bf385103 100644 --- a/Sming/Services/CommandProcessing/CommandOutput.cpp +++ b/Sming/Services/CommandProcessing/CommandOutput.cpp @@ -33,7 +33,7 @@ size_t CommandOutput::write(uint8_t outChar) outputSocket->sendString(tempSocket); tempSocket = ""; } else { - tempSocket = tempSocket + String(char(outChar)); + tempSocket += char(outChar); } return 1; diff --git a/Sming/Services/CommandProcessing/CommandOutput.h b/Sming/Services/CommandProcessing/CommandOutput.h index 774c672e7e..9ae25228e0 100644 --- a/Sming/Services/CommandProcessing/CommandOutput.h +++ b/Sming/Services/CommandProcessing/CommandOutput.h @@ -30,7 +30,7 @@ class CommandOutput : public Print #endif CommandOutput(Stream* reqStream); - virtual ~CommandOutput(); + ~CommandOutput(); size_t write(uint8_t outChar); diff --git a/Sming/System/include/muldiv.h b/Sming/System/include/muldiv.h index 72510bca99..2c32d9a95a 100644 --- a/Sming/System/include/muldiv.h +++ b/Sming/System/include/muldiv.h @@ -69,7 +69,7 @@ template struct MuldivLimits { } /** - * @brief Get the maximum value which can be used for a muldiv calcuation without overflowing + * @brief Get the maximum value which can be used for a muldiv calculation without overflowing * @retval ValType Values greater than this will return `overflow()` */ static constexpr ValType maxValue() diff --git a/Sming/Wiring/WHashMap.h b/Sming/Wiring/WHashMap.h index 1b1de76155..18dbd4bbb2 100644 --- a/Sming/Wiring/WHashMap.h +++ b/Sming/Wiring/WHashMap.h @@ -107,10 +107,15 @@ template class HashMap using Element = BaseElement; using ElementConst = BaseElement; - template - class Iterator : public std::iterator> + template class Iterator { public: + using iterator_category = std::random_access_iterator_tag; + using value_type = BaseElement; + using difference_type = std::ptrdiff_t; + using pointer = BaseElement*; + using reference = BaseElement&; + using Map = typename std::conditional::type; using Value = typename std::conditional::type; @@ -425,6 +430,7 @@ template class HashMap private: HashMap(const HashMap& that); + HashMap& operator=(const HashMap& that); }; template V& HashMap::operator[](const K& key) diff --git a/Sming/Wiring/WVector.h b/Sming/Wiring/WVector.h index 6da2e68965..6d6856326c 100644 --- a/Sming/Wiring/WVector.h +++ b/Sming/Wiring/WVector.h @@ -33,9 +33,15 @@ template class Vector : public Countable public: using Comparer = int (*)(const Element& lhs, const Element& rhs); - template class Iterator : public std::iterator + template class Iterator { public: + using iterator_category = std::random_access_iterator_tag; + using value_type = Element; + using difference_type = std::ptrdiff_t; + using pointer = Element*; + using reference = Element&; + using V = typename std::conditional::type; using E = typename std::conditional::type; diff --git a/Sming/build.mk b/Sming/build.mk index 14b1c0be99..a0b60ffc65 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -203,9 +203,10 @@ ifneq ($(STRICT),1) CXXFLAGS += -Wno-reorder endif -ifndef MAKE_CLEAN include $(ARCH_BASE)/build.mk +ifndef MAKE_CLEAN + # Detect compiler version DEBUG_VARS += GCC_VERSION GCC_VERSION := $(shell $(CC) -dumpversion) diff --git a/Sming/project.mk b/Sming/project.mk index c26eb49f0b..8f09896449 100644 --- a/Sming/project.mk +++ b/Sming/project.mk @@ -161,7 +161,7 @@ export PROJECT_SOC # $3 -> Build directory # $4 -> Output library directory define ParseComponent -ifneq (,$$(findstring $(SMING_SOC),$$(PROJECT_SOC))) +ifneq (,$$(filter $(SMING_SOC),$$(PROJECT_SOC))) $(if $V,$(info -- Parsing $1)) $(if $2,,$(error Component '$1' not found)) SUBMODULES += $(filter $2,$(ALL_SUBMODULES)) @@ -241,9 +241,6 @@ define ParseComponentList $(foreach c,$1,$(eval $(call ParseComponent,$c,$(call FindComponentDir,$c),$(SMING_HOME)/$(BUILD_BASE),$(USER_LIBDIR)))) endef -# Must parse the Application Component first to get project dependencies -$(eval $(call ParseComponent,App,$(CURDIR),$(BUILD_BASE),$(abspath $(APP_LIBDIR)))) - # Load cached configuration variables. On first run this file won't exist, so all values # will be as specified by defaults or in project's component.mk file. # Values may be overridden via command line to update the cache. @@ -253,6 +250,9 @@ ifeq (,$(filter config-clean dist-clean,$(MAKECMDGOALS))) -include $(CONFIG_CACHE_FILE) endif +# Must parse the Application Component first to get project dependencies +$(eval $(call ParseComponent,App,$(CURDIR),$(BUILD_BASE),$(abspath $(APP_LIBDIR)))) + # Also export debug variables here for access by external tools (e.g. python) CONFIG_DEBUG_FILE := $(OUT_BASE)/debug.mk @@ -357,7 +357,7 @@ $(foreach v,$(EXPORT_VARS),$(eval export $v)) ##@Building .PHONY: sample -ifeq (,$(findstring $(SMING_SOC),$(PROJECT_SOC))) +ifeq (,$(filter $(SMING_SOC),$(PROJECT_SOC))) sample: $(info Not building: Sample doesn't support $(SMING_SOC)) else @@ -367,8 +367,8 @@ endif .PHONY: checksoc checksoc: -ifeq (,$(findstring $(SMING_SOC),$(PROJECT_SOC))) - $(error Project only supports: $(PROJECT_SOC)) +ifeq (,$(filter $(SMING_SOC),$(PROJECT_SOC))) + $(error Project doesn't support $(SMING_SOC): run `make list-soc` to see supported devices) endif @@ -451,13 +451,13 @@ endif define GenerateComponentTargetRule ifeq (App,$1) $2: $1-build - $(Q) touch $$@ + $(Q) touch -c "$$@" else ifeq (,$(wildcard $2)) $2: $1-build - $(Q) touch $$@ + $(Q) touch -c "$$@" else ifneq (,$(filter $1,$(FULL_COMPONENT_BUILD))) $2: $1-build - $(Q) touch $$@ + $(Q) touch -c "$$@" endif endef @@ -535,7 +535,7 @@ fetch: ##Fetch Component or Library and display location CACHE_VARS += TRACE TRACE ?= .PHONY: decode-stacktrace -decode-stacktrace: ##Open the stack trace decoder ready to paste dump text. Alteratively, use `make decode-stacktrace TRACE=/path/to/crash.stack` +decode-stacktrace: ##Open the stack trace decoder ready to paste dump text. Alternatively, use `make decode-stacktrace TRACE=/path/to/crash.stack` $(Q) if [ -z "$(TRACE)" ]; then \ echo "Decode stack trace: Paste stack trace here"; \ fi @@ -741,7 +741,7 @@ list-soc: ##List supported and available SOCs .PHONY: list-soc-check checksoc-print: -ifeq (,$(findstring $(SMING_SOC),$(PROJECT_SOC))) +ifeq (,$(filter $(SMING_SOC),$(PROJECT_SOC))) $(info - NO: $(SMING_SOC)) else $(info - YES: $(SMING_SOC)) @@ -750,7 +750,7 @@ endif BOARDTOOL_CMDLINE = $(PYTHON) $(SMING_TOOLS)/boardtool.py $(if $V,-v) .PHONY: list-default-pins -list-default-pins: ##List default periperal pins +list-default-pins: ##List default peripheral pins $(Q) $(BOARDTOOL_CMDLINE) list-default-pins PIN_MENU := $(abspath $(OUT_BASE)/../pin.menu) diff --git a/Tools/boardtool.py b/Tools/boardtool.py index e3cb48327d..65767b0ebe 100644 --- a/Tools/boardtool.py +++ b/Tools/boardtool.py @@ -305,9 +305,11 @@ def generate_pinmenu(args): f' config PERIPH_{per.name}_ENABLE', f' bool "{per.name}"', f' default y', - f' help' ] - menu += [f' {s}' for s in per.help()] + help_items = per.help() + if help_items: + menu += [' help'] + menu += [f' {s}' for s in help_items] if per.swap: menu += [ f' config PERIPH_{per.name}_SWAP_ENABLE', diff --git a/Tools/ci/setenv.ps1 b/Tools/ci/setenv.ps1 index bbeb69abbe..e3d84ff351 100644 --- a/Tools/ci/setenv.ps1 +++ b/Tools/ci/setenv.ps1 @@ -14,7 +14,6 @@ $env:ESP_HOME = Join-Path $TOOLS_DIR "esp-quick-toolchain" # Esp32 $env:IDF_PATH = Join-Path $TOOLS_DIR "esp-idf" $env:IDF_TOOLS_PATH = Join-Path $TOOLS_DIR "esp32" -$env:IDF_BRANCH = "sming/release/v4.3" # Rp2040 $env:PICO_TOOLCHAIN_PATH = Join-Path $TOOLS_DIR "rp2040" diff --git a/Tools/ide/vscode/setup.py b/Tools/ide/vscode/setup.py index 52e68f7c8f..a9b2aceb2f 100644 --- a/Tools/ide/vscode/setup.py +++ b/Tools/ide/vscode/setup.py @@ -3,7 +3,7 @@ # Sming hardware configuration tool # -import os, sys +import os, sys, copy appPath = os.path.dirname(os.path.realpath(__file__)) libPath = appPath + '/../common/' @@ -96,9 +96,8 @@ def update_workspace(): ws = load_json(filename, False) template = load_template('workspace.json', appPath) if ws is None: - ws = template.copy() + ws = copy.deepcopy(template) schemas = ws['settings']['json.schemas'] = [] - # ws['settings']['json.schemas'] for schema in template['settings']['json.schemas']: schema['url'] = env.resolve(schema['url']) schemas += [schema] diff --git a/Tools/ide/vscode/template/workspace.json b/Tools/ide/vscode/template/workspace.json index 78c5eb2397..c8085183cc 100644 --- a/Tools/ide/vscode/template/workspace.json +++ b/Tools/ide/vscode/template/workspace.json @@ -9,6 +9,7 @@ "files.associations": { "*.hw": "jsonc", "*.fwfs": "jsonc", + "*.usbcfg": "jsonc", "optional": "cpp" }, "json.schemas": [ @@ -23,6 +24,12 @@ "*.fwfs" ], "url": "file://${SMING_HOME}/Components/IFS/fsbuild/schema.json" + }, + { + "fileMatch": [ + "*.usbcfg" + ], + "url": "file://${SMING_HOME}/Libraries/USB/schema.json" } ] } diff --git a/Tools/install.sh b/Tools/install.sh index 5e65f6480f..939aa68942 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -110,8 +110,16 @@ if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then else + MACHINE_PACKAGES="" case $DIST in debian) + case $(uname -m) in + arm | aarch64) + ;; + *) + MACHINE_PACKAGES="g++-multilib" + ;; + esac sudo apt-get -y update || echo "Update failed... Try to install anyway..." $PKG_INSTALL \ cmake \ @@ -121,17 +129,22 @@ else ninja-build \ unzip \ g++ \ - g++-multilib \ python3 \ python3-pip \ python3-setuptools \ wget \ + $MACHINE_PACKAGES \ $EXTRA_PACKAGES $PKG_INSTALL clang-format-8 || printf "\nWARNING: Failed to install optional clang-format-8.\n\n" ;; fedora) + case $(uname -m) in + x86_64) + MACHINE_PACKAGES="glibc-devel.i686 libstdc++.i686" + ;; + esac $PKG_INSTALL \ cmake \ gawk \ @@ -139,15 +152,14 @@ else gcc-c++ \ gettext \ git \ - glibc-devel.i686 \ - libstdc++.i686 \ make \ ninja-build \ python3 \ python3-pip \ sed \ unzip \ - wget + wget \ + $MACHINE_PACKAGES ;; esac diff --git a/docs/source/information/multitasking.rst b/docs/source/information/multitasking.rst index c1f287cd2d..b4a2670c76 100644 --- a/docs/source/information/multitasking.rst +++ b/docs/source/information/multitasking.rst @@ -13,7 +13,7 @@ older systems which only have a single CPU. The OS does this using a mechanism called *Pre-emptive Multitasking*. As far as your program is concerned, it just runs without any apparent interruptions, but in reality it only gets -a little 'slice' of time before the operating system forceably switches to a different program and +a little 'slice' of time before the operating system forcibly switches to a different program and lets it run for another 'slice' of time. (Hence the term, *time slicing*.) With pre-emptive multitasking the operating system has to maintain state for every single diff --git a/samples/Basic_Audio/app/application.cpp b/samples/Basic_Audio/app/application.cpp index 695b236d38..d0a2f3e1be 100644 --- a/samples/Basic_Audio/app/application.cpp +++ b/samples/Basic_Audio/app/application.cpp @@ -41,13 +41,13 @@ static constexpr unsigned statusIntervalMs = 5000; // One full sine-wave cycle static struct { - uint16_t* samples = nullptr; + std::unique_ptr samples; unsigned sampleCount = 0; unsigned readPos = 0; bool generate(float sampleRate, float frequency) { - delete samples; + samples.reset(); readPos = 0; sampleCount = round(sampleRate / frequency); @@ -57,8 +57,8 @@ static struct { Serial << _F("Generating sine wave table @ ") << frequency << _F(" Hz, ") << sampleCount << _F(" samples") << endl; - samples = new uint16_t[sampleCount]; - if(samples == nullptr) { + samples.reset(new uint16_t[sampleCount]); + if(!samples) { debug_e("Memory allocation failed"); return false; } diff --git a/samples/Basic_IFS/README.rst b/samples/Basic_IFS/README.rst index 2d01da92bb..354e75d4ba 100644 --- a/samples/Basic_IFS/README.rst +++ b/samples/Basic_IFS/README.rst @@ -35,3 +35,7 @@ To add support for SD Cards to this sample:: make ENABLE_SDCARD=1 See :library:`FatIFS` for further details of SD Card and FAT filing system support. + +To add support for a USB storage device:: + + make ENABLE_USB_STORAGE=1 diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 68b4f817c1..5bdfc2787a 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -35,6 +35,12 @@ #endif +#ifdef ENABLE_USB_STORAGE +#include +#include +USB::MSC::HostDevice usbStorage; +#endif + namespace { #ifdef ENABLE_FLASHSTRING_IMAGE @@ -215,7 +221,7 @@ bool initFileSystem() Storage::registerDevice(card); // Buffering allows byte read/write - card.allocateBuffers(2); + card->allocateBuffers(2); if(card->begin(PIN_CARD_CS, SPI_FREQ_LIMIT)) { Serial << "CSD" << endl << card->csd << endl; @@ -237,6 +243,69 @@ bool initFileSystem() #endif +#ifdef ENABLE_USB_STORAGE + USB::begin(); + USB::MSC::onMount([](auto inst) { + usbStorage.begin(inst); + usbStorage.enumerate([](auto& unit, const USB::MSC::Inquiry& inquiry) { +#define OUT(name, value) Serial << String(name).padLeft(30) << ": " << value << endl; +#define OUTR(name) OUT(#name, inquiry.resp.name) + Serial << _F("USB device '") << unit.getName() << _F("' mounted") << endl; + OUT("Vendor ID", inquiry.vendorId()) + OUT("Product ID", inquiry.productId()) + OUT("Product Revision", inquiry.productRev()) + OUTR(peripheral_device_type) + OUTR(peripheral_qualifier) + OUTR(is_removable) + OUTR(version) + OUTR(response_data_format) + OUTR(hierarchical_support) + OUTR(normal_aca) + OUTR(additional_length) + OUTR(protect) + OUTR(third_party_copy) + OUTR(target_port_group_support) + OUTR(access_control_coordinator) + OUTR(scc_support) + OUTR(addr16) + OUTR(multi_port) + OUTR(enclosure_service) + OUTR(cmd_que) + OUTR(sync) + OUTR(wbus16) +#undef OUTR +#undef OUT + + Storage::registerDevice(&unit); + unit.allocateBuffers(16); + + for(auto part : unit.partitions()) { + Serial << part << endl; + } + auto part = *unit.partitions().begin(); + auto fatfs = IFS::createFatFilesystem(part); + if(fatfs && fatfs->mount() == FS_OK) { + getFileSystem()->setVolume(3, fatfs); + Serial << F("FAT partition mounted") << endl; + } else { + Serial << F("FAT mount failed") << endl; + delete fatfs; + } + + return false; // Ignore other LUNs + }); + + return &usbStorage; + }); + + USB::MSC::onUnmount([](USB::MSC::HostDevice& dev) { + if(dev == usbStorage) { + getFileSystem()->setVolume(3, nullptr); + Serial << _F("USB '") << dev.getName() << _F("' unmounted") << endl; + } + }); +#endif + debug_i("File system initialised"); return true; } @@ -403,13 +472,11 @@ Timer statTimer; void init() { -#if DEBUG_BUILD Serial.begin(COM_SPEED_SERIAL); Serial.systemDebugOutput(true); debug_i("\n\n********************************************************\n" "Hello\n"); -#endif // Delay at startup so terminal gets time to start auto timer = new AutoDeleteTimer; diff --git a/samples/Basic_IFS/basic_ifs.usbcfg b/samples/Basic_IFS/basic_ifs.usbcfg new file mode 100644 index 0000000000..60dfe5cc7e --- /dev/null +++ b/samples/Basic_IFS/basic_ifs.usbcfg @@ -0,0 +1,5 @@ +{ + "host": { + "msc": 1 + } +} \ No newline at end of file diff --git a/samples/Basic_IFS/basic_ifs_Rp2040.hw b/samples/Basic_IFS/basic_ifs_Rp2040.hw index b6090a2e16..a63a50ea25 100644 --- a/samples/Basic_IFS/basic_ifs_Rp2040.hw +++ b/samples/Basic_IFS/basic_ifs_Rp2040.hw @@ -3,23 +3,24 @@ "arch": "Rp2040", "base_config": "basic_ifs", "options": [ - "2m" + "2m", + "cyw43_fw" ], "partitions": { "rom0": { - "size": "480K" + "size": "320K" }, "lfs1": { "size": "932K", - "address": "0x00078000" + "address": "0x0006b000" }, "spiffs0": { - "address": "0x00161000", + "address": "0x00154000", "size": "376K" }, "fwfs1": { - "address": "0x001bf000", - "size": "256K" + "address": "0x001b2000", + "size": "164K" } } } \ No newline at end of file diff --git a/samples/Basic_IFS/component.mk b/samples/Basic_IFS/component.mk index 50140848dd..33da075365 100644 --- a/samples/Basic_IFS/component.mk +++ b/samples/Basic_IFS/component.mk @@ -1,8 +1,6 @@ COMPONENT_DEPENDS := \ Spiffs \ - LittleFS \ - FatIFS \ - SdStorage + LittleFS # Empty SPIFFS partition please SPIFF_FILES := @@ -20,4 +18,17 @@ endif CONFIG_VARS += ENABLE_SDCARD ifeq ($(ENABLE_SDCARD),1) COMPONENT_CXXFLAGS += -DENABLE_SDCARD +COMPONENT_DEPENDS += SdStorage FatIFS +endif + +CONFIG_VARS += ENABLE_USB_STORAGE +ifeq ($(ENABLE_USB_STORAGE),1) +COMPONENT_CXXFLAGS += -DENABLE_USB_STORAGE +COMPONENT_DEPENDS += USB +USB_CONFIG := basic_ifs.usbcfg +endif + +ifeq ($(SMING_ARCH),Rp2040) +# For Rp2040, put firmware into partition +LINK_CYW43_FIRMWARE := 0 endif diff --git a/samples/Basic_IFS/fsimage.fwfs b/samples/Basic_IFS/fsimage.fwfs index cc8b6bfb88..302af234c3 100644 --- a/samples/Basic_IFS/fsimage.fwfs +++ b/samples/Basic_IFS/fsimage.fwfs @@ -15,7 +15,8 @@ "mountpoints": { "littlefs": 0, "spiffs": 1, - "fat": 2 + "sdcard": 2, + "usb": 3 }, // Rules for file metadata. All rules are evaluated in sequence for every file "rules": [ diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index 53e8a3a0b0..8b446c70b6 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -10,7 +10,7 @@ #define WIFI_PWD "PleaseEnterPass" #endif -Ota::Network::HttpUpgrader* otaUpdater; +std::unique_ptr otaUpdater; Storage::Partition spiffsPartition; OtaUpgrader ota; @@ -49,10 +49,7 @@ void doUpgrade() Serial.println(F("Updating...")); // need a clean object, otherwise if run before and failed will not run again - if(otaUpdater) { - delete otaUpdater; - } - otaUpdater = new Ota::Network::HttpUpgrader(); + otaUpdater.reset(new Ota::Network::HttpUpgrader); // select rom slot to flash auto part = ota.getNextBootPartition(); diff --git a/samples/Basic_ScannerI2C/app/application.cpp b/samples/Basic_ScannerI2C/app/application.cpp index eac15eac22..81ecd50d4f 100644 --- a/samples/Basic_ScannerI2C/app/application.cpp +++ b/samples/Basic_ScannerI2C/app/application.cpp @@ -6,7 +6,7 @@ // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. -// Version 2, Juni 2012, Using Arduino 1.0.1 +// Version 2, June 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold diff --git a/samples/Basic_Serial/app/SerialTransmitDemo.cpp b/samples/Basic_Serial/app/SerialTransmitDemo.cpp index f3186556ac..f4bf25eac6 100644 --- a/samples/Basic_Serial/app/SerialTransmitDemo.cpp +++ b/samples/Basic_Serial/app/SerialTransmitDemo.cpp @@ -6,7 +6,7 @@ void SerialTransmitDemo::sendDataChunk() { - if(serial.copyFrom(stream, chunkSize) == 0) { + if(serial.copyFrom(stream.get(), chunkSize) == 0) { Serial.println(_F("Finished sending stream to serial port")); // All done, delete ourselves diff --git a/samples/Basic_Serial/include/SerialTransmitDemo.h b/samples/Basic_Serial/include/SerialTransmitDemo.h index c3b626e6e2..2e9d032cb7 100644 --- a/samples/Basic_Serial/include/SerialTransmitDemo.h +++ b/samples/Basic_Serial/include/SerialTransmitDemo.h @@ -3,12 +3,14 @@ #include #include +#include class SerialTransmitDemo { public: - SerialTransmitDemo(HardwareSerial& serial, IDataSourceStream* stream) : serial(serial), stream(stream) + SerialTransmitDemo(HardwareSerial& serial, IDataSourceStream* stream) : serial(serial) { + this->stream.reset(stream); serial.onTransmitComplete(TransmitCompleteDelegate(&SerialTransmitDemo::onTransmitComplete, this)); } @@ -16,7 +18,6 @@ class SerialTransmitDemo { // Disconnect callback from serial port serial.onTransmitComplete(nullptr); - delete stream; } void begin() @@ -35,7 +36,7 @@ class SerialTransmitDemo private: HardwareSerial& serial; - IDataSourceStream* stream = nullptr; + std::unique_ptr stream; const size_t chunkSize = 32; }; diff --git a/samples/Basic_Tasks/component.mk b/samples/Basic_Tasks/component.mk index a6afd10a26..ba03b6dbd5 100644 --- a/samples/Basic_Tasks/component.mk +++ b/samples/Basic_Tasks/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* host ARDUINO_LIBRARIES := ArduinoFFT SignalGenerator ENABLE_TASK_COUNT := 1 diff --git a/samples/Basic_WebSkeletonApp/component.mk b/samples/Basic_WebSkeletonApp/component.mk index 1fd7647f2f..eab8e24b4e 100644 --- a/samples/Basic_WebSkeletonApp/component.mk +++ b/samples/Basic_WebSkeletonApp/component.mk @@ -1,4 +1,3 @@ -COMPONENT_SOC := esp* ARDUINO_LIBRARIES := ArduinoJson6 HWCONFIG := spiffs-2m diff --git a/samples/HttpServer_ConfigNetwork/app/application.cpp b/samples/HttpServer_ConfigNetwork/app/application.cpp index 2bc0a694b3..b9bf939fce 100644 --- a/samples/HttpServer_ConfigNetwork/app/application.cpp +++ b/samples/HttpServer_ConfigNetwork/app/application.cpp @@ -3,15 +3,20 @@ #include #include +namespace +{ HttpServer server; FtpServer ftp; -BssList networks; +HashMap networks; + String network, password; Timer connectionTimer; String lastModified; +SimpleTimer scanTimer; + // Instead of using a SPIFFS file, here we demonstrate usage of imported Flash Strings IMPORT_FSTR_LOCAL(flashSettings, PROJECT_DIR "/web/build/settings.html") @@ -90,7 +95,7 @@ void onFile(HttpRequest& request, HttpResponse& response) void onAjaxNetworkList(HttpRequest& request, HttpResponse& response) { - JsonObjectStream* stream = new JsonObjectStream(); + JsonObjectStream* stream = new JsonObjectStream(4096); JsonObject json = stream->getRoot(); json["status"] = (bool)true; @@ -103,16 +108,16 @@ void onAjaxNetworkList(HttpRequest& request, HttpResponse& response) } JsonArray netlist = json.createNestedArray("available"); - for(auto& nw : networks) { - if(nw.hidden) { + for(auto nw : networks) { + if(nw->hidden) { continue; } JsonObject item = netlist.createNestedObject(); - item["id"] = nw.getHashId(); + item["id"] = nw->getHashId(); // Copy full string to JSON buffer memory - item["title"] = nw.ssid; - item["signal"] = nw.rssi; - item["encryption"] = nw.getAuthorizationMethodName(); + item["title"] = nw->ssid; + item["signal"] = nw->rssi; + item["encryption"] = nw->getAuthorizationMethodName(); } response.setAllowCrossDomainOrigin("*"); @@ -121,6 +126,7 @@ void onAjaxNetworkList(HttpRequest& request, HttpResponse& response) void makeConnection() { + debug_i(">> makeConnection()"); WifiStation.enable(true); WifiStation.config(network, password); @@ -204,22 +210,39 @@ void startServers() startWebServer(); } +void scanNetworks(); + void networkScanCompleted(bool succeeded, BssList& list) { - if(!succeeded) { - return; - } - - networks.clear(); - for(auto& nw : list) { - if(!nw.hidden && nw.ssid.length() > 0) { - networks.add(nw); + if(succeeded) { + networks.clear(); + for(auto& nw : list) { + if(nw.hidden || nw.ssid.length() == 0) { + continue; + } + int i = networks.indexOf(nw.ssid); + if(i < 0 || nw.rssi > networks.valueAt(i).rssi) { + networks[nw.ssid] = nw; + } } + + // networks.sort([](const auto& a, const auto& b) { return b.value().rssi < a.value().rssi; }); } - networks.sort([](auto& a, auto& b) { return b.rssi - a.rssi; }); + scanTimer.initializeMs<30000>(scanNetworks); + scanTimer.startOnce(); } +void scanNetworks() +{ + if(!WifiStation.startScan(networkScanCompleted)) { + scanTimer.initializeMs<5000>(scanNetworks); + scanTimer.startOnce(); + } +} + +} // namespace + void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default @@ -244,7 +267,7 @@ void init() } } - WifiStation.startScan(networkScanCompleted); + scanNetworks(); // Start AP for configuration WifiAccessPoint.enable(true); diff --git a/samples/HttpServer_ConfigNetwork/web/build/index.html b/samples/HttpServer_ConfigNetwork/web/build/index.html index a89f8c23ad..4293fa40d6 100644 --- a/samples/HttpServer_ConfigNetwork/web/build/index.html +++ b/samples/HttpServer_ConfigNetwork/web/build/index.html @@ -1,4 +1,4 @@ Sming Framework WiFi Network configuration

Sming Based

Network Settings

Wireless network connection

Networks

\ No newline at end of file +

Sming Based

Network Settings

Wireless network connection

Networks

\ No newline at end of file diff --git a/samples/HttpServer_ConfigNetwork/web/dev/index.html b/samples/HttpServer_ConfigNetwork/web/dev/index.html index 40d3072c73..ad645de04d 100644 --- a/samples/HttpServer_ConfigNetwork/web/dev/index.html +++ b/samples/HttpServer_ConfigNetwork/web/dev/index.html @@ -104,7 +104,7 @@ if(data.status == true){ network = null; password = null; - App.Connect = setTimeout(worker, 50); + App.Connect = setTimeout(worker, 500); }else{ App.Utilities.HideLoader(); } diff --git a/tests/HostTests/component.mk b/tests/HostTests/component.mk index 3368f1f11e..3fd335e767 100644 --- a/tests/HostTests/component.mk +++ b/tests/HostTests/component.mk @@ -1,6 +1,5 @@ ifeq ($(SMING_ARCH),Rp2040) HWCONFIG = host-tests-1m -DISABLE_NETWORK := 1 else ifeq ($(SMING_ARCH),Esp32) HWCONFIG = host-tests-esp32 else diff --git a/tests/HostTests/modules/Clocks.cpp b/tests/HostTests/modules/Clocks.cpp index 41dc8a5f3f..fe9803b767 100644 --- a/tests/HostTests/modules/Clocks.cpp +++ b/tests/HostTests/modules/Clocks.cpp @@ -45,11 +45,13 @@ template class ClockTestTemplate : public TestG // } auto endTicks = Clock::ticks(); + // Handle both up and down counters + auto elapsedTicks = (endTicks >= startTicks) ? endTicks - startTicks : startTicks - endTicks; debug_w("System time elapsed: %u", time - startTime); - debug_w("%s ticks: %u", Clock::typeName(), endTicks - startTicks); - debug_w("Ratio: x %f", float(endTicks - startTicks) / (time - startTime)); - uint32_t us = Micros::ticksToTime(endTicks - startTicks); + debug_w("%s ticks: %u", Clock::typeName(), elapsedTicks); + debug_w("Ratio: x %f", float(elapsedTicks) / (time - startTime)); + uint32_t us = Micros::ticksToTime(elapsedTicks); debug_w("Apparent time: %u", us); // Up-timers may report 0 if inactive if(endTicks != 0 || startTicks != 0) {