From 85f1db827fee2927b4f498a2a924245d48a39c64 Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 31 May 2022 16:17:14 +0200 Subject: [PATCH 01/58] Fixed typo in the release workflow. (#2519) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d4abe542a..06cf230995 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: SMING_ARCH: Host RELEASE_TOKEN: ${{secrets.RELEASE_TOKEN}} CI_REPO_NAME: ${{github.repository}} - CHOCO_TOKEN: ${{secrets.CHOKO_TOKEN}} + CHOCO_TOKEN: ${{secrets.CHOCO_TOKEN}} run: | export CI_BUILD_DIR="$GITHUB_WORKSPACE" export SMING_HOME="$GITHUB_WORKSPACE/Sming" From c8155f8148aa3b48e1266e069edffcc6dcdd417b Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 27 Jun 2022 08:42:09 +0100 Subject: [PATCH 02/58] Revise station configuration to support BSSID (#2522) --- .../Arch/Esp32/Platform/StationImpl.cpp | 37 +++++++++++---- .../Network/Arch/Esp32/Platform/StationImpl.h | 3 +- .../Arch/Esp8266/Platform/StationImpl.cpp | 46 +++++++++++++------ .../Arch/Esp8266/Platform/StationImpl.h | 3 +- .../Arch/Host/Platform/StationImpl.cpp | 21 +++++---- .../Network/Arch/Host/Platform/StationImpl.h | 3 +- .../Arch/Rp2040/Platform/StationImpl.cpp | 7 ++- .../Arch/Rp2040/Platform/StationImpl.h | 3 +- .../Components/Network/src/Platform/Station.h | 38 +++++++++++++-- 9 files changed, 120 insertions(+), 41 deletions(-) diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index 744b595e12..cc4ae57c90 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -165,27 +165,34 @@ bool StationImpl::isEnabled() const return (mode == WIFI_MODE_STA) || (mode == WIFI_MODE_APSTA); } -bool StationImpl::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +bool StationImpl::config(const Config& cfg) { wifi_config_t config{}; - if(ssid.length() >= sizeof(config.sta.ssid)) { + if(cfg.ssid.length() >= sizeof(config.sta.ssid)) { return false; } - if(password.length() >= sizeof(config.sta.password)) { + if(cfg.password.length() >= sizeof(config.sta.password)) { return false; } - memcpy(config.sta.ssid, ssid.c_str(), ssid.length()); - memcpy(config.sta.password, password.c_str(), password.length()); + memcpy(config.sta.ssid, cfg.ssid.c_str(), cfg.ssid.length()); + memcpy(config.sta.password, cfg.password.c_str(), cfg.password.length()); - enable(true, save); + if(cfg.bssid) { + config.sta.bssid_set = true; + cfg.bssid.getOctets(config.sta.bssid); + } else { + config.sta.bssid_set = false; + } + + enable(true, cfg.save); - if(save) { - setAutoConnect(autoConnectOnStartup); + if(cfg.save) { + setAutoConnect(cfg.autoConnectOnStartup); } - ESP_ERROR_CHECK(esp_wifi_set_storage(save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_storage(cfg.save ? WIFI_STORAGE_FLASH : WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &config)); return connect(); @@ -328,6 +335,16 @@ String StationImpl::getSSID() const return ssid; } +MacAddress StationImpl::getBSSID() const +{ + wifi_config_t config{}; + if(esp_wifi_get_config(WIFI_IF_STA, &config) != ESP_OK) { + debug_e("Can't read station configuration!"); + return MacAddress{}; + } + return config.sta.bssid; +} + int8_t StationImpl::getRssi() const { wifi_ap_record_t info; @@ -472,7 +489,7 @@ void StationImpl::internalSmartConfig(smartconfig_event_t event_id, void* pdata) switch(event_id) { case SC_EVENT_GOT_SSID_PSWD: - config(evt.ssid, evt.password, true, true); + StationClass::config(evt.ssid, evt.password, true, true); connect(); break; case SC_EVENT_SEND_ACK_DONE: diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h index 1a1842d206..2fe46a9361 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.h @@ -35,7 +35,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void enable(bool enabled, bool save) override; bool isEnabled() const override; - bool config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) override; + bool config(const Config& cfg) override; bool connect() override; bool disconnect() override; StationConnectionStatus getConnectionStatus() const override; @@ -51,6 +51,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler IpAddress getNetworkBroadcast() const override; bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) override; String getSSID() const override; + MacAddress getBSSID() const override; String getPassword() const override; int8_t getRssi() const override; uint8_t getChannel() const override; diff --git a/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.cpp index 37b61adc0e..72fab1319f 100644 --- a/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.cpp @@ -51,13 +51,13 @@ bool StationImpl::isEnabled() const return wifi_get_opmode() & STATION_MODE; } -bool StationImpl::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +bool StationImpl::config(const Config& cfg) { station_config config = {0}; - if(ssid.length() >= sizeof(config.ssid)) { + if(cfg.ssid.length() >= sizeof(config.ssid)) { return false; } - if(password.length() >= sizeof(config.password)) { + if(cfg.password.length() >= sizeof(config.password)) { return false; } @@ -70,10 +70,10 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo bool setConfig; if(wifi_station_get_config(&config)) { // Determine if config has changed - setConfig = - strncmp(ssid.c_str(), reinterpret_cast(config.ssid), sizeof(config.ssid)) != 0 || - strncmp(password.c_str(), reinterpret_cast(config.password), sizeof(config.password)) != 0 || - config.bssid_set; + setConfig = strncmp(cfg.ssid.c_str(), reinterpret_cast(config.ssid), sizeof(config.ssid)) != 0 || + strncmp(cfg.password.c_str(), reinterpret_cast(config.password), + sizeof(config.password)) != 0 || + (config.bssid_set && cfg.bssid != config.bssid); } else { debugf("Can't read station configuration!"); setConfig = true; @@ -83,13 +83,19 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo if(setConfig) { memset(config.ssid, 0, sizeof(config.ssid)); memset(config.password, 0, sizeof(config.password)); - config.bssid_set = false; - ssid.getBytes(config.ssid, sizeof(config.ssid)); - password.getBytes(config.password, sizeof(config.password)); + cfg.ssid.getBytes(config.ssid, sizeof(config.ssid)); + cfg.password.getBytes(config.password, sizeof(config.password)); + + if(cfg.bssid) { + config.bssid_set = true; + cfg.bssid.getOctets(config.bssid); + } else { + config.bssid_set = false; + } noInterrupts(); - if(save) { + if(cfg.save) { success = wifi_station_set_config(&config); } else { success = wifi_station_set_config_current(&config); @@ -98,12 +104,12 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo interrupts(); if(success) { - debugf("Station configuration was updated to: %s", ssid.c_str()); + debugf("Station configuration was updated to: %s", cfg.ssid.c_str()); } else { debugf("Can't set station configuration!"); } } else { - debugf("Station configuration is: %s", ssid.c_str()); + debugf("Station configuration is: %s", cfg.ssid.c_str()); success = true; } @@ -115,7 +121,7 @@ bool StationImpl::config(const String& ssid, const String& password, bool autoCo } if(success) { - wifi_station_set_auto_connect(autoConnectOnStartup); + wifi_station_set_auto_connect(cfg.autoConnectOnStartup); } return success; @@ -234,6 +240,16 @@ String StationImpl::getSSID() const return ssid; } +MacAddress StationImpl::getBSSID() const +{ + station_config config = {0}; + if(!wifi_station_get_config(&config)) { + debugf("Can't read station configuration!"); + return MacAddress{}; + } + return config.bssid; +} + int8_t StationImpl::getRssi() const { debugf("Rssi: %d dBm", wifi_station_get_rssi()); @@ -364,7 +380,7 @@ void StationImpl::internalSmartConfig(sc_status status, void* pdata) case SC_STATUS_GETTING_SSID_PSWD: break; case SC_STATUS_LINK: - config(evt.ssid, evt.password, true, true); + StationClass::config(evt.ssid, evt.password, true, true); connect(); break; case SC_STATUS_LINK_OVER: diff --git a/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.h b/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.h index 4614a6c179..1fc08a5c8a 100644 --- a/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Esp8266/Platform/StationImpl.h @@ -28,7 +28,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void enable(bool enabled, bool save) override; bool isEnabled() const override; - bool config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) override; + bool config(const Config& cfg) override; bool connect() override; bool disconnect() override; StationConnectionStatus getConnectionStatus() const override; @@ -44,6 +44,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler IpAddress getNetworkBroadcast() const override; bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) override; String getSSID() const override; + MacAddress getBSSID() const override; String getPassword() const override; int8_t getRssi() const override; uint8_t getChannel() const override; diff --git a/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp index f2e6fc7e11..a981dc7ae6 100644 --- a/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Host/Platform/StationImpl.cpp @@ -158,30 +158,30 @@ bool StationImpl::isEnabled() const return currentConfig.enabled; } -bool StationImpl::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +bool StationImpl::config(const Config& cfg) { for(auto& ap : apInfoList) { - if(ssid == ap.ssid) { + if(cfg.ssid == ap.ssid) { if(ap.authMode != AUTH_OPEN) { - if(password != ap.pwd) { - debug_w("Bad password for '%s'", ssid.c_str()); + if(cfg.password != ap.pwd) { + debug_w("Bad password for '%s'", cfg.ssid.c_str()); return false; } } currentAp = ≈ - if(save) { + if(cfg.save) { savedAp = ≈ } - debug_i("Connected to SSID '%s'", ssid.c_str()); + debug_i("Connected to SSID '%s'", cfg.ssid.c_str()); - autoConnect = autoConnectOnStartup; + autoConnect = cfg.autoConnectOnStartup; return true; } } - debug_w("SSID '%s' not found", ssid.c_str()); + debug_w("SSID '%s' not found", cfg.ssid.c_str()); return false; } @@ -293,6 +293,11 @@ String StationImpl::getSSID() const return currentAp ? currentAp->ssid : nullptr; } +MacAddress StationImpl::getBSSID() const +{ + return MacAddress({0xff, 0xff, 0xff, 0x00, 0x01}); +} + int8_t StationImpl::getRssi() const { return getRandomRssi(); diff --git a/Sming/Components/Network/Arch/Host/Platform/StationImpl.h b/Sming/Components/Network/Arch/Host/Platform/StationImpl.h index 6523f4e0b0..6b76dd58c5 100644 --- a/Sming/Components/Network/Arch/Host/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Host/Platform/StationImpl.h @@ -36,7 +36,7 @@ class StationImpl : public StationClass // StationClass void enable(bool enabled, bool save) override; bool isEnabled() const override; - bool config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) override; + bool config(const Config& cfg) override; bool connect() override; bool disconnect() override; StationConnectionStatus getConnectionStatus() const override; @@ -52,6 +52,7 @@ class StationImpl : public StationClass IpAddress getNetworkBroadcast() const override; bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) override; String getSSID() const override; + MacAddress getBSSID() const override; String getPassword() const override; int8_t getRssi() const override; uint8_t getChannel() const override; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp index 5cf95b2b24..3004fc2201 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.cpp @@ -23,7 +23,7 @@ bool StationImpl::isEnabled() const return false; } -bool StationImpl::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +bool StationImpl::config(const Config& cfg) { return false; } @@ -96,6 +96,11 @@ String StationImpl::getSSID() const return nullptr; } +MacAddress StationImpl::getBSSID() const +{ + return {}; +} + int8_t StationImpl::getRssi() const { return 0; diff --git a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h index 43d189e865..d886a2ea46 100644 --- a/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h +++ b/Sming/Components/Network/Arch/Rp2040/Platform/StationImpl.h @@ -23,7 +23,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler void enable(bool enabled, bool save) override; bool isEnabled() const override; - bool config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) override; + bool config(const Config& cfg) override; bool connect() override; bool disconnect() override; StationConnectionStatus getConnectionStatus() const override; @@ -39,6 +39,7 @@ class StationImpl : public StationClass, protected ISystemReadyHandler IpAddress getNetworkBroadcast() const override; bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) override; String getSSID() const override; + MacAddress getBSSID() const override; String getPassword() const override; int8_t getRssi() const override; uint8_t getChannel() const override; diff --git a/Sming/Components/Network/src/Platform/Station.h b/Sming/Components/Network/src/Platform/Station.h index 32b9c37d70..3fcc5eca92 100644 --- a/Sming/Components/Network/src/Platform/Station.h +++ b/Sming/Components/Network/src/Platform/Station.h @@ -108,6 +108,17 @@ using WPSConfigDelegate = Delegate; class StationClass { public: + /** + * @brief Station configuration passed to config method + */ + struct Config { + String ssid; ///< Service Set to connect to (may be advertised by multiple access points) + String password; ///< Password (if required) + MacAddress bssid; ///< Set this to connect to a specific access point + bool autoConnectOnStartup = true; ///< Auto connect to this AP on system restart + bool save = true; ///< Store new settings in NV memory + }; + virtual ~StationClass() { } @@ -130,8 +141,24 @@ class StationClass * @param autoConnectOnStartup True to auto connect. False for manual. (Default: True) * @param save True to save the SSID and password in Flash. False otherwise. (Default: True) */ - virtual bool config(const String& ssid, const String& password, bool autoConnectOnStartup = true, - bool save = true) = 0; + virtual bool config(const Config& config) = 0; + + /** @brief Configure WiFi station + * @param ssid WiFi SSID + * @param password WiFi password + * @param autoConnectOnStartup True to auto connect. False for manual. (Default: True) + * @param save True to save the SSID and password in Flash. False otherwise. (Default: True) + */ + bool config(const String& ssid, const String& password, bool autoConnectOnStartup = true, bool save = true) + { + Config cfg{ + .ssid = ssid, + .password = password, + .autoConnectOnStartup = autoConnectOnStartup, + .save = save, + }; + return config(cfg); + } /** @brief Connect WiFi station to network */ @@ -250,11 +277,16 @@ class StationClass */ virtual bool setIP(IpAddress address, IpAddress netmask, IpAddress gateway) = 0; - /** @brief Get WiFi station SSID + /** @brief Get WiFi station SSID (Service Set Identifier) * @retval String WiFi station SSID */ virtual String getSSID() const = 0; + /** @brief Get BSSID (Basic Service Set Identifier) for connected AP + * @retval MacAddress Identifier of connected Access Point + */ + virtual MacAddress getBSSID() const = 0; + /** @brief Get WiFi station password * @retval String WiFi station password */ From 694ed967609cefc2efc89157058c8e9ea9250866 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 27 Jun 2022 09:42:29 +0200 Subject: [PATCH 03/58] Updated Bearssl. (#2520) --- Sming/Components/bearssl-esp8266/bearssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Components/bearssl-esp8266/bearssl b/Sming/Components/bearssl-esp8266/bearssl index c0b69dfb83..b024386d46 160000 --- a/Sming/Components/bearssl-esp8266/bearssl +++ b/Sming/Components/bearssl-esp8266/bearssl @@ -1 +1 @@ -Subproject commit c0b69dfb837f0027180c72f13f7c90cfafb83c16 +Subproject commit b024386d461abd1b7b9be3117e2516b7541f1201 From 27586170a97565062b6a6336c1bac9afe6db235b Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 28 Jun 2022 13:04:02 +0200 Subject: [PATCH 04/58] Feature: Bluetooth Low Energy (BLE) support for Esp32 (#2499) * Initial BLE Keyboard and Gamepad libraries and samples. * Updated docs and code. * Added Switch Joycon sample. Co-authored-by: mikee47 --- .gitmodules | 14 +- .../Arch/Esp32/Components/esp32/component.mk | 54 ++- .../Esp32/Components/esp32/sdk/config/common | 10 + .../Arch/Esp32/Components/esp_wifi/README.rst | 7 +- Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad | 1 + Sming/Libraries/BLEGamepad/README.rst | 65 +++ Sming/Libraries/BLEGamepad/component.mk | 8 + .../BLEGamepad/samples/Bluetooth_Gamepad/.cs | 0 .../samples/Bluetooth_Gamepad/Makefile | 9 + .../samples/Bluetooth_Gamepad/README.rst | 32 ++ .../Bluetooth_Gamepad/app/application.cpp | 42 ++ .../samples/Bluetooth_Gamepad/component.mk | 1 + .../Libraries/BLEKeyboard/ESP32-BLE-Keyboard | 1 + .../BLEKeyboard/ESP32-BLE-Keyboard.patch | 16 + Sming/Libraries/BLEKeyboard/README.rst | 81 ++++ Sming/Libraries/BLEKeyboard/component.mk | 9 + .../samples/Bluetooth_Keyboard/.cs | 0 .../samples/Bluetooth_Keyboard/Makefile | 9 + .../samples/Bluetooth_Keyboard/README.rst | 13 + .../Bluetooth_Keyboard/app/application.cpp | 48 ++ .../samples/Bluetooth_Keyboard/component.mk | 1 + Sming/Libraries/NimBLE/README.rst | 24 + Sming/Libraries/NimBLE/component.mk | 6 + Sming/Libraries/NimBLE/esp-nimble-cpp | 1 + Sming/Libraries/SwitchJoycon/.cs | 0 Sming/Libraries/SwitchJoycon/README.rst | 76 +++ Sming/Libraries/SwitchJoycon/component.mk | 4 + .../SwitchJoycon/samples/Bluetooth_Joycon/.cs | 0 .../samples/Bluetooth_Joycon/Makefile | 9 + .../samples/Bluetooth_Joycon/README.rst | 23 + .../Bluetooth_Joycon/app/application.cpp | 54 +++ .../samples/Bluetooth_Joycon/component.mk | 1 + Sming/Libraries/SwitchJoycon/src/.cs | 0 .../SwitchJoycon/src/SwitchJoycon.cpp | 438 ++++++++++++++++++ .../Libraries/SwitchJoycon/src/SwitchJoycon.h | 154 ++++++ .../src/SwitchJoyconConnection.cpp | 17 + .../SwitchJoycon/src/SwitchJoyconConnection.h | 35 ++ 37 files changed, 1255 insertions(+), 8 deletions(-) create mode 160000 Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad create mode 100644 Sming/Libraries/BLEGamepad/README.rst create mode 100644 Sming/Libraries/BLEGamepad/component.mk create mode 100644 Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/.cs create mode 100644 Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/Makefile create mode 100644 Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/README.rst create mode 100644 Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp create mode 100644 Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/component.mk create mode 160000 Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard create mode 100644 Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch create mode 100644 Sming/Libraries/BLEKeyboard/README.rst create mode 100644 Sming/Libraries/BLEKeyboard/component.mk create mode 100644 Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/.cs create mode 100644 Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/Makefile create mode 100644 Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/README.rst create mode 100644 Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/app/application.cpp create mode 100644 Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/component.mk create mode 100644 Sming/Libraries/NimBLE/README.rst create mode 100644 Sming/Libraries/NimBLE/component.mk create mode 160000 Sming/Libraries/NimBLE/esp-nimble-cpp create mode 100644 Sming/Libraries/SwitchJoycon/.cs create mode 100644 Sming/Libraries/SwitchJoycon/README.rst create mode 100644 Sming/Libraries/SwitchJoycon/component.mk create mode 100644 Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/.cs create mode 100644 Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/Makefile create mode 100644 Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/README.rst create mode 100644 Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/app/application.cpp create mode 100644 Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/component.mk create mode 100644 Sming/Libraries/SwitchJoycon/src/.cs create mode 100644 Sming/Libraries/SwitchJoycon/src/SwitchJoycon.cpp create mode 100644 Sming/Libraries/SwitchJoycon/src/SwitchJoycon.h create mode 100644 Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.cpp create mode 100644 Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.h diff --git a/.gitmodules b/.gitmodules index 7607e1ac02..c828c2366a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -377,8 +377,18 @@ # # Esp32 libraries # - -### NONE ### +[submodule "Libraries.ESP32-BLE-Gamepad"] + path = Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad + url = https://github.com/lemmingDev/ESP32-BLE-Gamepad.git + ignore = dirty +[submodule "Libraries.ESP32-BLE-Keyboard"] + path = Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard + url = https://github.com/T-vK/ESP32-BLE-Keyboard.git + ignore = dirty +[submodule "Libraries.esp-nimble-cpp"] + path = Sming/Libraries/NimBLE/esp-nimble-cpp + url = https://github.com/h2zero/esp-nimble-cpp.git + ignore = dirty # diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index affffe905e..e568d0efa6 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -17,11 +17,22 @@ SDKCONFIG_H := $(SDK_BUILD_BASE)/config/sdkconfig.h SDK_LIBDIRS := \ esp_wifi/lib/$(ESP_VARIANT) \ - xtensa/$(ESP_VARIANT)/ \ - hal/$(ESP_VARIANT)/ \ + xtensa/$(ESP_VARIANT) \ + hal/$(ESP_VARIANT) \ $(ESP_VARIANT)/ld \ esp_rom/$(ESP_VARIANT)/ld +# BLUETOOTH +ifeq ($(ESP_VARIANT),esp32) +SDK_LIBDIRS += bt/controller/lib_esp32/$(ESP_VARIANT) +ENABLE_BLUETOOTH := 1 +else ifneq (,$(findstring $(ESP_VARIANT),esp32c3 esp32s3)) +SDK_LIBDIRS += bt/controller/lib_esp32c3_family/$(ESP_VARIANT) +ENABLE_BLUETOOTH := 1 +else +ENABLE_BLUETOOTH := 0 +endif + ESP32_COMPONENT_PATH := $(COMPONENT_PATH) SDK_DEFAULT_PATH := $(ESP32_COMPONENT_PATH)/sdk @@ -71,6 +82,33 @@ SDK_INCDIRS := \ lwip/include/apps/sntp \ wpa_supplicant/include/esp_supplicant +ifeq ($(ENABLE_BLUETOOTH),1) +SDK_INCDIRS += \ + bt/include/$(ESP_VARIANT)/include \ + bt/common/api/include/api \ + bt/common/btc/profile/esp/blufi/include \ + bt/common/btc/profile/esp/include \ + bt/common/osi/include \ + bt/host/nimble/nimble/nimble/include \ + bt/host/nimble/nimble/nimble/host/include \ + bt/host/nimble/nimble/porting/nimble/include \ + bt/host/nimble/nimble/porting/npl/freertos/include \ + bt/host/nimble/nimble/nimble/host/services/ans/include \ + bt/host/nimble/nimble/nimble/host/services/bas/include \ + bt/host/nimble/nimble/nimble/host/services/dis/include \ + bt/host/nimble/nimble/nimble/host/services/gap/include \ + bt/host/nimble/nimble/nimble/host/services/gatt/include \ + bt/host/nimble/nimble/nimble/host/services/ias/include \ + bt/host/nimble/nimble/nimble/host/services/ipss/include \ + bt/host/nimble/nimble/nimble/host/services/lls/include \ + bt/host/nimble/nimble/nimble/host/services/tps/include \ + bt/host/nimble/nimble/nimble/host/util/include \ + bt/host/nimble/nimble/nimble/host/store/ram/include \ + bt/host/nimble/nimble/nimble/host/store/config/include \ + bt/host/nimble/esp-hci/include \ + bt/host/nimble/port/include +endif + ifdef IDF_TARGET_ARCH_RISCV SDK_INCDIRS += \ freertos/port/riscv/include \ @@ -151,6 +189,13 @@ SDK_ESP_WIFI_LIBS := \ pp \ smartconfig +ifeq ($(ENABLE_BLUETOOTH),1) +SDK_ESP_BLUETOOTH_LIBS := bt btdm_app +ifneq (,$(filter $(ESP_VARIANT),esp32c3 esp32s3)) +SDK_ESP_BLUETOOTH_LIBS += btbb +endif +endif + ifeq ($(ESP_VARIANT),esp32) SDK_ESP_WIFI_LIBS += rtc endif @@ -167,6 +212,11 @@ EXTRA_LIBS := \ ifneq ($(DISABLE_WIFI),1) EXTRA_LIBS += $(SDK_ESP_WIFI_LIBS) + +ifeq ($(ENABLE_BLUETOOTH),1) +EXTRA_LIBS += $(SDK_ESP_BLUETOOTH_LIBS) +endif + endif LinkerScript = -T $(ESP_VARIANT).$1.ld diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index 6bb6d89c55..a4caeb16e7 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -23,6 +23,16 @@ CONFIG_ETH_USE_SPI_ETHERNET=y CONFIG_ETH_SPI_ETHERNET_W5500=y CONFIG_ETH_SPI_ETHERNET_DM9051=y +# Bluetooth +CONFIG_BT_ENABLED=y +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=n +CONFIG_BLE_MESH=n +CONFIG_BT_NIMBLE_MESH=n + +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=n + # Mandatory Sming framework changes CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=16384 CONFIG_ESP_TASK_WDT_TIMEOUT_S=8 diff --git a/Sming/Arch/Esp32/Components/esp_wifi/README.rst b/Sming/Arch/Esp32/Components/esp_wifi/README.rst index 1e6d05f976..2a401d40ff 100644 --- a/Sming/Arch/Esp32/Components/esp_wifi/README.rst +++ b/Sming/Arch/Esp32/Components/esp_wifi/README.rst @@ -1,5 +1,4 @@ -Esp8266 WiFi -============ +Esp32 WiFi +========== -All related libraries for WiFi support. Definitions are provided in the -Espressif Non-OS SDK. +All related libraries for WiFi support. diff --git a/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad new file mode 160000 index 0000000000..544dc65029 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/ESP32-BLE-Gamepad @@ -0,0 +1 @@ +Subproject commit 544dc650296f4a4b9a22995b996458c2c66fa4e5 diff --git a/Sming/Libraries/BLEGamepad/README.rst b/Sming/Libraries/BLEGamepad/README.rst new file mode 100644 index 0000000000..c6a41f113f --- /dev/null +++ b/Sming/Libraries/BLEGamepad/README.rst @@ -0,0 +1,65 @@ +ESP32 BLE Gamepad +================= + +.. highlight:: c++ + +Introduction +------------ +This library allows you to make the ESP32 act as a Bluetooth gamepad and control what it does. +The library uses :library:`NimBLE` for faster and lighter communication. + +Features +-------- + +Using this library you can do the following: + + - Button press (128 buttons) + - Button release (128 buttons) + - Axes movement (6 axes (16 bit) (x, y, z, rZ, rX, rY) --> (Left Thumb X, Left Thumb Y, Right Thumb X, Right Thumb Y, Left Trigger, Right Trigger)) + - 2 Sliders (16 bit) (Slider 1 and Slider 2) + - 4 point of view hats (ie. d-pad plus 3 other hat switches) + - Simulation controls (rudder, throttle, accelerator, brake, steering) + - Configurable HID descriptor + - Report optional battery level to host (basically works, but it doesn't show up in Android's status bar) + - Customize Bluetooth device name/manufacturer + - Uses efficient NimBLE bluetooth library + - Compatible with Windows + - Compatible with Android (Android OS maps default buttons / axes / hats slightly differently than Windows) + - Compatible with Linux (limited testing) + - Compatible with MacOS X (limited testing) + +Using +----- + +1. Add ``COMPONENT_DEPENDS += BLEGamepad`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + namespace + { + BleGamepad bleGamepad; + + // ... + + } // namespace + + void init() + { + // ... + + bleGamepad.begin(); + } + + +Notes +----- +By default, reports are sent on every button press/release or axis/slider/hat/simulation movement, however this can be disabled, +and then you manually call sendReport on the gamepad instance as shown in the IndividualAxes.ino example. + +There is also Bluetooth specific information that you can use (optional): + +Instead of ``BleGamepad bleGamepad;`` you can do ``BleGamepad bleGamepad("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);``. +The third parameter is the initial battery level of your device. +Adjusting the battery level later on doesn't work. +By default the battery level will be set to 100%, the device name will be `ESP32 BLE Gamepad` and the manufacturer will be `Espressif`. \ No newline at end of file diff --git a/Sming/Libraries/BLEGamepad/component.mk b/Sming/Libraries/BLEGamepad/component.mk new file mode 100644 index 0000000000..1bec8c0d31 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/component.mk @@ -0,0 +1,8 @@ +COMPONENT_SUBMODULES := ESP32-BLE-Gamepad +COMPONENT_DEPENDS := NimBLE + +COMPONENT_SRCDIRS := ESP32-BLE-Gamepad +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) + +COMPONENT_CPPFLAGS:= -DUSE_NIMBLE=1 +APP_CFLAGS += -DUSE_NIMBLE=1 diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/.cs b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/Makefile b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/README.rst b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/README.rst new file mode 100644 index 0000000000..1572eddf96 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/README.rst @@ -0,0 +1,32 @@ +Bluetooth Gamepad +================= + +Introduction +------------ +This sample turns the ESP32 into a Bluetooth LE gamepad that presses buttons and moves axis + +Possible buttons are: BUTTON_1 through to BUTTON_16 +(16 buttons supported by default. Library can be configured to support up to 128) + +Possible DPAD/HAT switch position values are: +DPAD_CENTERED, DPAD_UP, DPAD_UP_RIGHT, DPAD_RIGHT, DPAD_DOWN_RIGHT, DPAD_DOWN, DPAD_DOWN_LEFT, DPAD_LEFT, DPAD_UP_LEFT +(or HAT_CENTERED, HAT_UP etc) + +bleGamepad.setAxes takes the following int16_t parameters for the Left/Right Thumb X/Y, Left/Right Triggers plus slider1 and slider2, and hat switch position as above: +(Left Thumb X, Left Thumb Y, Right Thumb X, Right Thumb Y, Left Trigger, Right Trigger, Hat switch position ^ (1 hat switch (dpad) supported by default. Library can be configured to support up to 4) + +Library can also be configured to support up to 5 simulation controls (can be set with setSimulationControls) +(rudder, throttle, accelerator, brake, steering), but they are not enabled by default. + + +Testing +------- + +You can use one of the following applications on your PC to test and see all buttons that were clicked. + +On Linux install ``jstest-gtk`` to test the ESP32 gamepad. Under Ubuntu this can be done by typing the following command:: + + sudo apt install jstest-gtk + +On Windows use this `Windows test application `__. + \ No newline at end of file diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp new file mode 100644 index 0000000000..7e10dbbfd7 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/app/application.cpp @@ -0,0 +1,42 @@ +#include +#include + +namespace +{ +BleGamepad bleGamepad; + +Timer procTimer; + +void loop() +{ + if(!bleGamepad.isConnected()) { + return; + } + + 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); + // 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); + delay(500); +} + +} // namespace + +void init() +{ + Serial.begin(COM_SPEED_SERIAL); + Serial.println("Starting BLE Gamepad sample!"); + bleGamepad.begin(); + // The default bleGamepad.begin() above is the same as bleGamepad.begin(16, 1, true, true, true, true, true, true, true, true, false, false, false, false, false); + // which enables a gamepad with 16 buttons, 1 hat switch, enabled x, y, z, rZ, rX, rY, slider 1, slider 2 and disabled rudder, throttle, accelerator, brake, steering + // Auto reporting is enabled by default. + // Use bleGamepad.setAutoReport(false); to disable auto reporting, and then use bleGamepad.sendReport(); as needed + + procTimer.initializeMs(500, loop).start(); +} diff --git a/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/component.mk b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/component.mk new file mode 100644 index 0000000000..c28c735b08 --- /dev/null +++ b/Sming/Libraries/BLEGamepad/samples/Bluetooth_Gamepad/component.mk @@ -0,0 +1 @@ +COMPONENT_DEPENDS := BLEGamepad diff --git a/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard new file mode 160000 index 0000000000..f8dd485211 --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard @@ -0,0 +1 @@ +Subproject commit f8dd4852113a722a6b8dc8af987e94cf84d73ad5 diff --git a/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch new file mode 100644 index 0000000000..2f7cee53ce --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/ESP32-BLE-Keyboard.patch @@ -0,0 +1,16 @@ +diff --git a/BleKeyboard.cpp b/BleKeyboard.cpp +index 0d043f4..3c2677c 100644 +--- a/BleKeyboard.cpp ++++ b/BleKeyboard.cpp +@@ -539,8 +539,8 @@ void BleKeyboard::delay_ms(uint64_t ms) { + if(ms){ + uint64_t e = (m + (ms * 1000)); + if(m > e){ //overflow +- while(esp_timer_get_time() > e) { } ++ while(uint64_t(esp_timer_get_time()) > e) { } + } +- while(esp_timer_get_time() < e) {} ++ while(uint64_t(esp_timer_get_time()) < e) {} + } + } +\ No newline at end of file diff --git a/Sming/Libraries/BLEKeyboard/README.rst b/Sming/Libraries/BLEKeyboard/README.rst new file mode 100644 index 0000000000..d27c3e5ced --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/README.rst @@ -0,0 +1,81 @@ +ESP32 BLE Keyboard +================== + +.. highlight:: c++ + +Introduction +------------ +This library allows you to make the ESP32 act as a Bluetooth keyboard and control what it does. +The library uses :library:`NimBLE` for faster and lighter communication. + +Features +-------- + +Using this library you can do the following: + + - Send key strokes + - Send text + - Press/release individual keys + - Media keys are supported + - Set battery level (basically works, but doesn't show up in Android's status bar) + - Compatible with Android + - Compatible with Windows + - Compatible with Linux + - Compatible with MacOS X (not stable, some people have issues, doesn't work with old devices) + - Compatible with iOS (not stable, some people have issues, doesn't work with old devices) + +Using +----- + +1. Add ``COMPONENT_DEPENDS += BLEKeyboard`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + + namespace + { + BleKeyboard bleKeyboard; + + // ... + + } // namespace + + void init() + { + // ... + + bleKeyboard.begin(); + } + + +API documentation +----------------- +The BleKeyboard interface is almost identical to the Keyboard Interface, so you can use documentation right here: +https://www.arduino.cc/reference/en/language/functions/usb/keyboard/ + +In addition to that you can send media keys (which is not possible with the USB keyboard library). Supported are the following: + + - KEY_MEDIA_NEXT_TRACK + - KEY_MEDIA_PREVIOUS_TRACK + - KEY_MEDIA_STOP + - KEY_MEDIA_PLAY_PAUSE + - KEY_MEDIA_MUTE + - KEY_MEDIA_VOLUME_UP + - KEY_MEDIA_VOLUME_DOWN + - KEY_MEDIA_WWW_HOME + - KEY_MEDIA_LOCAL_MACHINE_BROWSER // Opens "My Computer" on Windows + - KEY_MEDIA_CALCULATOR + - KEY_MEDIA_WWW_BOOKMARKS + - KEY_MEDIA_WWW_SEARCH + - KEY_MEDIA_WWW_STOP + - KEY_MEDIA_WWW_BACK + - KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION // Media Selection + - KEY_MEDIA_EMAIL_READER + +There is also Bluetooth specific information that you can set (optional): +Instead of ``BleKeyboard bleKeyboard;`` you can do ``BleKeyboard bleKeyboard("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);``. (Max length is 15 characters, anything beyond that will be truncated.) +The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. ``bleKeyboard.setBatteryLevel(50)`` (set battery level to 50%). +By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Keyboard` and the manufacturer will be `Espressif`. +There is also a ``setDelay`` method to set a delay between each key event. E.g. ``bleKeyboard.setDelay(10)`` (10 milliseconds). The default is `8`. +This feature is meant to compensate for some applications and devices that can't handle fast input and will skip letters if too many keys are sent in a small time frame. diff --git a/Sming/Libraries/BLEKeyboard/component.mk b/Sming/Libraries/BLEKeyboard/component.mk new file mode 100644 index 0000000000..6016b6b22a --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/component.mk @@ -0,0 +1,9 @@ +COMPONENT_SUBMODULES := ESP32-BLE-Keyboard + +COMPONENT_DEPENDS := NimBLE + +COMPONENT_SRCDIRS := ESP32-BLE-Keyboard +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) + +COMPONENT_CPPFLAGS:= -DUSE_NIMBLE=1 +APP_CFLAGS += -DUSE_NIMBLE=1 diff --git a/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/.cs b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/Makefile b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/README.rst b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/README.rst new file mode 100644 index 0000000000..4d01eb7a89 --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/README.rst @@ -0,0 +1,13 @@ +Bluetooth Keyboard +================== + +This sample demonstrates how to turn an Esp32 device into external keyboard. +The "keyboard" and your PC will be communicating using Bluetooth Low Energy (BLE). +The "keyboard" will write words, press Enter, press a media key and, if enabled in the sample code, Ctrl+Alt+Delete. + +Usage +----- +Once this sample is flashed and running on your ESP32 you can test it. +Open a new text editor on your PC. Then search from your PC for new bluetooth devices. +A device named "Sming BLE Keyboard" should show up. Connect to it and focus/open you text editor window. +Be fast. Soon enough a "Hello World" text will start to be "magically" typed inside your text editor. \ No newline at end of file diff --git a/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/app/application.cpp b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/app/application.cpp new file mode 100644 index 0000000000..bc6d959e34 --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/app/application.cpp @@ -0,0 +1,48 @@ +#include +#include + +namespace +{ +BleKeyboard bleKeyboard("Sming BLE Keyboard"); +Timer procTimer; + +void loop() +{ + if(!bleKeyboard.isConnected()) { + return; + } + + Serial.println("Sending 'Hello world'..."); + bleKeyboard.print("Hello world"); + + Serial.println("Sending Enter key..."); + bleKeyboard.write(KEY_RETURN); + + delay(1000); + + Serial.println("Sending Play/Pause media key..."); + bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); + + // + // Below is an example of pressing multiple keyboard modifiers + // which by default is commented out. + /* + Serial.println("Sending Ctrl+Alt+Delete..."); + bleKeyboard.press(KEY_LEFT_CTRL); + bleKeyboard.press(KEY_LEFT_ALT); + bleKeyboard.press(KEY_DELETE); + delay(100); + bleKeyboard.releaseAll(); + */ +} + +} // namespace + +void init() +{ + Serial.begin(COM_SPEED_SERIAL); + Serial.println("Starting BLE Keyboard sample!"); + bleKeyboard.begin(); + + procTimer.initializeMs(1000, loop).start(); +} diff --git a/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/component.mk b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/component.mk new file mode 100644 index 0000000000..0140a4bec6 --- /dev/null +++ b/Sming/Libraries/BLEKeyboard/samples/Bluetooth_Keyboard/component.mk @@ -0,0 +1 @@ +COMPONENT_DEPENDS := BLEKeyboard diff --git a/Sming/Libraries/NimBLE/README.rst b/Sming/Libraries/NimBLE/README.rst new file mode 100644 index 0000000000..0313349fb2 --- /dev/null +++ b/Sming/Libraries/NimBLE/README.rst @@ -0,0 +1,24 @@ +ESP32 NimBLE +============ + +.. highlight:: c++ + +Introduction +------------ +NimBLE is a completely open source Bluetooth Low Energy (BLE) stack produced by `Apache `_. +It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif. + +Using +----- + +1. Add ``COMPONENT_DEPENDS += NimBLE`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + void init() + { + // ... + + BLEDevice::init(""); + } diff --git a/Sming/Libraries/NimBLE/component.mk b/Sming/Libraries/NimBLE/component.mk new file mode 100644 index 0000000000..dd9d540ce3 --- /dev/null +++ b/Sming/Libraries/NimBLE/component.mk @@ -0,0 +1,6 @@ +COMPONENT_SUBMODULES := esp-nimble-cpp + +COMPONENT_SOC := esp32 esp32c3 esp32s3 + +COMPONENT_SRCDIRS := esp-nimble-cpp/src +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) diff --git a/Sming/Libraries/NimBLE/esp-nimble-cpp b/Sming/Libraries/NimBLE/esp-nimble-cpp new file mode 160000 index 0000000000..9e5db157f8 --- /dev/null +++ b/Sming/Libraries/NimBLE/esp-nimble-cpp @@ -0,0 +1 @@ +Subproject commit 9e5db157f88444bb95415e08a92c7eb817ff533d diff --git a/Sming/Libraries/SwitchJoycon/.cs b/Sming/Libraries/SwitchJoycon/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/SwitchJoycon/README.rst b/Sming/Libraries/SwitchJoycon/README.rst new file mode 100644 index 0000000000..537b2c9a4a --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/README.rst @@ -0,0 +1,76 @@ +Switch Joycon +============= + +.. highlight:: c++ + +Introduction +------------ +This library allows you to make the ESP32 act as a Nintendo Switch Joycon and control what it does. +The library uses :library:`NimBLE` for faster and lighter communication. + +Disclaimer +---------- +We are not affiliated, associated, authorized, endorsed by, or in any way officially connected with Nintendo, +or any of its subsidiaries or its affiliates. +The names Nintendo, Nintendo Switch and Joycon as well as related names, marks, emblems and images are +registered trademarks of their respective owners. + +Features +-------- + +Using this library you can do the following: + + - Button press and release (16 buttons) + - Switch Hat (1 hat ) + - Rotate 4 Axis + +Using +----- + +1. Add ``COMPONENT_DEPENDS += SwitchJoycon`` to your application componenent.mk file. +2. Add these lines to your application:: + + #include + + namespace + { + SwitchJoycon joycon; + + // ... + + } // namespace + + void init() + { + // ... + + joycon.begin(); + } + + +Notes +----- +By default, reports are sent on every button press/release or axis/hat movement, however this can be disabled:: + + joycon.setAutoReport(false); + +and then you should manually call sendReport on the joycon instance as shown below:: + + joycon.sendReport(); + + +HID Debugging +------------- + +On Linux you can install `hid-tools `__ using the command below:: + + sudo pip3 install . + +Once installed hid-recorder can be used to check the device HID report description and sniff the different reports:: + + sudo hid-recorder + +Useful Links +------------ +- `Tutorial about USB HID Report Descriptors `__ +- `HID constants `__ diff --git a/Sming/Libraries/SwitchJoycon/component.mk b/Sming/Libraries/SwitchJoycon/component.mk new file mode 100644 index 0000000000..e07e0f70a7 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/component.mk @@ -0,0 +1,4 @@ +COMPONENT_DEPENDS := NimBLE + +COMPONENT_SRCDIRS := src +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) \ No newline at end of file diff --git a/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/.cs b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/Makefile b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/Makefile new file mode 100644 index 0000000000..ff51b6c3a7 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/Makefile @@ -0,0 +1,9 @@ +##################################################################### +#### Please don't change this file. Use component.mk instead #### +##################################################################### + +ifndef SMING_HOME +$(error SMING_HOME is not set: please configure it as an environment variable) +endif + +include $(SMING_HOME)/project.mk diff --git a/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/README.rst b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/README.rst new file mode 100644 index 0000000000..94e0171a65 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/README.rst @@ -0,0 +1,23 @@ +Switch Joycon +============= + +Introduction +------------ +This sample turns the ESP32 into a Switch Joycon (Bluetooth LE gamepad) that presses buttons and moves axis + +Possible buttons are 0 through to 15. + +Possible HAT switch position values are: +Centered, Up, UpRight, Right, DownRight, Down, DownLeft, Left, UpLeft. + + +Testing +------- + +You can use one of the following applications on your PC to test and see all buttons that were clicked. + +On Linux install ``jstest-gtk`` to test the ESP32 gamepad. Under Ubuntu this can be done by typing the following command:: + + sudo apt install jstest-gtk + +On Windows use this `Windows test application `__. \ No newline at end of file diff --git a/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/app/application.cpp b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/app/application.cpp new file mode 100644 index 0000000000..caa9ef8fe4 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/app/application.cpp @@ -0,0 +1,54 @@ +#include +#include + +namespace +{ +Timer procTimer; + +void onConnect(NimBLEServer& server); +void onDisconnect(NimBLEServer& server); + +SwitchJoycon joycon(SwitchJoycon::Type::Left, 100, onConnect, onDisconnect); + +void loop() +{ + if(!joycon.isConnected()) { + return; + } + + uint8_t button = random(0, 15); + + joycon.press(button); + joycon.setHat(SwitchJoycon::JoystickPosition::UpLeft); + delay(5000); + + joycon.release(button); + joycon.setHat(SwitchJoycon::JoystickPosition::Center); + delay(5000); +} + +void onConnect(NimBLEServer& server) +{ + Serial.println("Connected :) !"); + + procTimer.initializeMs(500, loop).start(); +} + +void onDisconnect(NimBLEServer& server) +{ + procTimer.stop(); + Serial.println("Disconnected :(!"); +} + +} // namespace + +void init() +{ + Serial.begin(COM_SPEED_SERIAL); + Serial.systemDebugOutput(true); + + Serial.println("Starting Joycon Gamepad sample!"); + joycon.begin(); + // Auto reporting is enabled by default. + // Use joycon.setAutoReport(false); to disable auto reporting, and then use joycon.sendReport(); as needed +} diff --git a/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/component.mk b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/component.mk new file mode 100644 index 0000000000..1b24857470 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/samples/Bluetooth_Joycon/component.mk @@ -0,0 +1 @@ +COMPONENT_DEPENDS := SwitchJoycon diff --git a/Sming/Libraries/SwitchJoycon/src/.cs b/Sming/Libraries/SwitchJoycon/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.cpp b/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.cpp new file mode 100644 index 0000000000..75f10086e9 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.cpp @@ -0,0 +1,438 @@ +#include "SwitchJoycon.h" + +#include +#include +#include +#include +#include +#include + +#if DEBUG_VERBOSE_LEVEL == 3 +#include +HexDump dump; +#endif + +// TODO: Move report description to progmem +uint8_t tempHidReportDescriptor[150]; +int hidReportDescriptorSize = 0; + +constexpr uint8_t GAMEPAD_DEFAULT_REPORT_ID = 63; +constexpr uint8_t JOYSTICK_TYPE_GAMEPAD = 0x05; + +void SwitchJoycon::resetButtons() +{ + memset(&state.buttons, 0, sizeof(state.buttons)); +} + +bool SwitchJoycon::begin() +{ + if(started) { + debug_w("Service already started"); + return false; + } + + uint8_t axisCount = 0; + buttonCount = 0; + hatSwitchCount = 0; + switch(controllerType) { + case Type::Left: + /* fall through */ + case Type::Right: + buttonCount = 16; // buttonCount; + hatSwitchCount = 1; + axisCount = 4; // x, y, z and z rotation + break; + case Type::ProController: + buttonCount = 16; // buttonCount; + hatSwitchCount = 1; + axisCount = 4; // x, y, z and z rotation + break; + } + + started = true; + state.hat = static_cast(JoystickPosition::Center); + state.leftX[0] = 0x00; + state.leftX[1] = 0x80; + state.leftY[0] = 0x00; + state.leftY[1] = 0x80; + state.rightX[0] = 0x00; + state.rightX[1] = 0x80; + state.rightY[0] = 0x00; + state.rightY[1] = 0x80; + + /** + * For HID debugging see: https://gitlab.freedesktop.org/libevdev/hid-tools + * For HID report descriptors see: https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ + */ + + hidReportDescriptorSize = 0; + + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_PAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE (Joystick - 0x04; Gamepad - 0x05; Multi-axis Controller - 0x08) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = JOYSTICK_TYPE_GAMEPAD; + + // COLLECTION (Application) + tempHidReportDescriptor[hidReportDescriptorSize++] = COLLECTION(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_ID (Default: 3) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_ID(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = GAMEPAD_DEFAULT_REPORT_ID; + + if(buttonCount > 0) { + // USAGE_PAGE (Button) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_PAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + + // USAGE_MINIMUM (Button 1) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_MINIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE_MAXIMUM (Button 16) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_MAXIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = buttonCount; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MINIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MAXIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_SIZE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (# of buttons) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_COUNT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = buttonCount; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = HIDINPUT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + } // buttonCount + + if(hatSwitchCount > 0) { + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_PAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE (Hat Switch) + for(int i = 0; i < hatSwitchCount; i++) { + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x39; + } + + // Logical Min (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MINIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // Logical Max (7) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MAXIMUM(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x07; + + // Report Size (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_SIZE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // Report Count (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_COUNT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = hatSwitchCount; + + // Input (Data, Variable, Absolute) + tempHidReportDescriptor[hidReportDescriptorSize++] = HIDINPUT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x42; + + // -- Padding for the 4 unused bits in the hat switch byte -- + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_PAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + + // Report Size (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_SIZE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // Report Count (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_COUNT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // Input (Cnst,Arr,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = HIDINPUT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + } + + if(axisCount > 0) { + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE_PAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE (X) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x30; + + // USAGE (Y) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x31; + + // USAGE (Rx) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x33; + + // USAGE (Ry) + tempHidReportDescriptor[hidReportDescriptorSize++] = USAGE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x34; + + // LOGICAL_MINIMUM(255) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MINIMUM(2); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (255) + tempHidReportDescriptor[hidReportDescriptorSize++] = LOGICAL_MAXIMUM(3); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // REPORT_SIZE (16) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_SIZE(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x10; + + // REPORT_COUNT (axisCount) + tempHidReportDescriptor[hidReportDescriptorSize++] = REPORT_COUNT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = axisCount; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = HIDINPUT(1); + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + } + + // END_COLLECTION + tempHidReportDescriptor[hidReportDescriptorSize++] = END_COLLECTION(0); + + xTaskCreate(startServer, "server", 20000, (void*)this, 5, &taskHandle); + + return true; +} + +void SwitchJoycon::end() +{ + if(!started) { + return; + } + + if(taskHandle != nullptr) { + vTaskDelete(taskHandle); + } + + NimBLEDevice::deinit(true); + delete hid; + hid = nullptr; + delete inputGamepad; + inputGamepad = nullptr; + connectionStatus = nullptr; + memset(&state, 0, sizeof(state)); + + started = false; +} + +void SwitchJoycon::sendReport(void) +{ + if(!isConnected()) { + return; + } + + debug_d("Sending report ...."); + +#if DEBUG_VERBOSE_LEVEL == 3 + dump.resetAddr(); + dump.print(reinterpret_cast(&state), sizeof(state)); +#endif + + debug_d("================="); + + this->inputGamepad->setValue(state); + this->inputGamepad->notify(); +} + +bool SwitchJoycon::isPressed(uint8_t button) +{ + uint8_t index = button / 8; + uint8_t bit = button % 8; + + return bitRead(state.buttons[index], bit); +} +void SwitchJoycon::press(uint8_t button) +{ + if(isPressed(button)) { + return; + } + + uint8_t index = button / 8; + uint8_t bit = button % 8; + + bitSet(state.buttons[index], bit); + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::release(uint8_t button) +{ + if(!isPressed(button)) { + return; + } + + uint8_t index = button / 8; + uint8_t bit = button % 8; + + bitClear(state.buttons[index], bit); + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::setHat(JoystickPosition position) +{ + if(state.hat == static_cast(position)) { + return; + } + + state.hat = static_cast(position); + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::setXAxis(int16_t value) +{ + // TODO: add value checks + + state.leftX[0] = value; + state.leftX[1] = value >> 8; + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::setYAxis(int16_t value) +{ + // TODO: add value checks + + state.leftY[0] = value; + state.leftY[1] = value >> 8; + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::setZAxis(int16_t value) +{ + // TODO: add value checks + // if(value == -32768) { + // value = -32767; + // } + + state.rightX[0] = value; + state.rightX[1] = value >> 8; + + if(autoReport) { + sendReport(); + } +} + +void SwitchJoycon::setZAxisRotation(int16_t value) +{ + // TODO: add value checks + + state.rightY[0] = value; + state.rightY[1] = value >> 8; + + if(autoReport) { + sendReport(); + } +} + +bool SwitchJoycon::isConnected(void) +{ + if(connectionStatus == nullptr) { + return false; + } + + return connectionStatus->connected; +} + +void SwitchJoycon::setBatteryLevel(uint8_t level) +{ + batteryLevel = level; + if(hid != nullptr) { + hid->setBatteryLevel(batteryLevel); + } +} + +void SwitchJoycon::startServer(void* arg) +{ + SwitchJoycon* joycon = static_cast(arg); + + String deviceName; + uint16_t productId = 0; + // See: http://gtoal.com/vectrex/vecx-colour/SDL/src/joystick/controller_type.h + switch(joycon->controllerType) { + case Type::Left: + deviceName = F("Joy-Con (L)"); + productId = 0x2006; + break; + case Type::Right: + deviceName = F("Joy-Con (R)"); + productId = 0x2007; + break; + case Type::ProController: + deviceName = F("Pro Controller"); + productId = 0x2009; + break; + } + + NimBLEDevice::init(deviceName.c_str()); + NimBLEServer* server = NimBLEDevice::createServer(); + server->setCallbacks(joycon->connectionStatus); + + delete joycon->hid; // TODO: ?! + joycon->hid = new NimBLEHIDDevice(server); + joycon->inputGamepad = joycon->hid->inputReport(GAMEPAD_DEFAULT_REPORT_ID); + joycon->connectionStatus->inputGamepad = joycon->inputGamepad; + + joycon->hid->manufacturer()->setValue("Nintendo"); + joycon->hid->pnp(0x01, __builtin_bswap16(0x057e), __builtin_bswap16(productId), 0x0110); + joycon->hid->hidInfo(0x00, 0x01); + + NimBLEDevice::setSecurityAuth(true, true, true); + +#if DEBUG_VERBOSE_LEVEL == 3 + dump.resetAddr(); + dump.print(tempHidReportDescriptor, hidReportDescriptorSize); +#endif + + joycon->hid->reportMap(tempHidReportDescriptor, hidReportDescriptorSize); + joycon->hid->startServices(); + + joycon->onStarted(server); + + NimBLEAdvertising* pAdvertising = server->getAdvertising(); + pAdvertising->setAppearance(HID_GAMEPAD); + pAdvertising->addServiceUUID(joycon->hid->hidService()->getUUID()); + pAdvertising->start(); + joycon->hid->setBatteryLevel(joycon->batteryLevel); + + debug_d("Advertising started!"); + + vTaskDelay(portMAX_DELAY); +} diff --git a/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.h b/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.h new file mode 100644 index 0000000000..86a2e63011 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/src/SwitchJoycon.h @@ -0,0 +1,154 @@ +#pragma once + +#include + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "nimconfig.h" +#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) + +#include "SwitchJoyconConnection.h" +#include +#include + +class SwitchJoycon +{ +public: + enum class Type { + Left = 0, + Right, + ProController = 3, + }; + + enum class Button { + ButtonA = 0, + ButtonX, + ButtonB, + ButtonY, + ButtonSl, + ButtonSr, + + ButtonMunus = 8, + ButtonPlus, + + ButtonHome = 12, + ButtonCapture, + ButtonStickrl, + ButtonZrl, + }; + + enum class JoystickPosition { + Right = 0, + DownRight, + Down, + DownLeft, + Left, + UpLeft, + Up, + UpRight, + Center, + }; + + struct Gamepad // {00 00} 08 {00 80} {00 80} {00 80} {00 80} + { + uint8_t buttons[2]; + uint8_t hat; + uint8_t leftX[2]; + uint8_t leftY[2]; + uint8_t rightX[2]; + uint8_t rightY[2]; + }; + + SwitchJoycon(Type type, uint8_t batteryLevel = 100, SwitchJoyconConnection::Callback onConnected = nullptr, + SwitchJoyconConnection::Callback onDisconnected = nullptr) + : controllerType(type), batteryLevel(batteryLevel) + { + connectionStatus = new SwitchJoyconConnection(onConnected, onDisconnected); + } + + virtual ~SwitchJoycon() + { + end(); + } + + bool begin(); + + void end(); + + void setType(Type type) + { + controllerType = type; + } + + void setBatteryLevel(uint8_t level); + + // Buttons + + void press(Button button) + { + press(static_cast(button)); + } + + void press(uint8_t button); + + void release(Button button) + { + release(static_cast(button)); + } + + void release(uint8_t button); + + // Set Axis Values + + void setXAxis(int16_t value); + void setYAxis(int16_t value); + void setZAxis(int16_t value); + void setZAxisRotation(int16_t value); + + // Hat + + void setHat(JoystickPosition position); + + void setAutoReport(bool autoReport) + { + this->autoReport = autoReport; + } + + void sendReport(); + bool isPressed(uint8_t button); + bool isConnected(); + void resetButtons(); + +protected: + virtual void onStarted(NimBLEServer* pServer){}; + +private: + bool started{false}; + TaskHandle_t taskHandle{nullptr}; // owned + + // Joystick Type + Type controllerType; + + // Gamepad State + Gamepad state; + uint8_t batteryLevel{0}; + uint8_t buttonCount{0}; + uint8_t hatSwitchCount{0}; + + bool autoReport{true}; + size_t reportSize{0}; + + // HID Settings + NimBLEHIDDevice* hid{nullptr}; // owned + uint8_t hidReportId{0}; + + // Connection status and gamepad + SwitchJoyconConnection* connectionStatus{nullptr}; + NimBLECharacteristic* inputGamepad{nullptr}; // owned + + static void startServer(void* pvParameter); +}; + +#endif // CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#endif // CONFIG_BT_ENABLED diff --git a/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.cpp b/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.cpp new file mode 100644 index 0000000000..df2347e7d0 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.cpp @@ -0,0 +1,17 @@ +#include "SwitchJoyconConnection.h" + +void SwitchJoyconConnection::onConnect(NimBLEServer* server) +{ + connected = true; + if(connectCallback) { + connectCallback(*server); + } +} + +void SwitchJoyconConnection::onDisconnect(NimBLEServer* server) +{ + connected = false; + if(connectCallback) { + disconnectCallback(*server); + } +} diff --git a/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.h b/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.h new file mode 100644 index 0000000000..ffaaef0aa1 --- /dev/null +++ b/Sming/Libraries/SwitchJoycon/src/SwitchJoyconConnection.h @@ -0,0 +1,35 @@ +#pragma once + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include "nimconfig.h" +#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) + +#include +#include + +class SwitchJoyconConnection : public NimBLEServerCallbacks +{ +public: + using Callback = Delegate; + + bool connected{false}; + NimBLECharacteristic* inputGamepad{nullptr}; + + SwitchJoyconConnection(Callback onConnected = nullptr, Callback onDisconnected = nullptr) + { + connectCallback = onConnected; + disconnectCallback = onDisconnected; + } + + void onConnect(NimBLEServer* pServer); + void onDisconnect(NimBLEServer* pServer); + +private: + Callback connectCallback; + Callback disconnectCallback; +}; + +#endif // CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#endif // CONFIG_BT_ENABLED From 6cbbf6d7c2c4b3b598dd0baf52c747cc2bf65915 Mon Sep 17 00:00:00 2001 From: Mateusz Zakarczemny Date: Mon, 4 Jul 2022 11:01:15 +0200 Subject: [PATCH 05/58] More flexible distro detection (#2523) --- Tools/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/install.sh b/Tools/install.sh index 26f1c72939..0fb94d8107 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -76,10 +76,10 @@ DOWNLOADS="downloads" mkdir -p $DOWNLOADS # Identify package installer for distribution -if [ -n "$(grep debian /etc/os-release)" ]; then +if [ -n "$(command -v apt)" ]; then DIST=debian PKG_INSTALL="sudo apt-get install -y" -elif [ -n "$(grep fedora /etc/os-release)" ]; then +elif [ -n "$(command -v dnf)" ]; then DIST=fedora PKG_INSTALL="sudo dnf install -y" else From fa026fb7742c2bc6c1c60cb5d0df9cdcedc45997 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 15 Jul 2022 08:12:18 +0100 Subject: [PATCH 06/58] Fix RbootUpgrader to take notice of RBOOT_RTC_ENABLED (#2525) --- Sming/Arch/Esp8266/Platform/RTC.cpp | 2 +- Sming/Components/rboot/component.mk | 2 +- Sming/Libraries/Ota/component.mk | 2 ++ Sming/Libraries/Ota/src/Arch/Esp8266/RbootUpgrader.cpp | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Sming/Arch/Esp8266/Platform/RTC.cpp b/Sming/Arch/Esp8266/Platform/RTC.cpp index 5969cbf2a6..b06db69d65 100644 --- a/Sming/Arch/Esp8266/Platform/RTC.cpp +++ b/Sming/Arch/Esp8266/Platform/RTC.cpp @@ -14,7 +14,7 @@ RtcClass RTC; #define RTC_MAGIC 0x55aaaa55 -#define RTC_DES_ADDR 64 +#define RTC_DES_ADDR 64 + 3 ///< rBoot may require 3 words at start #define NS_PER_SECOND 1000000000 /** @brief Structure to hold RTC data diff --git a/Sming/Components/rboot/component.mk b/Sming/Components/rboot/component.mk index 3a99722dfc..7a88aac668 100644 --- a/Sming/Components/rboot/component.mk +++ b/Sming/Components/rboot/component.mk @@ -120,7 +120,7 @@ endif ifeq ($(RBOOT_RTC_ENABLED),1) # enable the temporary switch to rom feature - APP_CFLAGS += -DBOOT_RTC_ENABLED + GLOBAL_CFLAGS += -DBOOT_RTC_ENABLED endif ifeq ($(RBOOT_GPIO_ENABLED),1) diff --git a/Sming/Libraries/Ota/component.mk b/Sming/Libraries/Ota/component.mk index 964bde20cb..a06ea4d292 100644 --- a/Sming/Libraries/Ota/component.mk +++ b/Sming/Libraries/Ota/component.mk @@ -18,3 +18,5 @@ ifeq ($(COMPONENT_ARCH),Esp8266) endif COMPONENT_DOXYGEN_INPUT := src + +COMPONENT_RELINK_VARS += RBOOT_RTC_ENABLED diff --git a/Sming/Libraries/Ota/src/Arch/Esp8266/RbootUpgrader.cpp b/Sming/Libraries/Ota/src/Arch/Esp8266/RbootUpgrader.cpp index 50bbe5b372..b143b77126 100644 --- a/Sming/Libraries/Ota/src/Arch/Esp8266/RbootUpgrader.cpp +++ b/Sming/Libraries/Ota/src/Arch/Esp8266/RbootUpgrader.cpp @@ -50,7 +50,7 @@ bool RbootUpgrader::setBootPartition(Partition partition, bool save) { uint8_t slot = getSlotForPartition(partition); if(!save) { -#ifdef RBOOT_ENABLE_RTC +#ifdef BOOT_RTC_ENABLED return rboot_set_temp_rom(slot); #else return false; @@ -63,7 +63,7 @@ bool RbootUpgrader::setBootPartition(Partition partition, bool save) Partition RbootUpgrader::getRunningPartition() { uint8_t slot = rboot_get_current_rom(); -#ifdef RBOOT_ENABLE_RTC +#ifdef BOOT_RTC_ENABLED rboot_rtc_data rtc; if(rboot_get_rtc_data(&rtc) && rtc.last_mode == MODE_TEMP_ROM) { slot = rtc.last_rom; From b356d07422a7fdefb1d8dad3522c72424eec8ed9 Mon Sep 17 00:00:00 2001 From: Mateusz Zakarczemny Date: Tue, 19 Jul 2022 13:45:11 +0200 Subject: [PATCH 07/58] Update System.h with info about the deep sleep mode. (#2526) * Update System.h * Check documentation output, revise * Fix comments indentation. Co-authored-by: mikee47 Co-authored-by: Slavey Karadzhov --- Sming/Platform/System.h | 47 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/Sming/Platform/System.h b/Sming/Platform/System.h index 562e5d5074..ac5467527b 100644 --- a/Sming/Platform/System.h +++ b/Sming/Platform/System.h @@ -60,7 +60,7 @@ class ISystemReadyHandler } /** @brief Handle system ready events - */ + */ virtual void onSystemReady() = 0; }; @@ -112,8 +112,8 @@ class SystemClass static bool initialize(); /** @brief Check if system ready - * @retval bool True if system initialisation is complete and system is now ready - */ + * @retval bool True if system initialisation is complete and system is now ready + */ bool isReady() { return state == eSS_Ready; @@ -124,45 +124,56 @@ class SystemClass * @note A delay is often required to allow network callback code to complete correctly. * The restart is always deferred, either using the task queue (if deferMillis == 0) * or using a timer. This method always returns immediately. - */ + */ void restart(unsigned deferMillis = 0); /** @brief Set the CPU frequency - * @param freq Frequency to set CPU + * @param freq Frequency to set CPU * @retval bool true on success - */ + */ bool setCpuFrequency(CpuFrequency freq) { return system_update_cpu_freq(freq); } /** @brief Get the CPU frequency - * @retval CpuFrequency The frequency of the CPU - */ + * @retval CpuFrequency The frequency of the CPU + */ CpuFrequency getCpuFrequency() { return static_cast(system_get_cpu_freq()); } - /** @brief Enter deep sleep mode - * @param timeMilliseconds Quantity of milliseconds to remain in deep sleep mode - * @param options Deep sleep options - */ + /** @brief Enter deep sleep mode. + * Deep sleep turns off processor and keeps only the RTC memory active. + * @param timeMilliseconds Quantity of milliseconds to remain in deep sleep mode + * @param options Deep sleep options + * + * @note Determine reset cause like this: + * + * auto info = system_get_rst_info(); + * if(info->reason == REASON_DEEP_SLEEP_AWAKE) { + * // ... + * } + * + * @note ESP8266: Ensure GPIO 16 (XPD_DCDC) is connected to RST (EXT_RSTB). + * and call pinMode(16, WAKEUP_PULLUP) to enable wakeup from deep sleep. + */ bool deepSleep(uint32_t timeMilliseconds, DeepSleepOptions options = eDSO_RF_CAL_BY_INIT_DATA); /** @brief Set handler for system ready event - * @param readyHandler Function to handle event - * @note if system is ready, callback is executed immediately without deferral - */ + * @param readyHandler Function to handle event + * @note if system is ready, callback is executed immediately without deferral + */ void onReady(SystemReadyDelegate readyHandler) { queueCallback(readyHandler); } /** @brief Set handler for system ready event - * @param readyHandler Function to handle event - * @note if system is ready, callback is executed immediately without deferral - */ + * @param readyHandler Function to handle event + * @note if system is ready, callback is executed immediately without deferral + */ void onReady(ISystemReadyHandler* readyHandler) { if(readyHandler != nullptr) { From c126bb72551ae4d68abbb910cb6d8d58fb917f88 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 20 Jul 2022 08:15:34 +0100 Subject: [PATCH 08/58] Implement basic ESP32 deep sleep (#2527) * Propagate return value from `system_deep_sleep` * Implement basic ESP32 deep sleep --- .../Components/esp32/src/include/esp_sleep.h | 3 +- Sming/Arch/Esp32/Components/esp32/src/sleep.c | 9 +++-- .../Esp32/Components/esp32/src/system.cpp | 40 ++++++++++++------- .../Components/esp_hal/include/esp_sleep.h | 2 +- Sming/Arch/Host/Components/esp_hal/sleep.c | 3 +- .../Components/rp2040/src/include/esp_sleep.h | 2 +- .../Arch/Rp2040/Components/rp2040/src/sleep.c | 3 +- Sming/Platform/System.cpp | 3 +- 8 files changed, 41 insertions(+), 24 deletions(-) diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_sleep.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_sleep.h index 5aa2860b69..325c0df185 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_sleep.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_sleep.h @@ -2,6 +2,7 @@ #include #include +#include_next #ifdef __cplusplus extern "C" { @@ -13,7 +14,7 @@ enum sleep_type { MODEM_SLEEP_T, }; -void system_deep_sleep(uint32_t time_in_us); +bool system_deep_sleep(uint32_t time_in_us); bool system_deep_sleep_set_option(uint8_t option); /* These aren't defined in the RTOS SDK */ diff --git a/Sming/Arch/Esp32/Components/esp32/src/sleep.c b/Sming/Arch/Esp32/Components/esp32/src/sleep.c index 924e8f12b8..8b044ead7c 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/sleep.c +++ b/Sming/Arch/Esp32/Components/esp32/src/sleep.c @@ -1,13 +1,16 @@ -#include "include/esp_sleep.h" +#include #include -void system_deep_sleep(uint32_t time_in_us) +bool system_deep_sleep(uint32_t time_in_us) { + esp_deep_sleep(time_in_us); + return true; } bool system_deep_sleep_set_option(uint8_t option) { - return false; + (void)option; // Ignore + return true; } /* GPIO */ diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index 8633b37252..65063ad2fd 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -13,20 +13,32 @@ uint32_t system_get_time(void) struct rst_info* system_get_rst_info(void) { static rst_info info{}; - auto reason = esp_reset_reason(); - switch(reason) { - case ESP_RST_INT_WDT: - info.reason = REASON_SOFT_WDT_RST; - break; - case ESP_RST_BROWNOUT: - info.reason = REASON_WDT_RST; - break; - case ESP_RST_SDIO: - info.reason = REASON_SOFT_RESTART; - break; - default: - info.reason = reason; - } + + auto translateReason = [](uint8_t reason) -> uint8_t { + switch(reason) { + case ESP_RST_EXT: + case ESP_RST_BROWNOUT: + return REASON_EXT_SYS_RST; + case ESP_RST_PANIC: + return REASON_EXCEPTION_RST; + case ESP_RST_INT_WDT: + return REASON_SOFT_WDT_RST; + case ESP_RST_TASK_WDT: + case ESP_RST_WDT: + return REASON_WDT_RST; + case ESP_RST_DEEPSLEEP: + return REASON_DEEP_SLEEP_AWAKE; + case ESP_RST_SW: + case ESP_RST_SDIO: + return REASON_SOFT_RESTART; + case ESP_RST_UNKNOWN: + case ESP_RST_POWERON: + default: + return REASON_DEFAULT_RST; + } + }; + + info.reason = translateReason(esp_reset_reason()); return &info; } diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h b/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h index 83436d1b3d..82b4dfc028 100644 --- a/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h @@ -15,7 +15,7 @@ enum sleep_type { typedef void (*fpm_wakeup_cb)(void); -void system_deep_sleep(uint32_t time_in_us); +bool system_deep_sleep(uint32_t time_in_us); bool system_deep_sleep_set_option(uint8_t option); /* Forced sleep */ diff --git a/Sming/Arch/Host/Components/esp_hal/sleep.c b/Sming/Arch/Host/Components/esp_hal/sleep.c index 2c4880ccdc..d3aacca753 100644 --- a/Sming/Arch/Host/Components/esp_hal/sleep.c +++ b/Sming/Arch/Host/Components/esp_hal/sleep.c @@ -1,7 +1,8 @@ #include "include/esp_sleep.h" -void system_deep_sleep(uint32_t time_in_us) +bool system_deep_sleep(uint32_t time_in_us) { + return false; } bool system_deep_sleep_set_option(uint8_t option) 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 39d168354a..cda67e0fa1 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h +++ b/Sming/Arch/Rp2040/Components/rp2040/src/include/esp_sleep.h @@ -12,7 +12,7 @@ enum sleep_type { MODEM_SLEEP_T, }; -void system_deep_sleep(uint32_t time_in_us); +bool system_deep_sleep(uint32_t time_in_us); bool system_deep_sleep_set_option(uint8_t option); #ifdef __cplusplus diff --git a/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c b/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c index 6b6b38c998..9599aba2a9 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c +++ b/Sming/Arch/Rp2040/Components/rp2040/src/sleep.c @@ -1,7 +1,8 @@ #include "include/esp_sleep.h" -void system_deep_sleep(uint32_t time_in_us) +bool system_deep_sleep(uint32_t time_in_us) { + return false; } bool system_deep_sleep_set_option(uint8_t option) diff --git a/Sming/Platform/System.cpp b/Sming/Platform/System.cpp index f661d942fd..9d9aca0452 100644 --- a/Sming/Platform/System.cpp +++ b/Sming/Platform/System.cpp @@ -135,6 +135,5 @@ bool SystemClass::deepSleep(uint32_t timeMilliseconds, DeepSleepOptions options) return false; } // Note: In SDK Version 3+ system_deep_sleep() returns bool but it's void before that - system_deep_sleep(timeMilliseconds * 1000); - return true; + return system_deep_sleep(timeMilliseconds * 1000ULL); } From afa167e1ce47f61c4b5c2919d5cb8b23ef60a070 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 20 Jul 2022 08:16:43 +0100 Subject: [PATCH 09/58] Esp32 fixes (#2528) * Fix GPIO18/19 for ESP32-C3 Use HAL to control IO MUX which includes additional steps to disable internal USB. * Fix ESP32 hardware timer * Configure esp32 WiFi station for full scan and pick one with best signal If multiple APs exist for same SSID then picking first one found (fast scan) can cause reliability problems if signal strength is low --- Sming/Arch/Esp32/Components/driver/hw_timer.cpp | 8 +++++--- Sming/Arch/Esp32/Components/driver/uart.cpp | 5 +++-- Sming/Arch/Esp32/Core/Digital.cpp | 2 +- .../Network/Arch/Esp32/Platform/StationImpl.cpp | 4 ++++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Sming/Arch/Esp32/Components/driver/hw_timer.cpp b/Sming/Arch/Esp32/Components/driver/hw_timer.cpp index 73c1351342..63af06d45f 100644 --- a/Sming/Arch/Esp32/Components/driver/hw_timer.cpp +++ b/Sming/Arch/Esp32/Components/driver/hw_timer.cpp @@ -9,6 +9,7 @@ ****/ #include +#include #include #include @@ -36,11 +37,11 @@ void IRAM_ATTR timerIsr(void* arg) timer_hal_clear_intr_status(&timer.hal); - if(timer.autoload) { - timer_hal_set_alarm_enable(&timer.hal, true); - } else { + if(!timer.autoload) { timer_hal_set_counter_enable(&timer.hal, false); } + + timer_hal_set_alarm_enable(&timer.hal, true); } } // namespace @@ -102,6 +103,7 @@ 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); diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index 6808f46636..4a7f93bc59 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace { @@ -757,14 +758,14 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) auto& conn = uart_periph_signal[uart->uart_nr]; if(tx_pin != UART_PIN_NO_CHANGE) { - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_pin], PIN_FUNC_GPIO); + gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[tx_pin], PIN_FUNC_GPIO); gpio_set_level(gpio_num_t(tx_pin), true); gpio_matrix_out(tx_pin, conn.tx_sig, false, false); uart->tx_pin = tx_pin; } if(rx_pin != UART_PIN_NO_CHANGE) { - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_pin], PIN_FUNC_GPIO); + 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); gpio_matrix_in(rx_pin, conn.rx_sig, false); diff --git a/Sming/Arch/Esp32/Core/Digital.cpp b/Sming/Arch/Esp32/Core/Digital.cpp index 1fbc854d9a..92028643f4 100644 --- a/Sming/Arch/Esp32/Core/Digital.cpp +++ b/Sming/Arch/Esp32/Core/Digital.cpp @@ -82,7 +82,7 @@ void pinMode(uint16_t pin, uint8_t mode) gpio_ll_pullup_dis(&GPIO, gpio); } - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); + gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); } //Detect if pin is input diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index cc4ae57c90..4609bed48c 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -186,6 +186,10 @@ bool StationImpl::config(const Config& cfg) config.sta.bssid_set = false; } + // Find *all* APs for the requested SSID and pick the best one + config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; + enable(true, cfg.save); if(cfg.save) { From fa95914416b980814827e51724eb2999df9b8687 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 20 Jul 2022 08:17:53 +0100 Subject: [PATCH 10/58] Allow use of static and global File, Directory objects (#2529) Added simple default filesystem mechanism for `FsBase` objects. File system is passed to constructor, but null is now interpreted as 'default file system'. Sming implements the `IFS::getDefaultFileSystem()` function. --- Sming/Components/IFS | 2 +- Sming/Core/Data/Stream/FileStream.h | 4 +--- Sming/Core/FileSystem.cpp | 9 +++++++++ Sming/Core/FileSystem.h | 22 ++-------------------- 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 9dbc293071..a736cae1b7 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 9dbc29307169c426ab5c9e6eab1b8cf0dcedfa4a +Subproject commit a736cae1b795b70560ebdd425b7329b3bec23fa2 diff --git a/Sming/Core/Data/Stream/FileStream.h b/Sming/Core/Data/Stream/FileStream.h index 013ebf7de0..a2fa544c75 100644 --- a/Sming/Core/Data/Stream/FileStream.h +++ b/Sming/Core/Data/Stream/FileStream.h @@ -20,9 +20,7 @@ class FileStream : public IFS::FileStream { public: - FileStream() : IFS::FileStream(::getFileSystem()) - { - } + using IFS::FileStream::FileStream; /** @brief Create a file stream * @param fileName Name of file to open diff --git a/Sming/Core/FileSystem.cpp b/Sming/Core/FileSystem.cpp index 92f1e08ea6..b7ac70b2a8 100644 --- a/Sming/Core/FileSystem.cpp +++ b/Sming/Core/FileSystem.cpp @@ -17,6 +17,15 @@ namespace SmingInternal IFS::FileSystem* activeFileSystem; } +namespace IFS +{ +FileSystem* getDefaultFileSystem() +{ + return SmingInternal::activeFileSystem; +} + +} // namespace IFS + void fileSetFileSystem(IFS::IFileSystem* fileSystem) { if(SmingInternal::activeFileSystem != fileSystem) { diff --git a/Sming/Core/FileSystem.h b/Sming/Core/FileSystem.h index 179d875837..572c1950a9 100644 --- a/Sming/Core/FileSystem.h +++ b/Sming/Core/FileSystem.h @@ -29,6 +29,8 @@ using FileAttribute = IFS::FileAttribute; using FileAttributes = IFS::FileAttributes; using FileStat = IFS::Stat; using FileNameStat = IFS::NameStat; +using File = IFS::File; +using Directory = IFS::Directory; constexpr int FS_OK = IFS::FS_OK; namespace SmingInternal @@ -45,26 +47,6 @@ extern IFS::FileSystem* activeFileSystem; } // namespace SmingInternal -class File : public IFS::File -{ -public: - File() : IFS::File(SmingInternal::activeFileSystem) - { - } -}; - -/** - * @brief Directory stream class - * @ingroup stream data - */ -class Directory : public IFS::Directory -{ -public: - Directory() : IFS::Directory(SmingInternal::activeFileSystem) - { - } -}; - /* * Boilerplate check for file function wrappers to catch undefined filesystem. */ From 0918a6d13afcf26c10104fe0f1ba5dbbd218c48a Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 25 Jul 2022 09:17:22 +0100 Subject: [PATCH 11/58] Initial board-level configuration support (#2530) * Add SoC pin lists, expand definitions and add boardtool * Add 'swap' attribute to peripheral * Fix some codacy issues --- Sming/Arch/Esp32/esp32-pindefs.txt | 300 ++++++++++++++++++ Sming/Arch/Esp32/esp32-soc.json | 123 +++++++- Sming/Arch/Esp32/esp32c3-pindefs.txt | 163 ++++++++++ Sming/Arch/Esp32/esp32c3-soc.json | 75 ++++- Sming/Arch/Esp32/esp32s2-pindefs.txt | 237 ++++++++++++++ Sming/Arch/Esp32/esp32s2-soc.json | 90 +++++- Sming/Arch/Esp32/esp32s3-pindefs.txt | 356 +++++++++++++++++++++ Sming/Arch/Esp32/esp32s3-soc.json | 110 ++++++- Sming/Arch/Esp8266/esp8266-pindefs.txt | 19 ++ Sming/Arch/Esp8266/esp8266-soc.json | 56 +++- Sming/Arch/Host/host-pindefs.txt | 0 Sming/Arch/Host/host-soc.json | 5 +- Sming/Arch/Rp2040/rp2040-pindefs.txt | 32 ++ Sming/Arch/Rp2040/rp2040-soc.json | 51 ++- Sming/project.mk | 17 +- Tools/boardtool.py | 416 +++++++++++++++++++++++++ Tools/requirements.txt | 1 + 17 files changed, 2043 insertions(+), 8 deletions(-) create mode 100644 Sming/Arch/Esp32/esp32-pindefs.txt create mode 100644 Sming/Arch/Esp32/esp32c3-pindefs.txt create mode 100644 Sming/Arch/Esp32/esp32s2-pindefs.txt create mode 100644 Sming/Arch/Esp32/esp32s3-pindefs.txt create mode 100644 Sming/Arch/Esp8266/esp8266-pindefs.txt create mode 100644 Sming/Arch/Host/host-pindefs.txt create mode 100644 Sming/Arch/Rp2040/rp2040-pindefs.txt create mode 100644 Tools/boardtool.py diff --git a/Sming/Arch/Esp32/esp32-pindefs.txt b/Sming/Arch/Esp32/esp32-pindefs.txt new file mode 100644 index 0000000000..aeaa4b2bb0 --- /dev/null +++ b/Sming/Arch/Esp32/esp32-pindefs.txt @@ -0,0 +1,300 @@ +[io_mux] +gpio pad f0 f1 f2 f3 f4 f5 reset notes +0 GPIO0 GPIO0 CLK_OUT1 GPIO0 - - EMAC_TX_CLK 3 R +1 U0TXD U0TXD CLK_OUT3 GPIO1 - - EMAC_RXD2 3 - +2 GPIO2 GPIO2 HSPIWP GPIO2 HS2_DATA0 SD_DATA0 - 2 R +3 U0RXD U0RXD CLK_OUT2 GPIO3 - - - 3 - +4 GPIO4 GPIO4 HSPIHD GPIO4 HS2_DATA1 SD_DATA1 EMAC_TX_ER 2 R +5 GPIO5 GPIO5 VSPICS0 GPIO5 HS1_DATA6 - EMAC_RX_CLK 3 - +6 SD_CLK SD_CLK SPICLK GPIO6 HS1_CLK U1CTS - 3 - +7 SD_DATA_0 SD_DATA0 SPIQ GPIO7 HS1_DATA0 U2RTS - 3 - +8 SD_DATA_1 SD_DATA1 SPID GPIO8 HS1_DATA1 U2CTS - 3 - +9 SD_DATA_2 SD_DATA2 SPIHD GPIO9 HS1_DATA2 U1RXD - 3 - +10 SD_DATA_3 SD_DATA3 SPIWP GPIO10 HS1_DATA3 U1TXD - 3 - +11 SD_CMD SD_CMD SPICS0 GPIO11 HS1_CMD U1RTS - 3 - +12 MTDI MTDI HSPIQ GPIO12 HS2_DATA2 SD_DATA2 EMAC_TXD3 2 R +13 MTCK MTCK HSPID GPIO13 HS2_DATA3 SD_DATA3 EMAC_RX_ER 2 R +14 MTMS MTMS HSPICLK GPIO14 HS2_CLK SD_CLK EMAC_TXD2 3 R +15 MTDO MTDO HSPICS0 GPIO15 HS2_CMD SD_CMD EMAC_RXD3 3 R +16 GPIO16 GPIO16 - GPIO16 HS1_DATA4 U2RXD EMAC_CLK_OUT 1 - +17 GPIO17 GPIO17 - GPIO17 HS1_DATA5 U2TXD EMAC_CLK_180 1 - +18 GPIO18 GPIO18 VSPICLK GPIO18 HS1_DATA7 - - 1 - +19 GPIO19 GPIO19 VSPIQ GPIO19 U0CTS - EMAC_TXD0 1 - +21 GPIO21 GPIO21 VSPIHD GPIO21 - - EMAC_TX_EN 1 - +22 GPIO22 GPIO22 VSPIWP GPIO22 U0RTS - EMAC_TXD1 1 - +23 GPIO23 GPIO23 VSPID GPIO23 HS1_STROBE - - 1 - +25 GPIO25 GPIO25 - GPIO25 - - EMAC_RXD0 0 R +26 GPIO26 GPIO26 - GPIO26 - - EMAC_RXD1 0 R +27 GPIO27 GPIO27 - GPIO27 - - EMAC_RX_DV 0 R +32 32K_XP GPIO32 - GPIO32 - - - 0 R +33 32K_XN GPIO33 - GPIO33 - - - 0 R +34 VDET_1 GPIO34 - GPIO34 - - - 0 R, I +35 VDET_2 GPIO35 - GPIO35 - - - 0 R, I +36 SENSOR_VP GPIO36 - GPIO36 - - - 0 R, I +37 SENSOR_CAPP GPIO37 - GPIO37 - - - 0 R, I +38 SENSOR_CAPN GPIO38 - GPIO38 - - - 0 R, I +39 SENSOR_VN GPIO39 - GPIO39 - - - 0 R, I + +[rtc_mux] +rtc gpio pad a0 a1 a2 f0 f1 notes +0 36 SENSOR_VP ADC_H ADC1_CH0 - RTC_GPIO0 - +1 37 SENSOR_CAPP ADC_H ADC1_CH1 - RTC_GPIO1 - +2 38 SENSOR_CAPN ADC_H ADC1_CH2 - RTC_GPIO2 - +3 39 SENSOR_VN ADC_H ADC1_CH3 - RTC_GPIO3 - +4 34 VDET_1 - ADC1_CH6 - RTC_GPIO4 - +5 35 VDET_2 - ADC1_CH7 - RTC_GPIO5 - +6 25 GPIO25 DAC_1 ADC2_CH8 - RTC_GPIO6 - +7 26 GPIO26 DAC_2 ADC2_CH9 - RTC_GPIO7 - +8 33 32K_XN XTAL_32K_N ADC1_CH5 TOUCH8 RTC_GPIO8 - +9 32 32K_XP XTAL_32K_P ADC1_CH4 TOUCH9 RTC_GPIO9 - +10 4 GPIO4 - ADC2_CH0 TOUCH0 RTC_GPIO10 I2C_SCL ∗ +11 0 GPIO0 - ADC2_CH1 TOUCH1 RTC_GPIO11 I2C_SDA ∗ +12 2 GPIO2 - ADC2_CH2 TOUCH2 RTC_GPIO12 I2C_SCL ∗ +13 15 MTDO - ADC2_CH3 TOUCH3 RTC_GPIO13 I2C_SDA ∗ +14 13 MTCK - ADC2_CH4 TOUCH4 RTC_GPIO14 - +15 12 MTDI - ADC2_CH5 TOUCH5 RTC_GPIO15 - +16 14 MTMS - ADC2_CH6 TOUCH6 RTC_GPIO16 - +17 27 GPIO27 - ADC2_CH7 TOUCH7 RTC_GPIO17 - + +[gpio_matrix] +signal input default same output enable +0 SPICLK_in 0 yes SPICLK_out SPICLK_oe +1 SPIQ_in 0 yes SPIQ_out SPIQ_oe +2 SPID_in 0 yes SPID_out SPID_oe +3 SPIHD_in 0 yes SPIHD_out SPIHD_oe +4 SPIWP_in 0 yes SPIWP_out SPIWP_oe +5 SPICS0_in 0 yes SPICS0_out SPICS0_oe +6 SPICS1_in 0 no SPICS1_out SPICS1_oe +7 SPICS2_in 0 no SPICS2_out SPICS2_oe +8 HSPICLK_in 0 yes HSPICLK_out HSPICLK_oe +9 HSPIQ_in 0 yes HSPIQ_out HSPIQ_oe +10 HSPID_in 0 yes HSPID_out HSPID_oe +11 HSPICS0_in 0 yes HSPICS0_out HSPICS0_oe +12 HSPIHD_in 0 yes HSPIHD_out HSPIHD_oe +13 HSPIWP_in 0 yes HSPIWP_out HSPIWP_oe +14 U0RXD_in 0 yes U0TXD_out 1’d1 +15 U0CTS_in 0 yes U0RTS_out 1’d1 +16 U0DSR_in 0 no U0DTR_out 1’d1 +17 U1RXD_in 0 yes U1TXD_out 1’d1 +18 U1CTS_in 0 yes U1RTS_out 1’d1 +23 I2S0O_BCK_in 0 no I2S0O_BCK_out 1’d1 +24 I2S1O_BCK_in 0 no I2S1O_BCK_out 1’d1 +25 I2S0O_WS_in 0 no I2S0O_WS_out 1’d1 +26 I2S1O_WS_in 0 no I2S1O_WS_out 1’d1 +27 I2S0I_BCK_in 0 no I2S0I_BCK_out 1’d1 +28 I2S0I_WS_in 0 no I2S0I_WS_out 1’d1 +29 I2CEXT0_SCL_in 1 no I2CEXT0_SCL_out 1’d1 +30 I2CEXT0_SDA_in 1 no I2CEXT0_SDA_out 1’d1 +31 pwm0_sync0_in 0 no sdio_tohost_int_out 1’d1 +32 pwm0_sync1_in 0 no pwm0_out0a 1’d1 +33 pwm0_sync2_in 0 no pwm0_out0b 1’d1 +34 pwm0_f0_in 0 no pwm0_out1a 1’d1 +35 pwm0_f1_in 0 no pwm0_out1b 1’d1 +36 pwm0_f2_in 0 no pwm0_out2a 1’d1 +37 - 0 no pwm0_out2b 1’d1 +39 pcnt_sig_ch0_in0 0 no - 1’d1 +40 pcnt_sig_ch1_in0 0 no - 1’d1 +41 pcnt_ctrl_ch0_in0 0 no - 1’d1 +42 pcnt_ctrl_ch1_in0 0 no - 1’d1 +43 pcnt_sig_ch0_in1 0 no - 1’d1 +44 pcnt_sig_ch1_in1 0 no - 1’d1 +45 pcnt_ctrl_ch0_in1 0 no - 1’d1 +46 pcnt_ctrl_ch1_in1 0 no - 1’d1 +47 pcnt_sig_ch0_in2 0 no - 1’d1 +48 pcnt_sig_ch1_in2 0 no - 1’d1 +49 pcnt_ctrl_ch0_in2 0 no - 1’d1 +50 pcnt_ctrl_ch1_in2 0 no - 1’d1 +51 pcnt_sig_ch0_in3 0 no - 1’d1 +52 pcnt_sig_ch1_in3 0 no - 1’d1 +53 pcnt_ctrl_ch0_in3 0 no - 1’d1 +54 pcnt_ctrl_ch1_in3 0 no - 1’d1 +55 pcnt_sig_ch0_in4 0 no - 1’d1 +56 pcnt_sig_ch1_in4 0 no - 1’d1 +57 pcnt_ctrl_ch0_in4 0 no - 1’d1 +58 pcnt_ctrl_ch1_in4 0 no - 1’d1 +61 HSPICS1_in 0 no HSPICS1_out HSPICS1_oe +62 HSPICS2_in 0 no HSPICS2_out HSPICS2_oe +63 VSPICLK_in 0 yes VSPICLK_out_mux VSPICLK_oe +64 VSPIQ_in 0 yes VSPIQ_out VSPIQ_oe +65 VSPID_in 0 yes VSPID_out VSPID_oe +66 VSPIHD_in 0 yes VSPIHD_out VSPIHD_oe +67 VSPIWP_in 0 yes VSPIWP_out VSPIWP_oe +68 VSPICS0_in 0 yes VSPICS0_out VSPICS0_oe +69 VSPICS1_in 0 no VSPICS1_out VSPICS1_oe +70 VSPICS2_in 0 no VSPICS2_out VSPICS2_oe +71 pcnt_sig_ch0_in5 0 no ledc_hs_sig_out0 1’d1 +72 pcnt_sig_ch1_in5 0 no ledc_hs_sig_out1 1’d1 +73 pcnt_ctrl_ch0_in5 0 no ledc_hs_sig_out2 1’d1 +74 pcnt_ctrl_ch1_in5 0 no ledc_hs_sig_out3 1’d1 +75 pcnt_sig_ch0_in6 0 no ledc_hs_sig_out4 1’d1 +76 pcnt_sig_ch1_in6 0 no ledc_hs_sig_out5 1’d1 +77 pcnt_ctrl_ch0_in6 0 no ledc_hs_sig_out6 1’d1 +78 pcnt_ctrl_ch1_in6 0 no ledc_hs_sig_out7 1’d1 +79 pcnt_sig_ch0_in7 0 no ledc_ls_sig_out0 1’d1 +80 pcnt_sig_ch1_in7 0 no ledc_ls_sig_out1 1’d1 +81 pcnt_ctrl_ch0_in7 0 no ledc_ls_sig_out2 1’d1 +82 pcnt_ctrl_ch1_in7 0 no ledc_ls_sig_out3 1’d1 +83 rmt_sig_in0 0 no ledc_ls_sig_out4 1’d1 +84 rmt_sig_in1 0 no ledc_ls_sig_out5 1’d1 +85 rmt_sig_in2 0 no ledc_ls_sig_out6 1’d1 +86 rmt_sig_in3 0 no ledc_ls_sig_out7 1’d1 +87 rmt_sig_in4 0 no rmt_sig_out0 1’d1 +88 rmt_sig_in5 0 no rmt_sig_out1 1’d1 +89 rmt_sig_in6 0 no rmt_sig_out2 1’d1 +90 rmt_sig_in7 0 no rmt_sig_out3 1’d1 +91 - - - rmt_sig_out4 1’d1 +92 - - - rmt_sig_out6 1’d1 +94 twai_rx 1 no rmt_sig_out7 1’d1 +95 I2CEXT1_SCL_in 1 no I2CEXT1_SCL_out 1’d1 +96 I2CEXT1_SDA_in 1 no I2CEXT1_SDA_out 1’d1 +97 host_card_detect_n_1 0 no host_ccmd_od_pullup_en_n 1’d1 +98 host_card_detect_n_2 0 no host_rst_n_1 1’d1 +99 host_card_write_prt_1 0 no host_rst_n_2 1’d1 +100 host_card_write_prt_2 0 no gpio_sd0_out 1’d1 +101 host_card_int_n_1 0 no gpio_sd1_out 1’d1 +102 host_card_int_n_2 0 no gpio_sd2_out 1’d1 +103 pwm1_sync0_in 0 no gpio_sd3_out 1’d1 +104 pwm1_sync1_in 0 no gpio_sd4_out 1’d1 +105 pwm1_sync2_in 0 no gpio_sd5_out 1’d1 +106 pwm1_f0_in 0 no gpio_sd6_out 1’d1 +107 pwm1_f1_in 0 no gpio_sd7_out 1’d1 +108 pwm1_f2_in 0 no pwm1_out0a 1’d1 +109 pwm0_cap0_in 0 no pwm1_out0b 1’d1 +110 pwm0_cap1_in 0 no pwm1_out1a 1’d1 +111 pwm0_cap2_in 0 no pwm1_out1b 1’d1 +112 pwm1_cap0_in 0 no pwm1_out2a 1’d1 +113 pwm1_cap1_in 0 no pwm1_out2b 1’d1 +114 pwm1_cap2_in 0 no pwm2_out1h 1’d1 +115 pwm2_flta 1 no pwm2_out1l 1’d1 +116 pwm2_fltb 1 no pwm2_out2h 1’d1 +117 pwm2_cap1_in 0 no pwm2_out2l 1’d1 +118 pwm2_cap2_in 0 no pwm2_out3h 1’d1 +119 pwm2_cap3_in 0 no pwm2_out3l 1’d1 +120 pwm3_flta 1 no pwm2_out4h 1’d1 +121 pwm3_fltb 1 no pwm2_out4l 1’d1 +122 pwm3_cap1_in 0 no - 1’d1 +123 pwm3_cap2_in 0 no twai_tx 1’d1 +124 pwm3_cap3_in 0 no twai_bus_off_on 1’d1 +125 - - - twai_clkout 1’d1 +140 I2S0I_DATA_in0 0 no I2S0O_DATA_out0 1’d1 +141 I2S0I_DATA_in1 0 no I2S0O_DATA_out1 1’d1 +142 I2S0I_DATA_in2 0 no I2S0O_DATA_out2 1’d1 +143 I2S0I_DATA_in3 0 no I2S0O_DATA_out3 1’d1 +144 I2S0I_DATA_in4 0 no I2S0O_DATA_out4 1’d1 +145 I2S0I_DATA_in5 0 no I2S0O_DATA_out5 1’d1 +146 I2S0I_DATA_in6 0 no I2S0O_DATA_out6 1’d1 +147 I2S0I_DATA_in7 0 no I2S0O_DATA_out7 1’d1 +148 I2S0I_DATA_in8 0 no I2S0O_DATA_out8 1’d1 +149 I2S0I_DATA_in9 0 no I2S0O_DATA_out9 1’d1 +150 I2S0I_DATA_in10 0 no I2S0O_DATA_out10 1’d1 +151 I2S0I_DATA_in11 0 no I2S0O_DATA_out11 1’d1 +152 I2S0I_DATA_in12 0 no I2S0O_DATA_out12 1’d1 +153 I2S0I_DATA_in13 0 no I2S0O_DATA_out13 1’d1 +154 I2S0I_DATA_in14 0 no I2S0O_DATA_out14 1’d1 +155 I2S0I_DATA_in15 0 no I2S0O_DATA_out15 1’d1 +156 - - - I2S0O_DATA_out16 1’d1 +157 - - - I2S0O_DATA_out17 1’d1 +158 - - - I2S0O_DATA_out18 1’d1 +159 - - - I2S0O_DATA_out19 1’d1 +160 - - - I2S0O_DATA_out20 1’d1 +161 - - - I2S0O_DATA_out21 1’d1 +162 - - - I2S0O_DATA_out22 1’d1 +163 - - - I2S0O_DATA_out23 1’d1 +164 I2S1I_BCK_in 0 no I2S1I_BCK_out 1’d1 +165 I2S1I_WS_in 0 no I2S1I_WS_out 1’d1 +166 I2S1I_DATA_in0 0 no I2S1O_DATA_out0 1’d1 +167 I2S1I_DATA_in1 0 no I2S1O_DATA_out1 1’d1 +168 I2S1I_DATA_in2 0 no I2S1O_DATA_out2 1’d1 +169 I2S1I_DATA_in3 0 no I2S1O_DATA_out3 1’d1 +170 I2S1I_DATA_in4 0 no I2S1O_DATA_out4 1’d1 +171 I2S1I_DATA_in5 0 no I2S1O_DATA_out5 1’d1 +172 I2S1I_DATA_in6 0 no I2S1O_DATA_out6 1’d1 +173 I2S1I_DATA_in7 0 no I2S1O_DATA_out7 1’d1 +174 I2S1I_DATA_in8 0 no I2S1O_DATA_out8 1’d1 +175 I2S1I_DATA_in9 0 no I2S1O_DATA_out9 1’d1 +121 pwm3_fltb 1 no pwm2_out4l 1’d1 +122 pwm3_cap1_in 0 no - 1’d1 +123 pwm3_cap2_in 0 no twai_tx 1’d1 +124 pwm3_cap3_in 0 no twai_bus_off_on 1’d1 +125 - - - twai_clkout 1’d1 +140 I2S0I_DATA_in0 0 no I2S0O_DATA_out0 1’d1 +141 I2S0I_DATA_in1 0 no I2S0O_DATA_out1 1’d1 +142 I2S0I_DATA_in2 0 no I2S0O_DATA_out2 1’d1 +143 I2S0I_DATA_in3 0 no I2S0O_DATA_out3 1’d1 +144 I2S0I_DATA_in4 0 no I2S0O_DATA_out4 1’d1 +145 I2S0I_DATA_in5 0 no I2S0O_DATA_out5 1’d1 +146 I2S0I_DATA_in6 0 no I2S0O_DATA_out6 1’d1 +147 I2S0I_DATA_in7 0 no I2S0O_DATA_out7 1’d1 +148 I2S0I_DATA_in8 0 no I2S0O_DATA_out8 1’d1 +149 I2S0I_DATA_in9 0 no I2S0O_DATA_out9 1’d1 +150 I2S0I_DATA_in10 0 no I2S0O_DATA_out10 1’d1 +151 I2S0I_DATA_in11 0 no I2S0O_DATA_out11 1’d1 +152 I2S0I_DATA_in12 0 no I2S0O_DATA_out12 1’d1 +153 I2S0I_DATA_in13 0 no I2S0O_DATA_out13 1’d1 +154 I2S0I_DATA_in14 0 no I2S0O_DATA_out14 1’d1 +155 I2S0I_DATA_in15 0 no I2S0O_DATA_out15 1’d1 +156 - - - I2S0O_DATA_out16 1’d1 +157 - - - I2S0O_DATA_out17 1’d1 +158 - - - I2S0O_DATA_out18 1’d1 +159 - - - I2S0O_DATA_out19 1’d1 +160 - - - I2S0O_DATA_out20 1’d1 +161 - - - I2S0O_DATA_out21 1’d1 +162 - - - I2S0O_DATA_out22 1’d1 +163 - - - I2S0O_DATA_out23 1’d1 +164 I2S1I_BCK_in 0 no I2S1I_BCK_out 1’d1 +165 I2S1I_WS_in 0 no I2S1I_WS_out 1’d1 +166 I2S1I_DATA_in0 0 no I2S1O_DATA_out0 1’d1 +167 I2S1I_DATA_in1 0 no I2S1O_DATA_out1 1’d1 +168 I2S1I_DATA_in2 0 no I2S1O_DATA_out2 1’d1 +169 I2S1I_DATA_in3 0 no I2S1O_DATA_out3 1’d1 +170 I2S1I_DATA_in4 0 no I2S1O_DATA_out4 1’d1 +171 I2S1I_DATA_in5 0 no I2S1O_DATA_out5 1’d1 +172 I2S1I_DATA_in6 0 no I2S1O_DATA_out6 1’d1 +173 I2S1I_DATA_in7 0 no I2S1O_DATA_out7 1’d1 +174 I2S1I_DATA_in8 0 no I2S1O_DATA_out8 1’d1 +175 I2S1I_DATA_in9 0 no I2S1O_DATA_out9 1’d1 +176 I2S1I_DATA_in10 0 no I2S1O_DATA_out10 1’d1 +177 I2S1I_DATA_in11 0 no I2S1O_DATA_out11 1’d1 +178 I2S1I_DATA_in12 0 no I2S1O_DATA_out12 1’d1 +179 I2S1I_DATA_in13 0 no I2S1O_DATA_out13 1’d1 +180 I2S1I_DATA_in14 0 no I2S1O_DATA_out14 1’d1 +181 I2S1I_DATA_in15 0 no I2S1O_DATA_out15 1’d1 +182 - - - I2S1O_DATA_out16 1’d1 +183 - - - I2S1O_DATA_out17 1’d1 +184 - - - I2S1O_DATA_out18 1’d1 +185 - - - I2S1O_DATA_out19 1’d1 +186 - - - I2S1O_DATA_out20 1’d1 +187 - - - I2S1O_DATA_out21 1’d1 +188 - - - I2S1O_DATA_out22 1’d1 +189 - - - I2S1O_DATA_out23 1’d1 +190 I2S0I_H_SYNC 0 no pwm3_out1h 1’d1 +191 I2S0I_V_SYNC 0 no pwm3_out1l 1’d1 +192 I2S0I_H_ENABLE 0 no pwm3_out2h 1’d1 +193 I2S1I_H_SYNC 0 no pwm3_out2l 1’d1 +194 I2S1I_V_SYNC 0 no pwm3_out3h 1’d1 +195 I2S1I_H_ENABLE 0 no pwm3_out3l 1’d1 +196 - - - pwm3_out4h 1’d1 +197 - - - pwm3_out4l 1’d1 +198 U2RXD_in 0 yes U2TXD_out 1’d1 +199 U2CTS_in 0 yes U2RTS_out 1’d1 +200 emac_mdc_i 0 no emac_mdc_o emac_mdc_oe +201 emac_mdi_i 0 no emac_mdo_o emac_mdo_o_e +202 emac_crs_i 0 no emac_crs_o emac_crs_oe +203 emac_col_i 0 no emac_col_o emac_col_oe +204 pcmfsync_in 0 no bt_audio0_irq 1’d1 +205 pcmclk_in 0 no bt_audio1_irq 1’d1 +206 pcmdin 0 no bt_audio2_irq 1’d1 +207 - - - ble_audio0_irq 1’d1 +208 - - - ble_audio1_irq 1’d1 +209 - - - ble_audio2_irq 1’d1 +210 - - - pcmfsync_out pcmfsync_en +211 - - - pcmclk_out pcmclk_en +212 - - - pcmdout pcmdout_en +213 - - - ble_audio_sync0_p 1’d1 +214 - - - ble_audio_sync1_p 1’d1 +215 - - - ble_audio_sync2_p 1’d1 +224 - - - sig_in_func224 1’d1 +225 - - - sig_in_func225 1’d1 +226 - - - sig_in_func226 1’d1 +227 - - - sig_in_func227 1’d1 +228 - - - sig_in_func228 1’d1 diff --git a/Sming/Arch/Esp32/esp32-soc.json b/Sming/Arch/Esp32/esp32-soc.json index a03565cef1..030df1d65d 100644 --- a/Sming/Arch/Esp32/esp32-soc.json +++ b/Sming/Arch/Esp32/esp32-soc.json @@ -1,4 +1,125 @@ { "variant": "esp32", - "name": "ESP32" + "name": "ESP32", + "peripherals": { + "ADC": { + "sigmask": "ADC.+" + }, + "BLUETOOTH": { + "sigmask": "ble_.+|bt_.+" + }, + "CLOCKS": { + "sigmask": "CLK_.+|XTAL_.+" + }, + "DAC": { + "sigmask": "DAC.+" + }, + "EMAC": { + "title": "Ethernet Media Access Controller", + "sigmask": "emac_.+|EMAC.+" + }, + "GPIO": { + "sigmask": "GPIO.+|RTC_GPIO.+" + }, + "I2C": { + "sigmask": "I2C.+" + }, + "I2S[0-1]": { + "sigmask": "I2S{idx}.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "LEDC": { + "title": "LED PWM Controller", + "sigmask": "ledc_.+" + }, + "PCM": { + "sigmask": "pcm.+" + }, + "PCNT": { + "title": "Pulse Count Controller", + "sigmask": "pcnt_.+" + }, + "MCPWM[0-1]": { + "title": "Motor Control PWM", + "sigmask": "pwm{idx}_.+" + }, + "PWM[2-3]": { + "title": "Undocumented", + "sigmask": "pwm{idx}_.+" + }, + "RMT": { + "title": "Remote Control Peripheral", + "sigmask": "rmt_.+" + }, + "SDIO": { + "title": "SDIO Slave Controller", + "sigmask": "sdio_.+|SD_.+" + }, + "SDHOST": { + "title": "SD/MMC Host Controller", + "sigmask": "host_.+|HS1_.+|HS2_.+" + }, + "SPI1": { + "sigmask": "SPI.+" + }, + "SPI2": { + "sigmask": "HSPI.+" + }, + "SPI3": { + "sigmask": "VSPI.+" + }, + "TOUCH": { + "sigmask": "TOUCH.+" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 1 + ], + "RXD": [ + "U0RXD", + 3 + ] + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD_out", + 18 + ], + "RXD": [ + "U1RXD_in", + 19 + ] + } + }, + "UART2": { + "sigmask": "U2.+", + "default": { + "TXD": [ + "U2TXD", + 17 + ], + "RXD": [ + "U2RXD", + 16 + ] + } + }, + "SIGMA_DELTA": { + "title": "8-channel Sigma-Delta modulator", + "sigmask": "gpio_sd.+" + }, + "TWAI": { + "title": "Two-wire Automotive Interface", + "sigmask": "twai_.+" + }, + "WIFI": {} + } } \ No newline at end of file diff --git a/Sming/Arch/Esp32/esp32c3-pindefs.txt b/Sming/Arch/Esp32/esp32c3-pindefs.txt new file mode 100644 index 0000000000..b2cd8847ae --- /dev/null +++ b/Sming/Arch/Esp32/esp32c3-pindefs.txt @@ -0,0 +1,163 @@ +[io_mux] +gpio pad f0 f1 f2 f3 drv reset notes +0 XTAL_32K_P GPIO0 GPIO0 - - 2 0 R +1 XTAL_32K_N 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* G +7 MTDO MTDO GPIO7 FSPID - 2 1 G +8 GPIO8 GPIO8 GPIO8 - - 2 1 - +9 GPIO9 GPIO9 GPIO9 - - 2 3 - +10 GPIO10 GPIO10 GPIO10 FSPICS0 - 2 1 G +11 VDD_SPI GPIO11 GPIO11 - - 2 0 - +12 SPIHD SPIHD GPIO12 - - 2 3 - +13 SPIWP SPIWP GPIO13 - - 2 3 - +14 SPICS0 SPICS0 GPIO14 - - 2 3 - +15 SPICLK SPICLK GPIO15 - - 2 3 - +16 SPID SPID GPIO16 - - 2 3 - +17 SPIQ SPIQ GPIO17 - - 2 3 - +18 GPIO18 GPIO18 GPIO18 - - 3 0 USB, G +19 GPIO19 GPIO19 GPIO19 - - 3 0 * USB +20 U0RXD U0RXD GPIO20 - - 2 1 G +21 U0TXD U0TXD GPIO21 - - 2 1 - + +[io_mux_ana] +gpio pad a0 a1 +0 XTAL_32K_P XTAL_32K_P ADC1_CH0 +1 XTAL_32K_N XTAL_32K_N ADC1_CH1 +2 GPIO2 - ADC1_CH2 +3 GPIO3 - ADC1_CH3 +4 MTMS - ADC1_CH4 + +[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 yes U0RTS_out 1’d1 no +8 U0DSR_in 0 no U0DTR_out 1’d1 no +9 U1RXD_in 0 yes U1TXD_out 1’d1 no +10 U1CTS_in 0 yes U1RTS_out 1’d1 no +11 U1DSR_in 0 no U1DTR_out 1’d1 no +12 I2S_MCLK_in 0 no I2S_MCLK_out 1’d1 no +13 I2SO_BCK_in 0 no I2SO_BCK_out 1’d1 no +14 I2SO_WS_in 0 no I2SO_WS_out 1’d1 no +15 I2SI_SD_in 0 no I2SO_SD_out 1’d1 no +16 I2SI_BCK_in 0 no I2SI_BCK_out 1’d1 no +17 I2SI_WS_in 0 no I2SI_WS_out 1’d1 no +18 gpio_bt_priority 0 no gpio_wlan_prio 1’d1 no +19 gpio_bt_active 0 no gpio_wlan_active 1’d1 no +20 - - - - 1’d1 no +21 - - - - 1’d1 no +22 - - - - 1’d1 no +23 - - - - 1’d1 no +24 - - - - 1’d1 no +25 - - - - 1’d1 no +26 - - - - 1’d1 no +27 - - - - 1’d1 no +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 - - - usb_jtag_tck 1’d1 no +37 - - - usb_jtag_tms 1’d1 no +38 - - - usb_jtag_tdi 1’d1 no +39 - - - usb_jtag_tdo 1’d1 no +40 - - - - 1’d1 no +41 - - - - 1’d1 no +42 - - - - 1’d1 no +43 - - - - 1’d1 no +44 - - - - 1’d1 no +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 rmt_sig_in0 0 no rmt_sig_out0 1’d1 no +52 rmt_sig_in1 0 no rmt_sig_out1 1’d1 no +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 - - - gpio_sd0_out 1’d1 no +56 - - - gpio_sd1_out 1’d1 no +57 - - - gpio_sd2_out 1’d1 no +58 - - - gpio_sd3_out 1’d1 no +59 - - - I2SO_SD1_out 1’d1 no +60 - - - - 1’d1 no +61 - - - - 1’d1 no +62 - - - - 1’d1 no +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 twai_rx 1 no twai_tx 1’d1 no +75 - - - twai_bus_off_on 1’d1 no +76 - - - twai_clkout 1’d1 no +77 - - - - 1’d1 no +78 - - - - 1’d1 no +79 - - - - 1’d1 no +80 - - - - 1’d1 no +81 - - - - 1’d1 no +82 - - - - 1’d1 no +83 - - - - 1’d1 no +84 - - - - 1’d1 no +85 - - - - 1’d1 no +86 - - - - 1’d1 no +87 - - - - 1’d1 no +88 - - - - 1’d1 no +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 - - - - 1’d1 no +102 - - - - 1’d1 no +103 - - - - 1’d1 no +104 - - - - 1’d1 no +105 - - - - 1’d1 no +106 - - - - 1’d1 no +107 - - - - 1’d1 no +108 - - - - 1’d1 no +109 - - - - 1’d1 no +110 - - - - 1’d1 no +111 - - - - 1’d1 no +112 - - - - 1’d1 no +113 - - - - 1’d1 no +114 - - - - 1’d1 no +115 - - - - 1’d1 no +116 - - - - 1’d1 no +117 - - - - 1’d1 no +118 - - - - 1’d1 no +119 - - - - 1’d1 no +120 - - - - 1’d1 no +121 - - - - 1’d1 no +122 - - - - 1’d1 no +123 - - - CLK_OUT_out1 1’d1 no +124 - - - CLK_OUT_out2 1’d1 no +125 - - - CLK_OUT_out3 1’d1 no +126 - - - SPICS1_out 1’d1 no +127 - - - usb_jtag_trst 1’d1 no diff --git a/Sming/Arch/Esp32/esp32c3-soc.json b/Sming/Arch/Esp32/esp32c3-soc.json index 4e0ac3bf2e..fab4882198 100644 --- a/Sming/Arch/Esp32/esp32c3-soc.json +++ b/Sming/Arch/Esp32/esp32c3-soc.json @@ -1,4 +1,77 @@ { "variant": "esp32c3", - "name": "ESP32-C3" + "name": "ESP32-C3", + "peripherals": { + "ADC": { + "sigmask": "ADC.+|ext_adc_start" + }, + "BLUETOOTH": { + "sigmask": "gpio_bt_.+" + }, + "CLOCKS": { + "sigmask": "CLK_.+|XTAL_.+" + }, + "GPIO": { + "sigmask": "GPIO.+" + }, + "I2C": { + "sigmask": "I2C.+" + }, + "I2S": { + "sigmask": "I2S.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "LEDC": { + "sigmask": "ledc_.+" + }, + "RMT": { + "sigmask": "rmt_.+" + }, + "SIGMA_DELTA": { + "sigmask": "gpio_sd.+" + }, + "SPI1": { + "sigmask": "SPI.+" + }, + "SPI2": { + "sigmask": "FSPI.+" + }, + "TWAI": { + "sigmask": "twai_.+" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 21 + ], + "RXD": [ + "U0RXD", + 20 + ] + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD_out", + 10 + ], + "RXD": [ + "U1RXD_in", + 9 + ] + } + }, + "USB_JTAG": { + "sigmask": "usb_jtag_.+" + }, + "WIFI": { + "sigmask": "gpio_wlan_.+" + } + } } \ No newline at end of file diff --git a/Sming/Arch/Esp32/esp32s2-pindefs.txt b/Sming/Arch/Esp32/esp32s2-pindefs.txt new file mode 100644 index 0000000000..5b7ec005cf --- /dev/null +++ b/Sming/Arch/Esp32/esp32s2-pindefs.txt @@ -0,0 +1,237 @@ +[io_mux] +gpio pad f0 f1 f2 f3 f4 reset notes +0 GPIO0 GPIO0 GPIO0 - - - 3 R +1 GPIO1 GPIO1 GPIO1 - - - 1 R +2 GPIO2 GPIO2 GPIO2 - - - 1 R +3 GPIO3 GPIO3 GPIO3 - - - 0 R +4 GPIO4 GPIO4 GPIO4 - - - 0 R +5 GPIO5 GPIO5 GPIO5 - - - 0 R +6 GPIO6 GPIO6 GPIO6 - - - 0 R +7 GPIO7 GPIO7 GPIO7 - - - 0 R +8 GPIO8 GPIO8 GPIO8 - SUBSPICS1 - 0 R +9 GPIO9 GPIO9 GPIO9 - SUBSPIHD FSPIHD 1 R +10 GPIO10 GPIO10 GPIO10 FSPIIO4 SUBSPICS0 FSPICS0 1 R +11 GPIO11 GPIO11 GPIO11 FSPIIO5 SUBSPID FSPID 1 R +12 GPIO12 GPIO12 GPIO12 FSPIIO6 SUBSPICLK FSPICLK 1 R +13 GPIO13 GPIO13 GPIO13 FSPIIO7 SUBSPIQ FSPIQ 1 R +14 GPIO14 GPIO14 GPIO14 FSPIDQS SUBSPIWP FSPIWP 1 R +15 XTAL_32K_P XTAL_32K_P GPIO15 U0RTS - - 0 R +16 XTAL_32K_N XTAL_32K_N GPIO16 U0CTS - - 0 R +17 DAC_1 DAC_1 GPIO17 U1TXD - - 1 R +18 DAC_2 DAC_2 GPIO18 U1RXD CLK_OUT3 - 1 R +19 GPIO19 GPIO19 GPIO19 U1RTS CLK_OUT2 - 0 R +20 GPIO20 GPIO20 GPIO20 U1CTS CLK_OUT1 - 0 R +21 GPIO21 GPIO21 GPIO21 - - - 0 R +26 SPICS1 SPICS1 GPIO26 - - - 3 - +27 SPIHD SPIHD GPIO27 - - - 3 - +28 SPIWP SPIWP GPIO28 - - - 3 - +29 SPICS0 SPICS0 GPIO29 - - - 3 - +30 SPICLK SPICLK GPIO30 - - - 3 - +31 SPIQ SPIQ GPIO31 - - - 3 - +32 SPID SPID GPIO32 - - - 3 - +33 GPIO33 GPIO33 GPIO33 FSPIHD SUBSPIHD SPIIO4 1 - +34 GPIO34 GPIO34 GPIO34 FSPICS0 SUBSPICS0 SPIIO5 1 - +35 GPIO35 GPIO35 GPIO35 FSPID SUBSPID SPIIO6 1 - +36 GPIO36 GPIO36 GPIO36 FSPICLK SUBSPICLK SPIIO7 1 - +37 GPIO37 GPIO37 GPIO37 FSPIQ SUBSPIQ SPIDQS 1 - +38 GPIO38 GPIO38 GPIO38 FSPIWP SUBSPIWP - 1 - +39 MTCK MTCK GPIO39 CLK_OUT3 SUBSPICS1 - 1 - +40 MTDO MTDO GPIO40 CLK_OUT2 - - 1 - +41 MTDI MTDI GPIO41 CLK_OUT1 - - 1 - +42 MTMS MTMS GPIO42 - - - 1 - +43 U0TXD U0TXD GPIO43 CLK_OUT1 - - 3 - +44 U0RXD U0RXD GPIO44 CLK_OUT2 - - 3 - +45 GPIO45 GPIO45 GPIO45 - - - 2 - +46 GPIO46 GPIO46 GPIO46 - - - 2 I + +[rtc_mux] +# Table +rtc gpio a0 a1 f0 f1 f2 f3 +0 0 - - RTC_GPIO0 - - sar_i2c_scl_0 +1 1 TOUCH1 ADC1_CH0 RTC_GPIO1 - - sar_i2c_sda_0 +2 2 TOUCH2 ADC1_CH1 RTC_GPIO2 - - sar_i2c_scl_1 +3 3 TOUCH3 ADC1_CH2 RTC_GPIO3 - - sar_i2c_sda_1 +4 4 TOUCH4 ADC1_CH3 RTC_GPIO4 - - - +5 5 TOUCH5 ADC1_CH4 RTC_GPIO5 - - - +6 6 TOUCH6 ADC1_CH5 RTC_GPIO6 - - - +7 7 TOUCH7 ADC1_CH6 RTC_GPIO7 - - - +8 8 TOUCH8 ADC1_CH7 RTC_GPIO8 - - - +9 9 TOUCH9 ADC1_CH8 RTC_GPIO9 - - - +10 10 TOUCH10 ADC1_CH9 RTC_GPIO10 - - - +11 11 TOUCH11 ADC2_CH0 RTC_GPIO11 - - - +12 12 TOUCH12 ADC2_CH1 RTC_GPIO12 - - - +13 13 TOUCH13 ADC2_CH2 RTC_GPIO13 - - - +14 14 TOUCH14 ADC2_CH3 RTC_GPIO14 - - - +15 15 XTAL_32K_P ADC2_CH4 RTC_GPIO15 - - - +16 16 XTAL_32K_N ADC2_CH5 RTC_GPIO16 - - - +17 17 DAC_1 ADC2_CH6 RTC_GPIO17 - - - +18 18 DAC_2 ADC2_CH7 RTC_GPIO18 - - - +19 19 USB_DM ADC2_CH8 RTC_GPIO19 - - - +20 20 USB_DP ADC2_CH9 RTC_GPIO20 - - - +21 21 - RTC_GPIO21 - - - - + +[gpio_matrix] +signal input default direct_in output enable +0 SPIQ_in 0 yes SPIQ_out SPIQ_oe +1 SPID_in 0 yes SPID_out SPID_oe +2 SPIHD_in 0 yes SPIHD_out SPIHD_oe +3 SPIWP_in 0 yes SPIWP_out SPIWP_oe +4 - - - SPICLK_out_mux SPICLK_oe +5 - - - SPICS0_out SPICS0_oe +6 - - - SPICS1_out SPICS1_oe +7 SPID4_in 0 yes SPID4_out SPID4_oe +8 SPID5_in 0 yes SPID5_out SPID5_oe +9 SPID6_in 0 yes SPID6_out SPID6_oe +10 SPID7_in 0 yes SPID7_out SPID7_oe +11 SPIDQS_in 0 yes SPIDQS_out SPIDQS_oe +14 U0RXD_in 0 yes U0TXD_out 1’d1 +15 U0CTS_in 0 yes U0RTS_out 1’d1 +16 U0DSR_in 0 no U0DTR_out 1’d1 +17 U1RXD_in 0 yes U1TXD_out 1’d1 +18 U1CTS_in 0 yes U1RTS_out 1’d1 +21 U1DSR_in 0 no U1DTR_out 1’d1 +23 I2S0O_BCK_in 0 no I2S0O_BCK_out 1’d1 +25 I2S0O_WS_in 0 no I2S0O_WS_out 1’d1 +27 I2S0I_BCK_in 0 no I2S0I_BCK_out 1’d1 +28 I2S0I_WS_in 0 no I2S0I_WS_out 1’d1 +29 I2CEXT0_SCL_in 1 no I2CEXT0_SCL_out I2CEXT0_SCL_oe +30 I2CEXT0_SDA_in 1 no I2CEXT0_SDA_out I2CEXT0_SDA_oe +39 pcnt_sig_ch0_in0 0 no gpio_wlan_prio 1’d1 +40 pcnt_sig_ch1_in0 0 no gpio_wlan_active 1’d1 +41 pcnt_ctrl_ch0_in0 0 no - 1’d1 +42 pcnt_ctrl_ch1_in0 0 no - 1’d1 +43 pcnt_sig_ch0_in1 0 no - 1’d1 +44 pcnt_sig_ch1_in1 0 no - 1’d1 +45 pcnt_ctrl_ch0_in1 0 no - 1’d1 +46 pcnt_ctrl_ch1_in1 0 no - 1’d1 +47 pcnt_sig_ch0_in2 0 no - 1’d1 +48 pcnt_sig_ch1_in2 0 no - 1’d1 +49 pcnt_ctrl_ch0_in2 0 no - 1’d1 +50 pcnt_ctrl_ch1_in2 0 no - 1’d1 +51 pcnt_sig_ch0_in3 0 no - 1’d1 +52 pcnt_sig_ch1_in3 0 no - 1’d1 +53 pcnt_ctrl_ch0_in3 0 no - 1’d1 +54 pcnt_ctrl_ch1_in3 0 no - 1’d1 +64 usb_otg_iddig_in 0 no - 1’d1 +65 usb_otg_avalid_in 0 no - 1’d1 +66 usb_srp_bvalid_in 0 no usb_otg_idpullup 1’d1 +67 usb_otg_vbusvalid_in 0 no usb_otg_dppulldown 1’d1 +68 usb_srp_sessend_in 0 no usb_otg_dmpulldown 1’d1 +69 - - - usb_otg_drvvbus 1’d1 +70 - - - usb_srp_chrgvbus 1’d1 +71 - - - usb_srp_dischrgvbus 1’d1 +72 SPI3_CLK_in 0 no SPI3_CLK_out_mux SPI3_CLK_oe +73 SPI3_Q_in 0 no SPI3_Q_out SPI3_Q_oe +74 SPI3_D_in 0 no SPI3_D_out SPI3_D_oe +75 SPI3_HD_in 0 no SPI3_HD_out SPI3_HD_oe +76 SPI3_CS0_in 0 no SPI3_CS0_out SPI3_CS0_oe +77 - - - SPI3_CS1_out SPI3_CS1_oe +78 - - - SPI3_CS2_out SPI3_CS2_oe +79 - - - ledc_ls_sig_out0 1’d1 +80 - - - ledc_ls_sig_out1 1’d1 +81 - - - ledc_ls_sig_out2 1’d1 +82 - - - ledc_ls_sig_out3 1’d1 +83 rmt_sig_in0 0 no ledc_ls_sig_out4 1’d1 +84 rmt_sig_in1 0 no ledc_ls_sig_out5 1’d1 +85 rmt_sig_in2 0 no ledc_ls_sig_out6 1’d1 +86 rmt_sig_in3 0 no ledc_ls_sig_out7 1’d1 +87 - - - rmt_sig_out0 1’d1 +88 - - - rmt_sig_out1 1’d1 +89 - - - rmt_sig_out2 1’d1 +90 - - - rmt_sig_out3 1’d1 +95 I2CEXT1_SCL_in 1 no I2CEXT1_SCL_out I2CEXT1_SCL_oe +96 I2CEXT1_SDA_in 1 no I2CEXT1_SDA_out I2CEXT1_SDA_oe +100 - - - gpio_sd0_out 1’d1 +101 - - - gpio_sd1_out 1’d1 +102 - - - gpio_sd2_out 1’d1 +103 - - - gpio_sd3_out 1’d1 +104 - - - gpio_sd4_out 1’d1 +105 - - - gpio_sd5_out 1’d1 +106 - - - gpio_sd6_out 1’d1 +107 - - - gpio_sd7_out 1’d1 +108 FSPICLK_in 0 yes FSPICLK_out_mux FSPICLK_oe +109 FSPIQ_in 0 yes FSPIQ_out FSPIQ_oe +110 FSPID_in 0 yes FSPID_out FSPID_oe +111 FSPIHD_in 0 yes FSPIHD_out FSPIHD_oe +112 FSPIWP_in 0 yes FSPIWP_out FSPIWP_oe +113 FSPIIO4_in 0 yes FSPIIO4_out FSPIIO4_oe +114 FSPIIO5_in 0 yes FSPIIO5_out FSPIIO5_oe +115 FSPIIO6_in 0 yes FSPIIO6_out FSPIIO6_oe +116 FSPIIO7_in 0 yes FSPIIO7_out FSPIIO7_oe +117 FSPICS0_in 0 yes FSPICS0_out FSPICS0_oe +118 - - - FSPICS1_out FSPICS1_oe +119 - - - FSPICS2_out FSPICS2_oe +120 - - - FSPICS3_out FSPICS3_oe +121 - - - FSPICS4_out FSPICS4_oe +122 - - - FSPICS5_out FSPICS5_oe +123 twai_rx 1 no twai_tx 1’d1 +124 - - - twai_bus_off_on 1’d1 +125 - - - twai_clkout 1’d1 +126 - - - SUBSPICLK_out_mux SUBSPICLK_oe +127 SUBSPIQ_in 0 yes SUBSPIQ_out SUBSPIQ_oe +128 SUBSPID_in 0 yes SUBSPID_out SUBSPID_oe +129 SUBSPIHD_in 0 yes SUBSPIHD_out SUBSPIHD_oe +130 SUBSPIWP_in 0 yes SUBSPIWP_out SUBSPIWP_oe +131 - - - SUBSPICS0_out SUBSPICS0_oe +132 - - - SUBSPICS1_out SUBSPICS1_oe +133 - - - FSPIDQS_out FSPIDQS_oe +134 - - - FSPI_HSYNC_out FSPI_HSYNC_oe +135 - - - FSPI_VSYNC_out FSPI_VSYNC_oe +136 - - - FSPI_DE_out FSPI_DE_oe +137 - - - FSPICD_out FSPICD_oe +139 - - - SPI3_CD_out SPI3_CD_oe +140 - - - SPI3_DQS_out SPI3_DQS_oe +143 I2S0I_DATA_in0 0 no I2S0O_DATA_out0 1’d1 +144 I2S0I_DATA_in1 0 no I2S0O_DATA_out1 1’d1 +145 I2S0I_DATA_in2 0 no I2S0O_DATA_out2 1’d1 +146 I2S0I_DATA_in3 0 no I2S0O_DATA_out3 1’d1 +147 I2S0I_DATA_in4 0 no I2S0O_DATA_out4 1’d1 +148 I2S0I_DATA_in5 0 no I2S0O_DATA_out5 1’d1 +149 I2S0I_DATA_in6 0 no I2S0O_DATA_out6 1’d1 +150 I2S0I_DATA_in7 0 no I2S0O_DATA_out7 1’d1 +151 I2S0I_DATA_in8 0 no I2S0O_DATA_out8 1’d1 +152 I2S0I_DATA_in9 0 no I2S0O_DATA_out9 1’d1 +153 I2S0I_DATA_in10 0 no I2S0O_DATA_out10 1’d1 +154 I2S0I_DATA_in11 0 no I2S0O_DATA_out11 1’d1 +155 I2S0I_DATA_in12 0 no I2S0O_DATA_out12 1’d1 +156 I2S0I_DATA_in13 0 no I2S0O_DATA_out13 1’d1 +157 I2S0I_DATA_in14 0 no I2S0O_DATA_out14 1’d1 +158 I2S0I_DATA_in15 0 no I2S0O_DATA_out15 1’d1 +159 - - - I2S0O_DATA_out16 1’d1 +160 - - - I2S0O_DATA_out17 1’d1 +161 - - - I2S0O_DATA_out18 1’d1 +162 - - - I2S0O_DATA_out19 1’d1 +163 - - - I2S0O_DATA_out20 1’d1 +164 - - - I2S0O_DATA_out21 1’d1 +165 - - - I2S0O_DATA_out22 1’d1 +166 - - - I2S0O_DATA_out23 1’d1 +167 SUBSPID4_in 0 yes SUBSPID4_out SUBSPID4_oe +168 SUBSPID5_in 0 yes SUBSPID5_out SUBSPID5_oe +169 SUBSPID6_in 0 yes SUBSPID6_out SUBSPID6_oe +170 SUBSPID7_in 0 yes SUBSPID7_out SUBSPID7_oe +171 SUBSPIDQS_in 0 yes SUBSPIDQS_out SUBSPIDQS_oe +193 I2S0I_H_SYNC 0 no - 1’d1 +194 I2S0I_V_SYNC 0 no - 1’d1 +195 I2S0I_H_ENABLE 0 no - 1’d1 +215 - - - ant_sel0 1’d1 +216 - - - ant_sel1 1’d1 +217 - - - ant_sel2 1’d1 +218 - - - ant_sel3 1’d1 +219 - - - ant_sel4 1’d1 +220 - - - ant_sel5 1’d1 +221 - - - ant_sel6 1’d1 +222 - - - ant_sel7 1’d1 +223 sig_in_func_223 0 no sig_in_func223 1’d1 +224 sig_in_func_224 0 no sig_in_func224 1’d1 +225 sig_in_func_225 0 no sig_in_func225 1’d1 +226 sig_in_func_226 0 no sig_in_func226 1’d1 +227 sig_in_func_227 0 no sig_in_func227 1’d1 +235 pro_alonegpio_in0 0 no pro_alonegpio_out0 1’d1 +236 pro_alonegpio_in1 0 no pro_alonegpio_out1 1’d1 +237 pro_alonegpio_in2 0 no pro_alonegpio_out2 1’d1 +238 pro_alonegpio_in3 0 no pro_alonegpio_out3 1’d1 +239 pro_alonegpio_in4 0 no pro_alonegpio_out4 1’d1 +240 pro_alonegpio_in5 0 no pro_alonegpio_out5 1’d1 +241 pro_alonegpio_in6 0 no pro_alonegpio_out6 1’d1 +242 pro_alonegpio_in7 0 no pro_alonegpio_out7 1’d1 +251 - - - clk_i2s_mux 1’d1 diff --git a/Sming/Arch/Esp32/esp32s2-soc.json b/Sming/Arch/Esp32/esp32s2-soc.json index 7000a1c8f1..f5088511d8 100644 --- a/Sming/Arch/Esp32/esp32s2-soc.json +++ b/Sming/Arch/Esp32/esp32s2-soc.json @@ -1,4 +1,92 @@ { "variant": "esp32s2", - "name": "ESP32-S2" + "name": "ESP32-S2", + "peripherals": { + "ADC": { + "sigmask": "ADC.+|sar_.+" + }, + "CLOCKS": { + "sigmask": "CLK_.+|XTAL_.+" + }, + "DAC": { + "sigmask": "DAC.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "GPIO": { + "sigmask": "GPIO.+|RTC_GPIO.+" + }, + "TOUCH": { + "sigmask": "{name}.+" + }, + "DEDIC_GPIO": { + "sigmask": "pro_alonegpio.+" + }, + "I2C[0-1]": { + "sigmask": "I2CEXT{idx}.+" + }, + "I2S": { + "sigmask": "I2S.+|clk_i2s_mux" + }, + "LEDC": { + "sigmask": "ledc_.+" + }, + "PCNT[0-1]": { + "sigmask": "pcnt_ctrl_ch{idx}.+|pcnt_sig_ch{idx}.+" + }, + "RMT": { + "sigmask": "rmt_.+" + }, + "SIGMA_DELTA": { + "sigmask": "gpio_sd.+" + }, + "SPI1": { + "sigmask": "SPI[^3]+" + }, + "SPI2": { + "sigmask": "FSPI.+" + }, + "SPI3": { + "sigmask": "SPI3_.+" + }, + "SUBSPI": { + "sigmask": "SUBSPI.+" + }, + "TWAI": { + "sigmask": "twai_.+" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 43 + ], + "RXD": [ + "U0RXD", + 44 + ] + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD_out", + 10 + ], + "RXD": [ + "U1RXD_in", + 9 + ] + } + }, + "USB": { + "sigmask": "(usb_|USB).+" + }, + "WIFI": { + "sigmask": "gpio_wlan_.+" + } + } } \ No newline at end of file diff --git a/Sming/Arch/Esp32/esp32s3-pindefs.txt b/Sming/Arch/Esp32/esp32s3-pindefs.txt new file mode 100644 index 0000000000..7383d6dea8 --- /dev/null +++ b/Sming/Arch/Esp32/esp32s3-pindefs.txt @@ -0,0 +1,356 @@ +[io_mux] +gpio pad f0 f1 f2 f3 f4 drv reset notes +0 GPIO0 GPIO0 GPIO0 - - - 2 3 R +1 GPIO1 GPIO1 GPIO1 - - - 2 1 R +2 GPIO2 GPIO2 GPIO2 - - - 2 1 R +3 GPIO3 GPIO3 GPIO3 - - - 2 1 R +4 GPIO4 GPIO4 GPIO4 - - - 2 0 R +5 GPIO5 GPIO5 GPIO5 - - - 2 0 R +6 GPIO6 GPIO6 GPIO6 - - - 2 0 R +7 GPIO7 GPIO7 GPIO7 - - - 2 0 R +8 GPIO8 GPIO8 GPIO8 - SUBSPICS1 - 2 0 R +9 GPIO9 GPIO9 GPIO9 - SUBSPIHD FSPIHD 2 1 R +10 GPIO10 GPIO10 GPIO10 FSPIIO4 SUBSPICS0 FSPICS0 2 1 R +11 GPIO11 GPIO11 GPIO11 FSPIIO5 SUBSPID FSPID 2 1 R +12 GPIO12 GPIO12 GPIO12 FSPIIO6 SUBSPICLK FSPICLK 2 1 R +13 GPIO13 GPIO13 GPIO13 FSPIIO7 SUBSPIQ FSPIQ 2 1 R +14 GPIO14 GPIO14 GPIO14 FSPIDQS SUBSPIWP FSPIWP 2 1 R +15 XTAL_32K_P GPIO15 GPIO15 U0RTS - - 2 0 R +16 XTAL_32K_N GPIO16 GPIO16 U0CTS - - 2 0 R +17 GPIO17 GPIO17 GPIO17 U1TXD - - 2 1 R +18 GPIO18 GPIO18 GPIO18 U1RXD CLK_OUT3 - 2 1 R +19 GPIO19 GPIO19 GPIO19 U1RTS CLK_OUT2 - 2 0 R +20 GPIO20 GPIO20 GPIO20 U1CTS CLK_OUT1 - 2 0 R +21 GPIO21 GPIO21 GPIO21 - - - 2 0 R +26 SPICS1 SPICS1 GPIO26 - - - 2 3 - +27 SPIHD SPIHD GPIO27 - - - 3 3 - +28 SPIWP SPIWP GPIO28 - - - 3 3 - +29 SPICS0 SPICS0 GPIO29 - - - 3 3 - +30 SPICLK SPICLK GPIO30 - - - 3 3 - +31 SPIQ SPIQ GPIO31 - - - 3 3 - +32 SPID SPID GPIO32 - - - 3 3 - +33 GPIO33 GPIO33 GPIO33 FSPIHD SUBSPIHD SPIIO4 2 1 - +34 GPIO34 GPIO34 GPIO34 FSPICS0 SUBSPICS0 SPIIO5 2 1 - +35 GPIO35 GPIO35 GPIO35 FSPID SUBSPID SPIIO6 2 1 - +36 GPIO36 GPIO36 GPIO36 FSPICLK SUBSPICLK SPIIO7 2 1 - +37 GPIO37 GPIO37 GPIO37 FSPIQ SUBSPIQ SPIDQS 2 1 - +38 GPIO38 GPIO38 GPIO38 FSPIWP SUBSPIWP - 2 1 - +39 MTCK MTCK GPIO39 CLK_OUT3 SUBSPICS1 - 2 1* - +40 MTDO MTDO GPIO40 CLK_OUT2 - - 2 1 - +41 MTDI MTDI GPIO41 CLK_OUT1 - - 2 1 - +42 MTMS MTMS GPIO42 - - - 2 1 - +43 U0TXD U0TXD GPIO43 CLK_OUT1 - - 2 4 +44 U0RXD U0RXD GPIO44 CLK_OUT2 - - 2 3 - +45 GPIO45 GPIO45 GPIO45 - - - 2 2 - +46 GPIO46 GPIO46 GPIO46 - - - 2 2 - +47 SPICLK_P SPICLK_DIFF GPIO47 SUBSPICLK_P_DIFF - - 2 1 - +48 SPICLK_N SPICLK_DIFF GPIO48 SUBSPICLK_N_DIFF - - 2 1 - + +[rtc_mux] +rtc gpio pad f0 f1 f2 f3 notes +0 0 GPIO0 RTC_GPIO0 - - sar_i2c_scl_0a +1 1 GPIO1 RTC_GPIO1 - - sar_i2c_sda_0a +2 2 GPIO2 RTC_GPIO2 - - sar_i2c_scl_1a +3 3 GPIO3 RTC_GPIO3 - - sar_i2c_sda_1a +4 4 GPIO4 RTC_GPIO4 - - - +5 5 GPIO5 RTC_GPIO5 - - - +6 6 GPIO6 RTC_GPIO6 - - - +7 7 GPIO7 RTC_GPIO7 - - - +8 8 GPIO8 RTC_GPIO8 - - - +9 9 GPIO9 RTC_GPIO9 - - - +10 10 GPIO10 RTC_GPIO10 - - - +11 11 GPIO11 RTC_GPIO11 - - - +12 12 GPIO12 RTC_GPIO12 - - - +13 13 GPIO13 RTC_GPIO13 - - - +14 14 GPIO14 RTC_GPIO14 - - - +15 15 XTAL_32K_P RTC_GPIO15 - - - +16 16 XTAL_32K_N RTC_GPIO16 - - - +17 17 GPIO17 RTC_GPIO17 - - - +18 18 GPIO18 RTC_GPIO18 - - - +19 19 GPIO19 RTC_GPIO19 - - - +20 20 GPIO20 RTC_GPIO20 - - - +21 21 GPIO21 RTC_GPIO21 - - - + +[rtc_mux_ana] +rtc gpio pad a0 a1 notes +0 0 GPIO0 - - +1 1 GPIO1 TOUCH1 ADC1_CH0 +2 2 GPIO2 TOUCH2 ADC1_CH1 +3 3 GPIO3 TOUCH3 ADC1_CH2 +4 4 GPIO4 TOUCH4 ADC1_CH3 +5 5 GPIO5 TOUCH5 ADC1_CH4 +6 6 GPIO6 TOUCH6 ADC1_CH5 +7 7 GPIO7 TOUCH7 ADC1_CH6 +8 8 GPIO8 TOUCH8 ADC1_CH7 +9 9 GPIO9 TOUCH9 ADC1_CH8 +10 10 GPIO10 TOUCH10 ADC1_CH9 +11 11 GPIO11 TOUCH11 ADC2_CH0 +12 12 GPIO12 TOUCH12 ADC2_CH1 +13 13 GPIO13 TOUCH13 ADC2_CH2 +14 14 GPIO14 TOUCH14 ADC2_CH3 +15 15 XTAL_32K_P XTAL_32K_P ADC2_CH4 +16 16 XTAL_32K_N XTAL_32K_N ADC2_CH5 +17 17 GPIO17 - ADC2_CH6 +18 18 GPIO18 - ADC2_CH7 +19 19 GPIO19 USB_DM ADC2_CH8 +20 20 GPIO20 USB_DP ADC2_CH9 +21 21 GPIO21 - - + +[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 - - - SPICS1_out SPICS1_oe yes +7 SPID4_in 0 yes SPID4_out SPID4_oe yes +8 SPID5_in 0 yes SPID5_out SPID5_oe yes +9 SPID6_in 0 yes SPID6_out SPID6_oe yes +10 SPID7_in 0 yes SPID7_out SPID7_oe yes +11 SPIDQS_in 0 yes SPIDQS_out SPIDQS_oe yes +12 U0RXD_in 0 yes U0TXD_out 1’d1 yes +13 U0CTS_in 0 yes U0RTS_out 1’d1 yes +14 U0DSR_in 0 no U0DTR_out 1’d1 no +15 U1RXD_in 0 yes U1TXD_out 1’d1 yes +16 U1CTS_in 0 yes U1RTS_out 1’d1 yes +17 U1DSR_in 0 no U1DTR_out 1’d1 no +18 U2RXD_in 0 no U2TXD_out 1’d1 no +19 U2CTS_in 0 no U2RTS_out 1’d1 no +20 U2DSR_in 0 no U2DTR_out 1’d1 no +21 I2S1_MCLK_in 0 no I2S1_MCLK_out 1’d1 no +22 I2S0O_BCK_in 0 no I2S0O_BCK_out 1’d1 no +23 I2S0_MCLK_in 0 no I2S0_MCLK_out 1’d1 no +24 I2S0O_WS_in 0 no I2S0O_WS_out 1’d1 no +25 I2S0I_SD_in 0 no I2S0O_SD_out 1’d1 no +26 I2S0I_BCK_in 0 no I2S0I_BCK_out 1’d1 no +27 I2S0I_WS_in 0 no I2S0I_WS_out 1’d1 no +28 I2S1O_BCK_in 0 no I2S1O_BCK_out 1’d1 no +29 I2S1O_WS_in 0 no I2S1O_WS_out 1’d1 no +30 I2S1I_SD_in 0 no I2S1O_SD_out 1’d1 no +31 I2S1I_BCK_in 0 no I2S1I_BCK_out 1’d1 no +32 I2S1I_WS_in 0 no I2S1I_WS_out 1’d1 no +33 pcnt_sig_ch0_in0 0 no - 1’d1 no +34 pcnt_sig_ch1_in0 0 no - 1’d1 no +35 pcnt_ctrl_ch0_in0 0 no - 1’d1 - +36 pcnt_ctrl_ch1_in0 0 no - 1’d1 - +37 pcnt_sig_ch0_in1 0 no - 1’d1 - +38 pcnt_sig_ch1_in1 0 no - 1’d1 - +39 pcnt_ctrl_ch0_in1 0 no - 1’d1 - +40 pcnt_ctrl_ch1_in1 0 no - 1’d1 - +41 pcnt_sig_ch0_in2 0 no - 1’d1 - +42 pcnt_sig_ch1_in2 0 no - 1’d1 - +43 pcnt_ctrl_ch0_in2 0 no - 1’d1 - +44 pcnt_ctrl_ch1_in2 0 no - 1’d1 - +45 pcnt_sig_ch0_in3 0 no - 1’d1 - +46 pcnt_sig_ch1_in3 0 no - 1’d1 - +47 pcnt_ctrl_ch0_in3 0 no - 1’d1 - +48 pcnt_ctrl_ch1_in3 0 no - 1’d1 - +49 - - - - 1’d1 - +50 - - - - 1’d1 - +51 I2S0I_SD1_in 0 no - 1’d1 - +52 I2S0I_SD2_in 0 no - 1’d1 - +53 I2S0I_SD3_in 0 no - 1’d1 - +54 Core1_gpio_in7 0 no Core1_gpio_out7 1’d1 no +55 - - - - 1’d1 - +56 - - - - 1’d1 - +57 - - - - 1’d1 - +58 usb_otg_iddig_in 0 no - 1’d1 - +59 usb_otg_avalid_in 0 no - 1’d1 - +60 usb_srp_bvalid_in 0 no usb_otg_idpullup 1’d1 no +61 usb_otg_vbusvalid_in 0 no usb_otg_dppulldown 1’d1 no +62 usb_srp_sessend_in 0 no usb_otg_dmpulldown 1’d1 no +63 - - - usb_otg_drvvbus 1’d1 no +64 - - - usb_srp_chrgvbus 1’d1 no +65 - - - usb_srp_dischrgvbus 1’d1 no +66 SPI3_CLK_in 0 no SPI3_CLK_out_mux SPI3_CLK_oe no +67 SPI3_Q_in 0 no SPI3_Q_out SPI3_Q_oe no +68 SPI3_D_in 0 no SPI3_D_out SPI3_D_oe no +69 SPI3_HD_in 0 no SPI3_HD_out SPI3_HD_oe no +70 SPI3_WP_in 0 no SPI3_WP_out SPI3_WP_oe no +71 SPI3_CS0_in 0 no SPI3_CS0_out SPI3_CS0_oe no +72 - - - SPI3_CS1_out SPI3_CS1_oe no +73 ext_adc_start 0 no ledc_ls_sig_out0 1’d1 no +74 - - - ledc_ls_sig_out1 1’d1 no +75 - - - ledc_ls_sig_out2 1’d1 no +76 - - - ledc_ls_sig_out3 1’d1 no +77 - - - ledc_ls_sig_out4 1’d1 no +78 - - - ledc_ls_sig_out5 1’d1 no +79 - - - ledc_ls_sig_out6 1’d1 no +80 - - - ledc_ls_sig_out7 1’d1 no +81 rmt_sig_in0 0 no rmt_sig_out0 1’d1 no +82 rmt_sig_in1 0 no rmt_sig_out1 1’d1 no +83 rmt_sig_in2 0 no rmt_sig_out2 1’d1 no +84 rmt_sig_in3 0 no rmt_sig_out3 1’d1 no +85 - - - - 1’d1 - +86 - - - - 1’d1 - +87 - - - - 1’d1 - +88 - - - - 1’d1 - +89 I2CEXT0_SCL_in 1 no I2CEXT0_SCL_out I2CEXT0_SCL_oe no +90 I2CEXT0_SDA_in 1 no I2CEXT0_SDA_out I2CEXT0_SDA_oe no +91 I2CEXT1_SCL_in 1 no I2CEXT1_SCL_out I2CEXT1_SCL_oe no +92 I2CEXT1_SDA_in 1 no I2CEXT1_SDA_out I2CEXT1_SDA_oe no +93 - - - gpio_sd0_out 1’d1 no +94 - - - gpio_sd1_out 1’d1 no +95 - - - gpio_sd2_out 1’d1 no +96 - - - gpio_sd3_out 1’d1 no +97 - - - gpio_sd4_out 1’d1 no +98 - - - gpio_sd5_out 1’d1 no +99 - - - gpio_sd6_out 1’d1 no +100 - - - gpio_sd7_out 1’d1 no +101 FSPICLK_in 0 yes FSPICLK_out_mux FSPICLK_oe yes +102 FSPIQ_in 0 yes FSPIQ_out FSPIQ_oe yes +103 FSPID_in 0 yes FSPID_out FSPID_oe yes +104 FSPIHD_in 0 yes FSPIHD_out FSPIHD_oe yes +105 FSPIWP_in 0 yes FSPIWP_out FSPIWP_oe yes +106 FSPIIO4_in 0 yes FSPIIO4_out FSPIIO4_oe yes +107 FSPIIO5_in 0 yes FSPIIO5_out FSPIIO5_oe yes +108 FSPIIO6_in 0 yes FSPIIO6_out FSPIIO6_oe yes +109 FSPIIO7_in 0 yes FSPIIO7_out FSPIIO7_oe yes +110 FSPICS0_in 0 yes FSPICS0_out FSPICS0_oe yes +111 - - - FSPICS1_out FSPICS1_oe no +112 - - - FSPICS2_out FSPICS2_oe no +113 - - - FSPICS3_out FSPICS3_oe no +114 - - - FSPICS4_out FSPICS4_oe no +115 - - - FSPICS5_out FSPICS5_oe no +116 twai_rx 1 no twai_tx 1’d1 no +117 - - - twai_bus_off_on 1’d1 no +118 - - - twai_clkout 1’d1 no +119 - - - SUBSPICLK_out_mux SUBSPICLK_oe no +120 SUBSPIQ_in 0 yes SUBSPIQ_out SUBSPIQ_oe yes +121 SUBSPID_in 0 yes SUBSPID_out SUBSPID_oe yes +122 SUBSPIHD_in 0 yes SUBSPIHD_out SUBSPIHD_oe yes +123 SUBSPIWP_in 0 yes SUBSPIWP_out SUBSPIWP_oe yes +124 - - - SUBSPICS0_out SUBSPICS0_oe yes +125 - - - SUBSPICS1_out SUBSPICS1_oe yes +126 - - - FSPIDQS_out FSPIDQS_oe yes +127 - - - SPI3_CS2_out SPI3_CS2_oe no +128 - - - I2S0O_SD1_out 1’d1 no +129 Core1_gpio_in0 0 no Core1_gpio_out0 1’d1 no +130 Core1_gpio_in1 0 no Core1_gpio_out1 1’d1 no +131 Core1_gpio_in2 0 no Core1_gpio_out2 1’d1 no +132 - - - LCD_CS 1’d1 no +133 CAM_DATA_in0 0 no LCD_DATA_out0 1’d1 no +134 CAM_DATA_in1 0 no LCD_DATA_out1 1’d1 no +135 CAM_DATA_in2 0 no LCD_DATA_out2 1’d1 no +136 CAM_DATA_in3 0 no LCD_DATA_out3 1’d1 no +137 CAM_DATA_in4 0 no LCD_DATA_out4 1’d1 no +138 CAM_DATA_in5 0 no LCD_DATA_out5 1’d1 no +139 CAM_DATA_in6 0 no LCD_DATA_out6 1’d1 no +140 CAM_DATA_in7 0 no LCD_DATA_out7 1’d1 no +141 CAM_DATA_in8 0 no LCD_DATA_out8 1’d1 no +142 CAM_DATA_in9 0 no LCD_DATA_out9 1’d1 no +143 CAM_DATA_in10 0 no LCD_DATA_out10 1’d1 no +144 CAM_DATA_in11 0 no LCD_DATA_out11 1’d1 no +145 CAM_DATA_in12 0 no LCD_DATA_out12 1’d1 no +146 CAM_DATA_in13 0 no LCD_DATA_out13 1’d1 no +147 CAM_DATA_in14 0 no LCD_DATA_out14 1’d1 no +148 CAM_DATA_in15 0 no LCD_DATA_out15 1’d1 no +149 CAM_PCLK 0 no CAM_CLK 1’d1 no +150 CAM_H_ENABLE 0 no LCD_H_ENABLE 1’d1 no +151 CAM_H_SYNC 0 no LCD_H_SYNC 1’d1 no +152 CAM_V_SYNC 0 no LCD_V_SYNC 1’d1 no +153 - - - LCD_DC 1’d1 no +154 - - - LCD_PCLK 1’d1 no +155 SUBSPID4_in 0 yes SUBSPID4_out SUBSPID4_oe no +156 SUBSPID5_in 0 yes SUBSPID5_out SUBSPID5_oe no +157 SUBSPID6_in 0 yes SUBSPID6_out SUBSPID6_oe no +158 SUBSPID7_in 0 yes SUBSPID7_out SUBSPID7_oe no +159 SUBSPIDQS_in 0 yes SUBSPIDQS_out SUBSPIDQS_oe no +160 pwm0_sync0_in 0 no pwm0_out0a 1’d1 no +161 pwm0_sync1_in 0 no pwm0_out0b 1’d1 no +162 pwm0_sync2_in 0 no pwm0_out1a 1’d1 no +163 pwm0_f0_in 0 no pwm0_out1b 1’d1 no +164 pwm0_f1_in 0 no pwm0_out2a 1’d1 no +165 pwm0_f2_in 0 no pwm0_out2b 1’d1 no +166 pwm0_cap0_in 0 no pwm1_out0a 1’d1 no +167 pwm0_cap1_in 0 no pwm1_out0b 1’d1 no +168 pwm0_cap2_in 0 no pwm1_out1a 1’d1 no +169 pwm1_sync0_in 0 no pwm1_out1b 1’d1 no +170 pwm1_sync1_in 0 no pwm1_out2a 1’d1 no +171 pwm1_sync2_in 0 no pwm1_out2b 1’d1 no +172 pwm1_f0_in 0 no sdhost_cclk_out_1 1’d1 no +173 pwm1_f1_in 0 no sdhost_cclk_out_2 1’d1 no +174 pwm1_f2_in 0 no sdhost_rst_n_1 1’d1 no +175 pwm1_cap0_in 0 no sdhost_rst_n_2 1’d1 no +176 pwm1_cap1_in 0 no sdhost_ccmd_od_pullup_en_n 1’d1 no +177 pwm1_cap2_in 0 no sdio_tohost_int_out 1’d1 no +178 sdhost_ccmd_in_1 1 no sdhost_ccmd_out_1 sdhost_ccmd_out_en_1 no +179 sdhost_ccmd_in_2 1 no sdhost_ccmd_out_2 sdhost_ccmd_out_en_2 no +180 sdhost_cdata_in_10 1 no sdhost_cdata_out_10 sdhost_cdata_out_en_10 no +181 sdhost_cdata_in_11 1 no sdhost_cdata_out_11 sdhost_cdata_out_en_11 no +182 sdhost_cdata_in_12 1 no sdhost_cdata_out_12 sdhost_cdata_out_en_12 no +183 sdhost_cdata_in_13 1 no sdhost_cdata_out_13 sdhost_cdata_out_en_13 no +184 sdhost_cdata_in_14 1 no sdhost_cdata_out_14 sdhost_cdata_out_en_14 no +185 sdhost_cdata_in_15 1 no sdhost_cdata_out_15 sdhost_cdata_out_en_15 no +186 sdhost_cdata_in_16 1 no sdhost_cdata_out_16 sdhost_cdata_out_en_16 no +187 sdhost_cdata_in_17 1 no sdhost_cdata_out_17 sdhost_cdata_out_en_17 no +188 - - - - 1’d1 - +189 - - - - 1’d1 - +190 - - - - 1’d1 - +191 - - - - 1’d1 - +192 sdhost_data_strobe_1 0 no - 1’d1 - +193 sdhost_data_strobe_2 0 no - 1’d1 - +194 sdhost_card_detect_n_1 0 no - 1’d1 - +195 sdhost_card_detect_n_2 0 no - 1’d1 - +196 sdhost_card_write_prt_1 0 no - 1’d1 - +197 sdhost_card_write_prt_2 0 no - 1’d1 - +198 sdhost_card_int_n_1 0 no - 1’d1 - +199 sdhost_card_int_n_2 0 no - 1’d1 - +200 - - - - 1’d1 no +201 - - - - 1’d1 no +202 - - - - 1’d1 no +203 - - - - 1’d1 no +204 - - - - 1’d1 no +205 - - - - 1’d1 no +206 - - - - 1’d1 no +207 - - - - 1’d1 no +208 sig_in_func_208 0 no sig_in_func208 1’d1 no +209 sig_in_func_209 0 no sig_in_func209 1’d1 no +210 sig_in_func_210 0 no sig_in_func210 1’d1 no +211 sig_in_func_211 0 no sig_in_func211 1’d1 no +212 sig_in_func_212 0 no sig_in_func212 1’d1 no +213 sdhost_cdata_in_20 1 no sdhost_cdata_out_20 sdhost_cdata_out_en_20 no +214 sdhost_cdata_in_21 1 no sdhost_cdata_out_21 sdhost_cdata_out_en_21 no +215 sdhost_cdata_in_22 1 no sdhost_cdata_out_22 sdhost_cdata_out_en_22 no +216 sdhost_cdata_in_23 1 no sdhost_cdata_out_23 sdhost_cdata_out_en_23 no +217 sdhost_cdata_in_24 1 no sdhost_cdata_out_24 sdhost_cdata_out_en_24 no +218 sdhost_cdata_in_25 1 no sdhost_cdata_out_25 sdhost_cdata_out_en_25 no +219 sdhost_cdata_in_26 1 no sdhost_cdata_out_26 sdhost_cdata_out_en_26 no +220 sdhost_cdata_in_27 1 no sdhost_cdata_out_27 sdhost_cdata_out_en_27 no +221 pro_alonegpio_in0 0 no pro_alonegpio_out0 1’d1 no +222 pro_alonegpio_in1 0 no pro_alonegpio_out1 1’d1 no +223 pro_alonegpio_in2 0 no pro_alonegpio_out2 1’d1 no +224 pro_alonegpio_in3 0 no pro_alonegpio_out3 1’d1 no +225 pro_alonegpio_in4 0 no pro_alonegpio_out4 1’d1 no +226 pro_alonegpio_in5 0 no pro_alonegpio_out5 1’d1 no +227 pro_alonegpio_in6 0 no pro_alonegpio_out6 1’d1 no +228 pro_alonegpio_in7 0 no pro_alonegpio_out7 1’d1 no +229 - - - - 1’d1 - +230 - - - - 1’d1 - +231 - - - - 1’d1 - +232 - - - - 1’d1 - +233 - - - - 1’d1 - +234 - - - - 1’d1 - +235 - - - - 1’d1 - +236 - - - - 1’d1 - +237 - - - - 1’d1 - +238 - - - - 1’d1 - +239 - - - - 1’d1 - +240 - - - - 1’d1 - +241 - - - - 1’d1 - +242 - - - - 1’d1 - +243 - - - - 1’d1 - +244 - - - - 1’d1 - +245 - - - - 1’d1 - +246 - - - - 1’d1 - +247 - - - - 1’d1 - +248 - - - - 1’d1 - +249 - - - - 1’d1 - +250 - - - - 1’d1 - +251 usb_jtag_tdo_bridge 0 no usb_jtag_trst 1’d1 no +252 Core1_gpio_in3 0 no Core1_gpio_out3 1’d1 no +253 Core1_gpio_in4 0 no Core1_gpio_out4 1’d1 no +254 Core1_gpio_in5 0 no Core1_gpio_out5 1’d1 no +255 Core1_gpio_in6 0 no Core1_gpio_out6 1’d1 no diff --git a/Sming/Arch/Esp32/esp32s3-soc.json b/Sming/Arch/Esp32/esp32s3-soc.json index 65023576bb..afa0c4d277 100644 --- a/Sming/Arch/Esp32/esp32s3-soc.json +++ b/Sming/Arch/Esp32/esp32s3-soc.json @@ -1,4 +1,112 @@ { "variant": "esp32s3", - "name": "ESP32-S3" + "name": "ESP32-S3", + "peripherals": { + "ADC": { + "sigmask": "ADC.+|sar_.+|ext_adc_start" + }, + "CAM": { + "sigmask": "CAM.+" + }, + "CLOCKS": { + "sigmask": "CLK_.+|XTAL_.+" + }, + "DEDIC_GPIO": { + "sigmask": "pro_alonegpio.+|Core1_gpio.+" + }, + "GPIO": { + "sigmask": "GPIO.+|RTC_GPIO.+" + }, + "I2C[0-1]": { + "sigmask": "I2CEXT{idx}.+" + }, + "I2S[0-1]": { + "sigmask": "I2S{idx}.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "LCD": { + "sigmask": "LCD_.+" + }, + "LEDC": { + "sigmask": "ledc_.+" + }, + "PCNT[0-1]": { + "sigmask": "pcnt_ctrl_ch{idx}.+|pcnt_sig_ch{idx}.+" + }, + "MCPWM[0-1]": { + "sigmask": "pwm{idx}_.+" + }, + "RMT": { + "sigmask": "rmt_.+" + }, + "SDHOST": { + "sigmask": "sdhost.+" + }, + "SIGMA_DELTA": { + "sigmask": "gpio_sd.+" + }, + "SPI1": { + "sigmask": "SPI^\\d.+" + }, + "SPI2": { + "sigmask": "FSPI.+" + }, + "SPI3": { + "sigmask": "SPI3_.+" + }, + "SUBSPI": { + "sigmask": "SUBSPI.+" + }, + "TOUCH": { + "sigmask": "TOUCH.+" + }, + "TWAI": { + "sigmask": "twai_.+" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 43 + ], + "RXD": [ + "U0RXD", + 44 + ] + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD_out", + 10 + ], + "RXD": [ + "U1RXD_in", + 9 + ] + } + }, + "UART2": { + "sigmask": "U2.+", + "default": { + "TXD": [ + "U2TXD_out", + 17 + ], + "RXD": [ + "U2RXD_in", + 16 + ] + } + }, + "USB": { + "sigmask": "usb_.+|USB_.+" + }, + "WIFI": {} + } } \ No newline at end of file diff --git a/Sming/Arch/Esp8266/esp8266-pindefs.txt b/Sming/Arch/Esp8266/esp8266-pindefs.txt new file mode 100644 index 0000000000..64787ed5cf --- /dev/null +++ b/Sming/Arch/Esp8266/esp8266-pindefs.txt @@ -0,0 +1,19 @@ +[io_mux] +gpio pad f0 f1 f2 f3 f4 notes +0 GPIO0 GPIO0 SPI_CS2 - - CLK_OUT +1 U0TXD U0TXD SPI_CS1 GPIO1 CLK_RTC_BK U0RTS UART TX during flash programming +2 GPIO2 GPIO2 I2SO_WS U1TXD - U0TXD UART TX during flash programming +3 U0RXD U0RXD I2SO_DATA GPIO3 CLK_XTAL_BK U0CTS UART Rx during flash programming +4 GPIO4 GPIO4 CLK_XTAL - - - +5 GPIO5 GPIO5 CLK_RTC - - - +6 SDIO_CLK SD_CLK SPI_CLK - GPIO6 U1CTS Connect to SD_CLK (Series R: 200Ω) +7 SDIO_DATA_0 SD_DATA0 SPI_MISO - GPIO7 U1TXD Connect to SD_D0 (Series R: 200Ω) +8 SDIO_DATA_1 SD_DATA1 SPI_MOSI - GPIO8 U1RXD Connect to SD_D1 (Series R: 200Ω) +9 SDIO_DATA_2 SD_DATA2 SPIHD - GPIO9 HSPIHD Connect to SD_D2 (Series R: 20Ω) +10 SDIO_DATA_3 SD_DATA3 SPIWP - GPIO10 HSPIWP Connect to SD_D3 (Series R: 200Ω) +11 SDIO_CMD SD_CMD SPI_CS0 - GPIO11 U1RTS Connect to SD_CMD (Series R: 200Ω) +12 MTDI MTDI I2SI_DATA HSPI_MISO GPIO12 U0DTR +13 MTCK MTCK I2SI_BCK HSPI_MOSI GPIO13 U0CTS +14 MTMS MTMS I2SI_WS HSPI_CLK GPIO14 U0DSR +15 MTDO MTDO I2SO_BCK HSPI_CS GPIO15 U0RTS +16 XPD_DCDC GPIO16 - - - - Deep-sleep wakeup (need to be connected to EXT_RSTB) diff --git a/Sming/Arch/Esp8266/esp8266-soc.json b/Sming/Arch/Esp8266/esp8266-soc.json index 9e1d975039..e05c452652 100644 --- a/Sming/Arch/Esp8266/esp8266-soc.json +++ b/Sming/Arch/Esp8266/esp8266-soc.json @@ -1,4 +1,58 @@ { "variant": "esp8266", - "name": "ESP8266EX" + "name": "ESP8266EX", + "peripherals": { + "CLOCKS": { + "sigmask": "CLK.+" + }, + "GPIO": { + "sigmask": "GPIO.+" + }, + "JTAG": { + "sigmask": "MTCK|MTDI|MTDO|MTMS" + }, + "UART0": { + "sigmask": "U0.+", + "default": { + "TXD": [ + "U0TXD", + 1 + ], + "RXD": [ + "U0RXD", + 3 + ] + }, + "swap": { + "pins": { + "U0RXD": "U0CTS", + "U0TXD":"U0RTS" + }, + "help": "Use alternate pins by calling Serial.swap() *after* begin()" + } + }, + "UART1": { + "sigmask": "U1.+", + "default": { + "TXD": [ + "U1TXD", + 2 + ], + "RXD": null + } + }, + "SDIO": { + "sigmask": "SD.+" + }, + "SPI0": { + "sigmask": "SPI.+" + }, + "SPI1": { + "sigmask": "HSPI.+" + }, + "I2S": { + "sigmask": "I2S.+" + }, + "WIFI": {} + } } \ No newline at end of file diff --git a/Sming/Arch/Host/host-pindefs.txt b/Sming/Arch/Host/host-pindefs.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Arch/Host/host-soc.json b/Sming/Arch/Host/host-soc.json index f813fd1cb3..4d4bc950ee 100644 --- a/Sming/Arch/Host/host-soc.json +++ b/Sming/Arch/Host/host-soc.json @@ -1,4 +1,7 @@ { "variant": "host", - "name": "Host Emulator" + "name": "Host Emulator", + "peripherals": { + "WIFI": {} + } } \ No newline at end of file diff --git a/Sming/Arch/Rp2040/rp2040-pindefs.txt b/Sming/Arch/Rp2040/rp2040-pindefs.txt new file mode 100644 index 0000000000..c4b0f2a230 --- /dev/null +++ b/Sming/Arch/Rp2040/rp2040-pindefs.txt @@ -0,0 +1,32 @@ +[io_mux] +gpio f1 f2 f3 f4 ff5 ff6 ff7 f8 f9 notes +0 SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 - USB_OVCUR_DET +1 SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 - USB_VBUS_DET +2 SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 - USB_VBUS_EN +3 SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 - USB_OVCUR_DET +4 SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 - USB_VBUS_DET +5 SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 - USB_VBUS_EN +6 SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 - USB_OVCUR_DET +7 SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 - USB_VBUS_DET +8 SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 - USB_VBUS_EN +9 SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 - USB_OVCUR_DET +10 SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 - USB_VBUS_DET +11 SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 - USB_VBUS_EN +12 SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 - USB_OVCUR_DET +13 SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 - USB_VBUS_DET +14 SPI1_SCK UART0_CTS I2C1_SDA PWM7_A SIO PIO0 PIO1 - USB_VBUS_EN +15 SPI1_TX UART0_RTS I2C1_SCL PWM7_B SIO PIO0 PIO1 - USB_OVCUR_DET +16 SPI0_RX UART0_TX I2C0_SDA PWM0_A SIO PIO0 PIO1 - USB_VBUS_DET +17 SPI0_CSn UART0_RX I2C0_SCL PWM0_B SIO PIO0 PIO1 - USB_VBUS_EN +18 SPI0_SCK UART0_CTS I2C1_SDA PWM1_A SIO PIO0 PIO1 - USB_OVCUR_DET +19 SPI0_TX UART0_RTS I2C1_SCL PWM1_B SIO PIO0 PIO1 - USB_VBUS_DET +20 SPI0_RX UART1_TX I2C0_SDA PWM2_A SIO PIO0 PIO1 CLOCK_GPIN0 USB_VBUS_EN +21 SPI0_CSn UART1_RX I2C0_SCL PWM2_B SIO PIO0 PIO1 CLOCK_GPOUT0 USB_OVCUR_DET +22 SPI0_SCK UART1_CTS I2C1_SDA PWM3_A SIO PIO0 PIO1 CLOCK_GPIN1 USB_VBUS_DET +23 SPI0_TX UART1_RTS I2C1_SCL PWM3_B SIO PIO0 PIO1 CLOCK_GPOUT1 USB_VBUS_EN +24 SPI1_RX UART1_TX I2C0_SDA PWM4_A SIO PIO0 PIO1 CLOCK_GPOUT2 USB_OVCUR_DET +25 SPI1_CSn UART1_RX I2C0_SCL PWM4_B SIO PIO0 PIO1 CLOCK_GPOUT3 USB_VBUS_DET +26 SPI1_SCK UART1_CTS I2C1_SDA PWM5_A SIO PIO0 PIO1 - USB_VBUS_EN +27 SPI1_TX UART1_RTS I2C1_SCL PWM5_B SIO PIO0 PIO1 - USB_OVCUR_DET +28 SPI1_RX UART0_TX I2C0_SDA PWM6_A SIO PIO0 PIO1 - USB_VBUS_DET +29 SPI1_CSn UART0_RX I2C0_SCL PWM6_B SIO PIO0 PIO1 - USB_VBUS_EN diff --git a/Sming/Arch/Rp2040/rp2040-soc.json b/Sming/Arch/Rp2040/rp2040-soc.json index 214f361e03..0fa28982f0 100644 --- a/Sming/Arch/Rp2040/rp2040-soc.json +++ b/Sming/Arch/Rp2040/rp2040-soc.json @@ -1,4 +1,53 @@ { "variant": "rp2040", - "name": "RP2040" + "name": "RP2040", + "peripherals": { + "CLOCK": { + "sigmask": "{name}.+" + }, + "SPI[0-1]": { + "sigmask": "{name}.+" + }, + "UART0": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART0_TX", + 0 + ], + "RXD": [ + "UART0_RX", + 1 + ] + } + }, + "UART1": { + "sigmask": "{name}.+", + "default": { + "TXD": [ + "UART1_TX", + 4 + ], + "RXD": [ + "UART1_RX", + 5 + ] + } + }, + "I2C[0-1]": { + "sigmask": "{name}.+" + }, + "PIO[0-1]": { + "sigmask": "{name}.+" + }, + "PWM[0-7]": { + "sigmask": "{name}.+" + }, + "SIO": { + "sigmask": "{name}.+" + }, + "USB": { + "sigmask": "{name}.+" + } + } } \ No newline at end of file diff --git a/Sming/project.mk b/Sming/project.mk index cb5ce2ade6..c26eb49f0b 100644 --- a/Sming/project.mk +++ b/Sming/project.mk @@ -725,11 +725,12 @@ KCONFIG_ENV := \ KCONFIG_CONFIG=$(KCONFIG_CONFIG) CFGTOOL_CMDLINE = $(KCONFIG_ENV) $(PYTHON) $(SMING_TOOLS)/cfgtool.py $(CONFIG_CACHE_FILE) +MENUCONFIG = MENUCONFIG_STYLE="separator=fg:white,bg:red" $(PYTHON) -m menuconfig .PHONY: menuconfig menuconfig: checksoc ##Run option editor $(Q) $(CFGTOOL_CMDLINE) --to-kconfig - $(Q) $(KCONFIG_ENV) $(PYTHON) -m menuconfig $(SMING_HOME)/Kconfig + $(Q) $(KCONFIG_ENV) $(MENUCONFIG) $(SMING_HOME)/Kconfig $(Q) $(CFGTOOL_CMDLINE) --from-kconfig .PHONY: list-soc @@ -745,3 +746,17 @@ ifeq (,$(findstring $(SMING_SOC),$(PROJECT_SOC))) else $(info - YES: $(SMING_SOC)) endif + +BOARDTOOL_CMDLINE = $(PYTHON) $(SMING_TOOLS)/boardtool.py $(if $V,-v) + +.PHONY: list-default-pins +list-default-pins: ##List default periperal pins + $(Q) $(BOARDTOOL_CMDLINE) list-default-pins + +PIN_MENU := $(abspath $(OUT_BASE)/../pin.menu) +PIN_CONFIG := $(abspath $(OUT_BASE)/../pin.cfg) + +.PHONY: pinmenu +pinmenu: checksoc ##Run pin editor + $(Q) $(BOARDTOOL_CMDLINE) generate-pinmenu > $(PIN_MENU) + $(Q) CONFIG_=SMG_ KCONFIG_CONFIG=$(PIN_CONFIG) $(MENUCONFIG) $(PIN_MENU) diff --git a/Tools/boardtool.py b/Tools/boardtool.py new file mode 100644 index 0000000000..e3cb48327d --- /dev/null +++ b/Tools/boardtool.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +# +# Sming board configuration management tool +# +# Provides support for board features and pin configuration. +# +# + +import argparse, os, sys, json, re +import natsort as ns + +sys.path.insert(1, os.path.expandvars('${SMING_HOME}/../Tools/Python')) +from rjsmin import jsmin + +verbose = False + +def find(lst, item): + res = [x for x in lst if item == x] + return res[0] if res else None + + +class Group(object): + """A group of items from pindefs, such as io_mux, rtc_mux, etc.""" + + def __init__(self, name): + self.fieldnames = None + self.name = name + self.entries = [] + + def __repr__(self): + return self.name + + +class Entry(object): + """A group entry containing row of information fields from pindefs""" + + def __init__(self, group, fields): + self.group = group + self.fields = tuple(fields) + + def __getattr__(self, name): + if name == 'fieldnames': + return self.group.fieldnames + return self.__getitem__(name) + + def __getitem__(self, item): + """Allow entry access by name or index.""" + if isinstance(item, str): + try: + item = self.fieldnames.index(item) + except ValueError: + return None + return self.fields[item] + + def __repr__(self): + return str(self.fields) + + +class Signal(object): + """Describes a peripheral signal which can be connected to a pin.""" + + def __init__(self, entry, name, type): + self.entries = [entry] + self.name = name + self.type = type + self.peripheral = None + + def __repr__(self): + return f"{self.name}" + + def __eq__(self, other): + if isinstance(other, str): + return other == self.name + else: + return self.name == other.name + + +class Pin(object): + """Describes a physical pin using GPIO numbering.""" + + def __init__(self, gpio, name, type): + self.gpio = gpio + self.name = name or f"GPIO{gpio}" + self.signals = [] + self.type = type + + def __repr__(self): + # return f"{self.gpio}: " + ", ".join(f"{s}" for s in self.signals) + return f"{self.gpio}: " + ", ".join(f"{s} ({s.group})" for s in self.signals) + + +class Peripheral(object): + """Describes a peripheral with associated signals.""" + + def __init__(self, name, title, sigmask, default): + self.name = name + self.title = title + self.sigmask = re.compile(sigmask) if sigmask else None + self.default = default + self.signals = [] + self.swap = None + + def help(self): + """Obtain help text displayed in menus""" + res = [] + if self.title: + res += [f"{self.title}."] + res += [sig.name for sig in self.signals] + return res + + +class Config(object): + """Contains parsed SOC pin, signal and peripheral information.""" + + def __init__(self, arch, variant, name): + self.arch = arch + self.variant = variant + self.name = name + self.default = None + self.signals = [] + self.peripherals = [] + + def __repr__(self): + return self.name + + @classmethod + def load_file(cls, filename): + if verbose: + print(f"Loading '{os.path.basename(filename)}'", file=sys.stderr) + s = open(filename, 'r').read() + dn = os.path.dirname(filename) + arch = os.path.basename(dn) + spec = json.loads(jsmin(s)) + config = Config(arch, spec['variant'], spec['name']) + + pindefs = filename.replace('-soc.json', '-pindefs.txt') + with open(pindefs) as f: + lines = f.readlines() + config.parse_pindefs(lines) + + natsort_key = ns.natsort_keygen(key = lambda sig: sig.name, alg=ns.LOWERCASEFIRST) + config.signals.sort(key = natsort_key) + + config.parse_peripherals(spec['peripherals']) + return config + + def parse_pindefs(self, lines): + groups = {} + fieldnames = None + + for line in lines: + line = line.strip() + if line == '' or line.startswith(('#', ';', '//')): + continue + if line[0] == '[': + groupname = line[1:len(line)-1] + group = groups[groupname] = Group(groupname) + fieldnames = None + continue + if fieldnames is None: + fieldnames = group.fieldnames = line.split() + continue + fields = [] + for i in range(len(fieldnames)-1): + field, sep, line = line.partition(' ') + fields.append(field) + fields.append(line) + entry = Entry(group, fields) + group.entries.append(entry) + + self.pins = {} + for name, group in groups.items(): + if name == 'gpio_matrix': + self.parse_gpio_matrix(group) + else: + self.parse_iomux(group) + + def parse_iomux(self, group): + for e in group.entries: + gpio = int(e.gpio) + pin = self.pins.get(gpio) + if pin is None: + pin = self.pins[gpio] = Pin(gpio, e.pad, 'I' if 'I' in e.notes else 'IO') + p = re.compile("a|f[0-9]+") + for n in filter(p.match, group.fieldnames): + sig_name = e[n] + if sig_name is None or sig_name == '-': + continue + sig = find(self.signals, sig_name) + if sig is None: + sig = Signal(e, sig_name, pin.type) + self.signals.append(sig) + elif e not in sig.entries: + sig.entries.append(e) + if sig not in pin.signals: + pin.signals.append(sig) + p = re.compile("ff[0-9]+") + for n in filter(p.match, group.fieldnames): + sig = Signal(e, f"{e[n]}_{gpio}", pin.type) + pin.signals.append(sig) + self.signals.append(sig) + + def parse_gpio_matrix(self, group): + """Signals can be switched to any GPIO.""" + def addSignal(e, f): + sig = getattr(e, f) + if sig == '-': + return + is_input = (f == 'input') + sig = Signal(e, sig, 'I' if is_input else 'O') + self.signals.append(sig) + + for i, pin in self.pins.items(): + if is_input or 'O' in pin.type: + if not sig in pin.signals: + pin.signals.append(sig) + + for e in group.entries: + addSignal(e, 'input') + addSignal(e, 'output') + + def parse_peripherals(self, spec): + for name_spec, periphdef in spec.items(): + p = re.compile('\[([0-9]+)-([0-9]+)\]') + matches = p.findall(name_spec) + if len(matches) == 0: + indexRange = range(-1, 0) + else: + m = matches[0] + indexRange = range(int(m[0]), int(m[1]) + 1) + + title = periphdef.get('title') + for idx in indexRange: + name = p.sub(str(idx), name_spec) + mask = periphdef.get('sigmask') + if not mask: + break + for tok in ['idx', 'name']: + mask = mask.replace(f'{{{tok}}}', str(locals()[tok])) + per = Peripheral(name, title, mask, periphdef.get('default', {})) + self.peripherals.append(per) + for sig in self.signals: + if per.sigmask.match(sig.name): + per.signals.append(sig) + if sig.peripheral is not None: + raise RuntimeError(f"Attempted to assign signal {sig} to {per.name} but already assigned to {sig.peripheral.name}") + sig.peripheral = per + per.swap = periphdef.get('swap') + + + # Create 'Other' peripheral to catch undefined signals + per = Peripheral('Other', 'Signals not associated with any peripheral', '', '') + for sig in self.signals: + if sig.peripheral is None: + sig.peripheral = per + per.signals.append(sig) + if len(per.signals) != 0: + self.peripherals.append(per) + + +def load_configs(socs = ''): + """Load configurations for specific SOCs.""" + def match(path): + if socs == '': + return True + base = os.path.basename(path) + for s in socs.split(): + if base.startswith(s + '-'): + return True + return False + res = [] + for f in filter(match, os.environ['SOC_CONFIG_FILES'].split()): + res.append(Config.load_file(f)) + return res + + +def list_soc(args): + configs = load_configs() + configs.sort(key = lambda x: x.name) + for config in configs: + print() + print(config.variant) + print(f' name: {config.name}') + print(f' arch: {config.arch}') + print(f' pins: {len(config.pins)}') + print(f' signals: {len(config.signals)}') + print(f' peripherals: {len(config.peripherals)}') + if args.verbose: + for per in config.peripherals: + print(f'{per.name:>13}: {len(per.signals)} signals') + + +def load_active_config(): + return Config.load_file(os.environ['SOC_CONFIG_FILE']) + + +def generate_pinmenu(args): + config = load_active_config() + + menu = [f'mainmenu "{config.name} Pin Configuration"'] + + menu += ['menu "Peripherals"'] + for per in config.peripherals: + menu += [ + f' config PERIPH_{per.name}_ENABLE', + f' bool "{per.name}"', + f' default y', + f' help' + ] + menu += [f' {s}' for s in per.help()] + if per.swap: + menu += [ + f' config PERIPH_{per.name}_SWAP_ENABLE', + f' bool "Swap {per.name} signals"', + f' default n', + f' depends on PERIPH_{per.name}_ENABLE', + f' help', + f' {per.swap["help"]}' + ] + menu += ['endmenu'] + + menu += ['menu "Pin selections"'] + for n, pin in config.pins.items(): + menu += [ + f' choice', + f' prompt "GP{pin.type} {n}"', + f' default PINSEL{int(n):02d}_{pin.signals[0]}' + ] + + for sig in pin.signals: + per = sig.peripheral + alt = None + if per.swap is not None: + for a, b in per.swap['pins'].items(): + if a == sig.name: + alt = find(config.signals, b) + break + if b == sig.name: + alt = find(config.signals, a) + break + + def addsig(sig, swap = None): + nonlocal menu + depends = f"PERIPH_{per.name}_ENABLE" + if swap is not None: + depends += " &&" + if not swap: + depends += "!" + depends += f"PERIPH_{per.name}_SWAP_ENABLE" + menu += [ + f' config PINSEL{int(n):02d}_{sig.name}', + f' bool "{sig.name}"', + f' depends on {depends}', + f' help', + f' Peripheral "{per.name}", {", ".join(entry.group.name for entry in sig.entries)}' + ] + + if alt is None: + addsig(sig) + else: + addsig(sig, False) + addsig(alt, True) + + menu += [' endchoice'] + menu += ['endmenu'] + + for line in menu: + print(line) + + +def list_default_pins(args): + config = load_active_config() + + for per in config.peripherals: + if not per.default: + continue + print(f'/* {per.name} */\n') + for k, v in per.default.items(): + if v is None: + gpio = 0xff + else: + sig, gpio = v + if sig not in per.signals: + raise RuntimeError(f"Invalid signal '{sig}' for {per.name}") + pin = config.pins[gpio] + if sig not in pin.signals: + raise RuntimeError(f"Invalid signal '{sig}' for {pin.name}") + print(f"#define SMG_PINDEF_{per.name}_{k} {gpio}") + print('\n') + + +def main(): + global verbose + + parser = argparse.ArgumentParser(description='Sming board configuration tool') + parser.add_argument('-v', '--verbose', help='Verbose output', action='store_true', default=False) + subparsers = parser.add_subparsers() + + sub = subparsers.add_parser('list-soc', help="List available SOCs") + sub.set_defaults(func=list_soc) + + sub = subparsers.add_parser('generate-pinmenu', help="Generate pin menu") + sub.set_defaults(func=generate_pinmenu) + + sub = subparsers.add_parser('list-default-pins', help="List default pins") + sub.set_defaults(func=list_default_pins) + + args = parser.parse_args() + verbose = args.verbose + fn = args.func + if fn is not None: + fn(args) + + +if __name__ == '__main__': + main() diff --git a/Tools/requirements.txt b/Tools/requirements.txt index bc47cf1a0c..2dacbee54b 100644 --- a/Tools/requirements.txt +++ b/Tools/requirements.txt @@ -1,3 +1,4 @@ pyserial jsonschema kconfiglib +natsort From 08bcd36b0f91e3afc41034e5ff895846d3e990da Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 28 Jul 2022 14:03:31 +0100 Subject: [PATCH 12/58] Fixes for latest ESP32 SDK 4.3 (#2534) * Fixes for latest ESP32 SDK 4.3 * Fix ICACHE_FLASH_SECTION --- Sming/Arch/Esp32/Components/driver/uart.cpp | 2 +- Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index 4a7f93bc59..deb4f4ed1b 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -58,7 +58,7 @@ struct smg_uart_pins_t { #define UART2_PIN_DEFAULT UART_NUM_2_TXD_DIRECT_GPIO_NUM, UART_NUM_2_RXD_DIRECT_GPIO_NUM #elif defined(SOC_ESP32C3) #define UART0_PIN_DEFAULT 21, 20 -#define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM +#define UART1_PIN_DEFAULT 10, 9 #elif defined(SOC_ESP32S2) #define UART0_PIN_DEFAULT 43, 44 #define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM diff --git a/Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h b/Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h index ddae2e56eb..9e91a5fdab 100644 --- a/Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h +++ b/Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h @@ -16,7 +16,7 @@ #define DMEM_ATTR __attribute__((section(".bss"))) #define SHMEM_ATTR -#define ICACHE_FLASH_SECTION ".irom0.text" +#define ICACHE_FLASH_SECTION ".text" #undef ICACHE_FLASH_ATTR #define ICACHE_FLASH_ATTR \ From f91c6ada4413c6b2c5a0438d96f355ce1842ae83 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 28 Jul 2022 14:05:47 +0100 Subject: [PATCH 13/58] Fix rp2040 tx done interrupt (#2531) Interrupt is edge-triggered so can be left enabled --- Sming/Arch/Rp2040/Components/driver/uart.cpp | 22 +++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Sming/Arch/Rp2040/Components/driver/uart.cpp b/Sming/Arch/Rp2040/Components/driver/uart.cpp index ecb8a3e076..7bcf300c17 100644 --- a/Sming/Arch/Rp2040/Components/driver/uart.cpp +++ b/Sming/Arch/Rp2040/Components/driver/uart.cpp @@ -143,26 +143,20 @@ void IRAM_ATTR handleInterrupt(smg_uart_t* uart, uart_dev_t* dev) } } - // Unless we replenish TX FIFO, disable after handling interrupt auto txfifo_empty = mis & UART_UARTMIS_TXMIS_BITS; if(txfifo_empty) { // Dump as much data as we can from buffer into the TX FIFO if(uart->tx_buffer != nullptr) { size_t avail = uart->tx_buffer->available(); + if(avail != 0) { + // We're topping up TX FIFO so defer callback until next time + user_is &= ~UART_UARTMIS_TXMIS_BITS; + } while(avail-- && !uart_txfifo_full(dev)) { uint8_t c = uart->tx_buffer->readChar(); dev->dr = c; } } - - // If TX FIFO remains empty then we must disable TX FIFO EMPTY interrupt to stop it recurring. - if(uart_txfifo_empty(dev)) { - // The interrupt gets re-enabled by uart_write() - hw_clear_bits(&dev->imsc, UART_UARTIMSC_TXIM_BITS); - } else { - // We've topped up TX FIFO so defer callback until next time - user_is &= ~UART_UARTMIS_TXMIS_BITS; - } } } @@ -326,7 +320,8 @@ void smg_uart_start_isr(smg_uart_t* uart) * transfer direction and begin waiting for a response. */ - // TX FIFO empty interrupt only gets enabled via uart_write function() + // Enable TX FIFO EMPTY interrupt (edge-trigger) + int_ena |= UART_UARTIMSC_TXIM_BITS; // Trigger at <= 1/8 full fifo_level_select |= 0 << UART_UARTIFLS_TXIFLSEL_LSB; @@ -362,10 +357,7 @@ size_t smg_uart_write(smg_uart_t* uart, const void* buffer, size_t size) while(written < size && !uart_txfifo_full(dev)) { dev->dr = buf[written++]; } - - // Enable TX FIFO EMPTY interrupt dev->icr = UART_UARTMIS_TXMIS_BITS; - hw_set_bits(&dev->imsc, UART_UARTIMSC_TXIM_BITS); } // Write any remaining data into transmit buffer @@ -486,10 +478,10 @@ void smg_uart_flush(smg_uart_t* uart, smg_uart_mode_t mode) if(flushTx) { // Prevent TX FIFO EMPTY interrupts - don't need them until uart_write is called again - hw_clear_bits(&dev->imsc, UART_UARTIMSC_TXIM_BITS); while(!uart_txfifo_empty(dev)) { // } + dev->icr = UART_UARTICR_TXIC_BITS; } // If receive overflow occurred then these interrupts will be masked From a85f7b57cac9e52f4d0597c3f276175f4392d5ca Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 29 Jul 2022 11:51:51 +0100 Subject: [PATCH 14/58] Missing `#pragma once` in `Data/Range.h` (#2532) --- Sming/Core/Data/Range.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index 56fed9ee55..0a06825a03 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -8,6 +8,8 @@ * ****/ +#pragma once + #include #include From b1b4d79b48b2f5fff6faea4e8a48cb0499569808 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 29 Jul 2022 11:53:08 +0100 Subject: [PATCH 15/58] Fix Partition == operator (#2533) --- Sming/Components/Storage/src/include/Storage/Partition.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index d0f26c36e1..c101b3bfd3 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -352,7 +352,7 @@ class Partition bool operator==(const Partition& other) const { - return this == &other; + return mDevice == other.mDevice && mPart == other.mPart; } bool operator==(const char* name) const From d2923bdc26d8bf386863cd66e72c0638d19105ce Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 29 Jul 2022 11:53:35 +0100 Subject: [PATCH 16/58] Add support for TX_DONE interrupt for ESP32 in IOControl modbus (#2535) * Allow enabling of TX_DONE for ESP32 UART. Add interrupt mask control to smg_uart_intr_config_t * Update IOControl library with fixes for modbus on esp32c3, and use TX_DONE interrupt. --- Sming/Arch/Esp32/Components/driver/uart.cpp | 3 +++ Sming/Components/arch_driver/src/include/driver/uart.h | 4 ++++ Sming/Libraries/IOControl | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index deb4f4ed1b..0015310cc3 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -728,6 +728,9 @@ bool smg_uart_intr_config(smg_uart_t* uart, const smg_uart_intr_config_t* config uart_ll_set_txfifo_empty_thr(dev, TRange(0, UART_TXFIFO_EMPTY_THRHD).clip(config->txfifo_empty_intr_thresh)); } + dev->int_clr.val = config->intr_mask; + dev->int_ena.val = (dev->int_ena.val & ~config->intr_mask) | config->intr_enable; + return true; } diff --git a/Sming/Components/arch_driver/src/include/driver/uart.h b/Sming/Components/arch_driver/src/include/driver/uart.h index f7ed88c90e..7af7235452 100644 --- a/Sming/Components/arch_driver/src/include/driver/uart.h +++ b/Sming/Components/arch_driver/src/include/driver/uart.h @@ -149,6 +149,7 @@ enum smg_uart_format_t { // Status values enum smg_uart_status_t { + UART_STATUS_TX_DONE = BIT(14), ///< All data transmitted (ESP32 only) UART_STATUS_RXFIFO_TOUT = BIT(8), UART_STATUS_BRK_DET = BIT(7), UART_STATUS_CTS_CHG = BIT(6), @@ -284,6 +285,9 @@ typedef struct { uint8_t rx_timeout_thresh; uint8_t txfifo_empty_intr_thresh; uint8_t rxfifo_full_thresh; ///< Ignored if additional buffers are allocated + uint8_t reserved; + uint32_t intr_mask; ///< Mask of smg_uart_status_t indicating which interrupt bits to change + uint32_t intr_enable; ///< State of interrupt bits } smg_uart_intr_config_t; /** diff --git a/Sming/Libraries/IOControl b/Sming/Libraries/IOControl index 48a5f8ef43..d6a6ba1999 160000 --- a/Sming/Libraries/IOControl +++ b/Sming/Libraries/IOControl @@ -1 +1 @@ -Subproject commit 48a5f8ef43ce20452090ad79893f0b0735607828 +Subproject commit d6a6ba1999542c4eba74e0aca24eda26901ee4d8 From d15b0523eec053e4039fe9028af9badb2eaa03d7 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 30 Jul 2022 16:51:19 +0100 Subject: [PATCH 17/58] Fix valgrind invocation when ENABLE_HOST_UARTID is defined (#2537) --- Sming/Arch/Host/app.mk | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Sming/Arch/Host/app.mk b/Sming/Arch/Host/app.mk index 9a7bcac527..795589309a 100644 --- a/Sming/Arch/Host/app.mk +++ b/Sming/Arch/Host/app.mk @@ -30,12 +30,10 @@ $(TARGET_OUT_0): $(COMPONENTS_AR) $(Q) cat $(FW_MEMINFO) ##@Tools -.PHONY: valgrind -valgrind: all ##Run the application under valgrind to detect memory issues. Requires `valgrind` to be installed on the host system. - $(Q) valgrind --track-origins=yes --leak-check=full \ - $(foreach id,$(ENABLE_HOST_UARTID),echo '$(call RunHostTerminal,$(id))' >> $@;) \ - $(TARGET_OUT_0) $(CLI_TARGET_OPTIONS) -- $(HOST_PARAMETERS) +.PHONY: valgrind +valgrind: + $(Q) RUN_COMMAND_PREFIX="valgrind --track-origins=yes --leak-check=full" $(MAKE) run RUN_SCRIPT := $(FW_BASE)/run.sh @@ -46,7 +44,7 @@ run: all $(RUN_SCRIPT) ##Run the application image $(RUN_SCRIPT):: $(Q) echo '#!/bin/bash' > $@; \ $(foreach id,$(ENABLE_HOST_UARTID),echo '$(call RunHostTerminal,$(id))' >> $@;) \ - echo '$(TARGET_OUT_0) $(CLI_TARGET_OPTIONS) -- $(HOST_PARAMETERS)' >> $@; \ + echo '$(RUN_COMMAND_PREFIX) $(TARGET_OUT_0) $(CLI_TARGET_OPTIONS) -- $(HOST_PARAMETERS)' >> $@; \ chmod a+x $@ ##@Flashing From 6b5578877912b524ca171bb0060ff466466f4bf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Aug 2022 18:04:54 +0200 Subject: [PATCH 18/58] Bump mistune from 0.8.4 to 2.0.3 in /docs (#2536) Bumps [mistune](https://github.com/lepture/mistune) from 0.8.4 to 2.0.3. - [Release notes](https://github.com/lepture/mistune/releases) - [Changelog](https://github.com/lepture/mistune/blob/master/docs/changes.rst) - [Commits](https://github.com/lepture/mistune/compare/v0.8.4...v2.0.3) --- updated-dependencies: - dependency-name: mistune dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 4ee83e6283..804f7d2515 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,7 +3,7 @@ sphinx==4.2.0 sphinx-rtd-theme==1.0.0 m2r2==0.3.1 -mistune==0.8.4 # Version 2 not compatible with m2r2 +mistune==2.0.3 # Version 2 not compatible with m2r2 breathe==4.31.0 sphinxcontrib-wavedrom sphinx-copybutton From 8d126057644b774f31cd6a048701027b33ea01fc Mon Sep 17 00:00:00 2001 From: Simon Brazell Date: Sun, 7 Aug 2022 14:56:27 +1000 Subject: [PATCH 19/58] The Ultrasonic_HCSR04 sample missing Serial.begin. (#2539) Also added .DS_Store (macOS folder information files) to gitignore. --- .gitignore | 1 + samples/Ultrasonic_HCSR04/app/application.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4b6b1485ca..70e63abe10 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ nbproject GTAGS GRTAGS GPATH +.DS_Store # Tag files created by build system .submodule diff --git a/samples/Ultrasonic_HCSR04/app/application.cpp b/samples/Ultrasonic_HCSR04/app/application.cpp index bf3d87e8ba..756e9e3c76 100644 --- a/samples/Ultrasonic_HCSR04/app/application.cpp +++ b/samples/Ultrasonic_HCSR04/app/application.cpp @@ -28,6 +28,7 @@ void measure() void init() { + Serial.begin(SERIAL_BAUD_RATE); ultrasonic.begin(TRIG_PIN, ECHO_PIN); procTimer.initializeMs(500, measure).start(); } From 5d2000ae7d955a88570dfab624a9024ed36d58c9 Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 7 Aug 2022 08:39:01 +0100 Subject: [PATCH 20/58] Fix `pulseIn()` (#2538) --- Sming/Arch/Esp8266/Core/Digital.cpp | 37 ++++++++++++++--------------- Sming/Core/PolledTimer.h | 4 ++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Sming/Arch/Esp8266/Core/Digital.cpp b/Sming/Arch/Esp8266/Core/Digital.cpp index 1f6d31604d..434b69589f 100644 --- a/Sming/Arch/Esp8266/Core/Digital.cpp +++ b/Sming/Arch/Esp8266/Core/Digital.cpp @@ -13,6 +13,7 @@ #include #include #include +#include // Prototype declared in esp8266-peri.h const uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, @@ -143,36 +144,34 @@ unsigned long pulseIn(uint16_t pin, uint8_t state, unsigned long timeout) // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. uint32_t bit = digitalPinToBitMask(pin); - // uint8_t port = digitalPinToPort(pin); // Does nothing in Sming, comment-out to prevent compiler warning uint32_t stateMask = (state ? bit : 0); - unsigned long width = 0; // keep initialization out of time critical area - // convert the timeout from microseconds to a number of times through - // the initial loop; it takes 16 clock cycles per iteration. - unsigned long numloops = 0; - unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; + auto pinState = [&]() -> bool { return (*portInputRegister() & bit) == stateMask; }; + + OneShotFastUs timeoutTimer(timeout); // wait for any previous pulse to end - while((*portInputRegister(port) & bit) == stateMask) - if(numloops++ == maxloops) + while(pinState()) { + if(timeoutTimer.expired()) { return 0; + } + } // wait for the pulse to start - while((*portInputRegister(port) & bit) != stateMask) - if(numloops++ == maxloops) + while(!pinState()) { + if(timeoutTimer.expired()) { return 0; + } + } + + CpuCycleTimer cycleTimer; // wait for the pulse to stop - while((*portInputRegister(port) & bit) == stateMask) { - if(numloops++ == maxloops) + while(pinState()) { + if(timeoutTimer.expired()) { return 0; - width++; + } } - // convert the reading to microseconds. The loop has been determined - // to be 20 clock cycles long and have about 16 clocks between the edge - // and the start of the loop. There will be some error introduced by - // the interrupt handlers. - - return clockCyclesToMicroseconds(width * 21 + 16); + return cycleTimer.elapsedTime().as(); } diff --git a/Sming/Core/PolledTimer.h b/Sming/Core/PolledTimer.h index 1200e0df9f..2a85dc0cdb 100644 --- a/Sming/Core/PolledTimer.h +++ b/Sming/Core/PolledTimer.h @@ -225,7 +225,7 @@ class Timer : public NanoTime::TimeSource } private: - bool IRAM_ATTR checkExpired(const TickType& ticks) const + __forceinline bool IRAM_ATTR checkExpired(const TickType& ticks) const { // canWait() is not checked here // returns "can expire" and "time expired" @@ -248,7 +248,7 @@ class Timer : public NanoTime::TimeSource return result; } - bool IRAM_ATTR expiredOneShot() + __forceinline bool IRAM_ATTR expiredOneShot() { // Remain triggered until manually reset or cancelled if(!canWait() || hasExpired) { From 279460f9978a7826f10c71e18526a465bfddcbd9 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 8 Aug 2022 11:27:28 +0200 Subject: [PATCH 21/58] Revert mistune version bump. (#2540) --- docs/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 804f7d2515..f731a1c431 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,8 +2,8 @@ # list of Python packages used in documentation build sphinx==4.2.0 sphinx-rtd-theme==1.0.0 -m2r2==0.3.1 -mistune==2.0.3 # Version 2 not compatible with m2r2 +m2r2==0.3.2 +# mistune==2.0.3 # Version 2 not compatible with m2r2 breathe==4.31.0 sphinxcontrib-wavedrom sphinx-copybutton From 012ecf460bacb5b8c5e55c58fe6212be61c53bb9 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 15:42:33 +0100 Subject: [PATCH 22/58] Fix Storage partition issues (#2548) * Fix partition `offset` parameter type, should be `uint32_t` not `size_t` * Add missing `spiffs1` partition to `Basic_Ota` sample Also make `SMING_ARCH` and `SMING_SOC` available for `address` field. * Fix Storage README * Enable partition iteration using `for(auto: partitions...)` pattern * Revise out-of-date `rboot-ota` information page. --- Sming/Components/Storage/README.rst | 9 ++++---- .../Storage/Tools/hwconfig/config.py | 2 +- .../Storage/Tools/hwconfig/partition.py | 2 ++ Sming/Components/Storage/component.mk | 2 ++ Sming/Components/Storage/src/Debug.cpp | 4 ++-- Sming/Components/Storage/src/Iterator.cpp | 17 +++----------- Sming/Components/Storage/src/Partition.cpp | 6 ++--- .../Storage/src/include/Storage/Iterator.h | 22 ++++++++++++++++--- .../Storage/src/include/Storage/Partition.h | 8 +++---- .../src/include/Storage/PartitionTable.h | 4 ++-- docs/source/information/rboot-ota.rst | 6 ++--- samples/Basic_Ota/app/application.cpp | 4 ++-- samples/Basic_Ota/ota.hw | 9 ++++++++ samples/Basic_Storage/app/application.cpp | 6 ++--- tests/HostTests/modules/Storage.cpp | 3 +-- 15 files changed, 60 insertions(+), 44 deletions(-) diff --git a/Sming/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index 4b86403ff0..ef4a5cccd9 100644 --- a/Sming/Components/Storage/README.rst +++ b/Sming/Components/Storage/README.rst @@ -189,7 +189,7 @@ To customise the hardware configuration for a project, for example 'my_project': To rebuild these manually type:: - make partbuild + make buildpart These will be removed when ``make clean`` is run, but you can also clean them separately thus:: @@ -338,14 +338,13 @@ This is a C++ interface. Some examples:: } // Enumerate all partitions - for(auto it = Storage::findPartition(); it; ++it) { - auto part = *it; + for(auto part: Storage::findPartition()) { debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); } // Enumerate all SPIFFS partitions - for(auto it = Storage::findPartition(Partition::SubType::Data::spiffs; it; it++) { - debugf("Found '%s' at 0x%08x, size 0x%08x", it->name().c_str(), it->address(), it->size()); + for(auto part: Storage::findPartition(Storage::Partition::SubType::Data::spiffs)) { + debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); } diff --git a/Sming/Components/Storage/Tools/hwconfig/config.py b/Sming/Components/Storage/Tools/hwconfig/config.py index 2056c49461..fb5ebe9277 100644 --- a/Sming/Components/Storage/Tools/hwconfig/config.py +++ b/Sming/Components/Storage/Tools/hwconfig/config.py @@ -176,7 +176,7 @@ def dict(self): res['name'] = self.name if hasattr(self, 'comment'): res['comment'] = self.comment - res['arch'] = self.arch; + res['arch'] = self.arch res['options'] = self.options res['bootloader_size'] = size_format(self.bootloader_size) res['partition_table_offset'] = addr_format(self.partition_table_offset) diff --git a/Sming/Components/Storage/Tools/hwconfig/partition.py b/Sming/Components/Storage/Tools/hwconfig/partition.py index 6585d81544..51549d4e0d 100644 --- a/Sming/Components/Storage/Tools/hwconfig/partition.py +++ b/Sming/Components/Storage/Tools/hwconfig/partition.py @@ -395,6 +395,8 @@ def parse_dict(self, data, devices): def resolve_expressions(self): try: + SMING_ARCH = os.environ['SMING_ARCH'] + SMING_SOC = os.environ['SMING_SOC'] self.address = eval(str(self.address)) except Exception: self.address = parse_int(self.address) diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index b1691e2aaf..24967d8da7 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -39,6 +39,8 @@ PARTITION_TOOLS := $(PARTITION_PATH)/Tools HWCONFIG_SCHEMA := $(PARTITION_PATH)/schema.json HWCONFIG_VARS := \ SMING_HOME \ + SMING_ARCH \ + SMING_SOC \ OUT_BASE \ HWCONFIG_DIRS \ HWCONFIG_OPTS \ diff --git a/Sming/Components/Storage/src/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp index 37d261ecea..422c0573b1 100644 --- a/Sming/Components/Storage/src/Debug.cpp +++ b/Sming/Components/Storage/src/Debug.cpp @@ -26,9 +26,9 @@ void listPartitions(Print& out) { out.println(); out.println(_F("Registered partitions:")); - for(auto it = Storage::findPartition(); it; ++it) { + for(auto part : Storage::findPartition()) { out.print("- "); - printPartition(out, *it); + printPartition(out, part); } out.println(); } diff --git a/Sming/Components/Storage/src/Iterator.cpp b/Sming/Components/Storage/src/Iterator.cpp index e7a4e2a2ab..8abc2a6c5b 100644 --- a/Sming/Components/Storage/src/Iterator.cpp +++ b/Sming/Components/Storage/src/Iterator.cpp @@ -13,19 +13,8 @@ namespace Storage { -Iterator::Iterator(Device& device, uint8_t partitionIndex) - : mSearch{&device, Partition::Type::any, Partition::SubType::any}, mDevice(&device), mPos(partitionIndex) - -{ - if(partitionIndex >= device.partitions().count()) { - mDevice = nullptr; - mPos = afterEnd; - } -} - -Iterator::Iterator(Partition::Type type, uint8_t subtype) : mSearch{nullptr, type, subtype} +Iterator::Iterator(Partition::Type type, uint8_t subtype) : mSearch{nullptr, type, subtype}, mDevice(spiFlash) { - mDevice = spiFlash; next(); } @@ -46,9 +35,7 @@ bool Iterator::next() return true; } - mPos = afterEnd; if(mSearch.device != nullptr) { - mDevice = nullptr; break; } @@ -56,6 +43,8 @@ bool Iterator::next() mPos = beforeStart; } + mDevice = nullptr; + mPos = afterEnd; return false; } diff --git a/Sming/Components/Storage/src/Partition.cpp b/Sming/Components/Storage/src/Partition.cpp index d66c128fbb..4b08654b17 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -206,7 +206,7 @@ bool Partition::allowWrite() return true; } -bool Partition::read(size_t offset, void* dst, size_t size) +bool Partition::read(uint32_t offset, void* dst, size_t size) { if(!allowRead()) { return false; @@ -220,7 +220,7 @@ bool Partition::read(size_t offset, void* dst, size_t size) return mDevice ? mDevice->read(addr, dst, size) : false; } -bool Partition::write(size_t offset, const void* src, size_t size) +bool Partition::write(uint32_t offset, const void* src, size_t size) { if(!allowWrite()) { return false; @@ -234,7 +234,7 @@ bool Partition::write(size_t offset, const void* src, size_t size) return mDevice ? mDevice->write(addr, src, size) : false; } -bool Partition::erase_range(size_t offset, size_t size) +bool Partition::erase_range(uint32_t offset, size_t size) { if(!allowWrite()) { return false; diff --git a/Sming/Components/Storage/src/include/Storage/Iterator.h b/Sming/Components/Storage/src/include/Storage/Iterator.h index dcd3b7ca88..028090278a 100644 --- a/Sming/Components/Storage/src/include/Storage/Iterator.h +++ b/Sming/Components/Storage/src/include/Storage/Iterator.h @@ -18,11 +18,13 @@ class Device; class Iterator : public std::iterator { public: - Iterator(Device& device, uint8_t partitionIndex); + Iterator(Device& device) : mSearch{&device, Partition::Type::any, Partition::SubType::any}, mDevice(&device) + { + next(); + } - Iterator(Device& device, Partition::Type type, uint8_t subtype) : mSearch{&device, type, subtype} + Iterator(Device& device, Partition::Type type, uint8_t subtype) : mSearch{&device, type, subtype}, mDevice(&device) { - mDevice = &device; next(); } @@ -58,10 +60,24 @@ class Iterator : public std::iterator Partition operator*() const; + Iterator begin() + { + return mSearch.device ? Iterator(*mSearch.device) : Iterator(mSearch.type, mSearch.subType); + } + + Iterator end() + { + return Iterator(); + } + private: static constexpr int8_t beforeStart{-1}; static constexpr int8_t afterEnd{0x7f}; + Iterator() : mPos(afterEnd) + { + } + bool seek(uint8_t pos); bool next(); diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index c101b3bfd3..834e3126af 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -209,9 +209,9 @@ class Partition * @param size Size of data to be read, in bytes. * @retval bool true on success, false on error */ - bool read(size_t offset, void* dst, size_t size); + bool read(uint32_t offset, void* dst, size_t size); - template typename std::enable_if::value, bool>::type read(size_t offset, T& value) + template typename std::enable_if::value, bool>::type read(uint32_t offset, T& value) { return read(offset, &value, sizeof(value)); } @@ -224,7 +224,7 @@ class Partition * @retval bool true on success, false on error * @note Flash region must be erased first */ - bool write(size_t offset, const void* src, size_t size); + bool write(uint32_t offset, const void* src, size_t size); /** * @brief Erase part of the partition @@ -233,7 +233,7 @@ class Partition * @retval bool true on success, false on error * @note Both offset and size must be aligned to flash sector size (4Kbytes) */ - bool erase_range(size_t offset, size_t size); + bool erase_range(uint32_t offset, size_t size); /** * @brief Obtain partition type diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index 49cd59bf10..06033d6640 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -81,12 +81,12 @@ class PartitionTable Iterator begin() const { - return Iterator(mDevice, 0); + return Iterator(mDevice); } Iterator end() const { - return Iterator(mDevice, mCount); + return Iterator(mDevice).end(); } uint8_t count() const diff --git a/docs/source/information/rboot-ota.rst b/docs/source/information/rboot-ota.rst index 6cbe1e17fc..7b2c657e4e 100644 --- a/docs/source/information/rboot-ota.rst +++ b/docs/source/information/rboot-ota.rst @@ -77,9 +77,9 @@ To mount your SPIFFS at boot time add the following code to init: .. code-block:: c++ - int slot = rboot_get_current_rom(); - // Find the n'th SPIFFS partition - auto part = PartitionTable().find(Partition::SubType::Data::spiffs, slot); + String name = F("spiffs"); + name += rboot_get_current_rom(); + auto part = Storage::findPartition(name); if(part) { //debugf("trying to mount SPIFFS at %x, length %d", part.address(), part.size()); spiffs_mount(part); diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index 7d8283b18a..d3df87054a 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -14,10 +14,10 @@ Ota::Network::HttpUpgrader* otaUpdater; Storage::Partition spiffsPartition; OtaUpgrader ota; -Storage::Partition findSpiffsPartition(Storage::Partition partition) +Storage::Partition findSpiffsPartition(Storage::Partition appPart) { String name = F("spiffs"); - name += ota.getSlot(partition); + name += ota.getSlot(appPart); auto part = Storage::findPartition(name); if(!part) { debug_w("Partition '%s' not found", name.c_str()); diff --git a/samples/Basic_Ota/ota.hw b/samples/Basic_Ota/ota.hw index c5d71daa72..a6a64f6186 100644 --- a/samples/Basic_Ota/ota.hw +++ b/samples/Basic_Ota/ota.hw @@ -6,6 +6,15 @@ }, "rom1": { "subtype": "ota_1" + }, + "spiffs0": { + "size": "512K" + }, + "spiffs1": { + "address": "0x380000 if SMING_ARCH == 'Esp32' else 0x280000", + "size": "512K", + "type": "data", + "subtype": "spiffs" } } } \ No newline at end of file diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index a1ba039d47..0c3a2dcf14 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -8,11 +8,11 @@ IMPORT_FSTR(FS_app, PROJECT_DIR "/app/application.cpp") void listSpiffsPartitions() { Serial.println(_F("** Enumerate registered SPIFFS partitions")); - for(auto it = Storage::findPartition(Storage::Partition::SubType::Data::spiffs); it; ++it) { + for(auto part : Storage::findPartition(Storage::Partition::SubType::Data::spiffs)) { Serial.print(F(">> Mounting '")); - Serial.print((*it).name()); + Serial.print(part.name()); Serial.println("' ..."); - bool ok = spiffs_mount(*it); + bool ok = spiffs_mount(part); Serial.println(ok ? "OK, listing files:" : "Mount failed!"); if(ok) { Directory dir; diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index 06cd99c4cd..7579dd8999 100644 --- a/tests/HostTests/modules/Storage.cpp +++ b/tests/HostTests/modules/Storage.cpp @@ -63,8 +63,7 @@ class PartitionTest : public TestGroup void listPartitions() { - for(auto it = Storage::findPartition(); it; ++it) { - auto part = *it; + for(auto part : Storage::findPartition()) { Serial.print("* "); Storage::Debug::printPartition(Serial, part); From f5682d48b9d76eee0d83c44e088e3a3fe41c94dd Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 7 Sep 2022 15:43:32 +0100 Subject: [PATCH 23/58] Add 64-bit mprintf support (#2549) * Add 64-bit m_printf support: `%llu`, etc. * Add mprintf long tests * Correct hex case conversion * Add `format` attributes to m_printf functions --- Sming/System/include/m_printf.h | 8 +++--- Sming/System/m_printf.cpp | 44 ++++++++++++++++++++++++++++-- tests/HostTests/modules/Libc.cpp | 15 ++++++++++ tests/HostTests/modules/Stream.cpp | 2 +- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Sming/System/include/m_printf.h b/Sming/System/include/m_printf.h index ed36499842..46e74ea98a 100644 --- a/Sming/System/include/m_printf.h +++ b/Sming/System/include/m_printf.h @@ -37,10 +37,10 @@ nputs_callback_t m_setPuts(nputs_callback_t callback); extern "C" { #endif -int m_vsnprintf(char* buf, size_t maxLen, const char* fmt, va_list args); -int m_snprintf(char* buf, int length, const char* fmt, ...); -int m_printf(char const*, ...); -int m_vprintf(const char* format, va_list arg); +int m_vsnprintf(char* buf, size_t maxLen, const char* fmt, va_list args) __attribute__((format(printf, 3, 0))); +int m_snprintf(char* buf, int length, const char* fmt, ...) __attribute__((format(printf, 3, 4))); +int m_printf(char const*, ...) __attribute__((format(printf, 1, 2))); +int m_vprintf(const char* format, va_list arg) __attribute__((format(printf, 1, 0))); /** @brief output a single character * @param c diff --git a/Sming/System/m_printf.cpp b/Sming/System/m_printf.cpp index 46b29172ac..de12db413a 100644 --- a/Sming/System/m_printf.cpp +++ b/Sming/System/m_printf.cpp @@ -28,6 +28,18 @@ static nputs_callback_t _puts_callback; #define is_digit(c) ((c) >= '0' && (c) <= '9') #define is_print(c) ((c) >= ' ' && (c) <= '~') +static char to_upper(char c) +{ + return (c >= 'a' && c <= 'z') ? (c + 'A' - 'a') : c; +} + +static void str_upper(char* s) +{ + for(; *s != '\0'; ++s) { + *s = to_upper(*s); + } +} + static int skip_atoi(const char **s) { int i = 0; @@ -125,6 +137,8 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) int8_t precision = -1; int8_t width = 0; char pad = ' '; + uint8_t length = 0; + bool upcase = false; while (char f = *fmt) { if (f == '-') minus = 1; @@ -152,8 +166,19 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) if ( is_digit(*fmt) ) precision = skip_atoi(&fmt); } - // ignore length - while (*fmt == 'l' || *fmt == 'h' || *fmt == 'L') fmt++; + // while (*fmt == 'l' || *fmt == 'h' || *fmt == 'L') fmt++; + + // process length + do { + if ( *fmt == 'l' ) { + ++length; + ++fmt; + } else if ( *fmt == 'h' || *fmt == 'L' ) { + ++fmt; // ignore + } else { + break; + } + } while(true); // process type switch (char f = *fmt++) { @@ -202,8 +227,12 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) break; case 'x': + ubase = 16; + break; + case 'X': ubase = 16; + upcase = true; break; case 'u': @@ -217,7 +246,16 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) } // format unsigned numbers - if (ubase) s = ultoa_wp(va_arg(args, unsigned int), tempNum, ubase, width, pad); + if (ubase != 0) { + if(length >= 2) { + s = ulltoa_wp(va_arg(args, uint64_t), tempNum, ubase, width, pad); + } else { + s = ultoa_wp(va_arg(args, uint32_t), tempNum, ubase, width, pad); + } + if (upcase) { + str_upper(tempNum); + } + } // copy string to target while (*s) add(*s++); diff --git a/tests/HostTests/modules/Libc.cpp b/tests/HostTests/modules/Libc.cpp index 2ae0596fa1..73f0183068 100644 --- a/tests/HostTests/modules/Libc.cpp +++ b/tests/HostTests/modules/Libc.cpp @@ -66,6 +66,21 @@ class LibcTest : public TestGroup REQUIRE(isRomPtr(strstr)); } #endif + + TEST_CASE("64-bit mprintf") + { + char buffer[256]; + m_snprintf(buffer, sizeof(buffer), "%x", 0x12345678); + REQUIRE_EQ(String(buffer), "12345678"); + m_snprintf(buffer, sizeof(buffer), "%u", 12345678); + REQUIRE_EQ(String(buffer), "12345678"); + m_snprintf(buffer, sizeof(buffer), "%llx", 0x123456789ABCDEFULL); + REQUIRE_EQ(String(buffer), "123456789abcdef"); + m_snprintf(buffer, sizeof(buffer), "0x%016llX", 0x123456789ABCDEFULL); + REQUIRE_EQ(String(buffer), "0x0123456789ABCDEF"); + m_snprintf(buffer, sizeof(buffer), "%llu", 123456789123456789ULL); + REQUIRE_EQ(String(buffer), "123456789123456789"); + } } }; diff --git a/tests/HostTests/modules/Stream.cpp b/tests/HostTests/modules/Stream.cpp index 0f52776c96..d360be6d1d 100644 --- a/tests/HostTests/modules/Stream.cpp +++ b/tests/HostTests/modules/Stream.cpp @@ -95,7 +95,7 @@ class StreamTest : public TestGroup TEST_CASE("ChunkedStream / StreamTransformer") { DEFINE_FSTR_LOCAL(FS_INPUT, "Some test data"); - DEFINE_FSTR_LOCAL(FS_OUTPUT, "e\r\nSome test data\r\n0\r\n\r\n"); + DEFINE_FSTR_LOCAL(FS_OUTPUT, "E\r\nSome test data\r\n0\r\n\r\n"); ChunkedStream chunked(new FlashMemoryStream(FS_INPUT)); MemoryDataStream output; output.copyFrom(&chunked); From 2345c3e8aacd94af917441f93f55e9a60dd7cee3 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 13 Sep 2022 07:28:33 +0100 Subject: [PATCH 24/58] Add basic C++ output streaming support (#2551) * Replace all Print::println() overloads with one templated variadic method * Add `width` and `pad` parameters to number printing methods of Print * Add `width` and `pad` parameters to String number constructors * Extend `String::concat(number)` methods * Add `padLeft`, `padRight`, `pad` methods to String * Add `Print::print(enum class)` overload, calls `toString(E)` implementation * Add << stream insertion operator to Print * Starting updating samples * Add documentation * Fix operator << --- Sming/Core/DateTime.cpp | 33 ++-- Sming/Wiring/Print.cpp | 45 ++--- Sming/Wiring/Print.h | 162 +++++++----------- Sming/Wiring/WString.cpp | 92 +++++----- Sming/Wiring/WString.h | 77 +++++++-- .../framework/core/data/streams/index.rst | 65 +++++++ .../Accelerometer_MMA7455/app/application.cpp | 7 +- samples/Arducam/app/application.cpp | 25 +-- samples/Basic_APA102/app/application.cpp | 3 +- samples/Basic_AWS/app/application.cpp | 21 +-- samples/Basic_Audio/app/application.cpp | 10 +- samples/Basic_Capsense/app/application.cpp | 5 +- samples/Basic_DateTime/app/application.cpp | 21 +-- samples/Basic_Delegates/app/speed.cpp | 4 +- samples/Basic_Ethernet/app/application.cpp | 11 +- samples/Basic_Interrupts/app/application.cpp | 35 +--- samples/Basic_Neopixel/app/application.cpp | 12 +- samples/Basic_Ota/app/application.cpp | 84 +++++---- samples/Basic_ProgMem/app/application.cpp | 44 ++--- samples/Basic_ScannerI2C/app/application.cpp | 17 +- .../app/SerialReadingDelegateDemo.cpp | 10 +- samples/Basic_Serial/app/application.cpp | 20 +-- samples/Basic_Servo/app/application.cpp | 17 +- samples/Basic_SmartConfig/app/application.cpp | 3 +- samples/Basic_Ssl/app/application.cpp | 37 ++-- samples/Basic_Tasks/app/application.cpp | 21 +-- samples/Basic_Tasks/include/AnalogueReader.h | 15 +- samples/Basic_WiFi/app/application.cpp | 26 +-- samples/CanBus/app/application.cpp | 8 +- .../app/application.cpp | 25 +-- samples/Compass_HMC5883L/app/application.cpp | 28 ++- .../DS3232RTC_NTP_Setter/app/application.cpp | 14 +- samples/Distance_Vl53l0x/app/application.cpp | 14 +- samples/FtpServer_Files/app/application.cpp | 5 +- samples/Gesture_APDS-9960/app/application.cpp | 30 ++-- samples/HttpClient/app/application.cpp | 3 +- .../HttpClient_Instapush/app/application.cpp | 10 +- .../HttpClient_ThingSpeak/app/application.cpp | 6 +- samples/HttpServer_AJAX/app/application.cpp | 7 +- .../HttpServer_Bootstrap/app/application.cpp | 14 +- .../HttpServer_WebSockets/app/CUserData.cpp | 5 +- .../HttpServer_WebSockets/app/application.cpp | 10 +- samples/Humidity_AM2321/app/application.cpp | 6 +- samples/Humidity_BME280/app/application.cpp | 40 ++--- samples/Humidity_DHT22/app/application.cpp | 71 +++----- samples/Humidity_SI7021/app/application.cpp | 50 ++---- samples/Light_BH1750/app/application.cpp | 4 +- .../LiquidCrystal_44780/app/application.cpp | 6 +- samples/LiveDebug/app/application.cpp | 64 +++---- samples/MeteoControl_mqtt/app/application.cpp | 13 +- samples/MeteoControl_mqtt/app/bmp180.cpp | 18 +- samples/MeteoControl_mqtt/app/si7021.cpp | 23 ++- samples/MqttClient_Hello/app/application.cpp | 19 +- samples/Network_Ping/app/application.cpp | 7 +- .../PortExpander_MCP23S17/app/application.cpp | 2 +- samples/Pressure_BMP180/app/application.cpp | 24 +-- samples/Radio_RCSwitch/app/application.cpp | 13 +- samples/Radio_nRF24L01/app/application.cpp | 10 +- samples/Radio_si4432/app/application.cpp | 68 ++++---- samples/SDCard/app/application.cpp | 25 ++- .../ScreenOLED_SSD1306/app/application.cpp | 12 +- .../ScreenTFT_ILI9163C/app/application.cpp | 6 +- .../app/application.cpp | 10 +- 63 files changed, 692 insertions(+), 900 deletions(-) diff --git a/Sming/Core/DateTime.cpp b/Sming/Core/DateTime.cpp index 5cb961bd20..67367c13f7 100644 --- a/Sming/Core/DateTime.cpp +++ b/Sming/Core/DateTime.cpp @@ -271,13 +271,6 @@ String DateTime::format(const char* sFormat) String sReturn; - // Append a number to the return buffer, padding to a fixed number of digits - auto appendNumber = [&sReturn](unsigned number, unsigned digits, char padChar = '0') { - char buf[8]; - ultoa_wp(number, buf, 10, digits, padChar); - sReturn.concat(buf, digits); - }; - char c; while((c = *sFormat++) != '\0') { if(c != '%') { @@ -298,10 +291,10 @@ String DateTime::format(const char* sFormat) sReturn += Year; break; case 'y': // Year, last 2 digits as a decimal number [00..99] - appendNumber(Year % 100, 2); + sReturn.concat(Year % 100, DEC, 2); break; case 'C': // Year, first 2 digits as a decimal number [00..99] - appendNumber(Year / 100, 2); + sReturn.concat(Year / 100, DEC, 2); break; // Month (not implemented: Om) case 'b': // Abbreviated month name, e.g. Oct (always English) @@ -312,18 +305,18 @@ String DateTime::format(const char* sFormat) sReturn += CStringArray(flashMonthNames)[Month]; break; case 'm': // Month as a decimal number [01..12] - appendNumber(Month + 1, 2); + sReturn.concat(Month + 1, DEC, 2); break; // Week (not implemented: OU, OW, OV) case 'U': // Week of the year as a decimal number (Sunday is the first day of the week) [00..53] - appendNumber(calcWeek(0), 2); + sReturn.concat(calcWeek(0), DEC, 2); break; case 'V': // ISO 8601 week number (01-53) // !@todo Calculation of ISO 8601 week number is crude and frankly wrong but does anyone care? - appendNumber(calcWeek(1) + 1, 2); + sReturn.concat(calcWeek(1) + 1, DEC, 2); break; case 'W': // Week of the year as a decimal number (Monday is the first day of the week) [00..53] - appendNumber(calcWeek(1), 2); + sReturn.concat(calcWeek(1), DEC, 2); break; case 'x': // Locale preferred date format sReturn += format(_F(LOCALE_DATE)); @@ -333,13 +326,13 @@ String DateTime::format(const char* sFormat) break; // Day of year/month (Not implemented: Od, Oe) case 'j': // Day of the year as a decimal number [001..366] - appendNumber(DayofYear, 3); + sReturn.concat(DayofYear, DEC, 3); break; case 'd': // Day of the month as a decimal number [01..31] - appendNumber(Day, 2); + sReturn.concat(Day, DEC, 2); break; case 'e': // Day of the month as a decimal number [ 1,31] - appendNumber(Day, 2, ' '); + sReturn.concat(Day, DEC, 2, ' '); break; // Day of week (Not implemented: Ow, Ou) case 'w': // Weekday as a decimal number with Sunday as 0 [0..6] @@ -356,16 +349,16 @@ String DateTime::format(const char* sFormat) break; // Time (not implemented: OH, OI, OM, OS) case 'H': // Hour as a decimal number, 24 hour clock [00..23] - appendNumber(Hour, 2); + sReturn.concat(Hour, DEC, 2); break; case 'I': // Hour as a decimal number, 12 hour clock [0..12] - appendNumber(Hour ? ((Hour > 12) ? Hour - 12 : Hour) : 12, 2); + sReturn.concat(Hour ? ((Hour > 12) ? Hour - 12 : Hour) : 12, DEC, 2); break; case 'M': // Minute as a decimal number [00..59] - appendNumber(Minute, 2); + sReturn.concat(Minute, DEC, 2); break; case 'S': // Second as a decimal number [00..61] - appendNumber(Second, 2); + sReturn.concat(Second, DEC, 2); break; // Other (not implemented: Ec, Ex, EX, z, Z) case 'c': // Locale preferred date and time format, e.g. Tue Dec 11 08:48:32 2018 diff --git a/Sming/Wiring/Print.cpp b/Sming/Wiring/Print.cpp index 76b51d9fbd..bc7502faad 100644 --- a/Sming/Wiring/Print.cpp +++ b/Sming/Wiring/Print.cpp @@ -38,29 +38,6 @@ size_t Print::write(const uint8_t* buffer, size_t size) return n; } -size_t Print::print(long num, int base) -{ - if(base == 0) { - return write(num); - } - - if(base == 10 && num < 0) { - return print('-') + printNumber(static_cast(-num), base); - } - - return printNumber(static_cast(num), base); -} - -// Overload (signed long long) -size_t Print::print(const long long& num, int base) -{ - if(base == 10 && num < 0) { - return print('-') + printNumber(static_cast(-num), base); - } - - return printNumber(static_cast(num), base); -} - size_t Print::printf(const char* fmt, ...) { size_t buffSize = INITIAL_PRINTF_BUFFSIZE; @@ -83,17 +60,31 @@ size_t Print::printf(const char* fmt, ...) } } -size_t Print::printNumber(unsigned long num, uint8_t base) +size_t Print::printNumber(unsigned long num, uint8_t base, uint8_t width, char pad) +{ + char buf[8 * sizeof(num) + 1]; // Assumes 8-bit chars plus zero byte. + ultoa_wp(num, buf, base, width, pad); + return write(buf); +} + +size_t Print::printNumber(const unsigned long long& num, uint8_t base, uint8_t width, char pad) +{ + char buf[8 * sizeof(num) + 1]; // Assumes 8-bit chars plus zero byte. + ulltoa_wp(num, buf, base, width, pad); + return write(buf); +} + +size_t Print::printNumber(long num, uint8_t base, uint8_t width, char pad) { char buf[8 * sizeof(num) + 1]; // Assumes 8-bit chars plus zero byte. - ultoa(num, buf, base); + ltoa_wp(num, buf, base, width, pad); return write(buf); } -size_t Print::printNumber(const unsigned long long& num, uint8_t base) +size_t Print::printNumber(const long long& num, uint8_t base, uint8_t width, char pad) { char buf[8 * sizeof(num) + 1]; // Assumes 8-bit chars plus zero byte. - ulltoa(num, buf, base); + lltoa_wp(num, buf, base, width, pad); return write(buf); } diff --git a/Sming/Wiring/Print.h b/Sming/Wiring/Print.h index 40885eaa19..2a35307a41 100644 --- a/Sming/Wiring/Print.h +++ b/Sming/Wiring/Print.h @@ -115,7 +115,7 @@ class Print * * @{ */ - size_t print(unsigned long num, int base = DEC) + size_t print(unsigned long num, uint8_t base = DEC) { if(base == 0) { return write(num); @@ -124,28 +124,48 @@ class Print } } - size_t print(const unsigned long long& num, int base = DEC) + template size_t print(unsigned long num, Args... args) { - return printNumber(num, base); + return printNumber(num, args...); } - size_t print(long, int base = DEC); + template size_t print(const unsigned long long& num, Args... args) + { + return printNumber(num, args...); + } - size_t print(const long long&, int base = DEC); + size_t print(long num, uint8_t base = DEC) + { + if(base == 0) { + return write(num); + } else { + return printNumber(num, base); + } + } - size_t print(unsigned int num, int base = DEC) + template size_t print(long num, Args... args) { - return print((unsigned long)num, base); + return printNumber(num, args...); } - size_t print(unsigned char num, int base = DEC) + template size_t print(const long long& num, Args... args) { - return print((unsigned long)num, base); + return printNumber(num, args...); } - size_t print(int num, int base = DEC) + template size_t print(unsigned int num, Args... args) { - return print((long)num, base); + return print((unsigned long)num, args...); + } + + template size_t print(unsigned char num, Args... args) + { + return print((unsigned long)num, args...); + } + + template size_t print(int num, Args... args) + { + return printNumber((long)num, args...); } /** @} */ @@ -177,101 +197,30 @@ class Print return write(s.c_str(), s.length()); } - /** @brief Prints a newline to output stream - * @retval size_t Quantity of characters written to stream - */ - size_t println() - { - return print("\r\n"); - } - - /** @brief Prints a c-string to output stream, appending newline - * @param str c-string to print - * @retval size_t Quantity of characters written to stream - */ - size_t println(const char str[]) - { - return print(str) + println(); - } - - /** @brief Prints a single character to output stream, appending newline - * @param c Character to print - * @retval size_t Quantity of characters written to stream - */ - size_t println(char c) - { - return print(c) + println(); - } - - /** @name Print an integral number to output stream, appending newline - * @param num Number to print - * @param base The base for output (Default: Decimal (base 10)) - * @retval size_t Quantity of characters written to stream - * - * @{ - */ - size_t println(unsigned char num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(unsigned int num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(unsigned long num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(const unsigned long long& num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(int num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(long num, int base = DEC) - { - return print(num, base) + println(); - } - - size_t println(const long long& num, int base = DEC) - { - return print(num, base) + println(); - } - /** @} */ - - /** @brief Print a floating-point number to output stream, appending newline - * @param num Number to print - * @param digits The decimal places to print (Default: 2, e.g. 21.35) - * @retval size_t Quantity of characters written to stream - */ - size_t println(double num, int digits = 2) + /** + * @brief enums can be printed as strings provided they have a `toString(E)` implementation. + */ + template + typename std::enable_if::value && !std::is_convertible::value, size_t>::type print(E value) { - return print(num, digits) + println(); + extern String toString(E e); + return print(toString(value)); } - /** @brief Prints a Printable object to output stream, appending newline - * @param p Object to print + /** @brief Prints a newline to output stream * @retval size_t Quantity of characters written to stream */ - size_t println(const Printable& p) + size_t println() { - return print(p) + println(); + return print("\r\n"); } - /** @brief Prints a String to output stream, appending newline - * @param s String to print + /** @brief Print value plus newline to output stream * @retval size_t Quantity of characters written to stream */ - size_t println(const String& s) + template size_t println(const Args&... args) { - return print(s) + println(); + return print(args...) + println(); } /** @brief Prints a formatted c-string to output stream @@ -284,8 +233,10 @@ class Print private: int write_error = 0; - size_t printNumber(unsigned long num, uint8_t base); - size_t printNumber(const unsigned long long& num, uint8_t base); + size_t printNumber(unsigned long num, uint8_t base = DEC, uint8_t width = 0, char pad = '0'); + size_t printNumber(const unsigned long long& num, uint8_t base = DEC, uint8_t width = 0, char pad = '0'); + size_t printNumber(long num, uint8_t base = DEC, uint8_t width = 0, char pad = '0'); + size_t printNumber(const long long& num, uint8_t base = DEC, uint8_t width = 0, char pad = '0'); size_t printFloat(double num, uint8_t digits); protected: @@ -295,6 +246,23 @@ class Print } }; +template Print& operator<<(Print& p, const T& value) +{ + p.print(value); + return p; +} + +// Thanks to Arduino forum user Paul V. who suggested this +// clever technique to allow for expressions like +// Serial << "Hello!" << endl; +enum EndLineCode { endl }; + +inline Print& operator<<(Print& p, EndLineCode) +{ + p.println(); + return p; +} + /** @} */ #endif // __cplusplus diff --git a/Sming/Wiring/WString.cpp b/Sming/Wiring/WString.cpp index f7fa4ad78b..e6d6ac00a1 100644 --- a/Sming/Wiring/WString.cpp +++ b/Sming/Wiring/WString.cpp @@ -48,52 +48,38 @@ String::String(char c) : String() buffer()[0] = c; } -String::String(unsigned char value, unsigned char base) : String() +String::String(unsigned char value, unsigned char base, unsigned char width, char pad) : String() { char buf[8 + 8 * sizeof(value)]; ultoa(value, buf, base); *this = buf; } -String::String(int value, unsigned char base) : String() +String::String(long value, unsigned char base, unsigned char width, char pad) : String() { char buf[8 + 8 * sizeof(value)]; - itoa(value, buf, base); + ltoa_wp(value, buf, base, width, pad); *this = buf; } -String::String(unsigned int value, unsigned char base) : String() +String::String(long long value, unsigned char base, unsigned char width, char pad) : String() { char buf[8 + 8 * sizeof(value)]; - ultoa(value, buf, base); - *this = buf; -} - -String::String(long value, unsigned char base) : String() -{ - char buf[8 + 8 * sizeof(value)]; - ltoa(value, buf, base); + lltoa_wp(value, buf, base, width, pad); *this = buf; } -String::String(long long value, unsigned char base) : String() +String::String(unsigned long value, unsigned char base, unsigned char width, char pad) : String() { char buf[8 + 8 * sizeof(value)]; - lltoa(value, buf, base); + ultoa_wp(value, buf, base, width, pad); *this = buf; } -String::String(unsigned long value, unsigned char base) : String() +String::String(unsigned long long value, unsigned char base, unsigned char width, char pad) : String() { char buf[8 + 8 * sizeof(value)]; - ultoa(value, buf, base); - *this = buf; -} - -String::String(unsigned long long value, unsigned char base) : String() -{ - char buf[8 + 8 * sizeof(value)]; - ulltoa(value, buf, base); + ulltoa_wp(value, buf, base, width, pad); *this = buf; } @@ -408,52 +394,38 @@ bool String::concat(const char* cstr) return concat(cstr, strlen(cstr)); } -bool String::concat(unsigned char num) +bool String::concat(unsigned char num, unsigned char base, unsigned char width, char pad) { char buf[1 + 3 * sizeof(num)]; - itoa(num, buf, 10); + ultoa_wp(num, buf, base, width, pad); return concat(buf, strlen(buf)); } -bool String::concat(int num) +bool String::concat(long num, unsigned char base, unsigned char width, char pad) { char buf[8 + 3 * sizeof(num)]; - itoa(num, buf, 10); + ltoa_wp(num, buf, base, width, pad); return concat(buf, strlen(buf)); } -bool String::concat(unsigned int num) +bool String::concat(long long num, unsigned char base, unsigned char width, char pad) { char buf[8 + 3 * sizeof(num)]; - ultoa(num, buf, 10); + lltoa_wp(num, buf, base, width, pad); return concat(buf, strlen(buf)); } -bool String::concat(long num) +bool String::concat(unsigned long num, unsigned char base, unsigned char width, char pad) { char buf[8 + 3 * sizeof(num)]; - ltoa(num, buf, 10); + ultoa_wp(num, buf, base, width, pad); return concat(buf, strlen(buf)); } -bool String::concat(long long num) +bool String::concat(unsigned long long num, unsigned char base, unsigned char width, char pad) { char buf[8 + 3 * sizeof(num)]; - lltoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - -bool String::concat(unsigned long num) -{ - char buf[8 + 3 * sizeof(num)]; - ultoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - -bool String::concat(unsigned long long num) -{ - char buf[8 + 3 * sizeof(num)]; - ulltoa(num, buf, 10); + ulltoa_wp(num, buf, base, width, pad); return concat(buf, strlen(buf)); } @@ -951,6 +923,32 @@ void String::trim(const char* set) setlen(len); } +String& String::pad(int16_t minWidth, char c) +{ + size_t w = (minWidth < 0) ? -minWidth : minWidth; + auto len = length(); + if(w <= len) { + return *this; + } + + if(!reserve(std::max(w, len))) { + return *this; + } + + setLength(w); + auto buf = buffer(); + if(minWidth < 0) { + // Left-pad + memmove(buf + w - len, buf, len); + memset(buf, c, w - len); + } else { + // Right-pad + memset(buf + len, c, w - len); + } + + return *this; +} + /*********************************************/ /* Parsing / Conversion */ /*********************************************/ diff --git a/Sming/Wiring/WString.h b/Sming/Wiring/WString.h index 2566f6b620..f73324b134 100644 --- a/Sming/Wiring/WString.h +++ b/Sming/Wiring/WString.h @@ -191,13 +191,19 @@ class String String(StringSumHelper&& rval) noexcept; #endif explicit String(char c); - explicit String(unsigned char, unsigned char base = 10); - explicit String(int, unsigned char base = 10); - explicit String(unsigned int, unsigned char base = 10); - explicit String(long, unsigned char base = 10); - explicit String(long long, unsigned char base = 10); - explicit String(unsigned long, unsigned char base = 10); - explicit String(unsigned long long, unsigned char base = 10); + explicit String(unsigned char, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + explicit String(int num, unsigned char base = 10, unsigned char width = 0, char pad = '0') + : String(long(num), base, width, pad) + { + } + explicit String(unsigned int num, unsigned char base = 10, unsigned char width = 0, char pad = '0') + : String((unsigned long)(num), base, width, pad) + { + } + explicit String(long, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + explicit String(long long, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + explicit String(unsigned long, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + explicit String(unsigned long long, unsigned char base = 10, unsigned char width = 0, char pad = '0'); explicit String(float, unsigned char decimalPlaces = 2); explicit String(double, unsigned char decimalPlaces = 2); /** @} */ @@ -325,13 +331,19 @@ class String { return concat(&c, 1); } - bool concat(unsigned char num); - bool concat(int num); - bool concat(unsigned int num); - bool concat(long num); - bool concat(long long num); - bool concat(unsigned long num); - bool concat(unsigned long long num); + bool concat(unsigned char num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + bool concat(int num, unsigned char base = 10, unsigned char width = 0, char pad = '0') + { + return concat(long(num), base, width, pad); + } + bool concat(unsigned int num, unsigned char base = 10, unsigned char width = 0, char pad = '0') + { + return concat((unsigned long)(num), base, width, pad); + } + bool concat(long num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + bool concat(long long num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + bool concat(unsigned long num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); + bool concat(unsigned long long num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); bool concat(float num); bool concat(double num); /** @} */ @@ -794,6 +806,43 @@ class String */ void trim(const char* set = " \t\n\v\f\r"); + /** + * @name Pad string to a minimum length + * + * This is used, for example, when outputting tabular data. + * The string is modified in-situ to minimise memory reallocations. + * + * Methods may be chained like this:: + * + * Serial << String(value).padLeft(10, '.') << endl; + * + * @{ + */ + + /** + * @brief Insert padding at start of string if length is less than given width + */ + String& padLeft(uint16_t minWidth, char c = ' ') + { + return pad(-minWidth, c); + } + + /** + * @brief Insert padding at end of string if length is less than given width + */ + String& padRight(uint16_t minWidth, char c = ' ') + { + return pad(minWidth, c); + } + + /** + * @brief Pad string if length is less than given width + * @param width Left-padded if < 0, right-padded if > 0. + */ + String& pad(int16_t minWidth, char c = ' '); + + /** @} */ + // parsing/conversion long toInt(void) const; float toFloat(void) const; diff --git a/docs/source/framework/core/data/streams/index.rst b/docs/source/framework/core/data/streams/index.rst index a690def170..149b964743 100644 --- a/docs/source/framework/core/data/streams/index.rst +++ b/docs/source/framework/core/data/streams/index.rst @@ -1,6 +1,8 @@ Streams ======= +.. highlight:: c++ + Sming provides a set of Stream class which extend :cpp:class:`Stream` methods. :cpp:class:`IDataSourceStream` is used where read-only access is required. @@ -11,6 +13,69 @@ types and should be used with care. :cpp:class:`ReadWriteStream` is used where read/write operation is required. +Printing +-------- + +The arduino :cpp:class:`Print` class provides the basic output streaming mechanism. +Sming has some enhancements: + +C++ streaming operation << + Building output is commonly done like this:: + + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.print(" °C, humidity: "); + Serial.print(humidity); + Serial.println("%"); + + In Sming, this will produce exactly the same result:: + + Serial << "Temperature" << temperature << " °C, humidity: " << humidity << "%" << endl; + + .. note:: + + Sming does NOT support the C++ STL streaming classes, such as ``iostream``, etc. + + +Number Printing + Examples:: + + Serial.print(12, HEX); // "c" + Serial.print(12, HEX, 4); // "000c" + Serial.print(12, HEX, 4, '.'); // "...c" + Serial.print(12); // "12" + Serial.print(12, DEC, 4); // "0012" + + Similar extensions are provided for :cpp:class:`String` construction:: + + Serial << "0x" << String(12, HEX, 8); // "0x0000000c" + Serial << String(12, DEC, 4, '.'); // "..12" + + +Field-width control + Supported via String methods:: + + Serial << String(12).padLeft(4); // " 12" + Serial << String(12).padLeft(4, '0'); // "0012" + Serial << String(12).padRight(4); // "12 " + Serial << String(12).pad(-4, '0'); // "0012" + Serial << String(12).pad(4); // "12 " + + +Strongly-typed enumerations + Use of ``enum class`` is good practice as it produces strongly-typed and scoped values. + Most of these are also provided with a standard ``toString(E)`` function overload. + + This allows string equivalents to be printed very easily:: + + auto status = HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED; + auto type = MIME_HTML; + Serial.print(type); // "text/html" + // "Status: HTTP Version Not Supported, type: text/html" + Serial << "Status: " << status << ", type: " << type << endl; + // Status: 505, type: 0 + Serial << "Status: " << int(status) << ", type: " << int(type) << endl; + API Documentation ----------------- diff --git a/samples/Accelerometer_MMA7455/app/application.cpp b/samples/Accelerometer_MMA7455/app/application.cpp index f519736403..edff93d77a 100644 --- a/samples/Accelerometer_MMA7455/app/application.cpp +++ b/samples/Accelerometer_MMA7455/app/application.cpp @@ -12,12 +12,7 @@ void readSensor() int8_t x = accel.readAxis('x'); int8_t y = accel.readAxis('y'); int8_t z = accel.readAxis('z'); - Serial.print("Accelerometer data: "); - Serial.print(x); - Serial.print(", "); - Serial.print(y); - Serial.print(", "); - Serial.println(z); + Serial << _F("Accelerometer data: ") << x << ", " << y << ", " << z << endl; } void init() diff --git a/samples/Arducam/app/application.cpp b/samples/Arducam/app/application.cpp index 0a7163bbb2..af181f8989 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -78,9 +78,10 @@ void initCam() myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid); if((vid != 0x26) || (pid != 0x42)) { Serial.println("Can't find OV2640 module!"); - Serial.printf("vid = [%X] pid = [%X]\n", vid, pid); - } else + Serial << "vid = [" << String(vid, HEX) << "], pid = [" << String(pid, HEX) << "]" << endl; + } else { Serial.println("OV2640 detected"); + } // initialize SPI: pinMode(CAM_CS, OUTPUT); @@ -167,7 +168,7 @@ void onCapture(HttpRequest& request, HttpResponse& response) // get the picture OneShotFastMs timer; startCapture(); - Serial.printf("onCapture() startCapture() %s\r\n", timer.elapsedTime().toString().c_str()); + Serial << _F("onCapture() startCapture() ") << timer.elapsedTime() << endl; ArduCAMStream* stream = new ArduCAMStream(&myCAM); @@ -178,7 +179,7 @@ void onCapture(HttpRequest& request, HttpResponse& response) response.sendDataStream(stream, contentType); } - Serial.printf("onCapture() process Stream %s\r\n", timer.elapsedTime().toString().c_str()); + Serial << _F("onCapture() process Stream ") << timer.elapsedTime() << endl; } MultipartStream::BodyPart snapshotProducer() @@ -190,22 +191,22 @@ MultipartStream::BodyPart snapshotProducer() result.stream = camStream; result.headers = new HttpHeaders(); - (*result.headers)[HTTP_HEADER_CONTENT_TYPE] = "image/jpeg"; + (*result.headers)[HTTP_HEADER_CONTENT_TYPE] = toString(MIME_JPEG); return result; } void onStream(HttpRequest& request, HttpResponse& response) { - Serial.printf("perform onCapture()\r\n"); + Serial.println(_F("perform onCapture()")); // TODO: use request parameters to overwrite camera settings // setupCamera(camSettings); myCAM.clear_fifo_flag(); myCAM.write_reg(ARDUCHIP_FRAMES, 0x00); - MultipartStream* stream = new MultipartStream(snapshotProducer); - response.sendDataStream(stream, String("multipart/x-mixed-replace; boundary=") + stream->getBoundary()); + auto stream = new MultipartStream(snapshotProducer); + response.sendDataStream(stream, F("multipart/x-mixed-replace; boundary=") + stream->getBoundary()); } void onFavicon(HttpRequest& request, HttpResponse& response) @@ -228,15 +229,15 @@ void StartServers() server.paths.set("/favicon.ico", onFavicon); server.paths.setDefault(onFile); - Serial.println("\r\n=== WEB SERVER STARTED ==="); + Serial.println(_F("\r\n=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println("==============================\r\n"); + Serial.println(_F("==============================\r\n")); telnet.listen(23); telnet.enableDebug(true); - Serial.println("\r\n=== TelnetServer SERVER STARTED ==="); - Serial.println("==============================\r\n"); + Serial.println(_F("\r\n=== TelnetServer SERVER STARTED ===")); + Serial.println(_F("==============================\r\n")); } // Will be called when station is fully operational diff --git a/samples/Basic_APA102/app/application.cpp b/samples/Basic_APA102/app/application.cpp index 606c1e75e7..9297b41639 100644 --- a/samples/Basic_APA102/app/application.cpp +++ b/samples/Basic_APA102/app/application.cpp @@ -107,8 +107,7 @@ static void updateLED() cnt = 0; } - Serial.print("ping "); - Serial.println(cnt); + Serial << "ping " << cnt << endl; LED.show(cnt); // show shifted LED buffer break; } diff --git a/samples/Basic_AWS/app/application.cpp b/samples/Basic_AWS/app/application.cpp index dedcca2674..03c637a0ab 100644 --- a/samples/Basic_AWS/app/application.cpp +++ b/samples/Basic_AWS/app/application.cpp @@ -48,36 +48,31 @@ void publishMessage() // Callback for messages, arrived from MQTT server int onMessagePublish(MqttClient& client, mqtt_message_t* message) { - Serial.print("Publish: "); - Serial.print(MqttBuffer(message->publish.topic_name)); - Serial.print(":\r\n\t"); // Pretify alignment for printing - Serial.println(MqttBuffer(message->publish.content)); + Serial << _F("Publish: ") << MqttBuffer(message->publish.topic_name) << ':' << endl; + Serial << '\t' << MqttBuffer(message->publish.content) << endl; return 0; } int onMessageConnect(MqttClient& client, mqtt_message_t* message) { - Serial.print("Connect: "); - Serial.print(MqttBuffer(message->connect.protocol_name)); - Serial.print(", client: "); - Serial.println(MqttBuffer(message->connect.client_id)); + Serial << _F("Connect: ") << MqttBuffer(message->connect.protocol_name) << _F(", client: ") + << MqttBuffer(message->connect.client_id) << endl; return 0; } int onMessageDisconnect(MqttClient& client, mqtt_message_t* message) { - Serial.println("Disconnect"); + Serial.println(_F("Disconnect")); return 0; } void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print("Connected: "); - Serial.println(ip); + Serial << _F("Connected: ") << ip << endl; startMqttClient(); publishMessage(); // run once publishMessage - mqtt.subscribe("$aws/things/Basic_AWS/shadow/get"); + mqtt.subscribe(F("$aws/things/Basic_AWS/shadow/get")); } } // namespace @@ -87,7 +82,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); - Serial.println("Hello"); + Serial.println(_F("Hello")); // initialization config mqtt.setEventHandler(MQTT_TYPE_PUBLISH, onMessagePublish); diff --git a/samples/Basic_Audio/app/application.cpp b/samples/Basic_Audio/app/application.cpp index 50dd0b1676..695b236d38 100644 --- a/samples/Basic_Audio/app/application.cpp +++ b/samples/Basic_Audio/app/application.cpp @@ -54,11 +54,8 @@ static struct { // Modify frequency to fit in exact number of samples frequency = sampleRate / sampleCount; - Serial.print("Generating sine wave table @ "); - Serial.print(frequency); - Serial.print(" Hz, "); - Serial.print(sampleCount); - Serial.println(" samples"); + Serial << _F("Generating sine wave table @ ") << frequency << _F(" Hz, ") << sampleCount << _F(" samples") + << endl; samples = new uint16_t[sampleCount]; if(samples == nullptr) { @@ -202,8 +199,7 @@ static void initialiseI2S() #endif auto realSampleRate = i2s_get_real_rate(); - Serial.print(_F("I2S initialised, rate = ")); - Serial.println(realSampleRate); + Serial << _F("I2S initialised, rate = ") << realSampleRate << endl; #ifndef GENERATE_FIXED_VALUES /* diff --git a/samples/Basic_Capsense/app/application.cpp b/samples/Basic_Capsense/app/application.cpp index 38f07eae8e..8fcab1a935 100644 --- a/samples/Basic_Capsense/app/application.cpp +++ b/samples/Basic_Capsense/app/application.cpp @@ -13,9 +13,8 @@ Timer procTimer; void capsense() { - long total = cs_0_2.capacitiveSensor(30); //Read sensor with 30 samples - Serial.print("Sense Value: "); - Serial.println(total); // print sensor output + long total = cs_0_2.capacitiveSensor(30); //Read sensor with 30 samples + Serial << _F("Sense Value: ") << total << endl; // print sensor output } void init() diff --git a/samples/Basic_DateTime/app/application.cpp b/samples/Basic_DateTime/app/application.cpp index 5888a6760d..c941d5354e 100644 --- a/samples/Basic_DateTime/app/application.cpp +++ b/samples/Basic_DateTime/app/application.cpp @@ -57,20 +57,14 @@ void showTime(time_t timestamp) Serial.println(dt.format("%%x Locale date: %x")); Serial.println(dt.format("%%X Locale time: %X")); //HTTP date - Serial.print("toHTTPDate: "); - Serial.println(dt.toHTTPDate()); + Serial << "toHTTPDate: " << dt.toHTTPDate() << endl; DateTime dt2; dt2.fromHttpDate(dt.toHTTPDate()); - Serial.print("fromHTTPDate: "); - Serial.println(dt2.toHTTPDate()); - Serial.print("toFullDateTimeString: "); - Serial.println(dt.toFullDateTimeString()); - Serial.print("toISO8601: "); - Serial.println(dt.toISO8601()); - Serial.print("toShortDateString: "); - Serial.println(dt.toShortDateString()); - Serial.print("toShortTimeString: "); - Serial.println(dt.toShortTimeString()); + Serial << "fromHTTPDate: " << dt2.toHTTPDate() << endl; + Serial << "toFullDateTimeString: " << dt.toFullDateTimeString() << endl; + Serial << "toISO8601: " << dt.toISO8601() << endl; + Serial << "toShortDateString: " << dt.toShortDateString() << endl; + Serial << "toShortTimeString: " << dt.toShortTimeString() << endl; } void onRx(Stream& source, char arrivedChar, unsigned short availableCharsCount) @@ -79,8 +73,7 @@ void onRx(Stream& source, char arrivedChar, unsigned short availableCharsCount) case '\n': Serial.println(); Serial.println(); - Serial.print(_F("****Showing DateTime formatting options for Unix timestamp: ")); - Serial.println(timestamp); + Serial << _F("****Showing DateTime formatting options for Unix timestamp: ") << timestamp << endl; showTime(timestamp); Serial.print(commandPrompt); timestamp = 0; diff --git a/samples/Basic_Delegates/app/speed.cpp b/samples/Basic_Delegates/app/speed.cpp index 3250f2d1e8..1518d83af1 100644 --- a/samples/Basic_Delegates/app/speed.cpp +++ b/samples/Basic_Delegates/app/speed.cpp @@ -19,7 +19,7 @@ static CpuCycleTimer timer; static void printTime(const char* name, unsigned ticks) { - Serial.printf("%s: %u cycles, %s\r\n", name, ticks, timer.ticksToTime(ticks).toString().c_str()); + Serial << name << ": " << ticks << " cycles, " << timer.ticksToTime(ticks).toString() << endl; } static void __noinline evaluateCallback(const char* name, TestCallback callback, int testParam) @@ -46,7 +46,7 @@ void evaluateSpeed() { Serial.println(); Serial.println(); - Serial.printf("Timings are in CPU cycles per loop, averaged over %u iterations\r\n", ITERATIONS); + Serial << _F("Timings are in CPU cycles per loop, averaged over ") << ITERATIONS << _F(" iterations") << endl; int testParam = 123; diff --git a/samples/Basic_Ethernet/app/application.cpp b/samples/Basic_Ethernet/app/application.cpp index 944e5bdd00..0004f9984f 100644 --- a/samples/Basic_Ethernet/app/application.cpp +++ b/samples/Basic_Ethernet/app/application.cpp @@ -30,19 +30,12 @@ Ethernet::W5500Service ethernet; static void ethernetEventHandler(Ethernet::Event event) { - Serial.print(toString(event)); - Serial.print(_F(", MAC = ")); - Serial.println(ethernet.getMacAddress().toString()); + Serial << event << _F(", MAC = ") << ethernet.getMacAddress() << endl; } static void ethernetGotIp(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print(_F("Connected! Ethernet IP ")); - Serial.print(ip.toString()); - Serial.print(_F(", netmask ")); - Serial.print(netmask.toString()); - Serial.print(_F(", gateway ")); - Serial.println(gateway.toString()); + Serial << _F("Connected! Ethernet IP ") << ip << _F(", netmask ") << netmask << _F(", gateway ") << gateway << endl; } void init() diff --git a/samples/Basic_Interrupts/app/application.cpp b/samples/Basic_Interrupts/app/application.cpp index a08602cd69..aa12407101 100644 --- a/samples/Basic_Interrupts/app/application.cpp +++ b/samples/Basic_Interrupts/app/application.cpp @@ -7,22 +7,13 @@ #define INT_PIN_B 4 // GPIO4 #define TOGGLE_PIN 5 // GPIO5 -#define say(a) (Serial.print(a)) -#define newline() (Serial.println()) - static unsigned interruptToggleCount; void showInterruptToggleCount(uint32_t toggleCount) { - say("Toggle count hit "); - say(toggleCount); - say(", current value is "); - say(interruptToggleCount); - say("!"); - newline(); - say("Max tasks queued: "); - say(System.getMaxTaskCount()); - newline(); + Serial << _F("Toggle count hit ") << toggleCount << _F(", current value is ") << interruptToggleCount << '!' + << endl; + Serial << _F("Max tasks queued: ") << System.getMaxTaskCount() << endl; } /** @brief Low-level interrupt handler @@ -74,15 +65,10 @@ void IRAM_ATTR interruptHandler() void interruptDelegate() { // For this example, we write some stuff out of the serial port. - say(micros()); - say(" Pin changed, now "); - say(digitalRead(INT_PIN_B)); - newline(); + Serial << micros() << _F(" Pin changed, now ") << digitalRead(INT_PIN_B) << endl; // Interrupt delegates work by queueing your callback routine, so let's just show you how many requests got queued - say("Max tasks queued: "); - say(System.getMaxTaskCount()); - newline(); + Serial << _F("Max tasks queued: ") << System.getMaxTaskCount() << endl; /* OK, so you probably got a number which hit 255 pretty quickly! It stays there to indicate the task queue * overflowed, which happens because we're getting way more interrupts than we can process in a timely manner, so @@ -95,21 +81,16 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 or 9600 by default delay(3000); - say("======= Bring GPIO"); - say(INT_PIN_A); - say(" low to trigger interrupt(s) ======="); - newline(); + Serial << _F("======= Bring GPIO") << INT_PIN_A << _F(" low to trigger interrupt(s) =======") << endl; // Note we enable pullup on our test pin so it will stay high when not connected attachInterrupt(INT_PIN_A, interruptHandler, CHANGE); pinMode(INT_PIN_A, INPUT_PULLUP); - say("Interrupt A attached"); - newline(); + Serial.println(_F("Interrupt A attached")); // For an interrupt delegate callback, we simply cast our function or method using InterruptDelegate() pinMode(TOGGLE_PIN, OUTPUT); attachInterrupt(INT_PIN_B, InterruptDelegate(interruptDelegate), CHANGE); pinMode(INT_PIN_B, INPUT_PULLUP); - say("Interrupt B attached"); - newline(); + Serial.println(_F("Interrupt B attached")); } diff --git a/samples/Basic_Neopixel/app/application.cpp b/samples/Basic_Neopixel/app/application.cpp index c0cdccde52..82a6a11f3f 100644 --- a/samples/Basic_Neopixel/app/application.cpp +++ b/samples/Basic_Neopixel/app/application.cpp @@ -87,8 +87,7 @@ void TheaterChase() void StartDemo() { - Serial.print("NeoPixel Demo type: "); - Serial.println(StripDemoType); + Serial << _F("NeoPixel Demo type: ") << StripDemoType << endl; StripDemoTimer.stop(); // next demo wait until this demo ends @@ -142,15 +141,14 @@ void StartDemo() void got_IP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print("IP: "); - Serial.println(ip); - //You can put here other job like web,tcp etc. + Serial << "IP: " << ip << endl; + // You can put here other job like web,tcp etc. } // Will be called when WiFi station loses connection void connect_Fail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) { - Serial.println("I'm NOT CONNECTED!"); + Serial.println(_F("I'm NOT CONNECTED!")); } void init() @@ -158,7 +156,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(false); // Disable debug output to serial - Serial.print("NeoPixel demo .. start"); + Serial.print(_F("NeoPixel demo .. start")); #ifndef DISABLE_WIFI // Wifi could be used eg. for switching Neopixel from internet. diff --git a/samples/Basic_Ota/app/application.cpp b/samples/Basic_Ota/app/application.cpp index d3df87054a..53e8a3a0b0 100644 --- a/samples/Basic_Ota/app/application.cpp +++ b/samples/Basic_Ota/app/application.cpp @@ -27,14 +27,14 @@ Storage::Partition findSpiffsPartition(Storage::Partition appPart) void upgradeCallback(Ota::Network::HttpUpgrader& client, bool result) { - Serial.println("In callback..."); + Serial.println(_F("In callback...")); if(result == true) { // success ota.end(); auto part = ota.getNextBootPartition(); // set to boot new rom and then reboot - Serial.printf(_F("Firmware updated, rebooting to %s @ ...\r\n"), part.name().c_str()); + Serial << _F("Firmware updated, rebooting to ") << part.name() << _F(" @ ...") << endl; ota.setBootPartition(part); System.restart(); } else { @@ -87,8 +87,8 @@ void doSwitch() auto before = ota.getRunningPartition(); auto after = ota.getNextBootPartition(); - Serial.printf(_F("Swapping from %s @ 0x%08x to %s @ 0x%08x.\r\n"), before.name().c_str(), before.address(), - after.name().c_str(), after.address()); + Serial << _F("Swapping from ") << before.name() << " @ 0x" << String(before.address(), HEX) << " to " + << after.name() << " @ 0x" << String(after.address(), HEX) << endl; if(ota.setBootPartition(after)) { Serial.println(F("Restarting...\r\n")); System.restart(); @@ -99,18 +99,19 @@ void doSwitch() void showInfo() { - Serial.printf(_F("\r\nSDK: v%s\r\n"), system_get_sdk_version()); - Serial.printf(_F("Free Heap: %lu\r\n"), system_get_free_heap_size()); - Serial.printf(_F("CPU Frequency: %lu MHz\r\n"), system_get_cpu_freq()); - Serial.printf(_F("System Chip ID: %lx\r\n"), system_get_chip_id()); - Serial.printf(_F("SPI Flash ID: %lx\r\n"), Storage::spiFlash->getId()); - Serial.printf(_F("SPI Flash Size: %ux\r\n"), Storage::spiFlash->getSize()); + Serial.println(); + Serial << _F("SDK: v") << system_get_sdk_version() << endl; + Serial << _F("Free Heap: ") << system_get_free_heap_size() << endl; + Serial << _F("CPU Frequency: ") << system_get_cpu_freq() << " MHz" << endl; + Serial << _F("System Chip ID: ") << String(system_get_chip_id(), HEX) << endl; + Serial << _F("SPI Flash ID: ") << String(Storage::spiFlash->getId(), HEX) << endl; + Serial << _F("SPI Flash Size: ") << String(Storage::spiFlash->getSize(), HEX) << endl; auto before = ota.getRunningPartition(); auto after = ota.getNextBootPartition(); - Serial.printf(_F("Current %s @ 0x%08lx, future %s @ 0x%0l8x\r\n"), before.name().c_str(), before.address(), - after.name().c_str(), after.address()); + Serial << _F("Current ") << before.name() << " @ 0x" << String(before.address(), HEX) << ", future " << after.name() + << " @ 0x" << String(after.address(), HEX) << endl; } void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCharsCount) @@ -125,36 +126,32 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh } } - if(!strcmp(str, "connect")) { + if(F("connect") == str) { // connect to wifi WifiStation.config(WIFI_SSID, WIFI_PWD); WifiStation.enable(true); WifiStation.connect(); - } else if(!strcmp(str, "ip")) { - Serial.print("ip: "); - Serial.print(WifiStation.getIP()); - Serial.print(" mac: "); - Serial.println(WifiStation.getMacAddress()); - } else if(!strcmp(str, "ota")) { + } else if(F("ip") == str) { + Serial << "ip: " << WifiStation.getIP() << ", mac: " << WifiStation.getMacAddress() << endl; + } else if(F("ota") == str) { doUpgrade(); - } else if(!strcmp(str, "switch")) { + } else if(F("switch") == str) { doSwitch(); - } else if(!strcmp(str, "restart")) { + } else if(F("restart") == str) { System.restart(); - } else if(!strcmp(str, "ls")) { + } else if(F("ls") == str) { Directory dir; if(dir.open()) { while(dir.next()) { - Serial.print(" "); - Serial.println(dir.stat().name); + Serial << " " << dir.stat().name << endl; } } - Serial.printf(_F("filecount %u\r\n"), dir.count()); - } else if(!strcmp(str, "cat")) { + Serial << _F("filecount ") << dir.count() << endl; + } else if(F("cat") == str) { Directory dir; if(dir.open() && dir.next()) { auto filename = dir.stat().name.c_str(); - Serial.printf("dumping file %s:\r\n", filename); + Serial << "dumping file " << filename << ": " << endl; // We don't know how big the is, so streaming it is safest FileStream fs; fs.open(filename); @@ -163,21 +160,22 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh } else { Serial.println(F("Empty spiffs!")); } - } else if(!strcmp(str, "info")) { + } else if(F("info") == str) { showInfo(); - } else if(!strcmp(str, "help")) { - Serial.println(); - Serial.println(F("available commands:")); - Serial.println(F(" help - display this message")); - Serial.println(F(" ip - show current ip address")); - Serial.println(F(" connect - connect to wifi")); - Serial.println(F(" restart - restart the device")); - Serial.println(F(" switch - switch to the other rom and reboot")); - Serial.println(F(" ota - perform ota update, switch rom and reboot")); - Serial.println(F(" info - show device info")); + } else if(F("help") == str) { + Serial.print(_F("\r\n" + "available commands:\r\n" + " help - display this message\r\n" + " ip - show current ip address\r\n" + " connect - connect to wifi\r\n" + " restart - restart the device\r\n" + " switch - switch to the other rom and reboot\r\n" + " ota - perform ota update, switch rom and reboot\r\n" + " info - show device info\r\n")); + if(spiffsPartition) { - Serial.println(F(" ls - list files in spiffs")); - Serial.println(F(" cat - show first file in spiffs")); + Serial.print(_F(" ls - list files in spiffs\r\n" + " cat - show first file in spiffs\r\n")); } Serial.println(); } else { @@ -202,9 +200,9 @@ void init() WifiAccessPoint.enable(false); - Serial.printf(_F("\r\nCurrently running %s @ 0x%08lx.\r\n"), partition.name().c_str(), partition.address()); - Serial.println(F("Type 'help' and press enter for instructions.")); - Serial.println(); + Serial << _F("\r\nCurrently running ") << partition.name() << " @ 0x" << String(partition.address(), HEX) << '.' + << endl; + Serial << _F("Type 'help' and press enter for instructions.") << endl << endl; Serial.onDataReceived(serialCallBack); } diff --git a/samples/Basic_ProgMem/app/application.cpp b/samples/Basic_ProgMem/app/application.cpp index 2e0c30334c..498cdf68ef 100644 --- a/samples/Basic_ProgMem/app/application.cpp +++ b/samples/Basic_ProgMem/app/application.cpp @@ -27,50 +27,35 @@ const PROGMEM float floats[] = {13, 130, 1300, 13000, 130000, 1300000, 13000000, void assertEquals8(uint8_t expected, uint8_t actual) { if(expected != actual) { - Serial.print("assertEquals8: "); - Serial.print(expected); - Serial.print(" != "); - Serial.println(actual); + Serial << "assertEquals8: " << expected << " != " << actual << endl; } } void assertEquals16(uint16_t expected, uint16_t actual) { if(expected != actual) { - Serial.print("assertEquals16: "); - Serial.print(expected); - Serial.print(" != "); - Serial.println(actual); + Serial << "assertEquals16: " << expected << " != " << actual << endl; } } void assertEquals32(uint32_t expected, uint32_t actual) { if(expected != actual) { - Serial.print("assertEquals32: "); - Serial.print(expected); - Serial.print(" != "); - Serial.println(actual); + Serial << "assertEquals32: " << expected << " != " << actual << endl; } } void assertEqualsFloat(float expected, float actual) { if(expected != actual) { - Serial.print("assertEqualsFloat: "); - Serial.print(expected); - Serial.print(" != "); - Serial.println(actual); + Serial << "assertEqualsFloat: " << expected << " != " << actual << endl; } } void assertEqualsString(String expected, String actual) { if(expected != actual) { - Serial.print("assertEqualsString: "); - Serial.print(expected); - Serial.print(" != "); - Serial.println(actual); + Serial << "assertEqualsString: " << expected << " != " << actual << endl; } } @@ -80,10 +65,9 @@ void testPgm() for(uint8_t i = 0, b = 1; i < 8; i++, b++) { uint8_t d = pgm_read_byte(bytes + i); assertEquals8(b, d); - Serial.print(d); - Serial.print(" "); + Serial << d << ' '; } - Serial.println(""); + Serial.println(); for(uint16_t i = 0, w = 11; i < 8; i++, w += 10) { assertEquals16(w, pgm_read_word(words + i)); @@ -120,10 +104,9 @@ void testPgm() memcpy_P(buf, demoPgm, sizeof(demoPgm)); for(uint8_t i = 0; i < sizeof(demoPgm); i++) { assertEquals8(demoRam[i], buf[i]); - Serial.print((unsigned char)buf[i]); - Serial.print(" "); + Serial << (unsigned char)buf[i] << ' '; } - Serial.println(""); + Serial.println(); } void init() @@ -137,11 +120,6 @@ void init() Serial.println("> 0x3FFE8000 ~ 0x3FFFBFFF - User data RAM, 80kb. Available to applications."); Serial.println("> 0x40200000 ~ ... - SPI Flash."); - Serial.print("> demoRam array address: 0x"); - Serial.print((uint32_t)demoRam, HEX); - Serial.println(" is in the RAM"); - - Serial.print("> demoPgm array address: 0x"); - Serial.print((uint32_t)demoPgm, HEX); - Serial.println(" is in the Flash"); + Serial << "> demoRam array address: 0x" << String(uint32_t(demoRam), HEX) << " is in the RAM" << endl; + Serial << "> demoPgm array address: 0x" << String(uint32_t(demoPgm), HEX) << " is in the Flash" << endl; } diff --git a/samples/Basic_ScannerI2C/app/application.cpp b/samples/Basic_ScannerI2C/app/application.cpp index afda8fc274..eac15eac22 100644 --- a/samples/Basic_ScannerI2C/app/application.cpp +++ b/samples/Basic_ScannerI2C/app/application.cpp @@ -49,24 +49,17 @@ void scanBus() WDT.alive(); // Second option: notify Watch Dog what you are alive (feed it) if(error == 0) { - Serial.print("I2C device found at address 0x"); - if(address < 16) - Serial.print("0"); - Serial.print(address, HEX); - Serial.println(" !"); - + Serial << _F("I2C device found at address 0x") << String(address, HEX, 2) << " !" << endl; nDevices++; } else if(error == 4) { - Serial.print("Unknown error at address 0x"); - if(address < 16) - Serial.print("0"); - Serial.println(address, HEX); + Serial << _F("Unknown error at address 0x") << String(address, HEX, 2) << endl; } } - if(nDevices == 0) + if(nDevices == 0) { Serial.println("No I2C devices found\n"); - else + } else { Serial.println("done\n"); + } } void init() diff --git a/samples/Basic_Serial/app/SerialReadingDelegateDemo.cpp b/samples/Basic_Serial/app/SerialReadingDelegateDemo.cpp index 01a3ef963d..4e9b346b9e 100644 --- a/samples/Basic_Serial/app/SerialReadingDelegateDemo.cpp +++ b/samples/Basic_Serial/app/SerialReadingDelegateDemo.cpp @@ -8,7 +8,7 @@ void onDataCallback(Stream& stream, char arrivedChar, unsigned short availableCharsCount) { // Note: we're using the global Serial here, but it may not be the same port as stream - Serial.printf(_F("Char: %d, Count: %d\r\n"), (uint8_t)arrivedChar, availableCharsCount); + Serial << "Char: " << uint8_t(arrivedChar) << ", Count: " << availableCharsCount << endl; } void echoCallback(Stream& stream, char arrivedChar, unsigned short availableCharsCount) @@ -25,12 +25,8 @@ void SerialReadingDelegateDemo::begin(HardwareSerial& serial) void SerialReadingDelegateDemo::onData(Stream& stream, char arrivedChar, unsigned short availableCharsCount) { - serial->print(_F("Class Delegate Demo Time = ")); - serial->print(micros()); - serial->print(_F(" char = 0x")); - serial->print(arrivedChar, HEX); // char hex code - serial->print(_F(" available = ")); - serial->println(availableCharsCount); + Serial << _F("Class Delegate Demo Time = ") << micros() << _F(" char = 0x") << String(arrivedChar, HEX, 2) + << _F(" available = ") << availableCharsCount << endl; // Error detection unsigned status = serial->getStatus(); diff --git a/samples/Basic_Serial/app/application.cpp b/samples/Basic_Serial/app/application.cpp index f580e081da..0faceff2a4 100644 --- a/samples/Basic_Serial/app/application.cpp +++ b/samples/Basic_Serial/app/application.cpp @@ -149,19 +149,15 @@ HardwareSerial Serial1(UART_ID_1); void sayHello() { - Serial.print(_F("Hello Sming! Let's do smart things.")); - Serial.print(_F(" Time : ")); - Serial.println(micros()); - Serial.println(); - - Serial.printf(_F("This is Hello message %d \r\r\n"), ++helloCounter); + Serial << _F("Hello Sming! Let's do smart things. Time: ") << micros() << endl; + Serial << _F("This is Hello message ") << ++helloCounter << endl; } void testPrintf() { - Serial.print(_F("\r\n== PRINTF TEST START ==\r\n")); + Serial.println(_F("\r\n== PRINTF TEST START ==")); - Serial.print(_F("\r\nFloat numbers display test: \r\n")); + Serial.println(_F("\r\nFloat numbers display test:")); Serial.printf("Pi with 2 decimals: %.2f and with 4 decimals: %.4f \r\n", PI, PI); Serial.printf("Pi without specifying precision(default 9): %f\r\n", PI); @@ -217,19 +213,19 @@ void handleCommand(const String& command) String filename = F("README.md"); FileStream* fileStream = new FileStream; if(fileStream && fileStream->open(filename, File::ReadOnly)) { - Serial.printf(_F("Sending \"%s\" (%u bytes)\r\n"), filename.c_str(), fileStream->available()); + Serial << _F("Sending \"") << filename << "\" (" << fileStream->available() << " bytes)" << endl; auto demo = new SerialTransmitDemo(Serial1, fileStream); demo->begin(); } else { - Serial.printf(_F("Failed to open file \"%s\"\r\n"), filename.c_str()); + Serial << _F("Failed to open file \"") << filename << '"' << endl; delete fileStream; } } else if(command.equalsIgnoreCase(_F("text"))) { - Serial.printf(_F("Sending flash data, %u bytes\r\n"), testFlashData.length()); + Serial << _F("Sending flash data, ") << testFlashData.length() << " bytes" << endl; auto demo = new SerialTransmitDemo(Serial, new FlashMemoryStream(testFlashData)); demo->begin(); } else { - Serial.printf(_F("I don't know what \"%s\" means! Try typing: cat\r\n"), command.c_str()); + Serial << _F("I don't know what \"") << command << _F("\" means! Try typing: cat") << endl; } } diff --git a/samples/Basic_Servo/app/application.cpp b/samples/Basic_Servo/app/application.cpp index f77be8c461..9fb66c4390 100644 --- a/samples/Basic_Servo/app/application.cpp +++ b/samples/Basic_Servo/app/application.cpp @@ -44,8 +44,7 @@ void MyServoChannel::calcValue() auto pin = getPin(); Serial.write(indent, pin); - Serial.print("GPIO"); - Serial.print(pin); + Serial << "GPIO" << pin; #ifdef UPDATE_RAW @@ -64,13 +63,10 @@ void MyServoChannel::calcValue() value = 0; // overflow and restart linear ramp } - Serial.print(" value = "); - Serial.print(value); + Serial << " value = " << value; if(!setValue(value)) { - Serial.print(": setValue("); - Serial.print(value); - Serial.print(") failed!"); + Serial << ": setValue(" << value << ") failed!"; } #else @@ -81,13 +77,10 @@ void MyServoChannel::calcValue() ++degree; } - Serial.print(" degree = "); - Serial.print(degree); + Serial << " degree = " << degree; if(!setDegree(degree)) { - Serial.print(": setDegree("); - Serial.print(degree); - Serial.print(") failed!"); + Serial << ": setDegree(" << degree << ") failed!"; } #endif diff --git a/samples/Basic_SmartConfig/app/application.cpp b/samples/Basic_SmartConfig/app/application.cpp index 62a6057986..05f9eec4ca 100644 --- a/samples/Basic_SmartConfig/app/application.cpp +++ b/samples/Basic_SmartConfig/app/application.cpp @@ -29,8 +29,7 @@ bool smartConfigCallback(SmartConfigEvent event, const SmartConfigEventInfo& inf void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print("Connected: "); - Serial.println(ip); + Serial << "Connected: " << ip << endl; } void init() diff --git a/samples/Basic_Ssl/app/application.cpp b/samples/Basic_Ssl/app/application.cpp index 90c9174828..44d93887e2 100644 --- a/samples/Basic_Ssl/app/application.cpp +++ b/samples/Basic_Ssl/app/application.cpp @@ -18,17 +18,12 @@ OneShotFastMs connectTimer; void printHeap() { Serial.println(_F("Heap statistics")); - Serial.print(_F(" Free bytes: ")); - Serial.println(system_get_free_heap_size()); + Serial << _F(" Free bytes: ") << system_get_free_heap_size() << endl; #ifdef ENABLE_MALLOC_COUNT - Serial.print(_F(" Used: ")); - Serial.println(MallocCount::getCurrent()); - Serial.print(_F(" Peak used: ")); - Serial.println(MallocCount::getPeak()); - Serial.print(_F(" Allocations: ")); - Serial.println(MallocCount::getAllocCount()); - Serial.print(_F(" Total used: ")); - Serial.println(MallocCount::getTotal()); + Serial << _F(" Used: ") << MallocCount::getCurrent() << endl; + Serial << _F(" Peak used: ") << MallocCount::getPeak() << endl; + Serial << _F(" Allocations: ") << MallocCount::getAllocCount() << endl; + Serial << _F(" Total used: ") << MallocCount::getTotal() << endl; #endif } @@ -36,20 +31,13 @@ int onDownload(HttpConnection& connection, bool success) { auto elapsed = connectTimer.elapsedTime(); - Serial.print(_F("Got response code: ")); auto status = connection.getResponse()->code; - Serial.print(unsigned(status)); - Serial.print(" ("); - Serial.print(toString(status)); - Serial.print(_F("), success: ")); - Serial.print(success); + Serial << _F("Got response code: ") << unsigned(status) << " (" << status << _F("), success: ") << success; auto stream = connection.getResponse()->stream; assert(stream != nullptr); - Serial.print(_F(", received ")); - Serial.print(stream->available()); - Serial.println(_F(" bytes")); + Serial << _F(", received ") << stream->available() << _F(" bytes") << endl; auto& headers = connection.getResponse()->headers; for(unsigned i = 0; i < headers.count(); ++i) { @@ -61,8 +49,7 @@ int onDownload(HttpConnection& connection, bool success) ssl->printTo(Serial); } - Serial.print(_F("Time to connect and download page: ")); - Serial.println(elapsed.toString()); + Serial << _F("Time to connect and download page: ") << elapsed.toString() << endl; return 0; // return 0 on success in your callbacks } @@ -76,13 +63,13 @@ void grcSslInit(Ssl::Session& session, HttpRequest& request) // Use the Gibson Research fingerprints web page as an example. Unlike Google, these fingerprints change very infrequently. static const Ssl::Fingerprint::Cert::Sha1 sha1Fingerprint PROGMEM = { - 0x7A, 0x85, 0x1C, 0xF0, 0xF6, 0x9F, 0xD0, 0xCC, 0xEA, 0xEA, - 0x9A, 0x88, 0x01, 0x96, 0xBF, 0x79, 0x8C, 0xE1, 0xA8, 0x33, + 0xC3, 0xFB, 0x91, 0x85, 0xCC, 0x6B, 0x4C, 0x7D, 0xE7, 0x18, + 0xED, 0xD8, 0x00, 0xD2, 0x84, 0xE7, 0x6E, 0x97, 0x06, 0x07, }; static const Ssl::Fingerprint::Cert::Sha256 certSha256Fingerprint PROGMEM = { - 0xEC, 0xB2, 0x21, 0x7E, 0x43, 0xCC, 0x83, 0xE5, 0x5B, 0x35, 0x7F, 0x1A, 0xC2, 0x06, 0xE8, 0xBF, - 0xB1, 0x5F, 0x5B, 0xC8, 0x13, 0x9F, 0x93, 0x37, 0x3C, 0xF4, 0x8E, 0x82, 0xEC, 0x81, 0x28, 0xDF, + 0xC3, 0xFB, 0x91, 0x85, 0xCC, 0x6B, 0x4C, 0x7D, 0xE7, 0x18, + 0xED, 0xD8, 0x00, 0xD2, 0x84, 0xE7, 0x6E, 0x97, 0x06, 0x07, }; static const Ssl::Fingerprint::Pki::Sha256 publicKeyFingerprint PROGMEM = { diff --git a/samples/Basic_Tasks/app/application.cpp b/samples/Basic_Tasks/app/application.cpp index a049457c6b..8e6136bf87 100644 --- a/samples/Basic_Tasks/app/application.cpp +++ b/samples/Basic_Tasks/app/application.cpp @@ -43,17 +43,9 @@ void hwTimerDelegate(uint32_t count) static ElapseTimer timer; auto elapsed = timer.elapsedTime(); - Serial.print(F("count = ")); - Serial.print(count); - Serial.print(F(", hwTimerCount = ")); - Serial.print(hwTimerCount); - Serial.print(F(", av. interval = ")); - Serial.print(diff ? (elapsed / diff) : 0); - Serial.print(F(", maxTasks = ")); - Serial.print(System.getMaxTaskCount()); - Serial.print(F(", CPU usage = ")); - Serial.print(cpuUsage.getUtilisation() / 100.0); - Serial.println(F("%%")); + Serial << _F("count = ") << count << _F(", hwTimerCount = ") << hwTimerCount << _F(", av. interval = ") + << (diff ? (elapsed / diff) : 0) << _F(", maxTasks = ") << System.getMaxTaskCount() << _F(", CPU usage = ") + << cpuUsage.getUtilisation() / 100.0 << '%' << endl; cpuUsage.reset(); @@ -87,12 +79,7 @@ void onReady() WifiStation.enable(true); WifiAccessPoint.enable(false); WifiEvents.onStationGotIP([](IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print(F("GOTIP - IP: ")); - Serial.print(ip); - Serial.print(F(", mask: ")); - Serial.print(netmask); - Serial.print(F(", gateway: ")); - Serial.println(gateway); + Serial << _F("GOTIP - IP: ") << ip << _F(", mask: ") << netmask << _F(", gateway: ") << gateway << endl; }); #endif diff --git a/samples/Basic_Tasks/include/AnalogueReader.h b/samples/Basic_Tasks/include/AnalogueReader.h index 4bf3393458..b1264f2ed6 100644 --- a/samples/Basic_Tasks/include/AnalogueReader.h +++ b/samples/Basic_Tasks/include/AnalogueReader.h @@ -91,9 +91,7 @@ ANALOGUE_READER(void)::processSamples() } Serial.print(bands[i]); } - Serial.print(" - "); - Serial.print(missedSamples); - Serial.println(" missed"); + Serial << " - " << missedSamples << " missed" << endl; } ANALOGUE_READER(void)::loop() @@ -115,12 +113,8 @@ ANALOGUE_READER(void)::loop() missedSamples = 0; restartSampler = false; - // Serial.print("groupStartTicks = "); - // Serial.print(groupStartTicks); - // Serial.print(", now = "); - // Serial.print(now); - // Serial.print(", diff = "); - // Serial.println(int(now - groupStartTicks)); + // Serial << "groupStartTicks = " << groupStartTicks, + // " << now = " << now << ", diff = " << int(now - groupStartTicks) << endl; } else if(int(nextSampleTicks - now) <= 0) { unsigned index = (now - groupStartTicks) / sampleIntervalTicks; @@ -163,8 +157,7 @@ ANALOGUE_READER(void)::onNotify(Notify code) groupStartTicks = sampleTimer.ticks(); restartSampler = true; - Serial.print(_F("sampleIntervalTicks = ")); - Serial.println(sampleIntervalTicks); + Serial << F("sampleIntervalTicks = ") << sampleIntervalTicks << endl; break; default:; } diff --git a/samples/Basic_WiFi/app/application.cpp b/samples/Basic_WiFi/app/application.cpp index 2ff8b3fd76..a9eed2e2b9 100644 --- a/samples/Basic_WiFi/app/application.cpp +++ b/samples/Basic_WiFi/app/application.cpp @@ -15,12 +15,9 @@ void listNetworks(bool succeeded, BssList& list) } for(unsigned i = 0; i < list.count(); i++) { - Serial.print(_F("\tWiFi: ")); - Serial.print(list[i].ssid); - Serial.print(", "); - Serial.print(list[i].getAuthorizationMethodName()); + Serial << _F("\tWiFi: ") << list[i].ssid << ", " << list[i].getAuthorizationMethodName(); if(list[i].hidden) { - Serial.print(_F(" (hidden)")); + Serial << _F(" (hidden)"); } Serial.println(); } @@ -29,18 +26,15 @@ void listNetworks(bool succeeded, BssList& list) // Will be called when WiFi station was connected to AP void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) { - Serial.print(_F("I'm CONNECTED to ")); - Serial.println(ip); + Serial << _F("I'm CONNECTED to ") << ip << endl; } // Will be called when WiFi station was disconnected void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) { // The different reason codes can be found in user_interface.h. in your SDK. - Serial.print(_F("Disconnected from \"")); - Serial.print(ssid); - Serial.print(_F("\", reason: ")); - Serial.println(WifiEvents.getDisconnectReasonDesc(reason)); + Serial << _F("Disconnected from \"") << ssid << _F("\", reason: ") << WifiEvents.getDisconnectReasonDesc(reason) + << endl; /* * Print available access points @@ -62,10 +56,7 @@ void ready() Serial.println(_F("READY!")); if(WifiAccessPoint.isEnabled()) { - Serial.print(_F("AP. ip: ")); - Serial.print(WifiAccessPoint.getIP()); - Serial.print(_F(" mac: ")); - Serial.println(WifiAccessPoint.getMacAddress()); + Serial << _F("AP. ip: ") << WifiAccessPoint.getIP() << _F(" mac: ") << WifiAccessPoint.getMacAddress() << endl; } } @@ -92,10 +83,7 @@ void init() // Optional: Print details of any incoming probe requests WifiEvents.onAccessPointProbeReqRecved([](int rssi, MacAddress mac) { - Serial.print(_F("Probe request: RSSI = ")); - Serial.print(rssi); - Serial.print(_F(", mac = ")); - Serial.println(mac); + Serial << _F("Probe request: RSSI = ") << rssi << _F(", mac = ") << mac << endl; }); // Set callback that should be triggered when we have assigned IP diff --git a/samples/CanBus/app/application.cpp b/samples/CanBus/app/application.cpp index 35fffc293e..b616aae340 100644 --- a/samples/CanBus/app/application.cpp +++ b/samples/CanBus/app/application.cpp @@ -35,18 +35,18 @@ void init() // init CAN0 bus, baudrate: 250k@16MHz if(canBus0.begin(MCP_EXT, CAN_250KBPS, MCP_16MHZ) == CAN_OK) { - Serial.print("CAN0: Init OK!\r\n"); + Serial.println(_F("CAN0: Init OK!")); canBus0.setMode(MCP_NORMAL); } else { - Serial.print("CAN0: Init Fail!!!\r\n"); + Serial.println(_F("CAN0: Init Fail!!!")); } // init CAN1 bus, baudrate: 250k@16MHz if(canBus1.begin(MCP_EXT, CAN_250KBPS, MCP_16MHZ) == CAN_OK) { - Serial.print("CAN1: Init OK!\r\n"); + Serial.println(_F("CAN1: Init OK!")); canBus1.setMode(MCP_NORMAL); } else { - Serial.print("CAN1: Init Fail!!!\r\n"); + Serial.println(_F("CAN1: Init Fail!!!")); } // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz) diff --git a/samples/CommandProcessing_Debug/app/application.cpp b/samples/CommandProcessing_Debug/app/application.cpp index bccb385b05..e9b3ad4e32 100644 --- a/samples/CommandProcessing_Debug/app/application.cpp +++ b/samples/CommandProcessing_Debug/app/application.cpp @@ -42,29 +42,30 @@ int msgCount = 0; void wsConnected(WebsocketConnection& socket) { - Serial.printf("Socket connected\r\n"); + Serial.println(_F("Socket connected")); } void wsMessageReceived(WebsocketConnection& socket, const String& message) { - Serial.printf("WebsocketConnection message received:\r\n%s\r\n", message.c_str()); + Serial.println(_F("WebsocketConnection message received:")); + Serial.println(message); String response = "Echo: " + message; socket.sendString(response); } void wsBinaryReceived(WebsocketConnection& socket, uint8_t* data, size_t size) { - Serial.printf("Websocket binary data received, size: %d\r\n", size); + Serial << _F("Websocket binary data received, size: ") << size << endl; } void wsDisconnected(WebsocketConnection& socket) { - Serial.printf("Socket disconnected"); + Serial.println(_F("Socket disconnected")); } void processApplicationCommands(String commandLine, CommandOutput* commandOutput) { - commandOutput->printf("This command is handle by the application\r\n"); + commandOutput->println(_F("This command is handle by the application")); } void StartServers() @@ -82,29 +83,29 @@ void StartServers() server.paths.set("/ws", wsResource); - Serial.println("\r\n=== WEB SERVER STARTED ==="); + Serial.println(_F("\r\n=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println("==============================\r\n"); + Serial.println(_F("==============================\r\n")); // Start FTP server ftp.listen(21); ftp.addUser("me", "123"); // FTP account - Serial.println("\r\n=== FTP SERVER STARTED ==="); - Serial.println("==============================\r\n"); + Serial.println(_F("\r\n=== FTP SERVER STARTED ===")); + Serial.println(_F("==============================\r\n")); telnet.listen(23); telnet.enableDebug(true); - Serial.println("\r\n=== TelnetServer SERVER STARTED ==="); - Serial.println("==============================\r\n"); + Serial.println(_F("\r\n=== TelnetServer SERVER STARTED ===")); + Serial.println(_F("==============================\r\n")); } void startExampleApplicationCommand() { exampleCommand.initCommand(); commandHandler.registerCommand( - CommandDelegate("example", "Example Command from Class", "Application", processApplicationCommands)); + CommandDelegate(F("example"), F("Example Command from Class"), F("Application"), processApplicationCommands)); } void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) diff --git a/samples/Compass_HMC5883L/app/application.cpp b/samples/Compass_HMC5883L/app/application.cpp index 06f317c651..471dfebccf 100644 --- a/samples/Compass_HMC5883L/app/application.cpp +++ b/samples/Compass_HMC5883L/app/application.cpp @@ -21,10 +21,11 @@ void init() mag.initialize(); - if(mag.testConnection()) - Serial.println("[Compass] Magnetometer found"); - else - Serial.println("Can't connect to Magnetometer"); + if(mag.testConnection()) { + Serial.println(_F("[Compass] Magnetometer found")); + } else { + Serial.println(_F("Can't connect to Magnetometer")); + } // Start reading loop procTimer.initializeMs(100, readCompass).start(); @@ -35,21 +36,14 @@ void readCompass() // read raw heading measurements from device mag.getHeading(&mx, &my, &mz); - // display tab-separated gyro x/y/z values - Serial.print("mag:\t"); - Serial.print(mx); - Serial.print("\t"); - Serial.print(my); - Serial.print("\t"); - Serial.print(mz); - Serial.print("\t"); - // To calculate heading in degrees. 0 degree indicates North float heading = atan2(my, mx); - if(heading < 0) + if(heading < 0) { heading += 2 * PI; - if(heading > 2 * PI) + } else if(heading > 2 * PI) { heading -= 2 * PI; - Serial.print("heading:\t"); - Serial.println(heading * RAD_TO_DEG); + } + + // display tab-separated gyro x/y/z values and heading + Serial << "mag:\t" << mx << '\t' << my << '\t' << mz << "\theading:\t" << heading * RAD_TO_DEG << endl; } diff --git a/samples/DS3232RTC_NTP_Setter/app/application.cpp b/samples/DS3232RTC_NTP_Setter/app/application.cpp index 801c90286d..802812dbfe 100644 --- a/samples/DS3232RTC_NTP_Setter/app/application.cpp +++ b/samples/DS3232RTC_NTP_Setter/app/application.cpp @@ -23,20 +23,16 @@ void onPrintSystemTime() { DateTime rtcNow = DSRTC.get(); Serial.println(_F("Current time")); - Serial.print(_F(" System(LOCAL TZ): ")); - Serial.println(SystemClock.getSystemTimeString()); - Serial.print(_F(" UTC(UTC TZ): ")); - Serial.println(SystemClock.getSystemTimeString(eTZ_UTC)); - Serial.print(_F(" DSRTC(UTC TZ): ")); - Serial.println(rtcNow.toFullDateTimeString()); + Serial << _F(" System(LOCAL TZ): ") << SystemClock.getSystemTimeString() << endl; + Serial << _F(" UTC(UTC TZ): ") << SystemClock.getSystemTimeString(eTZ_UTC) << endl; + Serial << _F(" DSRTC(UTC TZ): ") << rtcNow.toFullDateTimeString() << endl; } void onNtpReceive(NtpClient& client, time_t timestamp) { SystemClock.setTime(timestamp, eTZ_UTC); //System timezone is LOCAL so to set it from UTC we specify TZ DSRTC.set(timestamp); //DSRTC timezone is UTC so we need TZ-correct DSRTC.get() - Serial.print(_F("Time synchronized: ")); - Serial.println(SystemClock.getSystemTimeString()); + Serial << _F("Time synchronized: ") << SystemClock.getSystemTimeString() << endl; } void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) @@ -50,7 +46,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true); // Allow debug print to serial - Serial.println("Sming DSRTC_NTP_SETTER started!"); + Serial.println(_F("Sming DSRTC_NTP_SETTER started!")); Wire.pins(SDA_PIN, SCL_PIN); Wire.begin(); diff --git a/samples/Distance_Vl53l0x/app/application.cpp b/samples/Distance_Vl53l0x/app/application.cpp index dcf5e72dcf..3a5e97a96b 100644 --- a/samples/Distance_Vl53l0x/app/application.cpp +++ b/samples/Distance_Vl53l0x/app/application.cpp @@ -15,14 +15,13 @@ void loop() { VL53L0X_RangingMeasurementData_t measure; - Serial.print("Reading a measurement... "); + Serial.print(_F("Reading a measurement... ")); lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout! if(measure.RangeStatus != 4) { // phase failures have incorrect data - Serial.print("Distance (mm): "); - Serial.println(measure.RangeMilliMeter); + Serial << _F("Distance: ") << measure.RangeMilliMeter << " mm" << endl; } else { - Serial.println(" out of range "); + Serial.println(_F("Out of range")); } } @@ -34,11 +33,10 @@ void init() Wire.begin(SDA, SCL); if(!lox.begin(VL53L0X_I2C_ADDR, false, &Wire, Adafruit_VL53L0X::VL53L0X_SENSE_LONG_RANGE)) { - Serial.println(F("Failed to boot VL53L0X")); - while(1) { - } + Serial.println(_F("Failed to boot VL53L0X")); + return; } - Serial.println(F("VL53L0X API Simple Ranging example\n\n")); + Serial.println(_F("VL53L0X API Simple Ranging example\n\n")); loopTimer.initializeMs<100>(loop).start(); } diff --git a/samples/FtpServer_Files/app/application.cpp b/samples/FtpServer_Files/app/application.cpp index 95481b31ea..0b659e560b 100644 --- a/samples/FtpServer_Files/app/application.cpp +++ b/samples/FtpServer_Files/app/application.cpp @@ -10,8 +10,7 @@ FtpServer ftp; void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print("IP: "); - Serial.println(ip); + Serial << "IP: " << ip << endl; // Start FTP server ftp.listen(21); // Add user accounts @@ -24,7 +23,7 @@ void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) // Will be called when WiFi station timeout was reached void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) { - Serial.println("I'm NOT CONNECTED. Need help!!! :("); + Serial.println(_F("I'm NOT CONNECTED. Need help!!! :(")); } void init() diff --git a/samples/Gesture_APDS-9960/app/application.cpp b/samples/Gesture_APDS-9960/app/application.cpp index b2595bbbb3..3018d2b7c0 100644 --- a/samples/Gesture_APDS-9960/app/application.cpp +++ b/samples/Gesture_APDS-9960/app/application.cpp @@ -14,25 +14,25 @@ void handleGesture() if(apds.isGestureAvailable()) { switch(apds.readGesture()) { case DIR_UP: - Serial.println("UP"); + Serial.println(_F("UP")); break; case DIR_DOWN: - Serial.println("DOWN"); + Serial.println(_F("DOWN")); break; case DIR_LEFT: - Serial.println("LEFT"); + Serial.println(_F("LEFT")); break; case DIR_RIGHT: - Serial.println("RIGHT"); + Serial.println(_F("RIGHT")); break; case DIR_NEAR: - Serial.println("NEAR"); + Serial.println(_F("NEAR")); break; case DIR_FAR: - Serial.println("FAR"); + Serial.println(_F("FAR")); break; default: - Serial.println("NONE"); + Serial.println(_F("NONE")); } } } @@ -55,23 +55,23 @@ void init() WifiAccessPoint.enable(false); #endif - Serial.println(); - Serial.println("--------------------------------"); - Serial.println("SparkFun APDS-9960 - GestureTest"); - Serial.println("--------------------------------"); + Serial.print(_F("\r\n" + "--------------------------------\r\n" + "SparkFun APDS-9960 - GestureTest\r\n" + "--------------------------------\r\n")); // Initialize APDS-9960 (configure I2C and initial values) if(apds.init()) { - Serial.println("APDS-9960 initialization complete"); + Serial.println(_F("APDS-9960 initialization complete")); } else { - Serial.println("Something went wrong during APDS-9960 init!"); + Serial.println(_F("Something went wrong during APDS-9960 init!")); } // Start running the APDS-9960 gesture sensor engine if(apds.enableGestureSensor(true)) { - Serial.println("Gesture sensor is now running"); + Serial.println(_F("Gesture sensor is now running")); } else { - Serial.println("Something went wrong during gesture sensor init!"); + Serial.println(_F("Something went wrong during gesture sensor init!")); } // Initialize interrupt service routine diff --git a/samples/HttpClient/app/application.cpp b/samples/HttpClient/app/application.cpp index bb54ee542f..ed50d78ad8 100644 --- a/samples/HttpClient/app/application.cpp +++ b/samples/HttpClient/app/application.cpp @@ -78,8 +78,7 @@ void sslRequestInit(Ssl::Session& session, HttpRequest& request) void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) { - Serial.print(F("Connected. Got IP: ")); - Serial.println(ip); + Serial << _F("Connected. Got IP: ") << ip << endl; // [ GET request: The example below shows how to make HTTP requests ] diff --git a/samples/HttpClient_Instapush/app/application.cpp b/samples/HttpClient_Instapush/app/application.cpp index 2e9862ca6c..f7c2d0333c 100644 --- a/samples/HttpClient_Instapush/app/application.cpp +++ b/samples/HttpClient_Instapush/app/application.cpp @@ -82,20 +82,20 @@ InstapushApplication pusher(APP_ID, APP_SECRET); // Publish our message void publishMessage() { - Serial.println("Push message now!"); + Serial.println(_F("Push message now!")); InstapushTrackers trackers; - trackers["title"] = "Sming Framework"; - trackers["text"] = "New test was successfully launched"; + trackers["title"] = F("Sming Framework"); + trackers["text"] = F("New test was successfully launched"); pusher.notify("notify", trackers); // event name, trackers } // Will be called when WiFi station was connected to AP void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.println("I'm CONNECTED"); + Serial << _F("I'm CONNECTED to ") << ip << endl; // Start publishing loop - procTimer.initializeMs(10 * 1000, publishMessage).start(true); // every 20 seconds + procTimer.initializeMs<10 * 1000>(publishMessage).start(); } void init() diff --git a/samples/HttpClient_ThingSpeak/app/application.cpp b/samples/HttpClient_ThingSpeak/app/application.cpp index 775373e3b4..ee6424f537 100644 --- a/samples/HttpClient_ThingSpeak/app/application.cpp +++ b/samples/HttpClient_ThingSpeak/app/application.cpp @@ -15,14 +15,12 @@ int onDataSent(HttpConnection& client, bool successful) Serial.println(successful ? _F("Success sent") : _F("Failed")); String response = client.getResponse()->getBody(); - Serial.print(_F("Server response: '")); - Serial.print(response); - Serial.println('\''); + Serial << _F("Server response: '") << response << '\'' << endl; if(response.length() > 0) { int intVal = response.toInt(); if(intVal == 0) { - Serial.println("Sensor value wasn't accepted. May be we need to wait a little?"); + Serial.println(_F("Sensor value wasn't accepted. May be we need to wait a little?")); } } diff --git a/samples/HttpServer_AJAX/app/application.cpp b/samples/HttpServer_AJAX/app/application.cpp index afdf4866c4..fda5a63e4c 100644 --- a/samples/HttpServer_AJAX/app/application.cpp +++ b/samples/HttpServer_AJAX/app/application.cpp @@ -78,16 +78,17 @@ void startWebServer() server.paths.set("/ajax/frequency", onAjaxFrequency); server.paths.setDefault(onFile); - Serial.println("\r\n=== WEB SERVER STARTED ==="); + Serial.println(_F("\r\n" + "=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println("==============================\r\n"); + Serial.println(_F("==========================\r\n")); } void startFTP() { if(!fileExist("index.html")) fileSetContent("index.html", - "

Please connect to FTP and upload files from folder 'web/build' (details in code)

"); + F("

Please connect to FTP and upload files from folder 'web/build' (details in code)

")); // Start FTP server ftp.listen(21); diff --git a/samples/HttpServer_Bootstrap/app/application.cpp b/samples/HttpServer_Bootstrap/app/application.cpp index a5a520e760..bf75ae9fba 100644 --- a/samples/HttpServer_Bootstrap/app/application.cpp +++ b/samples/HttpServer_Bootstrap/app/application.cpp @@ -56,9 +56,10 @@ void startWebServer() server.paths.set("/hello", onHello); server.paths.setDefault(onFile); - Serial.println("\r\n=== WEB SERVER STARTED ==="); + Serial.println(_F("\r\n" + "=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println("==============================\r\n"); + Serial.println(_F("==========================\r\n")); } Timer downloadTimer; @@ -66,9 +67,9 @@ HttpClient downloadClient; int dowfid = 0; void downloadContentFiles() { - downloadClient.downloadFile("http://simple.anakod.ru/templates/index.html"); - downloadClient.downloadFile("http://simple.anakod.ru/templates/bootstrap.css.gz"); - downloadClient.downloadFile("http://simple.anakod.ru/templates/jquery.js.gz", + downloadClient.downloadFile(F("http://simple.anakod.ru/templates/index.html")); + downloadClient.downloadFile(F("http://simple.anakod.ru/templates/bootstrap.css.gz")); + downloadClient.downloadFile(F("http://simple.anakod.ru/templates/jquery.js.gz"), (RequestCompletedDelegate)([](HttpConnection& connection, bool success) -> int { if(success) { startWebServer(); @@ -105,6 +106,5 @@ void init() // Max. out CPU frequency System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); - Serial.print("New CPU frequency is:"); - Serial.println(int(System.getCpuFrequency())); + Serial << _F("New CPU frequency is ") << System.getCpuFrequency() << " MHz" << endl; } diff --git a/samples/HttpServer_WebSockets/app/CUserData.cpp b/samples/HttpServer_WebSockets/app/CUserData.cpp index db65964221..801ea01470 100644 --- a/samples/HttpServer_WebSockets/app/CUserData.cpp +++ b/samples/HttpServer_WebSockets/app/CUserData.cpp @@ -30,10 +30,7 @@ void CUserData::printMessage(WebsocketConnection& connection, const String& msg) } if(i < activeWebSockets.count()) { - Serial.print(F("Received msg on connection ")); - Serial.print(i); - Serial.print(" :"); - Serial.print(msg); + Serial << _F("Received msg on connection ") << i << ": " << msg; } } diff --git a/samples/HttpServer_WebSockets/app/application.cpp b/samples/HttpServer_WebSockets/app/application.cpp index 65d34d8f62..77062a5bfd 100644 --- a/samples/HttpServer_WebSockets/app/application.cpp +++ b/samples/HttpServer_WebSockets/app/application.cpp @@ -47,7 +47,8 @@ void wsConnected(WebsocketConnection& socket) void wsMessageReceived(WebsocketConnection& socket, const String& message) { - Serial.printf("WebSocket message received:\r\n%s\r\n", message.c_str()); + Serial.println(_F("WebSocket message received:")); + Serial.println(message); if(message == _F("shutdown")) { String message(F("The server is shutting down...")); @@ -77,7 +78,7 @@ void wsMessageReceived(WebsocketConnection& socket, const String& message) void wsBinaryReceived(WebsocketConnection& socket, uint8_t* data, size_t size) { - Serial.printf(_F("Websocket binary data received, size: %d\r\n"), size); + Serial << _F("Websocket binary data received, size: ") << size << endl; } void wsDisconnected(WebsocketConnection& socket) @@ -110,9 +111,10 @@ void startWebServer() server.paths.set("/ws", wsResource); - Serial.println(F("\r\n=== WEB SERVER STARTED ===")); + Serial.println(_F("\r\n" + "=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println(F("==============================\r\n")); + Serial.println(_F("==========================\r\n")); } // Will be called when WiFi station becomes fully operational diff --git a/samples/Humidity_AM2321/app/application.cpp b/samples/Humidity_AM2321/app/application.cpp index ef986ce288..0890214c5e 100644 --- a/samples/Humidity_AM2321/app/application.cpp +++ b/samples/Humidity_AM2321/app/application.cpp @@ -12,11 +12,7 @@ const int SDA = 4; void read() { - Serial.print(am2321.read()); - Serial.print(","); - Serial.print(am2321.temperature / 10.0); - Serial.print(","); - Serial.println(am2321.humidity / 10.0); + Serial << am2321.read() << ',' << am2321.temperature / 10.0 << ',' << am2321.humidity / 10.0 << endl; } void init() diff --git a/samples/Humidity_BME280/app/application.cpp b/samples/Humidity_BME280/app/application.cpp index 3ff338a247..395d5a62a0 100644 --- a/samples/Humidity_BME280/app/application.cpp +++ b/samples/Humidity_BME280/app/application.cpp @@ -33,23 +33,10 @@ Timer procTimer; void printValues() { - Serial.print(F("Temperature = ")); - Serial.print(bme.readTemperature()); - Serial.println(" °C"); - - Serial.print(F("Pressure = ")); - - Serial.print(bme.readPressure() / 100.0F); - Serial.println(" hPa"); - - Serial.print(F("Approx. Altitude = ")); - Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); - Serial.println(" m"); - - Serial.print(F("Humidity = ")); - Serial.print(bme.readHumidity()); - Serial.println(" %"); - + Serial << _F("Temperature = ") << bme.readTemperature() << " °C" << endl; + Serial << _F("Pressure = ") << bme.readPressure() / 100.0F << " hPa" << endl; + Serial << _F("Approx. Altitude = ") << bme.readAltitude(SEALEVELPRESSURE_HPA) << " m" << endl; + Serial << _F("Humidity = ") << bme.readHumidity() << " %" << endl; Serial.println(); } @@ -58,26 +45,25 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Enable/disable debug output - Serial.println(F("BME280 test")); + Serial.println(_F("BME280 test")); #ifdef SDA Wire.pins(SDA, SCL); #endif if(!bme.begin()) { // if(!bme.begin(0x76, &Wire)) { if you need a specific address - Serial.println(F("Could not find a valid BME280 sensor, check wiring, address, sensor ID!")); - Serial.print(F("SensorID was: 0x")); - Serial.println(bme.sensorID(), 16); - Serial.println(F(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085")); - Serial.println(F(" ID of 0x56-0x58 represents a BMP 280,")); - Serial.println(F(" ID of 0x60 represents a BME 280.")); - Serial.println(F(" ID of 0x61 represents a BME 680.")); + Serial.println(_F("Could not find a valid BME280 sensor, check wiring, address, sensor ID!")); + Serial << _F("SensorID was: 0x") << String(bme.sensorID(), HEX) << endl; + Serial << _F(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\r\n" + " ID of 0x56-0x58 represents a BMP 280,\r\n" + " ID of 0x60 represents a BME 280.\r\n" + " ID of 0x61 represents a BME 680.\r\n"); return; } - Serial.println(F("-- Default Test --")); + Serial.println(_F("-- Default Test --")); Serial.println(); - procTimer.initializeMs(3000, printValues).start(); + procTimer.initializeMs<3000>(printValues).start(); } diff --git a/samples/Humidity_DHT22/app/application.cpp b/samples/Humidity_DHT22/app/application.cpp index 7ecc3b67e3..4f5f8e09ba 100644 --- a/samples/Humidity_DHT22/app/application.cpp +++ b/samples/Humidity_DHT22/app/application.cpp @@ -17,10 +17,10 @@ void init() dht.setup(WORK_PIN, DHTesp::DHT22); readTemperatureProcTimer.initializeMs(5 * 1000, onTimer_readTemperatures).start(); // every so often. - Serial.println("\nDHT improved lib"); - Serial.print("TickCount="); - Serial.print((int)(RTC.getRtcNanoseconds() / 1000000)); - Serial.println("Need to wait 1 second for the sensor to boot up"); + Serial.println(_F("\r\n" + "DHT improved lib")); + Serial << _F("TickCount=") << RTC.getRtcNanoseconds() / 1000000 + << _F("; Need to wait 1 second for the sensor to boot up") << endl; } void onTimer_readTemperatures() @@ -30,41 +30,30 @@ void onTimer_readTemperatures() toggle = !toggle; float humidity = 0; float temperature = 0; - Serial.print("TickCount="); - Serial.print((int)(RTC.getRtcNanoseconds() / 1000000)); + Serial << _F("TickCount=") << RTC.getRtcNanoseconds() / 1000000 << endl; if(toggle) { - Serial.print("Read using Adafruit API methods\n"); + Serial.println(_F("Read using Adafruit API methods")); humidity = dht.getHumidity(); temperature = dht.getTemperature(); // check if returns are valid, if they are NaN (not a number) then something went wrong! if(dht.getStatus() == DHTesp::ERROR_NONE) { - Serial.print("\tHumidity: "); - Serial.print(humidity); - Serial.print("% Temperature: "); - Serial.print(temperature); - Serial.print(" *C\n"); + Serial << _F("\tHumidity: ") << humidity << _F("% Temperature: ") << temperature << " °C" << endl; } else { - Serial.print("Failed to read from DHT: "); - Serial.println((int)dht.getStatus()); + Serial << _F("Failed to read from DHT: ") << dht.getStatus() << endl; } } else { //* improved reading method - Serial.print("\nRead using new API methods\n"); - TempAndHumidity th; - th = dht.getTempAndHumidity(); + Serial.println(_F("\r\n" + "Read using new API methods")); + TempAndHumidity th = dht.getTempAndHumidity(); humidity = th.humidity; temperature = th.temperature; if(dht.getStatus() == DHTesp::ERROR_NONE) { - Serial.print("\tHumidity: "); - Serial.print(th.humidity); - Serial.print("% Temperature: "); - Serial.print(th.temperature); - Serial.print(" *C\n"); + Serial << _F("\tHumidity: ") << th.humidity << _F("% Temperature: ") << th.temperature << " °C" << endl; } else { - Serial.print("Failed to read from DHT: "); - Serial.print(dht.getStatus()); + Serial << _F("Failed to read from DHT: ") << dht.getStatus() << endl; } } @@ -73,61 +62,55 @@ void onTimer_readTemperatures() // Heatindex is the perceived temperature taking humidity into account // More: https://en.wikipedia.org/wiki/Heat_index // - Serial.print("Heatindex: "); - Serial.print(dht.computeHeatIndex(temperature, humidity)); - Serial.print("*C\n"); + Serial << _F("Heatindex: ") << dht.computeHeatIndex(temperature, humidity) << " °C" << endl; // // Dewpoint is the temperature where condensation starts. // Water vapors will start condensing on an object having this temperature or below. // More: https://en.wikipedia.org/wiki/Dew_point // - Serial.printf("Dewpoint: "); - Serial.print(dht.computeDewPoint(temperature, humidity)); - Serial.print("*C\n"); + Serial << _F("Dewpoint: ") << dht.computeDewPoint(temperature, humidity) << " °C" << endl; // // Determine thermal comfort according to http://epb.apogee.net/res/refcomf.asp // ComfortState cf; - Serial.print("Comfort is at "); - Serial.print(dht.getComfortRatio(cf, temperature, humidity)); - Serial.print(" percent, ("); + Serial << _F("Comfort is at ") << dht.getComfortRatio(cf, temperature, humidity) << " %, ("; switch(cf) { case Comfort_OK: - Serial.print("OK"); + Serial.print(_F("OK")); break; case Comfort_TooHot: - Serial.print("Too Hot"); + Serial.print(_F("Too Hot")); break; case Comfort_TooCold: - Serial.print("Too Cold"); + Serial.print(_F("Too Cold")); break; case Comfort_TooDry: - Serial.print("Too Dry"); + Serial.print(_F("Too Dry")); break; case Comfort_TooHumid: - Serial.print("Too Humid"); + Serial.print(_F("Too Humid")); break; case Comfort_HotAndHumid: - Serial.print("Hot And Humid"); + Serial.print(_F("Hot And Humid")); break; case Comfort_HotAndDry: - Serial.print("Hot And Dry"); + Serial.print(_F("Hot And Dry")); break; case Comfort_ColdAndHumid: - Serial.print("Cold And Humid"); + Serial.print(_F("Cold And Humid")); break; case Comfort_ColdAndDry: - Serial.print("Cold And Dry"); + Serial.print(_F("Cold And Dry")); break; default: - Serial.print("Unknown:"); + Serial.print(_F("Unknown:")); Serial.print(cf); break; } - Serial.print(")\n"); + Serial.println(')'); } diff --git a/samples/Humidity_SI7021/app/application.cpp b/samples/Humidity_SI7021/app/application.cpp index 6b9bce7063..8861e78543 100644 --- a/samples/Humidity_SI7021/app/application.cpp +++ b/samples/Humidity_SI7021/app/application.cpp @@ -19,55 +19,35 @@ double getDewPoint(unsigned int humidity, int temperature) void si_read_ht() { - if(!hydrometer.begin()) - Serial.println("Could not connect to SI7021."); - Serial.print("Start reading Humidity and Temperature"); - Serial.println(); // Start a new line. + if(!hydrometer.begin()) { + Serial.println(_F("Could not connect to SI7021.")); + } + Serial.println(_F("Start reading Humidity and Temperature")); si7021_env env_data = hydrometer.getHumidityAndTemperature(); if(env_data.error_crc == 1) { - Serial.print("\tCRC ERROR: "); - Serial.println(); // Start a new line. + Serial.println(_F("\tCRC ERROR: ")); } else { - // Print out the Temperature - Serial.print("\tTemperature: "); - float tprint = env_data.temperature; - Serial.print(tprint / 100); - Serial.print("C"); - Serial.println(); // Start a new line. - // Print out the Humidity Percent - Serial.print("\tHumidity: "); - Serial.print(env_data.humidityPercent); - Serial.print("%"); - Serial.println(); // Start a new line. - // Print out the Dew Point - Serial.print("\tDew Point: "); - Serial.print(getDewPoint(env_data.humidityPercent, env_data.temperature)); - Serial.print("C"); - Serial.println(); + Serial << _F("\tTemperature: ") << env_data.temperature / 100.0 << " °C" << endl; + Serial << _F("\tHumidity: ") << env_data.humidityPercent << '%' << endl; + Serial << _F("\tDew Point: ") << getDewPoint(env_data.humidityPercent, env_data.temperature) << " °C" << endl; } } void si_read_olt() { - if(!hydrometer.begin()) - Serial.println("Could not connect to SI7021."); - Serial.print("Start reading Temperature"); - Serial.println(); // Start a new line. + if(!hydrometer.begin()) { + Serial.println(_F("Could not connect to SI7021.")); + } + Serial.println(_F("Start reading Temperature")); si7021_olt olt_data = hydrometer.getTemperatureOlt(); if(olt_data.error_crc == 1) { - Serial.print("\tCRC ERROR: "); - Serial.println(); // Start a new line. + Serial.println(_F("\tCRC ERROR: ")); } else { - // Print out the Temperature - Serial.print("\tTemperature: "); - float tprint = olt_data.temperature; - Serial.print(tprint / 100); - Serial.print("C"); - Serial.println(); // Start a new line. + Serial << _F("\tTemperature: ") << olt_data.temperature / 100.0 << " °C" << endl; } } @@ -75,7 +55,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Allow debug output to serial - Serial.print("Start I2c"); + Serial.print(_F("Start I2c")); Wire.pins(I2C_SDA, I2C_SCL); // SDA, SCL Wire.begin(); procTimer_ht.initializeMs(10000, si_read_ht).start(); diff --git a/samples/Light_BH1750/app/application.cpp b/samples/Light_BH1750/app/application.cpp index aa1f70ec1e..d55733ceb3 100644 --- a/samples/Light_BH1750/app/application.cpp +++ b/samples/Light_BH1750/app/application.cpp @@ -25,9 +25,9 @@ void init() Serial.systemDebugOutput(false); // Disable debug output to serial if(LightSensor.begin() == 0) - Serial.println("LightSensor initialized"); + Serial.println(_F("LightSensor initialized")); else - Serial.println("LightSensor not available. May be wrong I2C address?"); + Serial.println(_F("LightSensor not available. May be wrong I2C address?")); /* Set the Working Mode for this sensor diff --git a/samples/LiquidCrystal_44780/app/application.cpp b/samples/LiquidCrystal_44780/app/application.cpp index 024aa4bc4d..7bf4477424 100644 --- a/samples/LiquidCrystal_44780/app/application.cpp +++ b/samples/LiquidCrystal_44780/app/application.cpp @@ -16,7 +16,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Allow debug output to serial - Serial.println("Initializing lcd via I2C (IIC/TWI) interface"); + Serial.println(_F("Initializing lcd via I2C (IIC/TWI) interface")); lcd.begin(16, 2); // initialize the lcd for 16 chars 2 lines, turn on backlight @@ -32,7 +32,7 @@ void init() //-------- Write characters on the display ------------------ // NOTE: Cursor Position: (CHAR, LINE) start at 0 lcd.setCursor(0, 0); - lcd.print("SMING: Let's do"); + lcd.print(_F("SMING: Let's do")); lcd.setCursor(0, 1); - lcd.print("smart things!"); + lcd.print(_F("smart things!")); } diff --git a/samples/LiveDebug/app/application.cpp b/samples/LiveDebug/app/application.cpp index 32fec77f84..6b7a5bd780 100644 --- a/samples/LiveDebug/app/application.cpp +++ b/samples/LiveDebug/app/application.cpp @@ -159,7 +159,7 @@ void onDataReceived(Stream& source, char arrivedChar, unsigned short availableCh void readFile(const char* filename, bool display) { int file = gdbfs.open(filename, File::ReadOnly); - Serial.printf(_F("gdbfs.open(\"%s\") = %d\r\n"), filename, file); + Serial << _F("gdbfs.open(\"") << filename << "\") = " << file << endl; if(file >= 0) { OneShotFastMs timer; char buf[256]; @@ -175,8 +175,9 @@ void readFile(const char* filename, bool display) } } while(len == sizeof(buf)); auto elapsed = timer.elapsedTime(); - Serial.printf(_F("\r\ngdbfs.read() = %d, total = %u, elapsed = %s, av. %u bytes/sec\r\n"), len, total, - elapsed.toString().c_str(), total == 0 ? 0 : 1000U * total / elapsed); + Serial.println(); + Serial << _F("gdbfs.read() = ") << len << _F(", total = ") << total << _F(", elapsed = ") << elapsed.toString() + << _F(", av. ") << (total == 0 ? 0 : 1000U * total / elapsed) << _F(" bytes/sec") << endl; gdbfs.close(file); } @@ -202,7 +203,7 @@ void asyncReadCallback(const GdbSyscallInfo& info) case eGDBSYS_open: { int fd = info.result; String filename(FPSTR(info.open.filename)); - Serial.printf(_F("gdb_syscall_open(\"%s\") = %d\r\n"), filename.c_str(), fd); + Serial << _F("gdb_syscall_open(\"") << filename << "\") = " << fd << endl; if(fd > 0) { transfer.start = millis(); transfer.total = 0; @@ -227,8 +228,8 @@ void asyncReadCallback(const GdbSyscallInfo& info) case eGDBSYS_close: { long elapsed = millis() - transfer.start; long bps = (transfer.total == 0) ? 0 : 1000U * transfer.total / elapsed; - Serial.printf(_F("readFileAsync: total = %u, elapsed = %u ms, av. %u bytes/sec\r\n"), transfer.total, elapsed, - bps); + Serial << _F("readFileAsync: total = ") << transfer.total << _F(", elapsed = ") << elapsed << _F(" ms, av. ") + << bps << _F(" bytes/sec") << endl; readConsole(); } @@ -250,16 +251,14 @@ void fileStat(const char* filename) { gdb_stat_t stat; int res = gdb_syscall_stat(filename, &stat); - Serial.printf(_F("gdb_syscall_stat(\"%s\") returned %d\r\n"), filename, res); + Serial << _F("gdb_syscall_stat(\"") << filename << _F("\") returned ") << res << endl; if(res != 0) { return; } -#define PRT(x) Serial.printf(_F(" " #x " = %u\r\n"), stat.x) -#define PRT_HEX(x) Serial.printf(_F(" " #x " = 0x%08x\r\n"), stat.x) -#define PRT_TIME(x) \ - Serial.print(_F(" " #x " = ")); \ - Serial.println(DateTime(stat.x).toFullDateTimeString()); +#define PRT(x) Serial << _F(" " #x " = ") << stat.x << endl +#define PRT_HEX(x) Serial << _F(" " #x " = 0x") << String(stat.x, HEX) << endl +#define PRT_TIME(x) Serial << _F(" " #x " = ") << DateTime(stat.x).toFullDateTimeString() << endl PRT(st_dev); PRT(st_ino); @@ -350,10 +349,10 @@ COMMAND_HANDLER(time) gdb_timeval_t tv; int res = gdb_syscall_gettimeofday(&tv, nullptr); if(res < 0) { - Serial.printf(_F("gdb_syscall_gettimeofday() returned %d\r\n"), res); + Serial << _F("gdb_syscall_gettimeofday() returned ") << res << endl; } else { - Serial.printf(_F("tv_sec = %u, tv_usec = %u, "), tv.tv_sec, uint32_t(tv.tv_usec)); - Serial.println(DateTime(tv.tv_sec).toFullDateTimeString() + _F(" UTC")); + Serial << _F("tv_sec = ") << tv.tv_sec << _F(", tv_usec = ") << tv.tv_usec << ", " + << DateTime(tv.tv_sec).toFullDateTimeString() << _F(" UTC") << endl; } return true; } @@ -361,7 +360,7 @@ COMMAND_HANDLER(time) COMMAND_HANDLER(log) { if(logFile.isValid()) { - Serial.printf(_F("Log file is open, size = %u bytes\r\n"), logFile.getPos()); + Serial << _F("Log file is open, size = ") << logFile.getPos() << _F(" bytes") << endl; } else { Serial.println(_F("Log file not available")); } @@ -371,7 +370,7 @@ COMMAND_HANDLER(log) COMMAND_HANDLER(ls) { int res = gdb_syscall_system(PSTR("ls -la")); - Serial.printf(_F("gdb_syscall_system() returned %d\r\n"), res); + Serial << _F("gdb_syscall_system() returned ") << res << endl; return true; } @@ -415,7 +414,7 @@ COMMAND_HANDLER(read0) "then enter `c` to continue")); Serial.flush(); uint8_t value = *(uint8_t*)0; - Serial.printf("Value at address 0 = 0x%02x\r\n", value); + Serial << _F("Value at address 0 = 0x") << String(value, HEX, 2) << endl; return true; } @@ -426,7 +425,7 @@ COMMAND_HANDLER(write0) "then enter `c` to continue")); Serial.flush(); *(uint8_t*)0 = 0; - Serial.println("...still running!"); + Serial.println(_F("...still running!")); return true; } @@ -521,18 +520,11 @@ COMMAND_HANDLER(help) auto print = [](const char* tag, const char* desc) { const unsigned indent = 10; - Serial.print(" "); - String s(tag); - s.reserve(indent); - while(s.length() < indent) { - s += ' '; - } - Serial.print(s); - Serial.print(" : "); + Serial << " " << String(tag).pad(indent) << " : "; // Print multi-line descriptions in sections to maintain correct line indentation - s.setLength(2 + indent + 3); - memset(s.begin(), ' ', s.length()); + String s; + s.pad(2 + indent + 3); for(;;) { auto end = strchr(desc, '\n'); @@ -561,9 +553,7 @@ COMMAND_HANDLER(help) bool handleCommand(const String& cmd) { if(logFile.isValid()) { - logFile.print(_F("handleCommand('")); - logFile.print(cmd); - logFile.println(_F("')")); + logFile << _F("handleCommand('") << cmd << "')" << endl; } #define XX(tag, desc) \ @@ -573,7 +563,7 @@ bool handleCommand(const String& cmd) COMMAND_MAP(XX) #undef XX - Serial.printf(_F("Unknown command '%s', try 'help'\r\n"), cmd.c_str()); + Serial << _F("Unknown command '") << cmd << _F("', try 'help'") << endl; return true; } @@ -674,12 +664,8 @@ extern "C" void gdb_on_attach(bool attached) static void printTimerDetails() { - Serial.print(procTimer); - Serial.print(", maxTicks = "); - Serial.print(procTimer.maxTicks()); - Serial.print(", maxTime = "); - Serial.print(procTimer.micros().ticksToTime(procTimer.maxTicks()).value()); - Serial.println(); + Serial << procTimer << ", maxTicks = " << procTimer.maxTicks() + << ", maxTime = " << procTimer.micros().ticksToTime(procTimer.maxTicks()).value() << endl; } void GDB_IRAM_ATTR init() diff --git a/samples/MeteoControl_mqtt/app/application.cpp b/samples/MeteoControl_mqtt/app/application.cpp index 74622ca477..9fb95ca902 100644 --- a/samples/MeteoControl_mqtt/app/application.cpp +++ b/samples/MeteoControl_mqtt/app/application.cpp @@ -14,17 +14,15 @@ void publishMessage() // uncomment timer in connectOk() if need publishMessage() if(mqtt.getConnectionState() != eTCS_Connected) startMqttClient(); // Auto reconnect - Serial.println("publish message"); + Serial.println(_F("publish message")); mqtt.publish(VER_TOPIC, "ver.1.2"); // or publishWithQoS } // Callback for messages, arrived from MQTT server int onMessageReceived(MqttClient& client, mqtt_message_t* message) { - Serial.print("Received: "); - Serial.print(MqttBuffer(message->publish.topic_name)); - Serial.print(":\r\n\t"); // Pretify alignment for printing - Serial.println(MqttBuffer(message->publish.content)); + Serial << _F("Received: ") << MqttBuffer(message->publish.topic_name) << ':' << endl; + Serial << '\t' << MqttBuffer(message->publish.content) << endl; return 0; } @@ -33,14 +31,13 @@ void startMqttClient() { Url url(URI_SCHEME_MQTT, F(LOG), F(PASS), F(MQTT_SERVER), MQTT_PORT); mqtt.connect(url, CLIENT); - Serial.println("Connected to MQTT server"); + Serial.println(_F("Connected to MQTT server")); mqtt.subscribe(SUB_TOPIC); } void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - Serial.print("Connected: "); - Serial.println(ip); + Serial << _F("Connected: ") << ip << endl; startMqttClient(); publishMessage(); // run once publishMessage } diff --git a/samples/MeteoControl_mqtt/app/bmp180.cpp b/samples/MeteoControl_mqtt/app/bmp180.cpp index 816c7e8390..de51ac26c7 100644 --- a/samples/MeteoControl_mqtt/app/bmp180.cpp +++ b/samples/MeteoControl_mqtt/app/bmp180.cpp @@ -18,10 +18,10 @@ void publishBMP() if(mqtt.getConnectionState() != eTCS_Connected) startMqttClient(); // Auto reconnect - Serial.print("*********************************************"); - Serial.println("Start reading BMP180 sensor"); + Serial.print(_F("*********************************************")); + Serial.println(_F("Start reading BMP180 sensor")); if(!barometer.EnsureConnected()) { - Serial.println("Could not connect to BMP180"); + Serial.println(_F("Could not connect to BMP180")); } else { // Retrieve the current pressure in Pascals long currentPressure = barometer.GetPressure(); @@ -29,21 +29,17 @@ void publishBMP() float BMPPress = currentPressure / 133.322; // Print out the Pressure - Serial.print("Pressure: "); - Serial.print(BMPPress); - Serial.println(" mmHg"); + Serial << _F("Pressure: ") << BMPPress << _F(" mmHg") << endl; mqtt.publish(BMP_P, String(BMPPress)); // Retrieve the current temperature in degrees celsius float BMPTemp = barometer.GetTemperature(); // Print out the Temperature - Serial.print("Temperature: "); - Serial.print(BMPTemp); - Serial.println(" *C"); + Serial << _F("Temperature: ") << BMPTemp << " °C" << endl; mqtt.publish(BMP_T, String(BMPTemp)); - Serial.println("BMP180 sensor read and transmitted to server"); - Serial.println("*********************************************"); + Serial.println(_F("BMP180 sensor read and transmitted to server\r\n" + "********************************************")); } } diff --git a/samples/MeteoControl_mqtt/app/si7021.cpp b/samples/MeteoControl_mqtt/app/si7021.cpp index 73d7d002b5..8fb2c61fe6 100644 --- a/samples/MeteoControl_mqtt/app/si7021.cpp +++ b/samples/MeteoControl_mqtt/app/si7021.cpp @@ -12,33 +12,30 @@ Timer publishSITimer; void publishSI() { - if(mqtt.getConnectionState() != eTCS_Connected) + if(mqtt.getConnectionState() != eTCS_Connected) { startMqttClient(); // Auto reconnect + } - Serial.print("*********************************************"); - Serial.println("Start reading SI7021 sensor"); + Serial.println(_F("*********************************************\r\n" + "Start reading SI7021 sensor")); if(!hydrometer.begin()) { - Serial.println("Could not connect to SI7021"); + Serial.println(_F("Could not connect to SI7021")); } else { si7021_env data = hydrometer.getHumidityAndTemperature(); if(data.error_crc == 1) { - Serial.println("\tCRC ERROR"); + Serial.println(_F("\tCRC ERROR")); } else { float SIhum = data.humidityPercent; // Print out the humidity - Serial.print("Humidity: "); - Serial.print(SIhum); - Serial.println("%"); + Serial << _F("Humidity: ") << SIhum << '%' << endl; mqtt.publish(SI_H, String(SIhum)); float SITemp = data.temperature; // Print out the Temperature - Serial.print("Temperature: "); - Serial.print(SITemp / 100); - Serial.println(" *C"); + Serial << _F("Temperature: ") << SITemp / 100 << " °C" << endl; mqtt.publish(SI_T, String(SITemp / 100)); - Serial.println("SI sensor read and transmitted to server"); - Serial.println("*********************************************"); + Serial.println(_F("SI sensor read and transmitted to server\r\n" + "*********************************************")); } } } diff --git a/samples/MqttClient_Hello/app/application.cpp b/samples/MqttClient_Hello/app/application.cpp index 733eb4cd30..d2f8772610 100644 --- a/samples/MqttClient_Hello/app/application.cpp +++ b/samples/MqttClient_Hello/app/application.cpp @@ -42,8 +42,8 @@ void checkMQTTDisconnect(TcpClient& client, bool flag) int onMessageDelivered(MqttClient& client, mqtt_message_t* message) { - Serial.printf(_F("Message with id %d and QoS %d was delivered successfully.\n"), message->puback.message_id, - message->puback.qos); + Serial << _F("Message with id ") << message->puback.message_id << _F(" and QoS ") << message->puback.qos + << _F(" was delivered successfully.") << endl; return 0; } @@ -54,8 +54,7 @@ void publishMessage() startMqttClient(); // Auto reconnect } - Serial.print(_F("Let's publish message now. Memory free=")); - Serial.println(system_get_free_heap_size()); + Serial << _F("Let's publish message now. Memory free=") << system_get_free_heap_size() << endl; mqtt.publish(F("main/frameworks/sming"), F("Hello friends, from Internet of things :)")); mqtt.publish(F("important/frameworks/sming"), F("Request Return Delivery"), @@ -65,10 +64,8 @@ void publishMessage() // Callback for messages, arrived from MQTT server int onMessageReceived(MqttClient& client, mqtt_message_t* message) { - Serial.print("Received: "); - Serial.print(MqttBuffer(message->publish.topic_name)); - Serial.print(":\r\n\t"); // Pretify alignment for printing - Serial.println(MqttBuffer(message->publish.content)); + Serial << _F("Received: ") << MqttBuffer(message->publish.topic_name) << ':' << endl; + Serial << '\t' << MqttBuffer(message->publish.content) << endl; return 0; } @@ -86,8 +83,7 @@ void startMqttClient() mqtt.setEventHandler(MQTT_TYPE_PUBACK, onMessageDelivered); mqtt.setConnectedHandler([](MqttClient& client, mqtt_message_t* message) { - Serial.print(_F("Connected to ")); - Serial.println(client.getRemoteIp()); + Serial << _F("Connected to ") << client.getRemoteIp() << endl; // Start publishing message now publishMessage(); @@ -109,8 +105,7 @@ void startMqttClient() // 2. [Connect] Url url(MQTT_URL); - Serial.print(_F("Connecting to ")); - Serial.println(url); + Serial << _F("Connecting to ") << url << endl; mqtt.connect(url, F("esp8266")); mqtt.subscribe(F("main/status/#")); } diff --git a/samples/Network_Ping/app/application.cpp b/samples/Network_Ping/app/application.cpp index 1d86662d11..1c7521fb95 100644 --- a/samples/Network_Ping/app/application.cpp +++ b/samples/Network_Ping/app/application.cpp @@ -36,7 +36,7 @@ void onSent(void* arg, void* pdata) return; } - Serial.printf("Ping sent. Total failed attempts: %d.\n", failedAttempts); + Serial << _F("Ping sent. Total failed attempts: ") << failedAttempts << endl; if(failedAttempts / response->total_count > MAX_FAILED_ATTEMTPS) { debug_d("Scheduling system restart in %d seconds.", RESTART_DELAY_SECONDS); // schedule restart @@ -56,9 +56,8 @@ void onReceived(void* arg, void* pdata) return; } - Serial.printf("Ping received. Sequence: %d, Success: %d, Elapsed time: %d", response->seqno, - response->ping_err == 0, response->total_time); - Serial.println(); + Serial << _F("Ping received. Sequence: ") << response->seqno << _F(", Success: ") << (response->ping_err == 0) + << _F(", Elapsed time: ") << response->total_time << endl; if(response->ping_err) { failedAttempts++; diff --git a/samples/PortExpander_MCP23S17/app/application.cpp b/samples/PortExpander_MCP23S17/app/application.cpp index d607c9cd8e..4095b02ea8 100644 --- a/samples/PortExpander_MCP23S17/app/application.cpp +++ b/samples/PortExpander_MCP23S17/app/application.cpp @@ -16,7 +16,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(false); // Allow debug output to serial - Serial.println("<-= Sming start =->"); + Serial.println(_F("<-= Sming start =->")); // Set higher CPU freq & disable wifi sleep System.setCpuFrequency(CpuCycleClockFast::cpuFrequency()); diff --git a/samples/Pressure_BMP180/app/application.cpp b/samples/Pressure_BMP180/app/application.cpp index c9eeccd1ef..db9d44a384 100644 --- a/samples/Pressure_BMP180/app/application.cpp +++ b/samples/Pressure_BMP180/app/application.cpp @@ -10,7 +10,7 @@ void init() Wire.begin(); if(!barometer.EnsureConnected()) - Serial.println("Could not connect to BMP180."); + Serial.println(_F("Could not connect to BMP180.")); // When we have connected, we reset the device to ensure a clean start. //barometer.SoftReset(); @@ -18,24 +18,8 @@ void init() barometer.Initialize(); barometer.PrintCalibrationData(); - Serial.print("Start reading"); + Serial.print(_F("Start reading")); - // Retrieve the current pressure in Pascals. - long currentPressure = barometer.GetPressure(); - - // Print out the Pressure. - Serial.print("Pressure: "); - Serial.print(currentPressure); - Serial.print(" Pa"); - - // Retrieve the current temperature in degrees celsius. - float currentTemperature = barometer.GetTemperature(); - - // Print out the Temperature - Serial.print("\tTemperature: "); - Serial.print(currentTemperature); - Serial.write(176); - Serial.print("C"); - - Serial.println(); // Start a new line. + Serial << _F("Pressure: ") << barometer.GetPressure() << " Pa" << _F("\tTemperature: ") + << barometer.GetTemperature() << " °C" << endl; } diff --git a/samples/Radio_RCSwitch/app/application.cpp b/samples/Radio_RCSwitch/app/application.cpp index 617b012972..7ce74fc87c 100644 --- a/samples/Radio_RCSwitch/app/application.cpp +++ b/samples/Radio_RCSwitch/app/application.cpp @@ -11,22 +11,17 @@ RCSwitch mySwitch = RCSwitch(); void sendRF() { mySwitch.send(5393, 24); - Serial.println("RF command successful sent"); + Serial.println(_F("RF command successful sent")); } void receiveRF() { if(mySwitch.available()) { if(mySwitch.getReceivedValue() == 0) { - Serial.print("Unknown encoding"); + Serial.print(_F("Unknown encoding")); } else { - Serial.print("Received "); - Serial.print(mySwitch.getReceivedValue()); - Serial.print(" / "); - Serial.print(mySwitch.getReceivedBitlength()); - Serial.print("bit "); - Serial.print("Protocol: "); - Serial.println(mySwitch.getReceivedProtocol()); + Serial << _F("Received ") << mySwitch.getReceivedValue() << " / " << mySwitch.getReceivedBitlength() + << " bit, Protocol: " << mySwitch.getReceivedProtocol() << endl; } mySwitch.resetAvailable(); diff --git a/samples/Radio_nRF24L01/app/application.cpp b/samples/Radio_nRF24L01/app/application.cpp index bfaa62ef8e..167154e8eb 100644 --- a/samples/Radio_nRF24L01/app/application.cpp +++ b/samples/Radio_nRF24L01/app/application.cpp @@ -41,7 +41,7 @@ void loopListen() done = radio.read(&got_time, sizeof(unsigned long)); // Spew it - Serial.printf("Got payload %lu...", got_time); + Serial << _F("Got payload ") << got_time << "..."; // Forward this data packet to UDP/HTTP/MQTT here. // Example: @@ -58,7 +58,7 @@ void loopListen() // Send the final one back. radio.write(&got_time, sizeof(unsigned long)); - Serial.println("Sent response."); + Serial.println(_F("Sent response.")); // Now, resume listening so we catch the next packets. radio.startListening(); @@ -70,7 +70,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Allow debug output to serial - Serial.println("start"); + Serial.println(_F("start")); // // Setup and configure rf radio @@ -105,8 +105,8 @@ void init() // Dump the configuration of the rf unit for debugging // radio.printDetails(); - Serial.println("Initialization completed."); + Serial.println(_F("Initialization completed.")); procTimer.initializeMs(10, loopListen).start(); - Serial.println("Listening..."); + Serial.println(_F("Listening...")); } diff --git a/samples/Radio_si4432/app/application.cpp b/samples/Radio_si4432/app/application.cpp index 792887b940..7a947f63eb 100644 --- a/samples/Radio_si4432/app/application.cpp +++ b/samples/Radio_si4432/app/application.cpp @@ -37,18 +37,13 @@ void loopListen() if(millis() - lastPingTime > PING_PERIOD_MS) { lastPingTime = millis(); - Serial.print("Ping -> "); + Serial.print(_F("Ping -> ")); if(!radio->sendPacket(strlen((const char*)ping), ping, true, PING_WAIT_PONG_MS, &len, payLoad)) { Serial.println(" ERR!"); } else { - Serial.println(" SENT!"); - Serial.print("SYNC RX ("); - Serial.print(len, DEC); - Serial.print("): "); - - for(byte i = 0; i < len; ++i) { - Serial.print((char)payLoad[i]); - } + Serial.println(_F(" SENT!")); + Serial << "SYNC RX (" << len << "): "; + Serial.write(payLoad, len); Serial.println(); } } @@ -58,20 +53,15 @@ void loopListen() if(pkg) { radio->getPacketReceived(&len, payLoad); - Serial.print("ASYNC RX ("); - Serial.print(len, DEC); - Serial.print("): "); - - for(byte i = 0; i < len; ++i) { - Serial.print((char)payLoad[i]); - } + Serial << _F("ASYNC RX (") << len << "): "; + Serial.write(payLoad, len); Serial.println(); - Serial.print("Response -> "); + Serial.print(_F("Response -> ")); if(!radio->sendPacket(strlen((const char*)ack), ack)) { - Serial.println("ERR!"); + Serial.println(_F("ERR!")); } else { - Serial.println("SENT!"); + Serial.println(_F("SENT!")); } radio->startListening(); // restart the listening. @@ -84,35 +74,37 @@ void init() Serial.systemDebugOutput(true); //Allow debug output to serial - Serial.print("\nRadio si4432 example - !!! see code for HW setup !!! \n\n"); + Serial.println(_F("\nRadio si4432 example - !!! see code for HW setup !!! \n")); pRadioSPI = new SPISoft(PIN_RADIO_DO, PIN_RADIO_DI, PIN_RADIO_CK, PIN_RADIO_SS); - if(pRadioSPI) { + if(pRadioSPI != nullptr) { radio = new Si4432(pRadioSPI); } - if(radio) { - delay(100); + if(radio == nullptr) { + Serial.println(_F("Error: Not enough heap.")); + return; + } - //initialise radio with default settings - radio->init(); + delay(100); - //explicitly set baudrate and channel - radio->setBaudRateFast(eBaud_38k4); - radio->setChannel(0); + //initialise radio with default settings + radio->init(); - //dump the register configuration to console - radio->readAll(); + //explicitly set baudrate and channel + radio->setBaudRateFast(eBaud_38k4); + radio->setChannel(0); - //start listening for incoming packets - Serial.println("Listening..."); - radio->startListening(); + //dump the register configuration to console + radio->readAll(); - lastPingTime = millis(); + //start listening for incoming packets + Serial.println("Listening..."); + radio->startListening(); + + lastPingTime = millis(); - //start listen loop - procTimer.initializeMs(10, loopListen).start(); - } else - Serial.print("Error not enough heap\n"); + //start listen loop + procTimer.initializeMs(10, loopListen).start(); } diff --git a/samples/SDCard/app/application.cpp b/samples/SDCard/app/application.cpp index 2cdebb9222..7a777efb60 100644 --- a/samples/SDCard/app/application.cpp +++ b/samples/SDCard/app/application.cpp @@ -30,11 +30,12 @@ void writeToFile(const String& filename, uint32_t totalBytes, uint32_t bytesPerR { char* buf = new char[totalBytes]; if(buf == nullptr) { - Serial.println("Failed to allocate heap"); + Serial.println(_F("Failed to allocate heap")); return; } - Serial.printf(_F("Write %u kBytes in %u Bytes increment:\r\n"), totalBytes / 1024, bytesPerRound); + Serial << _F("Write ") << totalBytes / 1024 << _F(" kBytes in ") << bytesPerRound << _F(" Bytes increment:") + << endl; for(unsigned i = 0; i < totalBytes; i++) { buf[i] = (i % 10) + '0'; } @@ -51,7 +52,7 @@ void writeToFile(const String& filename, uint32_t totalBytes, uint32_t bytesPerR uint32_t bytesWritten = 0; f_write(&file, buf + i, remainingBytes, &bytesWritten); if(bytesWritten != remainingBytes) { - Serial.printf(_F("Only written %u bytes\r\n"), i + bytesWritten); + Serial << _F("Only written ") << i + bytesWritten << " bytes" << endl; break; } i += bytesWritten; @@ -62,10 +63,9 @@ void writeToFile(const String& filename, uint32_t totalBytes, uint32_t bytesPerR //get the time at test end unsigned elapsed = timer.elapsedTime(); - Serial.print((i / 1024.0f) * 1000000.0f / elapsed); - Serial.println(_F(" kB/s")); + Serial << (i / 1024.0f) * 1000000.0f / elapsed << _F(" kB/s") << endl; } else { - Serial.printf(_F("fopen FAIL: %u\r\n"), (unsigned int)fRes); + Serial << _F("fopen FAIL: ") << fRes << endl; } delete[] buf; @@ -77,8 +77,7 @@ void stat_file(char* fname) FRESULT fr = f_stat(fname, &fno); switch(fr) { case FR_OK: { - Serial.print(fno.fsize); - Serial.print('\t'); + Serial << fno.fsize << '\t'; uint8_t size = 0; if(fno.fattrib & AM_DIR) { @@ -96,11 +95,11 @@ void stat_file(char* fname) Serial.print('\t'); } - Serial.printf(_F("%u/%02u/%02u, %02u:%02u\t"), (fno.fdate >> 9) + 1980, (fno.fdate >> 5) & 15, fno.fdate & 31, - fno.ftime >> 11, (fno.ftime >> 5) & 63); - Serial.printf(_F("%c%c%c%c%c\r\n"), (fno.fattrib & AM_DIR) ? 'D' : '-', (fno.fattrib & AM_RDO) ? 'R' : '-', - (fno.fattrib & AM_HID) ? 'H' : '-', (fno.fattrib & AM_SYS) ? 'S' : '-', - (fno.fattrib & AM_ARC) ? 'A' : '-'); + Serial << (fno.fdate >> 9) + 1980 << '/' << String((fno.fdate >> 5) & 15, DEC, 2) << '/' + << String(fno.fdate & 31, DEC, 2) << ", " << String(fno.ftime >> 11, DEC, 2) << ':' + << String((fno.ftime >> 5) & 63, DEC, 2) << '\t' << ((fno.fattrib & AM_DIR) ? 'D' : '-') + << ((fno.fattrib & AM_RDO) ? 'R' : '-') << ((fno.fattrib & AM_HID) ? 'H' : '-') + << ((fno.fattrib & AM_SYS) ? 'S' : '-') << ((fno.fattrib & AM_ARC) ? 'A' : '-') << endl; break; } diff --git a/samples/ScreenOLED_SSD1306/app/application.cpp b/samples/ScreenOLED_SSD1306/app/application.cpp index 0322e588b6..d0b8d3b5f6 100644 --- a/samples/ScreenOLED_SSD1306/app/application.cpp +++ b/samples/ScreenOLED_SSD1306/app/application.cpp @@ -29,19 +29,19 @@ Timer DemoTimer; void Demo2() { - Serial.println("Display: some text"); + Serial.println(_F("Display: some text")); display.clearDisplay(); // text display tests display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0, 0); - display.println("Sming Framework"); + display.println(_F("Sming Framework")); display.setTextColor(BLACK, WHITE); // 'inverted' text display.setCursor(104, 7); - display.println("v1.0"); + display.println(_F("v1.0")); //---- display.setTextColor(WHITE); - display.println("Let's do smart things"); + display.println(_F("Let's do smart things")); display.setTextSize(3); display.print("IoT"); display.display(); @@ -50,7 +50,7 @@ void Demo2() void Demo1() { - Serial.println("Display: circle"); + Serial.println(_F("Display: circle")); // Clear the buffer. display.clearDisplay(); // draw a circle, 10 pixel radius @@ -63,7 +63,7 @@ void Demo1() void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Serial.println("Display: start"); + Serial.println(_F("Display: start")); // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) // initialize with the I2C addr 0x3c (for the 128x64) diff --git a/samples/ScreenTFT_ILI9163C/app/application.cpp b/samples/ScreenTFT_ILI9163C/app/application.cpp index e10a14a083..8994109c9c 100644 --- a/samples/ScreenTFT_ILI9163C/app/application.cpp +++ b/samples/ScreenTFT_ILI9163C/app/application.cpp @@ -18,7 +18,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Allow debug output to serial - Serial.println("Display start"); + Serial.println(_F("Display start")); tft.begin(); tft.setRotation(2); // try yourself tft.fillScreen(); @@ -30,12 +30,12 @@ void init() tft.setTextSize(1); tft.setTextColor(GREEN); tft.setCursor(0, 0); - tft.println("Sming Framework"); + tft.println(_F("Sming Framework")); tft.setTextColor(BLACK, WHITE); // 'inverted' text tft.setCursor(104, 7); tft.println("v1.0"); tft.setTextColor(WHITE); - tft.println("Let's do smart things"); + tft.println(_F("Let's do smart things")); tft.setTextSize(3); tft.setTextColor(BLUE); tft.print("IoT"); diff --git a/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp b/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp index 699b51755e..2b0ec9b1d3 100644 --- a/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp +++ b/samples/ScreenTFT_ILI9340-ILI9341/app/application.cpp @@ -76,10 +76,10 @@ void init() #endif spiffs_mount(); - Serial.println("FileSystem mounted."); + Serial.println(_F("FileSystem mounted.")); // delay(2000); - Serial.println("Display start"); + Serial.println(_F("Display start")); // text display tests tft.begin(); @@ -90,15 +90,15 @@ void init() tft.setTextColor(ILI9341_GREEN); tft.setCursor(0, 0); tft.setCursor(60, 60); - tft.println("Sming Framework"); + tft.println(_F("Sming Framework")); tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); // text tft.setCursor(60, 75); tft.println(" v1.1"); tft.setTextColor(ILI9341_CYAN); tft.setCursor(60, 90); - tft.println("ili9340-40C-41 "); + tft.println(_F("ili9340-40C-41 ")); tft.setCursor(60, 125); - tft.println("M.Bozkurt"); + tft.println(_F("M.Bozkurt")); delay(2000); tft.fillScreen(0); guiTimer.initializeMs<1000>(basicGui).start(false); From 50d32f4aaa29a9cf3ad1a1f3b87761f2ce353e73 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 13 Sep 2022 10:37:35 +0100 Subject: [PATCH 25/58] Fix ESP32 system restart problems (#2543) * Add `CREATE_EVENT_TASK` build variable *for debugging ONLY* * Call `esp_restart` in context of the IPC thread to avoid deadlock when `esp_wifi_stop()` gets called. --- Sming/Arch/Esp32/Components/esp32/README.rst | 15 +++++++++++++++ Sming/Arch/Esp32/Components/esp32/component.mk | 7 ++++++- .../Esp32/Components/esp32/src/event_loop.cpp | 7 ++++++- Sming/Arch/Esp32/Components/esp32/src/startup.cpp | 4 ++++ Sming/Arch/Esp32/Components/esp32/src/system.cpp | 11 ++++++++++- 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Sming/Arch/Esp32/Components/esp32/README.rst b/Sming/Arch/Esp32/Components/esp32/README.rst index d1419ec950..a545642fff 100644 --- a/Sming/Arch/Esp32/Components/esp32/README.rst +++ b/Sming/Arch/Esp32/Components/esp32/README.rst @@ -45,6 +45,21 @@ or if multiple versions are installed. By default, the most current version will Location of ESP-IDF python. +.. envvar:: CREATE_EVENT_TASK + + default: disabled + + .. warning:: + + This setting is provided for debugging purposes ONLY. + + Sming uses a custom event loop to ensure that timer and task callbacks are all executed in the same + thread context. + + Sometimes this behaviour can cause issues with IDF code. + Setting this to 1 will create the event loop in a separate thread, which is standard IDF behaviour. + + Background ---------- diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index e568d0efa6..119f993c10 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -8,7 +8,11 @@ COMPONENT_INCDIRS := src/include include # Applications can provide file with custom SDK configuration settings CACHE_VARS += SDK_CUSTOM_CONFIG -COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI +COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI CREATE_EVENT_TASK + +ifeq ($(CREATE_EVENT_TASK),1) +COMPONENT_CPPFLAGS += -DCREATE_EVENT_TASK +endif SDK_BUILD_BASE := $(COMPONENT_BUILD_BASE)/sdk SDK_COMPONENT_LIBDIR := $(COMPONENT_BUILD_BASE)/lib @@ -50,6 +54,7 @@ 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 \ diff --git a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp b/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp index 0972f7c008..583d611290 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp @@ -12,6 +12,7 @@ */ #include +#include namespace { @@ -22,7 +23,11 @@ esp_event_loop_handle_t sming_create_event_loop() { esp_event_loop_args_t loop_args = { .queue_size = CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE, - .task_name = nullptr, +#ifdef CREATE_EVENT_TASK + .task_name = "sys_evt", + .task_priority = ESP_TASKD_EVENT_PRIO, + .task_stack_size = ESP_TASKD_EVENT_STACK, +#endif }; ESP_ERROR_CHECK(esp_event_loop_create(&loop_args, &sming_event_loop)); diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index 48a89348c3..ed8f54c9f4 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -53,7 +53,11 @@ void main(void*) constexpr unsigned maxEventLoopInterval{1000 / portTICK_PERIOD_MS}; while(true) { esp_task_wdt_reset(); +#ifdef CREATE_EVENT_TASK + vTaskDelay(100); +#else esp_event_loop_run(loop, maxEventLoopInterval); +#endif } } diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index 65063ad2fd..e9a573e1c2 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -2,6 +2,7 @@ #include #include #include +#include extern "C" int64_t esp_system_get_time(); @@ -45,7 +46,15 @@ struct rst_info* system_get_rst_info(void) void system_restart(void) { - esp_restart(); + /* + * Internally, `esp_restart` calls `esp_wifi_stop`. + * This must not be called in the context of the task which handles the main event queue. + * i.e. The Sming main thread. + * Doing so causes a deadlock and a task watchdog timeout. + * + * Delegating this call to any other task fixes the issue. + */ + esp_ipc_call(0, esp_ipc_func_t(esp_restart), nullptr); } /* Watchdog */ From 5227df3c3562793c7e78719fa3159869c981f54b Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 15 Sep 2022 12:14:34 +0100 Subject: [PATCH 26/58] Apply printing improvements to remaining samples (#2553) * Revise printing for remaining samples * Avoid making `MacAddress` a virtual class * Use `MacAddress` in Wifi Sniffer * Validate SSID string in Wifi_Sniffer sample * Use class template for beacon/client info list * Change `makeHexString` argument from `uint8_t*` to `void*` Easier to use * Update `Basic_Storage` sample printing --- .../Arch/Esp8266/Platform/WifiSniffer.cpp | 10 +-- .../Network/src/Platform/WifiSniffer.h | 40 +++++------- Sming/Core/Data/HexString.cpp | 13 ++-- Sming/Core/Data/HexString.h | 2 +- Sming/Wiring/MacAddress.h | 12 ++-- samples/Arducam/app/ArduCamCommand.cpp | 15 ++--- samples/Arducam/app/application.cpp | 15 ++--- samples/Basic_Storage/app/application.cpp | 16 ++--- samples/SystemClock_NTP/app/NtpClientDemo.cpp | 17 ++---- samples/SystemClock_NTP/app/application.cpp | 12 ++-- .../TcpClient_NarodMon/app/application.cpp | 2 +- samples/Telnet_Server/app/application.cpp | 23 +++---- .../Temperature_DS1820/app/application.cpp | 52 ++++++++-------- samples/UdpServer_Echo/app/application.cpp | 12 ++-- samples/UdpServer_mDNS/app/application.cpp | 19 +++--- samples/WebcamServer/app/application.cpp | 17 +++--- samples/Websocket_Client/app/application.cpp | 36 ++++------- samples/Wifi_Sniffer/app/application.cpp | 61 ++++++++++++------- 18 files changed, 177 insertions(+), 197 deletions(-) diff --git a/Sming/Components/Network/Arch/Esp8266/Platform/WifiSniffer.cpp b/Sming/Components/Network/Arch/Esp8266/Platform/WifiSniffer.cpp index 27b6194d26..d78bb27ece 100644 --- a/Sming/Components/Network/Arch/Esp8266/Platform/WifiSniffer.cpp +++ b/Sming/Components/Network/Arch/Esp8266/Platform/WifiSniffer.cpp @@ -68,9 +68,9 @@ static void parseClientInfo(ClientInfo& ci, uint8_t* frame, uint16_t framelen, i break; } - memcpy(ci.station, station, ETH_MAC_LEN); - memcpy(ci.bssid, bssid, ETH_MAC_LEN); - memcpy(ci.ap, ap, ETH_MAC_LEN); + memcpy(&ci.station[0], station, ETH_MAC_LEN); + memcpy(&ci.bssid[0], bssid, ETH_MAC_LEN); + memcpy(&ci.ap[0], ap, ETH_MAC_LEN); ci.seq_n = (frame[23] * 0xFF) + (frame[22] & 0xF0); } @@ -121,7 +121,7 @@ static void parseBeaconInfo(BeaconInfo& bi, uint8_t* frame, uint16_t framelen, i bi.capa[0] = frame[34]; bi.capa[1] = frame[35]; - memcpy(bi.bssid, frame + 10, ETH_MAC_LEN); + memcpy(&bi.bssid[0], frame + 10, ETH_MAC_LEN); } void WifiSniffer::parseData(uint8_t* buf, uint16_t len) @@ -147,7 +147,7 @@ void WifiSniffer::parseData(uint8_t* buf, uint16_t len) ClientInfo ci; parseClientInfo(ci, data->buf, 36, data->rx_ctrl.rssi, data->rx_ctrl.channel); // Check BSSID and station don't match (why ?) - if(memcmp(ci.bssid, ci.station, ETH_MAC_LEN) != 0) { + if(ci.bssid != ci.station) { clientCallback(ci); } } diff --git a/Sming/Components/Network/src/Platform/WifiSniffer.h b/Sming/Components/Network/src/Platform/WifiSniffer.h index 5d89ea8e6a..6d911ea554 100644 --- a/Sming/Components/Network/src/Platform/WifiSniffer.h +++ b/Sming/Components/Network/src/Platform/WifiSniffer.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include "WVector.h" /** @defgroup wifi_sniffer WiFi Sniffer @@ -31,7 +32,7 @@ * @brief Decoded Wifi beacon (Access Point) information */ struct BeaconInfo { - uint8_t bssid[ETH_MAC_LEN]; + MacAddress bssid; uint8_t ssid[33]; uint8_t ssid_len; uint8_t channel; @@ -44,25 +45,22 @@ struct BeaconInfo { * @brief Decoded Wifi client information */ struct ClientInfo { - uint8_t bssid[ETH_MAC_LEN]; - uint8_t station[ETH_MAC_LEN]; - uint8_t ap[ETH_MAC_LEN]; + MacAddress bssid; + MacAddress station; + MacAddress ap; uint8_t channel; int8_t err; int8_t rssi; uint16_t seq_n; }; -/** - * @brief For applications to use to manage list of unique beacons - */ -class BeaconInfoList : public Vector +template class BeaconOrClientListTemplate : public Vector { public: - int indexOf(const uint8_t bssid[]) + int indexOf(const MacAddress& bssid) { - for(unsigned i = 0; i < count(); ++i) { - if(memcmp(elementAt(i).bssid, bssid, ETH_MAC_LEN) == 0) { + for(unsigned i = 0; i < this->count(); ++i) { + if(this->elementAt(i).bssid == bssid) { return i; } } @@ -72,22 +70,14 @@ class BeaconInfoList : public Vector }; /** - * @brief For applications to use to manage list of unique clients + * @brief For applications to use to manage list of unique beacons */ -class ClientInfoList : public Vector -{ -public: - int indexOf(const uint8_t station[]) - { - for(unsigned i = 0; i < count(); ++i) { - if(memcmp(elementAt(i).station, station, ETH_MAC_LEN) == 0) { - return i; - } - } +using BeaconInfoList = BeaconOrClientListTemplate; - return -1; - } -}; +/** + * @brief For applications to use to manage list of unique clients + */ +using ClientInfoList = BeaconOrClientListTemplate; using WifiSnifferCallback = Delegate; using WifiBeaconCallback = Delegate; diff --git a/Sming/Core/Data/HexString.cpp b/Sming/Core/Data/HexString.cpp index c09474bc86..fededbef54 100644 --- a/Sming/Core/Data/HexString.cpp +++ b/Sming/Core/Data/HexString.cpp @@ -11,7 +11,7 @@ #include "HexString.h" #include -String makeHexString(const uint8_t* data, unsigned length, char separator) +String makeHexString(const void* data, unsigned length, char separator) { if(data == nullptr || length == 0) { return nullptr; @@ -27,13 +27,14 @@ String makeHexString(const uint8_t* data, unsigned length, char separator) return nullptr; } - char* p = result.begin(); - for(unsigned i = 0; i < length; ++i) { + auto inptr = static_cast(data); + char* outptr = result.begin(); + for(unsigned i = 0; i < length; ++i, ++inptr) { if(i != 0 && separator != '\0') { - *p++ = separator; + *outptr++ = separator; } - *p++ = hexchar(data[i] >> 4); - *p++ = hexchar(data[i] & 0x0F); + *outptr++ = hexchar(*inptr >> 4); + *outptr++ = hexchar(*inptr & 0x0F); } return result; diff --git a/Sming/Core/Data/HexString.h b/Sming/Core/Data/HexString.h index 3b813e6190..bd8b864620 100644 --- a/Sming/Core/Data/HexString.h +++ b/Sming/Core/Data/HexString.h @@ -20,4 +20,4 @@ * @param separator optional character to put between hex-encoded bytes * @retval String */ -String makeHexString(const uint8_t* data, unsigned length, char separator = '\0'); +String makeHexString(const void* data, unsigned length, char separator = '\0'); diff --git a/Sming/Wiring/MacAddress.h b/Sming/Wiring/MacAddress.h index c8405348c8..7af333b3a8 100644 --- a/Sming/Wiring/MacAddress.h +++ b/Sming/Wiring/MacAddress.h @@ -35,7 +35,7 @@ * @author mikee47 * Sming integration */ -class MacAddress : public Printable +class MacAddress { // https://www.artima.com/cppsource/safebool.html using bool_type = void (MacAddress::*)() const; @@ -103,6 +103,11 @@ class MacAddress : public Printable */ String toString(char sep = ':') const; + operator String() const + { + return toString(); + } + /** * @brief Equality operator. */ @@ -147,11 +152,6 @@ class MacAddress : public Printable */ uint32_t getHash() const; - size_t printTo(Print& p) const override - { - return p.print(toString()); - } - private: Octets octets = {0}; }; diff --git a/samples/Arducam/app/ArduCamCommand.cpp b/samples/Arducam/app/ArduCamCommand.cpp index 8779c5923d..961fb0a2e7 100644 --- a/samples/Arducam/app/ArduCamCommand.cpp +++ b/samples/Arducam/app/ArduCamCommand.cpp @@ -43,8 +43,8 @@ void ArduCamCommand::processSetCommands(String commandLine, CommandOutput* comma } // handle command -> set else if(commandToken[1] == "help") { - commandOutput->printf("set img [bmp|jpeg]\r\n"); - commandOutput->printf("set size [160|176|320|352|640|800|1024|1280|1600]\r\n"); + *commandOutput << _F("set img [bmp|jpeg]") << endl; + *commandOutput << _F("set size [160|176|320|352|640|800|1024|1280|1600]") << endl; } // handle command -> set @@ -56,10 +56,11 @@ void ArduCamCommand::processSetCommands(String commandLine, CommandOutput* comma set_format(BMP); } else if(commandToken[2] == "jpg") { set_format(JPEG); - } else - commandOutput->printf("invalid image format [%s]\r\n", commandToken[2].c_str()); + } else { + *commandOutput << _F("invalid image format [") << commandToken[2] << ']' << endl; + } } else { - commandOutput->printf("Syntax: set img [bmp|jpeg]\r\n"); + *commandOutput << _F("Syntax: set img [bmp|jpeg]") << endl; } showSettings(commandOutput); } @@ -103,10 +104,10 @@ void ArduCamCommand::processSetCommands(String commandLine, CommandOutput* comma myCAM->OV2640_set_JPEG_size(OV2640_1600x1200); set_format(JPEG); } else { - commandOutput->printf("invalid size definition[%s]\r\n", commandToken[2].c_str()); + *commandOutput << _F("invalid size definition[") << commandToken[2] << ']' << endl; } } else { - commandOutput->printf("Syntax: set size [160|176|320|352|640|800|1024|1280|1600]\r\n"); + *commandOutput << _F("Syntax: set size [160|176|320|352|640|800|1024|1280|1600]") << endl; } showSettings(commandOutput); } diff --git a/samples/Arducam/app/application.cpp b/samples/Arducam/app/application.cpp index af181f8989..228601605b 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -77,10 +77,10 @@ void initCam() myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid); myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid); if((vid != 0x26) || (pid != 0x42)) { - Serial.println("Can't find OV2640 module!"); + Serial.println(_F("Can't find OV2640 module!")); Serial << "vid = [" << String(vid, HEX) << "], pid = [" << String(pid, HEX) << "]" << endl; } else { - Serial.println("OV2640 detected"); + Serial.println(_F("OV2640 detected")); } // initialize SPI: @@ -94,15 +94,16 @@ void initCam() uint8_t temp = myCAM.read_reg(ARDUCHIP_TEST1); if(temp != 0x55) { - Serial.println("SPI interface Error!"); - while(1) - ; + Serial.println(_F("SPI interface Error!")); + while(1) { + // loop forever + } } else { - Serial.println("SPI interface OK!"); + Serial.println(_F("SPI interface OK!")); } // init CAM - Serial.println("Initialize the OV2640 module"); + Serial.println(_F("Initialize the OV2640 module")); myCAM.set_format(JPEG); myCAM.InitCAM(); } diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index 0c3a2dcf14..98bdec0269 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -9,9 +9,7 @@ void listSpiffsPartitions() { Serial.println(_F("** Enumerate registered SPIFFS partitions")); for(auto part : Storage::findPartition(Storage::Partition::SubType::Data::spiffs)) { - Serial.print(F(">> Mounting '")); - Serial.print(part.name()); - Serial.println("' ..."); + Serial << _F(">> Mounting '") << part.name() << "' ..." << endl; bool ok = spiffs_mount(part); Serial.println(ok ? "OK, listing files:" : "Mount failed!"); if(ok) { @@ -22,9 +20,7 @@ void listSpiffsPartitions() Serial.println(dir.stat().name); } } - Serial.print(dir.count()); - Serial.println(F(" files found")); - Serial.println(); + Serial << dir.count() << _F(" files found") << endl << endl; } } } @@ -35,16 +31,16 @@ void printPart(Storage::Partition part) char buf[bufSize]; OneShotFastUs timer; if(!part.read(0, buf, bufSize)) { - debug_e("Error reading from partition '%s'", part.name().c_str()); + Serial << _F("Error reading from partition '") << part.name() << "'" << endl; } else { auto elapsed = timer.elapsedTime(); String s = part.getDeviceName(); s += '/'; s += part.name(); m_printHex(s.c_str(), buf, std::min(128U, bufSize)); - m_printf(_F("Elapsed: %s\r\n"), elapsed.toString().c_str()); + Serial << _F("Elapsed: ") << elapsed.toString() << endl; if(elapsed != 0) { - m_printf(_F("Speed: %u KB/s\r\n\r\n"), 1000 * bufSize / elapsed); + Serial << _F("Speed: ") << 1000 * bufSize / elapsed << " KB/s" << endl; } } Serial.println(); @@ -54,7 +50,7 @@ void printPart(const String& partitionName) { auto part = Storage::findPartition(partitionName); if(!part) { - debug_e("Partition '%s' not found", partitionName.c_str()); + Serial << _F("Partition '") << partitionName << _F("' not found") << endl; } else { printPart(part); } diff --git a/samples/SystemClock_NTP/app/NtpClientDemo.cpp b/samples/SystemClock_NTP/app/NtpClientDemo.cpp index 91510d4687..7ed6c6ec1d 100644 --- a/samples/SystemClock_NTP/app/NtpClientDemo.cpp +++ b/samples/SystemClock_NTP/app/NtpClientDemo.cpp @@ -18,24 +18,17 @@ void NtpClientDemo::ntpResult(NtpClient& client, time_t ntpTime) /* * Display the new time */ - Serial.print("ntpClientDemo Callback: ntpTime = "); - Serial.print(ntpTime); - Serial.print(", "); - Serial.print(SystemClock.getSystemTimeString(eTZ_UTC)); - Serial.print(" UTC, Local time = "); - Serial.print(SystemClock.getSystemTimeString(eTZ_Local)); - Serial.print(" "); - Serial.println(tz.utcTimeTag(ntpTime)); + Serial << _F("ntpClientDemo Callback: ntpTime = ") << ntpTime << ", " << SystemClock.getSystemTimeString(eTZ_UTC) + << _F(" UTC, Local time = ") << SystemClock.getSystemTimeString(eTZ_Local) << ' ' << tz.utcTimeTag(ntpTime) + << endl; /* * Display times of next sunrise and sunset */ DateTime sunrise = getNextSunriseSet(true); DateTime sunset = getNextSunriseSet(false); - Serial.print("Next sunrise at "); - Serial.print(sunrise.toShortTimeString()); - Serial.print(", sunset at "); - Serial.println(sunset.toShortTimeString()); + Serial << _F("Next sunrise at ") << sunrise.toShortTimeString() << _F(", sunset at ") << sunset.toShortTimeString() + << endl; } /* diff --git a/samples/SystemClock_NTP/app/application.cpp b/samples/SystemClock_NTP/app/application.cpp index 4ada03d350..5129bb6f22 100644 --- a/samples/SystemClock_NTP/app/application.cpp +++ b/samples/SystemClock_NTP/app/application.cpp @@ -45,11 +45,8 @@ NtpClientDemo* demo; void onPrintSystemTime() { - Serial.print("Local Time: "); - Serial.print(SystemClock.getSystemTimeString(eTZ_Local)); - Serial.print(" "); - Serial.print("UTC Time: "); - Serial.println(SystemClock.getSystemTimeString(eTZ_UTC)); + Serial << _F("Local Time: ") << SystemClock.getSystemTimeString(eTZ_Local) << _F(", UTC Time: ") + << SystemClock.getSystemTimeString(eTZ_UTC) << endl; } // Called when time has been received by NtpClient (option 1 or 2) @@ -59,8 +56,7 @@ void onNtpReceive(NtpClient& client, time_t timestamp) { SystemClock.setTime(timestamp, eTZ_UTC); - Serial.print("Time synchronized: "); - Serial.println(SystemClock.getSystemTimeString()); + Serial << _F("Time synchronized: ") << SystemClock.getSystemTimeString() << endl; } // Will be called when WiFi station timeout was reached @@ -99,7 +95,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true); // Allow debug print to serial - Serial.println("Sming. Let's do smart things!"); + Serial.println(_F("Sming. Let's do smart things!")); // Station - WiFi client WifiStation.enable(true); diff --git a/samples/TcpClient_NarodMon/app/application.cpp b/samples/TcpClient_NarodMon/app/application.cpp index 90a9d2437f..063bdd03a6 100644 --- a/samples/TcpClient_NarodMon/app/application.cpp +++ b/samples/TcpClient_NarodMon/app/application.cpp @@ -136,7 +136,7 @@ void init() // Настраиваем и включаем вывод в UART для дебага Serial.begin(COM_SPEED_SERIAL); Serial.systemDebugOutput(true); - Serial.println("Hello friendly world! :)"); + Serial.println(_F("Hello friendly world! :)")); // Disable AP // Отключаем AP diff --git a/samples/Telnet_Server/app/application.cpp b/samples/Telnet_Server/app/application.cpp index 956c190811..dfa10d920c 100644 --- a/samples/Telnet_Server/app/application.cpp +++ b/samples/Telnet_Server/app/application.cpp @@ -16,22 +16,21 @@ void checkHeap() { int currentHeap = system_get_free_heap_size(); if(currentHeap != savedHeap) { - Debug.printf(_F("Heap change, current = %u\r\n"), currentHeap); + Debug << _F("Heap change, current = ") << currentHeap << endl; savedHeap = currentHeap; } } void applicationCommand(String commandLine, CommandOutput* commandOutput) { - commandOutput->print(_F("Hello from Telnet Example application\r\nYou entered : '")); - commandOutput->print(commandLine.c_str()); - commandOutput->println('\''); - commandOutput->println(_F("Tokenized commandLine is : ")); + *commandOutput << _F("Hello from Telnet Example application") << endl + << _F("You entered : '") << commandLine << '\'' << endl + << _F("Tokenized commandLine is : ") << endl; Vector commandToken; unsigned numToken = splitString(commandLine, ' ', commandToken); for(unsigned i = 0; i < numToken; i++) { - commandOutput->printf(_F("%u : %s\r\n"), i, commandToken.at(i).c_str()); + *commandOutput << i << " : " << commandToken[i] << endl; } } @@ -50,7 +49,7 @@ void appheapCommand(String commandLine, CommandOutput* commandOutput) savedHeap = 0; memoryTimer.stop(); } else if(commandToken[1] == "now") { - commandOutput->printf(_F("Heap current free = %u\r\n"), system_get_free_heap_size()); + *commandOutput << _F("Heap current free = ") << system_get_free_heap_size() << endl; } else { commandOutput->println(_F("Usage appheap on/off/now")); } @@ -86,15 +85,17 @@ void startServers() { tcpServer.listen(8023); - Serial.println(_F("\r\n=== TCP SERVER Port 8023 STARTED ===")); + Serial.println(_F("\r\n" + "=== TCP SERVER Port 8023 STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println(_F("==============================\r\n")); + Serial.println(_F("====================================\r\n")); telnetServer.listen(23); - Serial.println(_F("\r\n=== Telnet SERVER Port 23 STARTED ===")); + Serial.println(_F("\r\n" + "=== Telnet SERVER Port 23 STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println(_F("==============================\r\n")); + Serial.println(_F("=====================================\r\n")); commandHandler.registerCommand(CommandDelegate( F("application"), F("This command is defined by the application\r\n"), F("testGroup"), applicationCommand)); diff --git a/samples/Temperature_DS1820/app/application.cpp b/samples/Temperature_DS1820/app/application.cpp index 8bc84bd224..75d695c349 100644 --- a/samples/Temperature_DS1820/app/application.cpp +++ b/samples/Temperature_DS1820/app/application.cpp @@ -1,8 +1,11 @@ #include #include +#define I2C_PIN 4 + DS18S20 ReadTemp; Timer procTimer; + //********************************************************** // DS18S20 example, reading // You can connect multiple sensors to a single port @@ -21,43 +24,36 @@ void readData() { if(!ReadTemp.MeasureStatus()) // the last measurement completed { - if(ReadTemp.GetSensorsCount()) // is minimum 1 sensor detected ? - Serial.println("******************************************"); - Serial.println(" Reding temperature DEMO"); - for(uint8_t a = 0; a < ReadTemp.GetSensorsCount(); a++) // prints for all sensors - { - Serial.print(" T"); - Serial.print(a + 1); - Serial.print(" = "); - if(ReadTemp.IsValidTemperature(a)) // temperature read correctly ? - { - Serial.print(ReadTemp.GetCelsius(a)); - Serial.print(" Celsius, ("); - Serial.print(ReadTemp.GetFahrenheit(a)); - Serial.println(" Fahrenheit)"); - } else - Serial.println("Temperature not valid"); - - Serial.print(" 0) { + Serial.println(_F("******************************************")); + } + Serial.println(_F(" Reading temperature DEMO")); + // prints for all sensors + for(unsigned a = 0; a < sensorCount; a++) { + Serial << " T" << a + 1 << " = "; + if(ReadTemp.IsValidTemperature(a)) { + Serial << ReadTemp.GetCelsius(a) << _F(" Celsius, (") << ReadTemp.GetFahrenheit(a) << _F(" Fahrenheit)") + << endl; + } else { + Serial.println(_F("Temperature not valid")); + } - uint64_t info = ReadTemp.GetSensorID(a) >> 32; - Serial.print((uint32_t)info, 16); - Serial.print((uint32_t)ReadTemp.GetSensorID(a), 16); - Serial.println(">"); + Serial << _F(" ' << endl; } - Serial.println("******************************************"); + Serial.println(_F("******************************************")); ReadTemp.StartMeasure(); // next measure, result after 1.2 seconds * number of sensors } else - Serial.println("No valid Measure so far! wait please"); + Serial.println(_F("No valid Measure so far! wait please")); } void init() { - Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Serial.systemDebugOutput(true); // Allow debug output to serial + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); - ReadTemp.Init(4); // select PIN It's required for one-wire initialization! + ReadTemp.Init(I2C_PIN); ReadTemp.StartMeasure(); // first measure start,result after 1.2 seconds * number of sensors - procTimer.initializeMs(10000, readData).start(); // every 10 seconds + procTimer.initializeMs<10000>(readData).start(); } diff --git a/samples/UdpServer_Echo/app/application.cpp b/samples/UdpServer_Echo/app/application.cpp index a06e85ab6c..52cf2503ec 100644 --- a/samples/UdpServer_Echo/app/application.cpp +++ b/samples/UdpServer_Echo/app/application.cpp @@ -17,8 +17,7 @@ void onReceive(UdpConnection& connection, char* data, int size, IpAddress remote debugf("UDP Server callback from %s:%d, %d bytes", remoteIP.toString().c_str(), remotePort, size); // We implement string mode server for example - Serial.print(">\t"); - Serial.print(data); + Serial << ">\t" << data; // Send echo to remote sender String text = String("echo: ") + data; @@ -29,11 +28,10 @@ void gotIP(IpAddress ip, IpAddress gateway, IpAddress netmask) { udp.listen(EchoPort); - Serial.println("\r\n=== UDP SERVER STARTED ==="); - Serial.print(WifiStation.getIP()); - Serial.print(":"); - Serial.println(EchoPort); - Serial.println("=============================\r\n"); + Serial.println(_F("\r\n" + "=== UDP SERVER STARTED ===")); + Serial << WifiStation.getIP() << ':' << EchoPort << endl; + Serial.println(_F("==========================\r\n")); } void init() diff --git a/samples/UdpServer_mDNS/app/application.cpp b/samples/UdpServer_mDNS/app/application.cpp index 48b282604f..15638491f0 100644 --- a/samples/UdpServer_mDNS/app/application.cpp +++ b/samples/UdpServer_mDNS/app/application.cpp @@ -99,12 +99,12 @@ void test() // speedTest(question); - checkLike(question, "_services._dns-sd._udp.local", true); - checkLike(question, "_dns-sd._udp.local", true); - checkLike(question, "_udp.local", true); - checkLike(question, "local", true); + checkLike(question, _F("_services._dns-sd._udp.local"), true); + checkLike(question, _F("_dns-sd._udp.local"), true); + checkLike(question, _F("_udp.local"), true); + checkLike(question, _F("local"), true); - checkParser("_some-service-or-other._http._tcp.sming.local"); + checkParser(_F("_some-service-or-other._http._tcp.sming.local")); // debug_i("(question == fstrServicesLocal): %u", question->getName() == fstrServicesLocal); printMessage(Serial, query); @@ -145,9 +145,9 @@ void onFile(HttpRequest& request, HttpResponse& response) { String file = request.uri.getRelativePath(); - if(file[0] == '.') + if(file[0] == '.') { response.code = HTTP_STATUS_FORBIDDEN; - else { + } else { response.setCache(86400, true); // It's important to use cache for better performance. response.sendFile(file); } @@ -158,9 +158,10 @@ void startWebServer() server.listen(80); server.paths.set("/", onIndex); - Serial.println("\r\n=== WEB SERVER STARTED ==="); + Serial.println(_F("\r\n" + "=== WEB SERVER STARTED ===")); Serial.println(WifiStation.getIP()); - Serial.println("==============================\r\n"); + Serial.println(_F("==========================\r\n")); } void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) diff --git a/samples/WebcamServer/app/application.cpp b/samples/WebcamServer/app/application.cpp index 7e27c65855..84a1320747 100644 --- a/samples/WebcamServer/app/application.cpp +++ b/samples/WebcamServer/app/application.cpp @@ -26,9 +26,9 @@ void onFile(HttpRequest& request, HttpResponse& response) { String file = request.uri.getRelativePath(); - if(file[0] == '.') + if(file[0] == '.') { response.code = HTTP_STATUS_FORBIDDEN; - else { + } else { response.setCache(86400, true); // It's important to use cache for better performance. response.sendFile(file); } @@ -42,17 +42,17 @@ MultipartStream::BodyPart snapshotProducer() result.stream = webcamStream; result.headers = new HttpHeaders(); - (*result.headers)["Content-Type"] = camera->getMimeType(); + (*result.headers)[HTTP_HEADER_CONTENT_TYPE] = camera->getMimeType(); return result; } void onStream(HttpRequest& request, HttpResponse& response) { - Serial.printf("perform onCapture()\r\n"); + Serial.println(_F("perform onCapture()")); MultipartStream* stream = new MultipartStream(snapshotProducer); - response.sendDataStream(stream, String("multipart/x-mixed-replace; boundary=") + stream->getBoundary()); + response.sendDataStream(stream, F("multipart/x-mixed-replace; boundary=") + stream->getBoundary()); } void onFavicon(HttpRequest& request, HttpResponse& response) @@ -65,10 +65,11 @@ void startWebServer() { // Initialize the camera Vector images; - char buf[13] = {0}; for(unsigned int i = 1; i < 6; i++) { - sprintf(buf, "img%02d.jpeg", i); - images.add(buf); + String s = "img"; + s.concat(i, DEC, 2); + s += ".jpeg"; + images.add(s); } camera = new FakeCamera(images); camera->init(); diff --git a/samples/Websocket_Client/app/application.cpp b/samples/Websocket_Client/app/application.cpp index 4cb39dde4f..7b80fb4974 100644 --- a/samples/Websocket_Client/app/application.cpp +++ b/samples/Websocket_Client/app/application.cpp @@ -45,31 +45,30 @@ void wsMessageSent(); void wsConnected(WebsocketConnection& wsConnection) { - Serial.printf(_F("Start sending messages every %u second(s)...\r\n"), MESSAGE_INTERVAL); + Serial << _F("Start sending messages every ") << MESSAGE_INTERVAL << _F(" second(s)...") << endl; msgTimer.initializeMs(MESSAGE_INTERVAL * 1000, wsMessageSent); msgTimer.start(); } void wsMessageReceived(WebsocketConnection& wsConnection, const String& message) { - Serial.printf(_F("WebSocket message received: %s\r\n"), message.c_str()); - Serial.printf(_F("Free Heap: %u\r\n"), system_get_free_heap_size()); + Serial << _F("WebSocket message received: ") << message << endl; + Serial << _F("Free Heap: ") << system_get_free_heap_size() << endl; } void wsBinReceived(WebsocketConnection& wsConnection, uint8_t* data, size_t size) { Serial.println(_F("WebSocket BINARY received")); for(uint8_t i = 0; i < size; i++) { - Serial.printf("wsBin[%u] = 0x%02X\r\n", i, data[i]); + Serial << "wsBin[" << i << "] = 0x" << String(data[i], HEX, 2) << endl; } - Serial.print(_F("Free Heap: ")); - Serial.println(system_get_free_heap_size()); + Serial << _F("Free Heap: ") << system_get_free_heap_size() << endl; } void restart() { - Serial.println("restart..."); + Serial.println(_F("restart...")); msg_cnt = 0; wsClient.connect(String(ws_Url)); @@ -77,7 +76,7 @@ void restart() void wsDisconnected(WebsocketConnection& wsConnection) { - Serial.printf(_F("Restarting websocket client after %u seconds\r\n"), RESTART_PERIOD); + Serial << _F("Restarting websocket client after ") << RESTART_PERIOD << _F(" seconds") << endl; msgTimer.setCallback(restart); msgTimer.setIntervalMs(RESTART_PERIOD * 1000); msgTimer.startOnce(); @@ -100,15 +99,14 @@ void wsMessageSent() #ifndef WS_BINARY String message = F("Hello ") + String(msg_cnt++); - Serial.print(_F("Sending websocket message: ")); - Serial.println(message); + Serial << _F("Sending websocket message: ") << message << endl; wsClient.sendString(message); #else uint8_t buf[] = {0xF0, 0x00, 0xF0}; buf[1] = msg_cnt++; Serial.println(_F("Sending websocket binary buffer")); for(uint8_t i = 0; i < 3; i++) { - Serial.printf("wsBin[%u] = 0x%02X\r\n", i, buf[i]); + Serial << "wsBin[" << i << "] = 0x" << String(buf[i], HEX, 2) << endl; } wsClient.sendBinary(buf, 3); @@ -117,15 +115,9 @@ void wsMessageSent() void STAGotIP(IpAddress ip, IpAddress mask, IpAddress gateway) { - Serial.print(_F("GOTIP - IP: ")); - Serial.print(ip); - Serial.print(_F(", MASK: ")); - Serial.print(mask); - Serial.print(_F(", GW: ")); - Serial.println(gateway); + Serial << _F("GOTIP - IP: ") << ip << _F(", MASK: ") << mask << _F(", GW: ") << gateway << endl; - Serial.print(_F("Connecting to Websocket Server ")); - Serial.println(ws_Url); + Serial << _F("Connecting to Websocket Server ") << ws_Url << endl; wsClient.setMessageHandler(wsMessageReceived); wsClient.setBinaryHandler(wsBinReceived); @@ -137,10 +129,8 @@ void STAGotIP(IpAddress ip, IpAddress mask, IpAddress gateway) void STADisconnect(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) { - Serial.print(_F("DISCONNECT - SSID: ")); - Serial.print(ssid); - Serial.print(_F(", REASON: ")); - Serial.println(WifiEvents.getDisconnectReasonDesc(reason)); + Serial << _F("DISCONNECT - SSID: ") << ssid << _F(", REASON: ") << WifiEvents.getDisconnectReasonDesc(reason) + << endl; } void init() diff --git a/samples/Wifi_Sniffer/app/application.cpp b/samples/Wifi_Sniffer/app/application.cpp index 31ed2d91b3..37343ca383 100644 --- a/samples/Wifi_Sniffer/app/application.cpp +++ b/samples/Wifi_Sniffer/app/application.cpp @@ -11,51 +11,63 @@ const unsigned scanTimeoutMs = 2000; ///< End scan on channel if no new devices WifiSniffer sniffer; SimpleTimer timer; +/* + * There may be non-printable characters in received SSID strings. + * Replace these with ?. + * Return a String of exactly 32 characters. + */ +static String makeSsidString(const uint8_t* ssid, size_t len) +{ + String s; + s.pad(32); + len = std::min(len, s.length()); + std::transform(ssid, ssid + len, s.begin(), [](char c) { return isprint(c) ? c : '?'; }); + return s; +} + static void printBeacon(const BeaconInfo& beacon) { if(beacon.err != 0) { - Serial.printf(_F("BEACON ERR: (%d)\n"), beacon.err); + Serial << _F("BEACON ERR: (") << beacon.err << ')' << endl; } else { - Serial.printf(_F("BEACON: <=============== [%32s] "), beacon.ssid); - Serial.print(makeHexString(beacon.bssid, sizeof(beacon.bssid))); - Serial.printf(_F(" %2d"), beacon.channel); - Serial.printf(_F(" %4d\n"), beacon.rssi); + String ssid = makeSsidString(beacon.ssid, beacon.ssid_len); + Serial << _F("BEACON: <==================== [") << ssid << "] " << beacon.bssid << " " + << String(beacon.channel).pad(2) << " " << String(beacon.rssi).padLeft(4) << endl; } + Serial << makeHexString(beacon.ssid, 32) << " " << beacon.ssid_len << endl; } static void printClient(const ClientInfo& client) { if(client.err != 0) { - Serial.printf(_F("CLIENT ERR: (%d)\n"), client.err); + Serial << _F("CLIENT ERR: (") << client.err << ')' << endl; } else { - Serial.print(_F("DEVICE: ")); - Serial.print(makeHexString(client.station, sizeof(client.station))); - Serial.print(_F(" ==> ")); - - int ap = knownAPs.indexOf(client.bssid); - if(ap < 0) { - Serial.print(_F(" Unknown/Malformed packet, BSSID = ")); - Serial.println(makeHexString(client.bssid, sizeof(client.bssid))); + Serial << _F("DEVICE: ") << client.station << _F(" ==> "); + + int i = knownAPs.indexOf(client.bssid); + if(i < 0) { + Serial << _F("Unknown/Malformed packet, BSSID = ") << client.bssid << endl; } else { - Serial.printf(_F("[%32s]"), knownAPs[ap].ssid); - Serial.print(_F(" ")); - Serial.print(makeHexString(client.ap, sizeof(client.ap))); - Serial.printf(_F(" %3i"), knownAPs[ap].channel); - Serial.printf(_F(" %4d\n"), client.rssi); + auto& ap = knownAPs[i]; + String ssid = makeSsidString(ap.ssid, ap.ssid_len); + Serial << '[' << ssid << ']' << " " << client.ap << " " << String(ap.channel).padLeft(3) << " " + << String(client.rssi).padLeft(4) << endl; } } } static void printSummary() { - Serial.println("\n-------------------------------------------------------------------------------------\n"); + Serial.println("\r\n" + "-------------------------------------------------------------------------------------\r\n"); for(unsigned u = 0; u < knownClients.count(); u++) { printClient(knownClients[u]); } for(unsigned u = 0; u < knownAPs.count(); u++) { printBeacon(knownAPs[u]); } - Serial.println("\n-------------------------------------------------------------------------------------\n"); + Serial.println("\r\n" + "-------------------------------------------------------------------------------------\r\n"); } static void onBeacon(const BeaconInfo& beacon) @@ -97,9 +109,12 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Debug output to serial - Serial.printf(_F("\n\nSDK version:%s\n"), system_get_sdk_version()); + Serial << _F("\r\n\r\n" + "SDK version:") + << system_get_sdk_version() << endl; Serial.println(_F("ESP8266 mini-sniff by Ray Burnette http://www.hackster.io/rayburne/projects")); - Serial.println(_F("Type: /-------MAC------/-----WiFi Access Point SSID-----/ /----MAC---/ Chnl RSSI")); + Serial.println( + _F("Type: /---------MAC---------/-----WiFi Access Point SSID-----/ /------MAC------/ Chnl RSSI")); sniffer.onBeacon(onBeacon); sniffer.onClient(onClient); From 9ef62484c1e27501c0436ec5101d8644f9b8f96c Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 15 Sep 2022 14:04:12 +0100 Subject: [PATCH 27/58] Add general UUID / GUID support (#2552) This PR moves the `Uuid` object out of the `SSDP` library and makes some improvements. UUIDs/GUIDs are not exclusively network entities. They're required for filesystems, for example. - Add template constructor for arbitrary 16-byte entities - Add comparison operators - Add Uuid test module - Fix test message truncation by updating SmingTest to write messages directly to Serial --- Sming/Core/Data/Uuid.cpp | 140 +++++++++++++++++++++++++ Sming/Core/Data/Uuid.h | 166 ++++++++++++++++++++++++++++++ Sming/Libraries/SSDP | 2 +- Sming/Libraries/SmingTest | 2 +- Sming/Libraries/UPnP | 2 +- tests/HostTests/include/modules.h | 1 + tests/HostTests/modules/Uuid.cpp | 68 ++++++++++++ 7 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 Sming/Core/Data/Uuid.cpp create mode 100644 Sming/Core/Data/Uuid.h create mode 100644 tests/HostTests/modules/Uuid.cpp diff --git a/Sming/Core/Data/Uuid.cpp b/Sming/Core/Data/Uuid.cpp new file mode 100644 index 0000000000..fdb8ddc71c --- /dev/null +++ b/Sming/Core/Data/Uuid.cpp @@ -0,0 +1,140 @@ +/**** + * 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. + * + * Uuid.cpp - Universal Unique Identifier + * + * See https://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm. + * + * @author mikee47 + * + ****/ + +#include "Uuid.h" +#include +#include + +extern "C" { +uint32_t os_random(); +void os_get_random(void* buf, size_t n); +} + +bool Uuid::generate(MacAddress mac) +{ + uint8_t version = 1; // DCE version + uint8_t variant = 2; // DCE variant + uint16_t clock_seq = os_random(); + uint32_t time; + if(SystemClock.isSet()) { + time = SystemClock.now(eTZ_UTC); + } else { + time = os_random(); + } + // Time only provides 32 bits, we need 60 + time_low = (os_random() & 0xFFFFFFFC) | (time & 0x00000003); + time_mid = (time >> 2) & 0xFFFF; + time_hi_and_version = (version << 12) | ((time >> 18) << 2); + clock_seq_hi_and_reserved = (variant << 6) | ((clock_seq >> 8) & 0x3F); + clock_seq_low = clock_seq & 0xFF; + mac.getOctets(node); + + return SystemClock.isSet(); +} + +bool Uuid::generate() +{ + MacAddress::Octets mac; + os_get_random(mac, sizeof(mac)); + // RFC4122 requires LSB of first octet to be 1 + mac[0] |= 0x01; + return generate(mac); +} + +bool Uuid::decompose(const char* s, size_t len) +{ + if(len != stringSize) { + return false; + } + + char* p; + time_low = strtoul(s, &p, 16); + if(*p != '-' || p - s != 8) { + return false; + } + s = ++p; + + time_mid = strtoul(s, &p, 16); + if(*p != '-' || p - s != 4) { + return false; + } + s = ++p; + + time_hi_and_version = strtoul(s, &p, 16); + if(*p != '-' || p - s != 4) { + return false; + } + s = ++p; + + uint16_t x = strtoul(s, &p, 16); + if(*p != '-' || p - s != 4) { + return false; + } + clock_seq_hi_and_reserved = x >> 8; + clock_seq_low = x & 0xff; + s = ++p; + + for(unsigned i = 0; i < sizeof(node); ++i) { + uint8_t c = unhex(*s++) << 4; + c |= unhex(*s++); + node[i] = c; + } + + return true; +} + +size_t Uuid::toString(char* buffer, size_t bufSize) const +{ + if(isFlashPtr(this)) { + return Uuid(*this).toString(buffer, bufSize); + } + + if(buffer == nullptr || bufSize < stringSize) { + return 0; + } + + auto set = [&](unsigned offset, uint32_t value, unsigned digits) { + ultoa_wp(value, &buffer[offset], 16, digits, '0'); + }; + + // 2fac1234-31f8-11b4-a222-08002b34c003 + // 0 9 14 19 24 36 + + set(0, time_low, 8); + buffer[8] = '-'; + set(9, time_mid, 4); + buffer[13] = '-'; + set(14, time_hi_and_version, 4); + buffer[18] = '-'; + set(19, clock_seq_hi_and_reserved, 2); + set(21, clock_seq_low, 2); + buffer[23] = '-'; + + unsigned pos = 24; + for(unsigned i = 0; i < 6; ++i) { + buffer[pos++] = hexchar(node[i] >> 4); + buffer[pos++] = hexchar(node[i] & 0x0f); + } + + return stringSize; +} + +String Uuid::toString() const +{ + String s; + if(s.setLength(stringSize)) { + toString(s.begin(), stringSize); + } + return s; +} diff --git a/Sming/Core/Data/Uuid.h b/Sming/Core/Data/Uuid.h new file mode 100644 index 0000000000..75a351f721 --- /dev/null +++ b/Sming/Core/Data/Uuid.h @@ -0,0 +1,166 @@ +/**** + * 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. + * + * Uuid.h - Universal Unique Identifier + * + * @author mikee47 + * + ****/ + +#pragma once + +#include +#include + +/** + * @brief Class for manipulating UUID (aka GUID) entities + * + * UUID: Universally Unique IDentifier + * GUID: Globally Unique IDentifier + * + * See https://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm. + */ +struct Uuid { + uint32_t time_low{0}; // 0-3 + uint16_t time_mid{0}; // 4-5 + uint16_t time_hi_and_version{0}; // 6-7, version = top 4 bits + uint8_t clock_seq_hi_and_reserved{0}; // 8, variant = top 2 bits + uint8_t clock_seq_low{0}; // 9 + uint8_t node[6]{}; // 10-15 + + /** + * @brief Number of characters in a UUID string (excluding NUL terminator) + */ + static constexpr size_t stringSize = 36; + + Uuid() + { + } + + explicit Uuid(const char* s) + { + decompose(s); + } + + explicit Uuid(const char* s, size_t len) + { + decompose(s, len); + } + + explicit Uuid(const String& s) : Uuid(s.c_str(), s.length()) + { + } + + explicit Uuid(const FlashString& s) : Uuid(String(s)) + { + } + + explicit constexpr Uuid(uint32_t time_low, uint16_t time_mid, uint16_t time_hi_and_version, + uint8_t clock_seq_hi_and_reserved, uint8_t clock_seq_low, uint8_t n1, uint8_t n2, + uint8_t n3, uint8_t n4, uint8_t n5, uint8_t n6) + : time_low(time_low), time_mid(time_mid), time_hi_and_version(time_hi_and_version), + clock_seq_hi_and_reserved(clock_seq_hi_and_reserved), + clock_seq_low(clock_seq_low), node{n1, n2, n3, n4, n5, n6} + { + } + + explicit operator bool() const + { + Uuid Null{}; + return memcmp(this, &Null, sizeof(Null)) != 0; + } + + bool operator==(const Uuid& other) const + { + return memcmp(this, &other, sizeof(Uuid)) == 0; + } + + bool operator!=(const Uuid& other) const + { + return !operator==(other); + } + + /** + * @brief Generate a UUID using a MAC node address + * @param mac Node address to use in generating the UUID, typically from WifiStation + * @retval bool true if system clock time was used, false if substituted with random number + */ + bool generate(MacAddress mac); + + /** + * @brief Generate UUID using random number instead of MAC + * @retval bool true if system clock time was used, false if substituted with random number + * + * Used where MAC address is not available or it is not desirable to expose it. + */ + bool generate(); + + /** + * @name Decompse string into UUID + * @{ + */ + bool decompose(const char* s, size_t len); + + bool decompose(const char* s) + { + return s ? decompose(s, strlen(s)) : false; + } + + bool decompose(const String& s) + { + return decompose(s.c_str(), s.length()); + } + /** @} */ + + /** + * @name Get string representation of UUID + * @{ + */ + + /** + * @param uuid + * @param buffer + * @param bufSize Must be at least UUID_STRING_SIZE + * @retval size_t number of characters written (either 0 or UUID_STRING_SIZE) + * @note Converts UUID into a string of the form + * + * ---- + * + * e.g. 2fac1234-31f8-11b4-a222-08002b34c003 + */ + size_t toString(char* buffer, size_t bufSize) const; + + String toString() const; + + operator String() const + { + return toString(); + } + + /** @} */ +}; + +static_assert(sizeof(Uuid) == 16, "Bad Uuid"); + +inline String toString(const Uuid& uuid) +{ + return uuid.toString(); +} + +inline bool fromString(const char* s, Uuid& uuid) +{ + return uuid.decompose(s); +} + +inline bool fromString(const String& s, Uuid& uuid) +{ + return uuid.decompose(s); +} + +/** + * @deprecated Use `Uuid` instead. + */ +typedef Uuid UUID SMING_DEPRECATED; diff --git a/Sming/Libraries/SSDP b/Sming/Libraries/SSDP index a864d47dc7..f2fe3f8b19 160000 --- a/Sming/Libraries/SSDP +++ b/Sming/Libraries/SSDP @@ -1 +1 @@ -Subproject commit a864d47dc7a554e451ce3abe458285ec64a68ecf +Subproject commit f2fe3f8b19473ee28bcaa3fb053607b76683960c diff --git a/Sming/Libraries/SmingTest b/Sming/Libraries/SmingTest index 1a25cc1ea7..a6c7f94341 160000 --- a/Sming/Libraries/SmingTest +++ b/Sming/Libraries/SmingTest @@ -1 +1 @@ -Subproject commit 1a25cc1ea71b68139fbccbd4e66afc5db8b89846 +Subproject commit a6c7f9434135fc6350da72b7e226a825f0092356 diff --git a/Sming/Libraries/UPnP b/Sming/Libraries/UPnP index 983ecdfd2b..28348c3d3e 160000 --- a/Sming/Libraries/UPnP +++ b/Sming/Libraries/UPnP @@ -1 +1 @@ -Subproject commit 983ecdfd2b814e744fe2231867d45e5d50edd312 +Subproject commit 28348c3d3e60d7e3b38e53ba853493f0549b894c diff --git a/tests/HostTests/include/modules.h b/tests/HostTests/include/modules.h index 9a87341b3f..dd302fb86b 100644 --- a/tests/HostTests/include/modules.h +++ b/tests/HostTests/include/modules.h @@ -33,6 +33,7 @@ XX(ObjectMap) \ XX_NET(Base64) \ XX(DateTime) \ + XX(Uuid) \ XX_NET(Http) \ XX_NET(Url) \ XX(ArduinoJson5) \ diff --git a/tests/HostTests/modules/Uuid.cpp b/tests/HostTests/modules/Uuid.cpp new file mode 100644 index 0000000000..1707fa5979 --- /dev/null +++ b/tests/HostTests/modules/Uuid.cpp @@ -0,0 +1,68 @@ +#include + +#include +#include + +namespace +{ +using guid_t = Uuid; + +#define DEFINE_GUID(name, a, b, c, d...) static constexpr guid_t name PROGMEM{a, b, c, d}; + +DEFINE_GUID(PARTITION_SYSTEM_GUID, 0xc12a7328, 0xf81f, 0x11d2, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b) +#define PARTITION_SYSTEM_GUID_PSTR "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" +DEFINE_FSTR_LOCAL(PARTITION_SYSTEM_GUID_FSTR, PARTITION_SYSTEM_GUID_PSTR) + +} // namespace + +class UuidTest : public TestGroup +{ +public: + UuidTest() : TestGroup(_F("UUID")) + { + } + + void execute() override + { + TEST_CASE("NULL GUID") + { + Uuid uuid; + uint8_t empty[16]{}; + REQUIRE(memcmp(&uuid, empty, 16) == 0); + } + + TEST_CASE("Struct") + { + REQUIRE_EQ(String(PARTITION_SYSTEM_GUID_FSTR), Uuid(PARTITION_SYSTEM_GUID)); + } + + TEST_CASE("Decomposition") + { + REQUIRE_EQ(String(PARTITION_SYSTEM_GUID_FSTR), Uuid(PARTITION_SYSTEM_GUID_PSTR)); + REQUIRE_EQ(String(PARTITION_SYSTEM_GUID_FSTR), Uuid(PARTITION_SYSTEM_GUID_FSTR)); + } + + TEST_CASE("Copy") + { + Uuid u1; + Uuid u2(PARTITION_SYSTEM_GUID); + u1 = u2; + REQUIRE_EQ(u1, u2); + } + + TEST_CASE("Printing") + { + MemoryDataStream str; + const Uuid& u1(PARTITION_SYSTEM_GUID); + str << u1; + String s = str.readString(Uuid::stringSize); + REQUIRE_EQ(str.available(), 0); + REQUIRE_EQ(s, u1); + } + } +}; + +void REGISTER_TEST(Uuid) +{ + registerGroup(); +} From 90a99e8dc09f01baa594ab37c41b5d7a34c9bb72 Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 20 Sep 2022 17:36:11 +0200 Subject: [PATCH 28/58] Typos reported by codespell. (#2555) --- docs/source/framework/core/pgmspace.rst | 2 +- samples/Basic_Delegates/app/application.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/framework/core/pgmspace.rst b/docs/source/framework/core/pgmspace.rst index b376e93af1..0827288dfc 100644 --- a/docs/source/framework/core/pgmspace.rst +++ b/docs/source/framework/core/pgmspace.rst @@ -33,7 +33,7 @@ memcpy_aligned -------------- Once in flash memory, string data must be read into RAM before it can be used. Accessing the flash -memory directly is awkard. If locations are not strictly accessed as 4-byte words the system will +memory directly is awkward. If locations are not strictly accessed as 4-byte words the system will probably crash; I say 'probably' because sometimes it just behaves weirdly if the RAM address isn't aligned. diff --git a/samples/Basic_Delegates/app/application.cpp b/samples/Basic_Delegates/app/application.cpp index 701c7d1822..e3bfae764e 100644 --- a/samples/Basic_Delegates/app/application.cpp +++ b/samples/Basic_Delegates/app/application.cpp @@ -41,21 +41,21 @@ class Task taskTimer.initializeMs(taskInterval, b).start(); } - // This example shows how to use a lamda expression as a callback - void callLamda() + // This example shows how to use a lambda expression as a callback + void callLambda() { int foo = 123; taskTimer .initializeMs( taskInterval, - [foo] // capture just foo by value (Note it would be bad to pass by reference as foo would be out of scope when the lamda function runs later) + [foo] // capture just foo by value (Note it would be bad to pass by reference as foo would be out of scope when the lambda function runs later) () // No parameters to the callback -> void // Returns nothing { if(foo == 123) { - debugf("lamda Callback foo is 123"); + debugf("lambda Callback foo is 123"); } else { - debugf("lamda Callback foo is not 123, crikey!"); + debugf("lambda Callback foo is not 123, crikey!"); } }) .start(); @@ -117,5 +117,5 @@ void init() task4.callMemberFunction(); task5.setTimer(1800); - task5.callLamda(); + task5.callLambda(); } From 2ef58d1bfc674d5e389f265d4914fc67d4837d9e Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 21 Sep 2022 12:12:32 +0100 Subject: [PATCH 29/58] Improve HashMap memory usage, add sorting capability (#2556) The `HashMap` class template currently stores both keys and values using double-indirection. This is necessary for object types (e.g. String) but for simple (scalar) types it is very wasteful of memory. This PR delegates key/value storage to separate list class optimised for either scalar or pointer (class) types. Also, the allocation algorithm has been adjusted to expand storage by 4 or 16 entries, instead of only one. The `stdc++` library has also been added so that `std::map` and `std::vector` can be used to compare memory usage. The `Wiring` module in `HostTests` has been updated to show this. A `HashMap` containing 13 items now uses 96 bytes instead of 182. `std::map` uses 312 bytes. NB. enum declarations default to 32-bits, so reducing storage class for `MimeType` to uint8_t reduces map further to 48 bytes, whilst `std::map` reduces to 260 bytes. One reason for the reduced memory usage is that HashMap uses two lists: one for keys, and a second for values, whilst `std::map` uses a single list of `std::pair` structures. These structures must be aligned so with small data types there is unused space. Note, however, that a `std::map` will likely out-perform a simple HashMap for larger data sets as they use more sophisticated storage mechanisms https://en.cppreference.com/w/cpp/container/map. HashMap is much simpler, does not sort the keys and does lookups by iterating from the start of the map. This PR also adds a basic `sort()` method so entries can be re-ordered, perhaps as part of post-processing or display. --- .../Components/esp_no_wifi/user_interface.c | 2 +- .../Arch/Esp8266/Components/libc/component.mk | 22 +++ .../Rp2040/Components/rp2040/component.mk | 3 +- .../src/Network/Http/HttpHeaderFields.h | 2 +- .../Network/src/Network/Http/HttpParams.cpp | 4 +- Sming/Components/malloc_count/component.mk | 16 +- Sming/Core/Data/WebConstants.h | 2 +- .../CommandProcessing/CommandDelegate.cpp | 22 --- .../CommandProcessing/CommandDelegate.h | 16 +- .../CommandProcessing/CommandHandler.cpp | 26 +-- .../CommandProcessing/CommandHandler.h | 3 +- Sming/Wiring/WHashMap.h | 186 ++++++++---------- Sming/Wiring/WiringList.h | 135 +++++++++++++ tests/HostTests/modules/Wiring.cpp | 115 ++++++++++- 14 files changed, 386 insertions(+), 168 deletions(-) delete mode 100644 Sming/Services/CommandProcessing/CommandDelegate.cpp create mode 100644 Sming/Wiring/WiringList.h diff --git a/Sming/Arch/Esp8266/Components/esp_no_wifi/user_interface.c b/Sming/Arch/Esp8266/Components/esp_no_wifi/user_interface.c index 967a291d54..8bbf3e0e2f 100644 --- a/Sming/Arch/Esp8266/Components/esp_no_wifi/user_interface.c +++ b/Sming/Arch/Esp8266/Components/esp_no_wifi/user_interface.c @@ -137,7 +137,7 @@ uint16_t system_get_vdd33(void) return phy_get_vdd33() & 0x3FF; } // Fetch enum `flash_size_map` value -unsigned system_get_flash_size_map(void) +enum flash_size_map system_get_flash_size_map(void) { uint32_t hdr; spi_flash_read(0, &hdr, sizeof(hdr)); diff --git a/Sming/Arch/Esp8266/Components/libc/component.mk b/Sming/Arch/Esp8266/Components/libc/component.mk index 8d7698360d..930c83d177 100644 --- a/Sming/Arch/Esp8266/Components/libc/component.mk +++ b/Sming/Arch/Esp8266/Components/libc/component.mk @@ -12,3 +12,25 @@ COMPONENT_SRCDIRS += src/oldlib LIBDIRS += $(COMPONENT_PATH)/lib EXTRA_LIBS += microc microgcc setjmp endif + +# build customised libstdc++ +# https://github.com/esp8266/Arduino/blob/master/tools/sdk/lib/README.md +LIBSTDCPP_SRC = $(call FixPath,$(shell $(CC) -print-file-name=libstdc++.a)) +LIBSTDCPP_DST = $(USER_LIBDIR)/libstdc++.a + +$(COMPONENT_RULE)$(LIBSTDCPP_DST): $(LIBSTDCPP_SRC) + $(info Prepare libstdc++) + $(Q) cp $< $@ + $(Q) $(AR) d $@ pure.o + $(Q) $(AR) d $@ vterminate.o + $(Q) $(AR) d $@ guard.o + $(Q) $(AR) d $@ functexcept.o + $(Q) $(AR) d $@ del_op.o + $(Q) $(AR) d $@ del_ops.o + $(Q) $(AR) d $@ del_opv.o + $(Q) $(AR) d $@ new_op.o + $(Q) $(AR) d $@ new_opv.o + +COMPONENT_TARGETS += $(LIBSTDCPP_DST) + +EXTRA_LIBS += stdc++ diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index fc87b4cd6a..ebbe18cfa1 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -90,7 +90,8 @@ LIBDIRS += \ EXTRA_LIBS += \ pico \ - m + m \ + stdc++ RP2040_CMAKE_OPTIONS := \ -G Ninja \ diff --git a/Sming/Components/Network/src/Network/Http/HttpHeaderFields.h b/Sming/Components/Network/src/Network/Http/HttpHeaderFields.h index 618fcf6971..0ddce3cd95 100644 --- a/Sming/Components/Network/src/Network/Http/HttpHeaderFields.h +++ b/Sming/Components/Network/src/Network/Http/HttpHeaderFields.h @@ -81,7 +81,7 @@ XX(PROXY_AUTHENTICATE, "Proxy-Authenticate", Flag::Multi, \ "Indicates proxy authentication scheme(s) and applicable parameters") -enum class HttpHeaderFieldName { +enum class HttpHeaderFieldName : uint8_t { UNKNOWN = 0, #define XX(tag, str, flags, comment) tag, HTTP_HEADER_FIELDNAME_MAP(XX) diff --git a/Sming/Components/Network/src/Network/Http/HttpParams.cpp b/Sming/Components/Network/src/Network/Http/HttpParams.cpp index a84fabe589..fc4a5bdec8 100644 --- a/Sming/Components/Network/src/Network/Http/HttpParams.cpp +++ b/Sming/Components/Network/src/Network/Http/HttpParams.cpp @@ -36,9 +36,7 @@ void HttpParams::parseQuery(char* query) return; } - allocate(paramCount); - if(keys == nullptr || values == nullptr) { - // Allocation failure + if(!allocate(paramCount)) { return; } diff --git a/Sming/Components/malloc_count/component.mk b/Sming/Components/malloc_count/component.mk index 06023a9f35..c37331ac6c 100644 --- a/Sming/Components/malloc_count/component.mk +++ b/Sming/Components/malloc_count/component.mk @@ -8,21 +8,21 @@ ifeq ($(ENABLE_MALLOC_COUNT),1) COMPONENT_CXXFLAGS += -DENABLE_MALLOC_COUNT=1 # Hook all the memory allocation functions we need to monitor heap activity -ifeq ($(SMING_ARCH),Esp8266) MC_WRAP_FUNCS := \ + malloc \ + calloc \ + realloc \ + free \ + strdup +ifeq ($(SMING_ARCH),Esp8266) +MC_WRAP_FUNCS += \ + realloc \ pvPortMalloc \ pvPortCalloc \ pvPortRealloc \ pvPortZalloc \ pvPortZallocIram \ vPortFree -else -MC_WRAP_FUNCS := \ - malloc \ - calloc \ - realloc \ - free \ - strdup endif EXTRA_LDFLAGS := $(call UndefWrap,$(MC_WRAP_FUNCS)) diff --git a/Sming/Core/Data/WebConstants.h b/Sming/Core/Data/WebConstants.h index d44fde5123..b058cb9dc8 100644 --- a/Sming/Core/Data/WebConstants.h +++ b/Sming/Core/Data/WebConstants.h @@ -50,7 +50,7 @@ XX(FORM_URL_ENCODED, "", "application/x-www-form-urlencoded") \ XX(FORM_MULTIPART, "", "multipart/form-data") -enum class MimeType { +enum class MimeType : uint8_t { #define XX(name, extensionStart, mime) name, MIME_TYPE_MAP(XX) #undef XX diff --git a/Sming/Services/CommandProcessing/CommandDelegate.cpp b/Sming/Services/CommandProcessing/CommandDelegate.cpp deleted file mode 100644 index 3b0bd8c2a7..0000000000 --- a/Sming/Services/CommandProcessing/CommandDelegate.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * CommandDelegate.cpp - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#include "CommandDelegate.h" - -CommandDelegate::CommandDelegate() -{ -} - -CommandDelegate::CommandDelegate(String reqName, String reqHelp, String reqGroup, CommandFunctionDelegate reqFunction) - : commandName(reqName), commandHelp(reqHelp), commandGroup(reqGroup), commandFunction(reqFunction) -{ -} - -CommandDelegate::~CommandDelegate() -{ - // TODO Auto-generated destructor stub -} diff --git a/Sming/Services/CommandProcessing/CommandDelegate.h b/Sming/Services/CommandProcessing/CommandDelegate.h index 59ca69f256..c43e2d0751 100644 --- a/Sming/Services/CommandProcessing/CommandDelegate.h +++ b/Sming/Services/CommandProcessing/CommandDelegate.h @@ -25,9 +25,6 @@ using CommandFunctionDelegate = Delegate; - public: /** Instantiate a command delegate * @param reqName Command name - the text a user types to invoke the command @@ -35,16 +32,19 @@ class CommandDelegate * @param reqGroup The command group to which this command belongs * @param reqFunction Delegate that should be invoked (triggered) when the command is entered by a user */ - CommandDelegate(String reqName, String reqHelp, String reqGroup, CommandFunctionDelegate reqFunction); - ~CommandDelegate(); + CommandDelegate(String reqName, String reqHelp, String reqGroup, CommandFunctionDelegate reqFunction) + : commandName(reqName), commandHelp(reqHelp), commandGroup(reqGroup), commandFunction(reqFunction) + { + } + + CommandDelegate() + { + } String commandName; ///< Command name String commandHelp; ///< Command help String commandGroup; ///< Command group CommandFunctionDelegate commandFunction; ///< Command Delegate (function that is called when command is invoked) - -private: - CommandDelegate(); }; /** @} */ diff --git a/Sming/Services/CommandProcessing/CommandHandler.cpp b/Sming/Services/CommandProcessing/CommandHandler.cpp index 039a1a1816..c1ba3406ea 100644 --- a/Sming/Services/CommandProcessing/CommandHandler.cpp +++ b/Sming/Services/CommandProcessing/CommandHandler.cpp @@ -22,12 +22,6 @@ CommandHandler::CommandHandler() : currentPrompt(F("Sming>")), currentWelcomeMessage(F("Welcome to the Sming CommandProcessing\r\n")) { - registeredCommands = new HashMap; -} - -CommandHandler::~CommandHandler() -{ - delete registeredCommands; } void CommandHandler::registerSystemCommands() @@ -49,9 +43,9 @@ void CommandHandler::registerSystemCommands() CommandDelegate CommandHandler::getCommandDelegate(const String& commandString) { - if(registeredCommands->contains(commandString)) { + if(registeredCommands.contains(commandString)) { debugf("Returning Delegate for %s \r\n", commandString.c_str()); - return (*registeredCommands)[commandString]; + return registeredCommands[commandString]; } else { debugf("Command %s not recognized, returning NULL\r\n", commandString.c_str()); return CommandDelegate("", "", "", nullptr); @@ -60,12 +54,12 @@ CommandDelegate CommandHandler::getCommandDelegate(const String& commandString) bool CommandHandler::registerCommand(CommandDelegate reqDelegate) { - if(registeredCommands->contains(reqDelegate.commandName)) { + if(registeredCommands.contains(reqDelegate.commandName)) { // Command already registered, don't allow duplicates debugf("Commandhandler duplicate command %s", reqDelegate.commandName.c_str()); return false; } else { - (*registeredCommands)[reqDelegate.commandName] = reqDelegate; + registeredCommands[reqDelegate.commandName] = reqDelegate; debugf("Commandhandlercommand %s registered", reqDelegate.commandName.c_str()); return true; } @@ -73,11 +67,11 @@ bool CommandHandler::registerCommand(CommandDelegate reqDelegate) bool CommandHandler::unregisterCommand(CommandDelegate reqDelegate) { - if(!registeredCommands->contains(reqDelegate.commandName)) { + if(!registeredCommands.contains(reqDelegate.commandName)) { // Command not registered, cannot remove return false; } else { - registeredCommands->remove(reqDelegate.commandName); + registeredCommands.remove(reqDelegate.commandName); // (*registeredCommands)[reqDelegate.commandName] = reqDelegate; return true; } @@ -87,12 +81,12 @@ void CommandHandler::procesHelpCommand(String commandLine, CommandOutput* comman { debugf("HelpCommand entered"); commandOutput->println(_F("Commands available are :")); - for(unsigned idx = 0; idx < registeredCommands->count(); idx++) { - commandOutput->print(registeredCommands->valueAt(idx).commandName); + for(unsigned idx = 0; idx < registeredCommands.count(); idx++) { + commandOutput->print(registeredCommands.valueAt(idx).commandName); commandOutput->print(" | "); - commandOutput->print(registeredCommands->valueAt(idx).commandGroup); + commandOutput->print(registeredCommands.valueAt(idx).commandGroup); commandOutput->print(" | "); - commandOutput->print(registeredCommands->valueAt(idx).commandHelp); + commandOutput->print(registeredCommands.valueAt(idx).commandHelp); commandOutput->print("\r\n"); } } diff --git a/Sming/Services/CommandProcessing/CommandHandler.h b/Sming/Services/CommandProcessing/CommandHandler.h index c6dbf3d23a..8c6d2d4919 100644 --- a/Sming/Services/CommandProcessing/CommandHandler.h +++ b/Sming/Services/CommandProcessing/CommandHandler.h @@ -43,7 +43,6 @@ class CommandHandler /** @brief Instantiate a CommandHandler */ CommandHandler(); - ~CommandHandler(); CommandHandler(const CommandHandler&) = delete; @@ -152,7 +151,7 @@ class CommandHandler // int deleteGroup(String reqGroup); private: - HashMap* registeredCommands; + HashMap registeredCommands; void procesHelpCommand(String commandLine, CommandOutput* commandOutput); void procesStatusCommand(String commandLine, CommandOutput* commandOutput); void procesEchoCommand(String commandLine, CommandOutput* commandOutput); diff --git a/Sming/Wiring/WHashMap.h b/Sming/Wiring/WHashMap.h index 790e530356..37a1685001 100644 --- a/Sming/Wiring/WHashMap.h +++ b/Sming/Wiring/WHashMap.h @@ -31,6 +31,7 @@ #include #include #include +#include "WiringList.h" /** * @brief HashMap class template @@ -39,8 +40,6 @@ template class HashMap { public: - using Comparator = bool (*)(const K&, const K&); - template struct BaseElement { public: using Value = typename std::conditional::type; @@ -156,6 +155,16 @@ template class HashMap unsigned index{0}; }; + /** + * @brief Compare two keys for equality + */ + using Comparator = bool (*)(const K&, const K&); + + /** + * @brief Return true if key1 < key2 + */ + using SortCompare = bool (*)(const ElementConst& e1, const ElementConst& e2); + /* || @constructor || | Default constructor @@ -176,11 +185,6 @@ template class HashMap { } - ~HashMap() - { - clear(); - } - /* || @description || | Get the size of this HashMap @@ -207,7 +211,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *keys[idx]; + return keys[idx]; } K& keyAt(unsigned int idx) @@ -215,7 +219,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *keys[idx]; + return keys[idx]; } /* @@ -232,7 +236,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *values[idx]; + return values[idx]; } V& valueAt(unsigned int idx) @@ -240,7 +244,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *values[idx]; + return values[idx]; } /* @@ -263,7 +267,7 @@ template class HashMap { // Don't create non-existent values auto i = indexOf(key); - return (i >= 0) ? *values[i] : nil; + return (i >= 0) ? values[i] : nil; } /* @@ -279,7 +283,15 @@ template class HashMap */ V& operator[](const K& key); - void allocate(unsigned int newSize); + bool allocate(unsigned int newSize) + { + return keys.allocate(newSize, K{}) && values.allocate(newSize, nil); + } + + /** + * @brief Sort map entries + */ + void sort(SortCompare compare); /* || @description @@ -290,7 +302,19 @@ template class HashMap || || @return The index of the key, or -1 if key does not exist */ - int indexOf(const K& key) const; + int indexOf(const K& key) const + { + for(unsigned i = 0; i < currentIndex; i++) { + if(cb_comparator) { + if(cb_comparator(key, keys[i])) { + return i; + } + } else if(key == keys[i]) { + return i; + } + } + return -1; + } /* || @description @@ -313,7 +337,17 @@ template class HashMap || || @parameter index location to remove from this HashMap */ - void removeAt(unsigned index); + void removeAt(unsigned index) + { + if(index >= currentIndex) { + return; + } + + keys.remove(index); + values.remove(index); + + currentIndex--; + } /* || @description @@ -330,9 +364,19 @@ template class HashMap } } - void clear(); + void clear() + { + keys.clear(); + values.clear(); + currentIndex = 0; + } - void setMultiple(const HashMap& map); + void setMultiple(const HashMap& map) + { + for(auto e : map) { + (*this)[e.key()] = e.value(); + } + } void setNullValue(const V& nullv) { @@ -360,12 +404,14 @@ template class HashMap } protected: - K** keys = nullptr; - V** values = nullptr; - V nil; - uint16_t currentIndex = 0; - uint16_t size = 0; - Comparator cb_comparator = nullptr; + using KeyList = wiring_private::List; + using ValueList = wiring_private::List; + + KeyList keys; + ValueList values; + Comparator cb_comparator{nullptr}; + unsigned currentIndex{0}; + V nil{}; private: HashMap(const HashMap& that); @@ -375,92 +421,28 @@ template V& HashMap::operator[](const K& key) { int i = indexOf(key); if(i >= 0) { - return *values[i]; + return values[i]; } - if(currentIndex >= size) { - allocate(currentIndex + 1); + if(currentIndex >= values.size) { + allocate(currentIndex + ((values.size < 16) ? 4 : 16)); } - *keys[currentIndex] = key; - *values[currentIndex] = nil; + keys[currentIndex] = key; + values[currentIndex] = nil; currentIndex++; - return *values[currentIndex - 1]; + return values[currentIndex - 1]; } -template void HashMap::allocate(unsigned int newSize) +template void HashMap::sort(SortCompare compare) { - if(newSize <= size) - return; - - K** nkeys = new K*[newSize]; - V** nvalues = new V*[newSize]; - - if(keys != nullptr) { - for(unsigned i = 0; i < size; i++) { - nkeys[i] = keys[i]; - nvalues[i] = values[i]; - } - - delete[] keys; - delete[] values; - } - for(unsigned i = size; i < newSize; i++) { - nkeys[i] = new K(); - nvalues[i] = new V(); - } - - keys = nkeys; - values = nvalues; - size = newSize; -} - -template int HashMap::indexOf(const K& key) const -{ - for(unsigned i = 0; i < currentIndex; i++) { - if(cb_comparator) { - if(cb_comparator(key, *keys[i])) { - return i; - } - } else { - if(key == *keys[i]) { - return i; + auto n = count(); + for(unsigned i = 0; i < n - 1; ++i) { + for(unsigned j = 0; j < n - i - 1; ++j) { + HashMap::ElementConst e1{keys[j + 1], values[j + 1]}; + HashMap::ElementConst e2{keys[j], values[j]}; + if(compare(e1, e2)) { + std::swap(keys[j], keys[j + 1]); + std::swap(values[j], values[j + 1]); } } } - return -1; -} - -template void HashMap::removeAt(unsigned index) -{ - if(index >= currentIndex) - return; - - for(unsigned i = index + 1; i < size; i++) { - *keys[i - 1] = *keys[i]; - *values[i - 1] = *values[i]; - } - - currentIndex--; -} - -template void HashMap::clear() -{ - if(keys != nullptr) { - for(unsigned i = 0; i < size; i++) { - delete keys[i]; - delete values[i]; - } - delete[] keys; - delete[] values; - keys = nullptr; - values = nullptr; - } - currentIndex = 0; - size = 0; -} - -template void HashMap::setMultiple(const HashMap& map) -{ - for(unsigned i = 0; i < map.count(); i++) { - (*this)[map.keyAt(i)] = *(map.values)[i]; - } } diff --git a/Sming/Wiring/WiringList.h b/Sming/Wiring/WiringList.h new file mode 100644 index 0000000000..120520812e --- /dev/null +++ b/Sming/Wiring/WiringList.h @@ -0,0 +1,135 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * WiringList.h - Private class templates used by HashMap + * + ****/ + +#pragma once + +namespace wiring_private +{ +/** + * @brief List of object pointers + */ +template struct ObjectList { + T** values{nullptr}; + size_t size{0}; + + ~ObjectList() + { + clear(); + } + + bool allocate(size_t newSize, ...); + + void clear() + { + while(size != 0) { + delete values[--size]; + } + free(values); + values = nullptr; + } + + void remove(unsigned index) + { + delete values[index]; + memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T*)); + values[size - 1] = nullptr; + } + + T& operator[](unsigned index) + { + auto& ptr = values[index]; + if(ptr == nullptr) { + ptr = new T{}; + } + return *ptr; + } + + const T& operator[](unsigned index) const + { + return const_cast(*this)[index]; + } +}; + +/** + * @brief List of scalar values + */ +template struct ScalarList { + T* values{nullptr}; + size_t size{0}; + + ~ScalarList() + { + clear(); + } + + bool allocate(size_t newSize, const T& nil); + + void clear() + { + free(values); + values = nullptr; + size = 0; + } + + void remove(unsigned index) + { + memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T)); + } + + T& operator[](unsigned index) + { + return values[index]; + } + + const T& operator[](unsigned index) const + { + return const_cast(*this)[index]; + } +}; + +template bool ObjectList::allocate(size_t newSize, ...) +{ + if(newSize <= size) { + return true; + } + + auto newmem = realloc(values, sizeof(T*) * newSize); + if(newmem == nullptr) { + return false; + } + + values = static_cast(newmem); + std::fill_n(&values[size], newSize - size, nullptr); + + size = newSize; + return true; +} + +template bool ScalarList::allocate(size_t newSize, const T& nil) +{ + if(newSize <= size) { + return true; + } + + auto newmem = realloc(values, sizeof(T) * newSize); + if(newmem == nullptr) { + return false; + } + + values = static_cast(newmem); + std::fill_n(&values[size], newSize - size, nil); + size = newSize; + return true; +} + +template +using List = typename std::conditional::value, ScalarList, ObjectList>::type; + +} // namespace wiring_private diff --git a/tests/HostTests/modules/Wiring.cpp b/tests/HostTests/modules/Wiring.cpp index c66e3cfa50..63595ea939 100644 --- a/tests/HostTests/modules/Wiring.cpp +++ b/tests/HostTests/modules/Wiring.cpp @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include +#include class WiringTest : public TestGroup { @@ -25,16 +29,53 @@ class WiringTest : public TestGroup } } + template void println(const std::pair& e) const + { + Serial.print(e.first); + Serial.print(" = "); + Serial.println(e.second); + } + + template void print(const std::map& map) const + { + for(auto e : map) { + println(e); + } + } + + template void fillMap(T& map) + { + auto startMem = MallocCount::getCurrent(); + map[MIME_HTML] = os_random() % 0xffff; + map[MIME_TEXT] = os_random() % 0xffff; + map[MIME_JS] = os_random() % 0xffff; + map[MIME_CSS] = os_random() % 0xffff; + map[MIME_XML] = os_random() % 0xffff; + map[MIME_JSON] = os_random() % 0xffff; + map[MIME_JPEG] = os_random() % 0xffff; + map[MIME_GIF] = os_random() % 0xffff; + map[MIME_PNG] = os_random() % 0xffff; + map[MIME_SVG] = os_random() % 0xffff; + map[MIME_ICO] = os_random() % 0xffff; + map[MIME_GZIP] = os_random() % 0xffff; + map[MIME_ZIP] = os_random() % 0xffff; + Serial << "fillMap heap " << MallocCount::getCurrent() - startMem << endl; + } + void execute() override { - TEST_CASE("HashMap(String, String)") + TEST_CASE("HashMap") { + auto startMem = MallocCount::getCurrent(); + HashMap map; map["a"] = "value(a)"; map["b"] = "value(b)"; map["c"] = "value(c)"; map["d"] = "value(d)"; + Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + print(map); for(auto e : map) { @@ -51,14 +92,82 @@ class WiringTest : public TestGroup print(map); } - TEST_CASE("Vector(String)") + TEST_CASE("HashMap") { - Vector vector; + using TestMap = HashMap; + TestMap map; + fillMap(map); + print(map); + + Serial.println(); + + using Func = Delegate; + auto time = [this](const String& description, Func function) { + Serial << description << " ..." << endl; + TestMap map; + fillMap(map); + CpuCycleTimer timer; + function(map); + auto elapsed = timer.elapsedTime(); + print(map); + Serial << "... took " << elapsed.toString() << endl << endl; + }; + + time("sort by key String", [](auto& map) { + map.sort([](const auto& e1, const auto& e2) { return toString(e1.key()) < toString(e2.key()); }); + }); + + time("Sort by key numerically", + [](auto& map) { map.sort([](const auto& e1, const auto& e2) { return e1.key() < e2.key(); }); }); + + time("Sort by value", + [](auto& map) { map.sort([](const auto& e1, const auto& e2) { return e1.value() < e2.value(); }); }); + } + + TEST_CASE("std::map") + { + std::map map; + fillMap(map); + print(map); + } + + TEST_CASE("Vector") + { + auto startMem = MallocCount::getCurrent(); + + Vector vector(4); vector.add("value(a)"); vector.add("value(b)"); vector.add("value(c)"); vector.add("value(d)"); + Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + + for(auto& e : vector) { + Serial.println(e); + } + + for(auto& e : vector) { + e += ": gobbed"; + } + + for(auto& e : vector) { + Serial.println(e); + } + } + + TEST_CASE("std::vector") + { + auto startMem = MallocCount::getCurrent(); + + std::vector vector; + vector.push_back("value(a)"); + vector.push_back("value(b)"); + vector.push_back("value(c)"); + vector.push_back("value(d)"); + + Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + for(auto& e : vector) { Serial.println(e); } From d21bf5afea8f6846418bacb199295cb84e714bf2 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 26 Sep 2022 13:50:56 +0100 Subject: [PATCH 30/58] Enable better printing support for Storage/IFS classes, BitSet, TRange (#2557) - Classes don't need to be virtual to support `printTo` method - Avoid `strlen` call in `Print::println()` - Fix issue with streaming operator and char[] - Replace String += operator overloads with template method - Update HostTests using Serial instead of debugf() - Add BitSet printTo() - Update HostTests printing - Revise Storage/IFS debug printing, making Device, Partition and various IFS classes printable - Add TRange printing --- Sming/Components/FlashString | 2 +- Sming/Components/IFS | 2 +- Sming/Components/Network/src/IpAddress.h | 4 +- .../Network/src/Network/Http/HttpParams.h | 4 +- .../Network/src/Network/Mqtt/MqttBuffer.h | 4 +- Sming/Components/Storage/src/Debug.cpp | 35 ++------- Sming/Components/Storage/src/Device.cpp | 12 +++ Sming/Components/Storage/src/Partition.cpp | 21 +++++ .../Storage/src/include/Storage/Debug.h | 1 - .../Storage/src/include/Storage/Device.h | 3 + .../Storage/src/include/Storage/Partition.h | 3 + .../src/include/Storage/PartitionTable.h | 5 ++ Sming/Core/Data/BitSet.h | 25 ++++++ Sming/Core/Data/Range.h | 9 ++- Sming/Libraries/LittleFS | 2 +- .../samples/Upgrade/app/application.cpp | 16 ++-- Sming/Services/Profiling/MinMax.h | 4 +- Sming/Wiring/Print.h | 31 ++++++-- Sming/Wiring/WString.h | 59 +++----------- samples/Basic_ProgMem/app/TestProgmem.cpp | 26 +++---- samples/Basic_Ssl/app/application.cpp | 2 +- samples/Basic_Tasks/include/AnalogueReader.h | 2 +- tests/HostTests/modules/BitSet.cpp | 6 +- .../modules/Network/Arch/Host/HttpRequest.cpp | 1 + tests/HostTests/modules/Network/Http.cpp | 31 ++++---- tests/HostTests/modules/Network/Url.cpp | 16 ++-- tests/HostTests/modules/Precache.cpp | 2 +- tests/HostTests/modules/Storage.cpp | 3 +- tests/HostTests/modules/String.cpp | 8 +- tests/HostTests/modules/TemplateStream.cpp | 4 +- tests/HostTests/modules/Timers.cpp | 78 +++++-------------- 31 files changed, 205 insertions(+), 216 deletions(-) diff --git a/Sming/Components/FlashString b/Sming/Components/FlashString index 9daf0d5b3b..0045c67179 160000 --- a/Sming/Components/FlashString +++ b/Sming/Components/FlashString @@ -1 +1 @@ -Subproject commit 9daf0d5b3bcba93ba7a2d749638e8d0fdbe016ed +Subproject commit 0045c67179833555256e2c3e0e3b82eaca3dc851 diff --git a/Sming/Components/IFS b/Sming/Components/IFS index a736cae1b7..1aaa86e1e1 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit a736cae1b795b70560ebdd425b7329b3bec23fa2 +Subproject commit 1aaa86e1e1ffba3c939c9f32caf91bae63325070 diff --git a/Sming/Components/Network/src/IpAddress.h b/Sming/Components/Network/src/IpAddress.h index 29a2102d83..c092e8f356 100644 --- a/Sming/Components/Network/src/IpAddress.h +++ b/Sming/Components/Network/src/IpAddress.h @@ -41,7 +41,7 @@ using ip4_addr_t = ip_addr_t; * @brief A class to make it easier to handle and pass around IP addresses * @ingroup wiring */ -class IpAddress : public Printable +class IpAddress { private: ip_addr_t address{0}; ///< IPv4 address @@ -191,7 +191,7 @@ class IpAddress : public Printable return *this; } - size_t printTo(Print& p) const override; + size_t printTo(Print& p) const; }; inline String toString(IpAddress address) diff --git a/Sming/Components/Network/src/Network/Http/HttpParams.h b/Sming/Components/Network/src/Network/Http/HttpParams.h index ecbd4240b1..b13d29f6e3 100644 --- a/Sming/Components/Network/src/Network/Http/HttpParams.h +++ b/Sming/Components/Network/src/Network/Http/HttpParams.h @@ -31,7 +31,7 @@ * @ingroup http * */ -class HttpParams : public HashMap, public Printable +class HttpParams : public HashMap { public: HttpParams() = default; @@ -69,7 +69,7 @@ class HttpParams : public HashMap, public Printable } // Printable - size_t printTo(Print& p) const override; + size_t printTo(Print& p) const; /** * @brief Printable output for debugging diff --git a/Sming/Components/Network/src/Network/Mqtt/MqttBuffer.h b/Sming/Components/Network/src/Network/Mqtt/MqttBuffer.h index 370836105a..f7da302ef1 100644 --- a/Sming/Components/Network/src/Network/Mqtt/MqttBuffer.h +++ b/Sming/Components/Network/src/Network/Mqtt/MqttBuffer.h @@ -16,7 +16,7 @@ /** * @brief Helper class to simplify printing and parsing message buffers */ -class MqttBuffer : public Printable +class MqttBuffer { public: MqttBuffer(const mqtt_buffer_t& buf) : buf(buf) @@ -28,7 +28,7 @@ class MqttBuffer : public Printable return String(reinterpret_cast(buf.data), buf.length); } - size_t printTo(Print& p) const override + size_t printTo(Print& p) const { return p.write(buf.data, buf.length); } diff --git a/Sming/Components/Storage/src/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp index 422c0573b1..1ff281190b 100644 --- a/Sming/Components/Storage/src/Debug.cpp +++ b/Sming/Components/Storage/src/Debug.cpp @@ -6,29 +6,12 @@ namespace Storage { namespace Debug { -void printPartition(Print& out, Partition part, bool includeDevice) -{ - out.print(part.name()); - if(includeDevice) { - out.print(" on "); - out.print(part.getDeviceName()); - } - out.print(" ("); - out.print(part.typeString()); - out.print(_F(" @ 0x")); - out.print(part.address(), HEX); - out.print(_F(", size 0x")); - out.print(part.size(), HEX); - out.println(")"); -} - void listPartitions(Print& out) { out.println(); out.println(_F("Registered partitions:")); for(auto part : Storage::findPartition()) { - out.print("- "); - printPartition(out, part); + out << "- " << part << endl; } out.println(); } @@ -38,14 +21,8 @@ void listDevices(Print& out, bool fullPartitionInfo) out.println(); out.println(_F("Registered storage devices:")); for(auto& dev : Storage::getDevices()) { - out.print(" name = '"); - out.print(dev.getName()); - out.print(_F("', type = ")); - out.print(toString(dev.getType())); - out.print(_F(", size = 0x")); - out.print(dev.getSize(), HEX); - out.print(_F(", partitions:")); - if(dev.partitions().count() == 0) { + out << " " << dev << _F(". Partitions:"); + if(!dev.partitions()) { out.println(_F(" None.")); continue; } @@ -53,11 +30,9 @@ void listDevices(Print& out, bool fullPartitionInfo) out.println(); for(auto part : dev.partitions()) { if(fullPartitionInfo) { - out.print(" "); - printPartition(out, part, false); + out << " " << part << endl; } else { - out.print(" "); - out.print(part.name()); + out << " " << part.name(); } } out.println(); diff --git a/Sming/Components/Storage/src/Device.cpp b/Sming/Components/Storage/src/Device.cpp index 127396828a..d7aaa49d71 100644 --- a/Sming/Components/Storage/src/Device.cpp +++ b/Sming/Components/Storage/src/Device.cpp @@ -12,6 +12,7 @@ #include "include/Storage/Device.h" #include "include/Storage/partition_info.h" #include +#include #include namespace @@ -109,4 +110,15 @@ bool Device::loadPartitions(Device& source, uint32_t tableOffset) return false; } +size_t Device::printTo(Print& p) const +{ + size_t n{0}; + n += p.print(getName()); + n += p.print(_F(": type ")); + n += p.print(getType()); + n += p.print(_F(", size 0x")); + n += p.print(getSize(), HEX); + return n; +} + } // namespace Storage diff --git a/Sming/Components/Storage/src/Partition.cpp b/Sming/Components/Storage/src/Partition.cpp index 4b08654b17..0cb6af2554 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -11,6 +11,7 @@ #include "include/Storage/Partition.h" #include "include/Storage/Device.h" #include +#include #include using namespace Storage; @@ -248,4 +249,24 @@ bool Partition::erase_range(uint32_t offset, size_t size) return mDevice ? mDevice->erase_range(addr, size) : false; } +size_t Partition::printTo(Print& p) const +{ + size_t n{0}; + if(*this) { + n += p.print(getDeviceName()); + n += p.print('/'); + n += p.print(name()); + n += p.print(" ("); + n += p.print(typeString()); + n += p.print(" @ 0x"); + n += p.print(address(), HEX); + n += p.print(_F(", size 0x")); + n += p.print(size(), HEX); + n += p.print(')'); + } else { + n += p.print(_F("(none)")); + } + return n; +} + } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/Debug.h b/Sming/Components/Storage/src/include/Storage/Debug.h index 74c99c3b57..113a1dd19e 100644 --- a/Sming/Components/Storage/src/include/Storage/Debug.h +++ b/Sming/Components/Storage/src/include/Storage/Debug.h @@ -7,7 +7,6 @@ namespace Storage { namespace Debug { -void printPartition(Print& out, Partition part, bool includeDevice = true); void listPartitions(Print& out); void listDevices(Print& out, bool fullPartitionInfo = true); diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index c6100e1561..b8ce634555 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include "PartitionTable.h" @@ -139,6 +140,8 @@ class Device : public LinkedObjectTemplate */ virtual bool erase_range(uint32_t address, size_t size) = 0; + size_t printTo(Print& p) const; + protected: PartitionTable mPartitions; }; diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 834e3126af..18eb0930ac 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -26,6 +26,7 @@ ****/ #pragma once +#include #include #include #include @@ -370,6 +371,8 @@ class Partition */ size_t getBlockSize() const; + size_t printTo(Print& p) const; + protected: Device* mDevice{nullptr}; const Info* mPart{nullptr}; diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index 06033d6640..a243d803bb 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -22,6 +22,11 @@ class PartitionTable { } + explicit operator bool() const + { + return mCount != 0; + } + /** * @name Partition search * @{ diff --git a/Sming/Core/Data/BitSet.h b/Sming/Core/Data/BitSet.h index 27aaef3d76..2b45d5d3fd 100644 --- a/Sming/Core/Data/BitSet.h +++ b/Sming/Core/Data/BitSet.h @@ -17,6 +17,7 @@ #include #include #include +#include /** * @brief Manage a set of bit values using enumeration @@ -366,6 +367,30 @@ template class BitSet return any() ? &BitSet::IfHelper : 0; } + /** + * @brief Class template to print the contents of a BitSet to a String + * @note Requires an implementation of `toString(E)` + */ + size_t printTo(Print& p, const String& separator = ", ") const + { + extern String toString(E e); + + size_t n{0}; + + for(unsigned i = 0; i < size(); ++i) { + auto e = E(i); + if(!test(e)) { + continue; + } + if(n != 0) { + n += p.print(separator); + } + n += p.print(e); + } + + return n; + } + private: void IfHelper() const { diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index 0a06825a03..67f399c185 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -82,7 +82,7 @@ template struct TRange { /** * @brief Determine if range contains a value */ - bool contains(T value) + bool contains(T value) const { return (value >= min) && (value <= max); } @@ -90,7 +90,7 @@ template struct TRange { /** * @brief Clip values to within the range */ - T clip(T value) + T clip(T value) const { return (value < min) ? min : (value > max) ? max : value; } @@ -122,6 +122,11 @@ template struct TRange { s += max; return s; } + + operator String() const + { + return toString(); + } }; template inline String toString(TRange range) diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 804705b99f..27be7f5b4b 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 804705b99f95e5297fa193ad3c5aff12f32f1ec0 +Subproject commit 27be7f5b4bd59cd4e44d8a1e05f8d9bed740feca diff --git a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp index 516616749d..009c1ed25a 100644 --- a/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp +++ b/Sming/Libraries/OtaUpgradeMqtt/samples/Upgrade/app/application.cpp @@ -98,19 +98,19 @@ void showInfo() Serial.printf(_F("System Chip ID: %x\r\n"), system_get_chip_id()); int total = 0; - for(auto it = OtaManager.getBootPartitions(); it; ++it) { - debug_d("ROM %s: 0x%08x, SubType: %s", it->name().c_str(), it->address(), - toLongString(it->type(), it->subType()).c_str()); + for(auto part : OtaManager.getBootPartitions()) { + Serial.println(part); total++; } - debug_d("======================="); - debug_d("Bootable ROMs found: %d", total); + Serial.println(_F("=======================")); + Serial << _F("Bootable ROMs found: ") << total << endl; auto part = OtaManager.getRunningPartition(); - Serial.printf(_F("\r\nCurrently running %s: 0x%08x. Application version: %s\r\n"), part.name().c_str(), - part.address(), APP_VERSION); - Serial.println(); + Serial << _F("\r\n" + "Currently running ") + << part.name() << ": 0x" << String(part.address(), HEX) << _F(". Application version: ") << APP_VERSION + << endl; } void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) diff --git a/Sming/Services/Profiling/MinMax.h b/Sming/Services/Profiling/MinMax.h index d1d3cf542f..fe6f30bf86 100644 --- a/Sming/Services/Profiling/MinMax.h +++ b/Sming/Services/Profiling/MinMax.h @@ -19,7 +19,7 @@ namespace Profiling /** * @brief Class to track minimum and maximum values of a set of data, with average, total and count */ -template class MinMax : public Printable +template class MinMax { public: MinMax(const String& title) : title(title) @@ -57,7 +57,7 @@ template class MinMax : public Printable return count; } - size_t printTo(Print& p) const override; + size_t printTo(Print& p) const; private: String title; diff --git a/Sming/Wiring/Print.h b/Sming/Wiring/Print.h index 2a35307a41..f9ca622aee 100644 --- a/Sming/Wiring/Print.h +++ b/Sming/Wiring/Print.h @@ -179,13 +179,27 @@ class Print return printFloat(num, digits); } + /* + * Helper class using SFINAE to identify *any* class with a `printTo` method, even if not a base of `Printable`. + * + * https://stackoverflow.com/a/257382 + */ + template class has_printTo + { + template static uint8_t test(decltype(&C::printTo)); + template static uint32_t test(...); + + public: + enum { value = (sizeof(test(0)) == 1) }; + }; + /** @brief Prints a Printable object to output stream - * @param p Object to print + * @param obj Object to print * @retval size_t Quantity of characters written to stream */ - size_t print(const Printable& p) + template typename std::enable_if::value, size_t>::type print(const T& obj) { - return p.printTo(*this); + return obj.printTo(*this); } /** @brief Prints a String to output stream @@ -212,7 +226,7 @@ class Print */ size_t println() { - return print("\r\n"); + return write("\r\n", 2); } /** @brief Print value plus newline to output stream @@ -246,7 +260,14 @@ class Print } }; -template Print& operator<<(Print& p, const T& value) +inline Print& operator<<(Print& p, const char value[]) +{ + p.print(value); + return p; +} + +template +typename std::enable_if::value, Print&>::type operator<<(Print& p, const T& value) { p.print(value); return p; diff --git a/Sming/Wiring/WString.h b/Sming/Wiring/WString.h index f73324b134..054065b1bd 100644 --- a/Sming/Wiring/WString.h +++ b/Sming/Wiring/WString.h @@ -346,6 +346,14 @@ class String bool concat(unsigned long long num, unsigned char base = 10, unsigned char width = 0, char pad = '0'); bool concat(float num); bool concat(double num); + + template + constexpr typename std::enable_if::value && !std::is_convertible::value, bool>::type + concat(E value) + { + extern String toString(E); + return concat(toString(value)); + } /** @} */ /** @@ -371,55 +379,10 @@ class String concat(cstr); return (*this); } - String& operator+=(char c) - { - concat(c); - return (*this); - } - String& operator+=(unsigned char num) - { - concat(num); - return (*this); - } - String& operator+=(int num) - { - concat(num); - return (*this); - } - String& operator+=(unsigned int num) - { - concat(num); - return (*this); - } - String& operator+=(long num) - { - concat(num); - return (*this); - } - String& operator+=(long long num) - { - concat(num); - return (*this); - } - String& operator+=(unsigned long num) - { - concat(num); - return (*this); - } - String& operator+=(unsigned long long num) + template String& operator+=(T value) { - concat(num); - return (*this); - } - String& operator+=(float num) - { - concat(num); - return (*this); - } - String& operator+=(double num) - { - concat(num); - return (*this); + concat(value); + return *this; } /** @} */ diff --git a/samples/Basic_ProgMem/app/TestProgmem.cpp b/samples/Basic_ProgMem/app/TestProgmem.cpp index f922abf4b2..aac4f916b1 100644 --- a/samples/Basic_ProgMem/app/TestProgmem.cpp +++ b/samples/Basic_ProgMem/app/TestProgmem.cpp @@ -49,9 +49,7 @@ void testPSTR(Print& out) // Note that characters after first nul won't be shown ... out.print("> demoPSTR1 (print char*): "); - out.print('"'); - out.print(_FLOAD(demoPSTR1)); - out.println('"'); + out << '"' << _FLOAD(demoPSTR1) << '"' << endl; // ... now they will: note buf will be aligned up to next dword boundary though out.print("> demoPSTR1 (write): "); @@ -67,9 +65,7 @@ void testPSTR(Print& out) char buf2[100]; strncpy_P(buf2, externalPSTR1, sizeof(buf2)); buf2[sizeof(buf2) - 1] = '\0'; - out.print('"'); - out.print(buf2); - out.println('"'); + out << '"' << buf2 << '"' << endl; // out.print("> PSTR_ARRAY: "); @@ -130,8 +126,7 @@ void testFSTR(Print& out) char data[5]; } demoArray1 PROGMEM = {{5}, {1, 2, 3, 4, 5}}; auto& arr = demoArray1.object.as>(); - arr.printTo(out); - out.println(); + out << arr << endl; // Test equality operators #define TEST(_test) out.printf(_F("%s: %s\n"), (_test) ? _F("PASS") : _F("FAIL"), _F(#_test)); @@ -150,11 +145,11 @@ void testFSTR(Print& out) // Table entries may be accessed directly as they are word-aligned out.println(_F("FSTR tables -")); - out.printf(_F(" fstr1 = '%s'\n"), String(table[0]).c_str()); - out.printf(_F(" fstr1.length() = %" PRIu32 "\n"), table[0].length()); - out.printf(_F(" entries = %" PRIu32 "\n"), table.length()); + out << _F(" fstr1 = '") << table[0] << endl; + out << _F(" fstr1.length() = ") << table[0].length() << endl; + out << _F(" entries = ") << table.length() << endl; - out.println("< testFSTR() end\n"); + out.println("< testFSTR() end\r\n"); } /* @@ -171,14 +166,15 @@ void testSpeed(Print& out) _FPUTS("Baseline test, read string in RAM..."); timer.start(); - for(unsigned i = 0; i < iterations; ++i) + for(unsigned i = 0; i < iterations; ++i) { tmp += sumBuffer(demoText, sizeof(demoText)); + } baseline = timer.elapsedTime(); - out.printf("Elapsed: %" PRIu32 "\n", baseline); + out << "Elapsed: " << baseline << endl; #define END() \ elapsed = timer.elapsedTime(); \ - out.printf("Elapsed: %" PRIu32 " (baseline + %" PRIu32 ")\n", elapsed, elapsed - baseline); + out << "Elapsed: " << elapsed << " (baseline + " << elapsed - baseline << ')' << endl; _FPUTS("Load PSTR into stack buffer..."); timer.start(); diff --git a/samples/Basic_Ssl/app/application.cpp b/samples/Basic_Ssl/app/application.cpp index 44d93887e2..6c89546433 100644 --- a/samples/Basic_Ssl/app/application.cpp +++ b/samples/Basic_Ssl/app/application.cpp @@ -46,7 +46,7 @@ int onDownload(HttpConnection& connection, bool success) auto ssl = connection.getSsl(); if(ssl != nullptr) { - ssl->printTo(Serial); + Serial.print(*ssl); } Serial << _F("Time to connect and download page: ") << elapsed.toString() << endl; diff --git a/samples/Basic_Tasks/include/AnalogueReader.h b/samples/Basic_Tasks/include/AnalogueReader.h index b1264f2ed6..e20a08de7e 100644 --- a/samples/Basic_Tasks/include/AnalogueReader.h +++ b/samples/Basic_Tasks/include/AnalogueReader.h @@ -157,7 +157,7 @@ ANALOGUE_READER(void)::onNotify(Notify code) groupStartTicks = sampleTimer.ticks(); restartSampler = true; - Serial << F("sampleIntervalTicks = ") << sampleIntervalTicks << endl; + Serial << _F("sampleIntervalTicks = ") << sampleIntervalTicks << endl; break; default:; } diff --git a/tests/HostTests/modules/BitSet.cpp b/tests/HostTests/modules/BitSet.cpp index 4f0b85a85b..7ce28f7e58 100644 --- a/tests/HostTests/modules/BitSet.cpp +++ b/tests/HostTests/modules/BitSet.cpp @@ -72,8 +72,7 @@ class BitSetTest : public TestGroup TEST_CASE("Operations") { - Serial.print(_F("fixedBasket contains: ")); - Serial.println(toString(fixedBasket)); + Serial << _F("fixedBasket contains: ") << fixedBasket << endl; FruitBasket basket; REQUIRE(basket.value() == 0); @@ -123,8 +122,7 @@ class BitSetTest : public TestGroup { using NumberSet = BitSet; NumberSet numbers = uint32_t(0x12345678); - Serial.print(_F("numbers = ")); - Serial.println(toString(numbers)); + Serial << _F("numbers = ") << numbers << endl; REQUIRE(numbers.value() == 0x12345678U); numbers = NumberSet{}; diff --git a/tests/HostTests/modules/Network/Arch/Host/HttpRequest.cpp b/tests/HostTests/modules/Network/Arch/Host/HttpRequest.cpp index 04123022d3..5782443abb 100644 --- a/tests/HostTests/modules/Network/Arch/Host/HttpRequest.cpp +++ b/tests/HostTests/modules/Network/Arch/Host/HttpRequest.cpp @@ -52,6 +52,7 @@ class HttpRequestTest : public TestGroup server->paths.setDefault([](HttpRequest& request, HttpResponse& response) { auto path = request.uri.getRelativePath(); bool ok = response.sendFile(path); + (void)ok; debug_i("Request from '%s' for '%s': %s", request.uri.Host.c_str(), path.c_str(), ok ? "OK" : "FAIL"); }); diff --git a/tests/HostTests/modules/Network/Http.cpp b/tests/HostTests/modules/Network/Http.cpp index e8b1e2657f..ff4e329620 100644 --- a/tests/HostTests/modules/Network/Http.cpp +++ b/tests/HostTests/modules/Network/Http.cpp @@ -24,11 +24,12 @@ class HttpTest : public TestGroup #if DEBUG_VERBOSE_LEVEL == DBG for(int i = 0; i < 100; ++i) { auto err = HttpError(i); - debug_d("httpError(%d) = \"%s\", \"%s\"", i, toString(err).c_str(), httpGetErrorDescription(err).c_str()); + Serial << _F("httpError(") << i << ") = \"" << err << "\", \"" << httpGetErrorDescription(err) << '"' + << endl; } for(int i = 100; i < 550; ++i) { - debug_d("HTTP Status(%d) = \"%s\"", i, toString(HttpStatus(i)).c_str()); + Serial << _F("HTTP Status(") << i << ") = \"" << HttpStatus(i) << '"' << endl; } #endif @@ -47,7 +48,7 @@ class HttpTest : public TestGroup static void printHeaders(const HttpHeaders& headers) { #if DEBUG_VERBOSE_LEVEL == DBG - debugf(" count: %d", headers.count()); + Serial << _F(" count: ") << headers.count() << endl; for(unsigned i = 0; i < headers.count(); ++i) { String s = headers[i]; m_printHex(" ", s.c_str(), s.length(), 0, 32); @@ -57,7 +58,7 @@ class HttpTest : public TestGroup void profileHttpHeaders() { - debugf("\nPROFILING"); + Serial.println(_F("\r\nPROFILING")); // Allocate everything on the heap so we can track memory usage auto freeHeap = system_get_free_heap_size(); @@ -80,18 +81,18 @@ class HttpTest : public TestGroup headers[F("Vary")] = _F("Accept-Encoding"); headers[F("X-Fastly-Request-ID")] = _F("38ef411e0ec3bf681d29d8b4b51f3516d3ef9e03"); auto totalElapsed = timer.elapsedTime(); - debugf("Set header values"); - debugf(" Elapsed standard: %s, total: %s, heap used: %u", standardElapsed.toString().c_str(), - totalElapsed.toString().c_str(), freeHeap - system_get_free_heap_size()); + Serial.println(_F("Set header values")); + Serial << _F(" Elapsed standard: ") << standardElapsed.toString() << ", total: " << totalElapsed.toString() + << ", heap used: " << freeHeap - system_get_free_heap_size() << endl; // Query header value by field name auto queryByEnum = [&](HttpHeaderFieldName name) { - debugf(" header[\"%s\"]: %s", headers.toString(name).c_str(), headers[name].c_str()); + Serial << _F(" header[\"") << headers.toString(name) << "\"]: " << headers[name] << endl; }; auto queryByString = [&](const String& name) { - debugf(" header[\"%s\"]: %s", name.c_str(), headers[name].c_str()); + Serial << _F(" header[\"") << name << "\"]: " << headers[name] << endl; }; - debugf("Query header values"); + Serial.println(_F("Query header values")); timer.start(); queryByEnum(HTTP_HEADER_CONTENT_ENCODING); queryByEnum(HTTP_HEADER_CONTENT_LENGTH); @@ -106,15 +107,15 @@ class HttpTest : public TestGroup queryByString("Vary"); queryByString("X-Fastly-Request-ID"); totalElapsed = timer.elapsedTime(); - debugf(" Elapsed standard: %u, total: %u", standardElapsed, totalElapsed); - debugf(" Elapsed standard: %s, total: %s", standardElapsed.toString().c_str(), - totalElapsed.toString().c_str()); + Serial << _F(" Elapsed standard: ") << standardElapsed << ", total: " << totalElapsed << endl; + Serial << _F(" Elapsed standard: ") << standardElapsed.toString() << ", total: " << totalElapsed.toString() + << endl; // Print header values - accessed by index - debugf("Printing %u headers", headers.count()); + Serial << _F("Printing ") << headers.count() << _F(" headers") << endl; timer.start(); printHeaders(headers); - debugf(" Elapsed: %s", timer.elapsedTime().toString().c_str()); + Serial << _F(" Elapsed: ") << timer.elapsedTime().toString() << endl; delete headersPtr; } diff --git a/tests/HostTests/modules/Network/Url.cpp b/tests/HostTests/modules/Network/Url.cpp index f03860b9e3..812de0fb83 100644 --- a/tests/HostTests/modules/Network/Url.cpp +++ b/tests/HostTests/modules/Network/Url.cpp @@ -22,7 +22,7 @@ class UrlTest : public TestGroup TEST_CASE("formUrlParser test") { auto testUrl = [this](const FlashString& urlText, const char* param) { - debugf("URL '%s'", String(urlText).c_str()); + Serial << _F("URL \"") << urlText << '"' << endl; Url url(urlText); String query = url.Query; const char* p = query.c_str(); @@ -36,7 +36,7 @@ class UrlTest : public TestGroup formUrlParser(request, nullptr, PARSE_DATAEND); printParams(request.postParams); String cid = request.getPostParameter("cid"); - debugf("cid = %s", cid.c_str()); + Serial << _F("cid = ") << cid << endl; REQUIRE(cid == param); }; @@ -50,8 +50,8 @@ class UrlTest : public TestGroup TEST_CASE("HttpRequest getQueryParameter()") { request.uri = FS_URL2; - debugf("URL = \"%s\"", request.uri.toString().c_str()); - debugf("cid = %s", request.getQueryParameter("cid").c_str()); + Serial << _F("URL = \"") << request.uri << '"' << endl; + Serial << _F("cid = ") << request.getQueryParameter("cid") << endl; } TEST_CASE("HttpRequest postParams test"); @@ -60,10 +60,10 @@ class UrlTest : public TestGroup "param+1=Mary+had+a+little+lamb%2c¶m+2=It%27s+fleece+was+very+red.¶m+3=The+" "reason+for+this+was%2c+you+see¶m+4=It+had+a+pickaxe+through+its+head."); HttpParams params; - params["param 1"] = "Mary had a little lamb,"; - params["param 2"] = "It's fleece was very red."; - params["param 3"] = "The reason for this was, you see"; - params["param 4"] = "It had a pickaxe through its head."; + params["param 1"] = F("Mary had a little lamb,"); + params["param 2"] = F("It's fleece was very red."); + params["param 3"] = F("The reason for this was, you see"); + params["param 4"] = F("It had a pickaxe through its head."); UrlencodedOutputStream stream(params); char buffer[256]; unsigned n = 0; diff --git a/tests/HostTests/modules/Precache.cpp b/tests/HostTests/modules/Precache.cpp index 9a02090f6e..c70a9c2bfc 100644 --- a/tests/HostTests/modules/Precache.cpp +++ b/tests/HostTests/modules/Precache.cpp @@ -22,7 +22,7 @@ class PreCacheTest : public TestGroup sum += i; } IRAM_PRECACHE_END(hosttests_test); - debugf("Sum = %u", sum); + Serial << _F("Sum = ") << sum << endl; REQUIRE(sum == 499500); } }; diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index 7579dd8999..fc329e7586 100644 --- a/tests/HostTests/modules/Storage.cpp +++ b/tests/HostTests/modules/Storage.cpp @@ -64,8 +64,7 @@ class PartitionTest : public TestGroup void listPartitions() { for(auto part : Storage::findPartition()) { - Serial.print("* "); - Storage::Debug::printPartition(Serial, part); + Serial << "* " << part << endl; testRead(part, 0xE0, 0x20, true); testRead(part, 10, 20, true); diff --git a/tests/HostTests/modules/String.cpp b/tests/HostTests/modules/String.cpp index 42d07457f7..ab0e0d87fa 100644 --- a/tests/HostTests/modules/String.cpp +++ b/tests/HostTests/modules/String.cpp @@ -126,8 +126,8 @@ class StringTest : public TestGroup String path = "/path/to"; String query; - debugf("path = \"%s\"", path.c_str()); - debugf("query = \"%s\"", query.c_str()); + Serial << _F("path = \"") << path << '"' << endl; + Serial << _F("query = \"") << query << '"' << endl; TEST_CASE("validity check") { @@ -142,14 +142,14 @@ class StringTest : public TestGroup TEST_CASE("string + nullstr") { String s = path + query; - debugf("path + query = \"%s\"", s.c_str()); + Serial << _F("path + query = \"") << s << '"' << endl; REQUIRE(s == path); } TEST_CASE("nullstr + string") { String s = query + path; - debugf("query + path = \"%s\"", s.c_str()); + Serial << _F("query + path = \"") << s << '"' << endl; REQUIRE(s == path); } } diff --git a/tests/HostTests/modules/TemplateStream.cpp b/tests/HostTests/modules/TemplateStream.cpp index eb618e0625..3f325130e7 100644 --- a/tests/HostTests/modules/TemplateStream.cpp +++ b/tests/HostTests/modules/TemplateStream.cpp @@ -126,14 +126,14 @@ class TemplateStreamTest : public TestGroup { HostFileStream fs("test-src1.out", File::CreateNewAlways | File::WriteOnly); int res = fs.copyFrom(&tmpl); - debug_e("copyfrom(src) = %d", res); + Serial << _F("copyfrom(src) = ") << res << endl; tmpl.gotoSection(0); } { HostFileStream fs("test-src2.out", File::CreateNewAlways | File::WriteOnly); int res = fs.copyFrom(&tmpl); - debug_e("copyfrom(src) = %d", res); + Serial << _F("copyfrom(src) = ") << res << endl; tmpl.gotoSection(0); } #endif diff --git a/tests/HostTests/modules/Timers.cpp b/tests/HostTests/modules/Timers.cpp index 6f9c4e943b..5e0eda4fba 100644 --- a/tests/HostTests/modules/Timers.cpp +++ b/tests/HostTests/modules/Timers.cpp @@ -29,7 +29,7 @@ class CallbackTimerTest : public TestGroup { System.queueCallback( [](void* param) { - debugf("timer1 expired"); + Serial.println(_F("timer1 expired")); auto tmr = static_cast(param); if(++tmr->count == 5) { tmr->stop(); @@ -47,11 +47,7 @@ class CallbackTimerTest : public TestGroup checkCallbackTimer(); checkCallbackTimer(); -#define SHOW_SIZE(Type) \ - { \ - Serial.print("sizeof(" #Type ") = "); \ - Serial.println(sizeof(Type)); \ - } +#define SHOW_SIZE(Type) Serial << _F("sizeof(" #Type ") = ") << sizeof(Type) << endl SHOW_SIZE(os_timer_t); SHOW_SIZE(OsTimerApi); @@ -114,7 +110,7 @@ class CallbackTimerTest : public TestGroup tmp->initializeMs<1200>( [](void* arg) { auto self = static_cast(arg); - debugf("%s fired", String(self->timer64).c_str()); + Serial << self->timer64 << _F(" fired") << endl; }, this); tmp->startOnce(); @@ -127,15 +123,13 @@ class CallbackTimerTest : public TestGroup Serial.println(longTimer.toString()); Serial.print("Elapsed ticks = "); Serial.println(ticks - longStartTicks); - debugf("Finally done!"); + Serial.println(_F("Finally done!")); }); - Serial.print("longTimer.maxTicks = "); - Serial.println(longTimer.maxTicks()); + Serial << _F("longTimer.maxTicks = ") << longTimer.maxTicks() << endl; longTimer.setIntervalMs<15000>(); longTimer.startOnce(); longStartTicks = Timer::Clock::ticks(); - Serial.print("longTimer.start = "); - Serial.println(longStartTicks); + Serial << _F("longTimer.start = ") << longStartTicks << endl; ++activeTimerCount; Serial.println(longTimer.toString()); } @@ -155,12 +149,8 @@ class CallbackTimerTest : public TestGroup } auto mem = MallocCount::getCurrent(); - Serial.print("Timers allocated, memStart = "); - Serial.print(memStart); - Serial.print(", now mem = "); - Serial.print(mem); - Serial.print(", used = "); - Serial.println(mem - memStart); + Serial << _F("Timers allocated, memStart = ") << memStart << _F(", now mem = ") << mem << _F(", used = ") + << mem - memStart << endl; pending(); } @@ -169,12 +159,8 @@ class CallbackTimerTest : public TestGroup { TimerType timer; - Serial.print(timer); - Serial.print(", maxTicks = "); - Serial.print(TimerType::maxTicks()); - Serial.print(", maxTime = "); - Serial.print(TimerType::Micros::MaxClockTime::value()); - Serial.println(); + Serial << timer << _F(", maxTicks = ") << TimerType::maxTicks() << _F(", maxTime = ") + << TimerType::Micros::MaxClockTime::value() << endl; // CpuCycleTimer timer; // Serial.print(timer); @@ -192,30 +178,15 @@ class CallbackTimerTest : public TestGroup // const auto time = NanoTime::time(NanoTime::Microseconds, 5000); //500020107; auto ticks = timer.usToTicks(time); - Serial.print("time = "); - Serial.print(time.toString()); - Serial.print(", ticks = "); - Serial.print(ticks); - Serial.print(", "); - Serial.print(TimerType::Micros::ticksToTime(ticks).toString()); - Serial.println(); + Serial << _F("time = ") << time.toString() << _F(", ticks = ") << ticks << ", " + << TimerType::Micros::ticksToTime(ticks).toString() << endl; // auto t1 = timer.micros().template timeConst<5000>(); t1.check(); - Serial.print("t1 = "); - Serial.print(t1.toString()); - Serial.print(", "); - Serial.print(t1.clock().toString()); - Serial.print(", ticksPerUnit = "); - Serial.print(t1.ticksPerUnit()); - Serial.print(", ticks = "); - Serial.print(t1.ticks()); - Serial.print(", "); - Serial.print(t1.clockTime()); - Serial.print(", "); - Serial.print(t1.clockValue()); - Serial.println(); + Serial << _F("t1 = ") << t1.toString() << ", " << t1.clock().toString() + << ", ticksPerUnit = " << t1.ticksPerUnit() << ", ticks = " << t1.ticks() << ", " << t1.clockTime() + << ", " << t1.clockValue() << endl; // ElapseTimer et; // timer.reset<500000000>(); @@ -235,15 +206,9 @@ class CallbackTimerTest : public TestGroup // auto nanos = NanoTime::TicksConst::as(); // auto nanos = Nanos::template ticksConst(); - Serial.print("nanos = "); - Serial.print(nanos.template as().toString()); - Serial.println(); + Serial << _F("nanos = ") << nanos.template as().toString() << endl; - Serial.print("interval = "); - Serial.print(timer.getIntervalUs()); - Serial.print("us, ticks = "); - Serial.print(timer.getInterval()); - Serial.println(); + Serial << _F("interval = ") << timer.getIntervalUs() << _F("us, ticks = ") << timer.getInterval() << endl; } private: @@ -355,12 +320,9 @@ template class CallbackTimerSpeedTest : public TestGroup Serial.println(times4); Serial.println(times5); - Serial.print("Combined set/start: "); - Serial.println(times2a.getAverage() + times4.getAverage()); - Serial.print("Combined set/start, ticks: "); - Serial.println(times3a.getAverage() + times4.getAverage()); - Serial.print("Combined set/start, templated: "); - Serial.println(times2b.getAverage() + times4.getAverage()); + Serial << _F("Combined set/start: ") << times2a.getAverage() + times4.getAverage() << endl; + Serial << _F("Combined set/start, ticks: ") << times3a.getAverage() + times4.getAverage() << endl; + Serial << _F("Combined set/start, templated: ") << times2b.getAverage() + times4.getAverage() << endl; Serial.println(); } From 34a796f7e9216b892cba34220105e64b7737e3d2 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 28 Sep 2022 09:43:50 +0100 Subject: [PATCH 31/58] Tidy up and improve Vector class memory usage (#2558) This PR follows on from #2556 to reduce memory usage and performance when Vector is used with simple (scalar) values. Additional tests added. --- Sming/Wiring/WHashMap.h | 12 +- Sming/Wiring/WVector.h | 397 +++++++----------- Sming/Wiring/WiringList.h | 139 ++++-- .../app/application.cpp | 38 +- tests/HostTests/modules/Wiring.cpp | 200 ++++++--- 5 files changed, 436 insertions(+), 350 deletions(-) diff --git a/Sming/Wiring/WHashMap.h b/Sming/Wiring/WHashMap.h index 37a1685001..1b1de76155 100644 --- a/Sming/Wiring/WHashMap.h +++ b/Sming/Wiring/WHashMap.h @@ -32,6 +32,7 @@ #include #include #include "WiringList.h" +#include "Print.h" /** * @brief HashMap class template @@ -89,6 +90,15 @@ template class HashMap return &v; } + size_t printTo(Print& p) const + { + size_t n{0}; + n += p.print(k); + n += p.print(" = "); + n += p.print(v); + return n; + } + private: const K& k; Value& v; @@ -285,7 +295,7 @@ template class HashMap bool allocate(unsigned int newSize) { - return keys.allocate(newSize, K{}) && values.allocate(newSize, nil); + return keys.allocate(newSize) && values.allocate(newSize); } /** diff --git a/Sming/Wiring/WVector.h b/Sming/Wiring/WVector.h index 9f6cb46a1e..6da2e68965 100644 --- a/Sming/Wiring/WVector.h +++ b/Sming/Wiring/WVector.h @@ -22,6 +22,7 @@ #include #include #include +#include "WiringList.h" /** * @brief Vector class template @@ -74,7 +75,7 @@ template class Vector : public Countable return !operator==(rhs); } - Element& operator*() + template typename std::enable_if::type operator*() { return vector[index]; } @@ -90,72 +91,162 @@ template class Vector : public Countable }; // constructors - Vector(unsigned int initialCapacity = 10, unsigned int capacityIncrement = 10); - Vector(const Vector& rhv); - ~Vector(); + Vector(unsigned int initialCapacity = 10, unsigned int capacityIncrement = 10) : _increment(capacityIncrement) + { + _data.allocate(initialCapacity); + } + + Vector(const Vector& rhv) + { + copyFrom(rhv); + } // methods - unsigned int capacity() const; - bool contains(const Element& elem) const; - const Element& firstElement() const; + unsigned int capacity() const + { + return _data.size; + } + + bool contains(const Element& elem) const + { + return indexOf(elem) >= 0; + } + + const Element& firstElement() const + { + if(_size == 0) { + abort(); + } + + return _data[0]; + } + int indexOf(const Element& elem) const; - bool isEmpty() const; - const Element& lastElement() const; + + bool isEmpty() const + { + return _size == 0; + } + + const Element& lastElement() const + { + if(_size == 0) { + abort(); + } + + return _data[_size - 1]; + } + int lastIndexOf(const Element& elem) const; + unsigned int count() const override { return size(); } - unsigned int size() const; + + unsigned int size() const + { + return _size; + } + void copyInto(Element* array) const; + bool add(const Element& obj) { return addElement(obj); } + bool addElement(const Element& obj); bool addElement(Element* objp); + void clear() { removeAllElements(); } + bool ensureCapacity(unsigned int minCapacity); - void removeAllElements(); - bool removeElement(const Element& obj); + + void removeAllElements() + { + _data.clear(); + _size = 0; + } + + bool removeElement(const Element& obj) + { + return removeElementAt(indexOf(obj)); + } + + /** + * @brief Reduce or increase number of items + * @retval true on success, false on memory reallocation failure + * + * If increasing number of items, new items will be set to current `nil` value. + * If reducing number of items, old items will be deleted. + */ bool setSize(unsigned int newSize); - void trimToSize(); - const Element& elementAt(unsigned int index) const; + + /** + * @brief Reduce capacity to match current size + */ + void trimToSize() + { + if(_size < _data.size) { + _data.trim(_size, true); + } + } + + const Element& elementAt(unsigned int index) const + { + if(index >= _size) { + abort(); + } + return _data[index]; + } + bool insertElementAt(const Element& obj, unsigned int index); - const void remove(unsigned int index); - void removeElementAt(unsigned int index); + + bool remove(unsigned int index) + { + return removeElementAt(index); + } + + bool removeElementAt(unsigned int index); bool setElementAt(const Element& obj, unsigned int index); + const Element& get(unsigned int index) const { return elementAt(index); } - const Element& operator[](unsigned int index) const override; - Element& operator[](unsigned int index) override; + const Element& operator[](unsigned int index) const override + { + return elementAt(index); + } + + Element& operator[](unsigned int index) override + { + if(index >= _size) { + abort(); + } + return _data[index]; + } const Vector& operator=(const Vector& rhv) { - if(this != &rhv) + if(this != &rhv) { copyFrom(rhv); + } return *this; } - const Vector& operator=(const Vector&& other) noexcept // move assignment + + const Vector& operator=(Vector&& other) noexcept // move assignment { - if(_data != nullptr) { - removeAllElements(); - delete[] _data; // delete this storage - } - _data = other._data; // move - _size = other._size; - _capacity = other._capacity; - _increment = other._increment; - other._data = nullptr; // leave moved-from in valid state - other._size = 0; - other._capacity = 0; - other._increment = 0; + clear(); + _increment = 0; + std::swap(_data, other._data); + std::swap(_size, other._size); + std::swap(_increment, other._increment); return *this; } @@ -171,12 +262,12 @@ template class Vector : public Countable return Iterator(*this, count()); } - Iterator begin() const + const Iterator begin() const { return Iterator(*this, 0); } - Iterator end() const + const Iterator end() const { return Iterator(*this, count()); } @@ -185,94 +276,44 @@ template class Vector : public Countable void copyFrom(const Vector& rhv); protected: - unsigned int _size = 0; - unsigned int _capacity = 0; - unsigned int _increment; - Element** _data = nullptr; -}; - -template Vector::Vector(unsigned int initialCapacity, unsigned int capacityIncrement) -{ - _size = 0; - _capacity = initialCapacity; - _data = new Element*[_capacity]; - _increment = capacityIncrement; - if(_data == nullptr) { - _capacity = _increment = 0; - } -} + using ElementList = wiring_private::List; -template Vector::Vector(const Vector& rhv) -{ - copyFrom(rhv); -} + unsigned int _size{0}; + unsigned int _increment{0}; + ElementList _data; +}; template void Vector::copyFrom(const Vector& rhv) { - if(_data != nullptr) { - removeAllElements(); - delete[] _data; + _data.clear(); + if(!_data.allocate(rhv._data.size)) { + _size = _increment = 0; + return; } + _size = rhv._size; - _capacity = rhv._capacity; - _data = new Element*[_capacity]; _increment = rhv._increment; - if(_data == nullptr) { - _size = _capacity = _increment = 0; - } for(unsigned int i = 0; i < _size; i++) { - _data[i] = new Element(*(rhv._data[i])); + _data[i] = rhv._data[i]; } } -template Vector::~Vector() -{ - removeAllElements(); - delete[] _data; -} - -template unsigned int Vector::capacity() const -{ - return _capacity; -} - -template bool Vector::contains(const Element& elem) const -{ - return indexOf(elem) >= 0; -} - template void Vector::copyInto(Element* array) const { - if(array != nullptr) { - for(unsigned int i = 0; i < _size; i++) { - array[i] = *_data[i]; - } - } -} - -template const Element& Vector::elementAt(unsigned int index) const -{ - if(index >= _size || !_data) { - abort(); + if(array == nullptr) { + return; } - // add check for valid index - return *_data[index]; -} -template const Element& Vector::firstElement() const -{ - if(_size == 0 || !_data) { - abort(); + for(unsigned int i = 0; i < _size; i++) { + array[i] = _data[i]; } - - return *_data[0]; } template int Vector::indexOf(const Element& elem) const { for(unsigned int i = 0; i < _size; i++) { - if(*_data[i] == elem) { + if(_data[i] == elem) { return i; } } @@ -280,20 +321,6 @@ template int Vector::indexOf(const Element& elem) const return -1; } -template bool Vector::isEmpty() const -{ - return _size == 0; -} - -template const Element& Vector::lastElement() const -{ - if(_size == 0 || !_data) { - abort(); - } - - return *_data[_size - 1]; -} - template int Vector::lastIndexOf(const Element& elem) const { // check for empty vector @@ -305,7 +332,7 @@ template int Vector::lastIndexOf(const Element& elem) c do { i--; - if(*_data[i] == elem) { + if(_data[i] == elem) { return i; } } while(i != 0); @@ -313,17 +340,12 @@ template int Vector::lastIndexOf(const Element& elem) c return -1; } -template unsigned int Vector::size() const -{ - return _size; -} - template bool Vector::addElement(const Element& obj) { if(!ensureCapacity(_size + 1)) { return false; } - _data[_size++] = new Element(obj); + _data[_size++] = obj; return true; } @@ -338,22 +360,12 @@ template bool Vector::addElement(Element* objp) template bool Vector::ensureCapacity(unsigned int minCapacity) { - if(_capacity >= minCapacity) { + if(_data.size >= minCapacity) { return true; } - auto newCapacity = std::max(minCapacity, _capacity + _increment); - Element** temp = new Element*[newCapacity]; - // copy all elements - if(temp == nullptr) { - return false; - } - - _capacity = newCapacity; - memcpy(temp, _data, sizeof(Element*) * _size); - delete[] _data; - _data = temp; - return true; + auto newCapacity = std::max(minCapacity, _data.size + _increment); + return _data.allocate(newCapacity); } template bool Vector::insertElementAt(const Element& obj, unsigned int index) @@ -362,7 +374,6 @@ template bool Vector::insertElementAt(const Element& ob return addElement(obj); } - // need to verify index, right now you must know what you're doing if(index > _size) { return false; } @@ -370,66 +381,24 @@ template bool Vector::insertElementAt(const Element& ob return false; } - Element* newItem = new Element(obj); // pointer to new item - if(newItem == nullptr) { + if(!_data.insert(index, obj)) { return false; } - for(unsigned int i = index; i <= _size; i++) { - Element* tmp = _data[i]; - _data[i] = newItem; - - if(i != _size) { - newItem = tmp; - } else { - break; - } - } _size++; return true; } -template const void Vector::remove(unsigned int index) -{ - removeElementAt(index); -} - -template void Vector::removeAllElements() -{ - // avoid memory leak - for(unsigned int i = 0; i < _size; i++) { - delete _data[i]; - } - - _size = 0; -} - -template bool Vector::removeElement(const Element& obj) -{ - for(unsigned int i = 0; i < _size; i++) { - if(*_data[i] == obj) { - removeElementAt(i); - return true; - } - } - return false; -} - -template void Vector::removeElementAt(unsigned int index) +template bool Vector::removeElementAt(unsigned int index) { // check for valid index if(index >= _size) { - return; - } - - delete _data[index]; - - unsigned int i; - for(i = index + 1; i < _size; i++) { - _data[i - 1] = _data[i]; + return false; } + _data.remove(index); _size--; + return true; } template bool Vector::setElementAt(const Element& obj, unsigned int index) @@ -438,7 +407,7 @@ template bool Vector::setElementAt(const Element& obj, if(index >= _size) { return false; } - *_data[index] = obj; + _data[index] = obj; return true; } @@ -448,63 +417,23 @@ template bool Vector::setSize(unsigned int newSize) return false; } - if(newSize < _size) { - for(unsigned int i = newSize; i < _size; i++) { - delete _data[i]; - } - - _size = newSize; - } - + _data.trim(newSize, false); + _size = std::min(_size, newSize); return true; } -template void Vector::trimToSize() -{ - if(_size != _capacity) { - Element** temp = new Element*[_size]; - if(temp == nullptr) { - return; - } - - for(unsigned int i = 0; i < _size; i++) { - temp[i] = _data[i]; - } - - delete[] _data; - - _data = temp; - _capacity = _size; - } -} - -template const Element& Vector::operator[](unsigned int index) const -{ - return elementAt(index); -} - -template Element& Vector::operator[](unsigned int index) -{ - // check for valid index - //static Element dummy_writable_element; - if(index >= _size || !_data) { - //dummy_writable_element = 0; - //return dummy_writable_element; - abort(); - } - return *_data[index]; -} - template void Vector::sort(Comparer compareFunction) { - for(unsigned j = 1; j < _size; j++) // Start with 1 (not 0) - { - Element* key = _data[j]; + // Start with 1 (not 0) + for(unsigned j = 1; j < _size; j++) { + auto key = _data.values[j]; + Element& keyRef = _data[j]; + // Smaller values move up int i; - for(i = j - 1; (i >= 0) && compareFunction(*_data[i], *key) > 0; i--) // Smaller values move up - { - _data[i + 1] = _data[i]; + for(i = j - 1; (i >= 0) && compareFunction(_data[i], keyRef) > 0; i--) { + _data.values[i + 1] = _data.values[i]; } - _data[i + 1] = key; //Put key into its proper location + // Put key into its proper location + _data.values[i + 1] = key; } } diff --git a/Sming/Wiring/WiringList.h b/Sming/Wiring/WiringList.h index 120520812e..d799215cc4 100644 --- a/Sming/Wiring/WiringList.h +++ b/Sming/Wiring/WiringList.h @@ -13,119 +13,168 @@ namespace wiring_private { /** - * @brief List of object pointers + * @brief List of scalar values */ -template struct ObjectList { - T** values{nullptr}; +template struct ScalarList { + T* values{nullptr}; size_t size{0}; - ~ObjectList() + ~ScalarList() { clear(); } - bool allocate(size_t newSize, ...); + bool allocate(size_t newSize); void clear() { - while(size != 0) { - delete values[--size]; - } free(values); values = nullptr; + size = 0; + } + + bool insert(unsigned index, T value) + { + memmove(&values[index + 1], &values[index], size - index - 1); + values[index] = value; + return true; } void remove(unsigned index) { - delete values[index]; - memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T*)); - values[size - 1] = nullptr; + memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T)); } - T& operator[](unsigned index) + void trim(size_t newSize, bool reallocate) { - auto& ptr = values[index]; - if(ptr == nullptr) { - ptr = new T{}; + if(!reallocate) { + return; + } + + auto newmem = realloc(values, sizeof(T) * newSize); + if(newmem == nullptr) { + return; } - return *ptr; + + values = static_cast(newmem); + size = newSize; + } + + T& operator[](unsigned index) + { + return values[index]; } const T& operator[](unsigned index) const { - return const_cast(*this)[index]; + return const_cast(*this)[index]; } }; /** - * @brief List of scalar values + * @brief List of object pointers */ -template struct ScalarList { - T* values{nullptr}; - size_t size{0}; +template struct ObjectList : public ScalarList { + struct Element { + T*& value; + + Element& operator=(T* v) + { + delete value; + value = v; + return *this; + } - ~ScalarList() + template + typename std::enable_if::value, Element&>::type operator=(const U& v) + { + delete value; + value = new U{v}; + return *this; + } + + operator T&() + { + return *value; + } + }; + + ~ObjectList() { clear(); } - bool allocate(size_t newSize, const T& nil); + bool allocate(size_t newSize); void clear() { - free(values); - values = nullptr; - size = 0; + while(this->size != 0) { + delete this->values[--this->size]; + } + ScalarList::clear(); + } + + bool insert(unsigned index, const T& value) + { + auto el = new T(value); + if(el == nullptr) { + return false; + } + return ScalarList::insert(index, el); } void remove(unsigned index) { - memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T)); + delete this->values[index]; + ScalarList::remove(index); + this->values[this->size - 1] = nullptr; } - T& operator[](unsigned index) + void trim(size_t newSize, bool reallocate) { - return values[index]; + for(unsigned i = this->size; i > newSize; --i) { + delete this->values[i - 1]; + this->values[i - 1] = nullptr; + } + + ScalarList::trim(newSize, reallocate); + } + + Element operator[](unsigned index) + { + return Element{this->values[index]}; } const T& operator[](unsigned index) const { - return const_cast(*this)[index]; + return *this->values[index]; } }; -template bool ObjectList::allocate(size_t newSize, ...) +template bool ScalarList::allocate(size_t newSize) { if(newSize <= size) { return true; } - auto newmem = realloc(values, sizeof(T*) * newSize); + auto newmem = realloc(values, sizeof(T) * newSize); if(newmem == nullptr) { return false; } - values = static_cast(newmem); - std::fill_n(&values[size], newSize - size, nullptr); - + values = static_cast(newmem); size = newSize; return true; } -template bool ScalarList::allocate(size_t newSize, const T& nil) +template bool ObjectList::allocate(size_t newSize) { - if(newSize <= size) { - return true; - } - - auto newmem = realloc(values, sizeof(T) * newSize); - if(newmem == nullptr) { + auto curSize = this->size; + if(!ScalarList::allocate(newSize)) { return false; } - values = static_cast(newmem); - std::fill_n(&values[size], newSize - size, nil); - size = newSize; + std::fill_n(&this->values[curSize], newSize - curSize, nullptr); return true; } diff --git a/samples/HttpServer_ConfigNetwork/app/application.cpp b/samples/HttpServer_ConfigNetwork/app/application.cpp index 6d0b8a623f..2bc0a694b3 100644 --- a/samples/HttpServer_ConfigNetwork/app/application.cpp +++ b/samples/HttpServer_ConfigNetwork/app/application.cpp @@ -69,16 +69,16 @@ int onIpConfig(HttpServerConnection& connection, HttpRequest& request, HttpRespo void onFile(HttpRequest& request, HttpResponse& response) { - if(lastModified.length() > 0 && request.headers[HTTP_HEADER_IF_MODIFIED_SINCE].equals(lastModified)) { + if(lastModified.length() > 0 && request.headers[HTTP_HEADER_IF_MODIFIED_SINCE] == lastModified) { response.code = HTTP_STATUS_NOT_MODIFIED; return; } String file = request.uri.getRelativePath(); - if(file[0] == '.') + if(file[0] == '.') { response.code = HTTP_STATUS_FORBIDDEN; - else { + } else { if(lastModified.length() > 0) { response.headers[HTTP_HEADER_LAST_MODIFIED] = lastModified; } @@ -103,15 +103,16 @@ void onAjaxNetworkList(HttpRequest& request, HttpResponse& response) } JsonArray netlist = json.createNestedArray("available"); - for(unsigned i = 0; i < networks.count(); i++) { - if(networks[i].hidden) + for(auto& nw : networks) { + if(nw.hidden) { continue; + } JsonObject item = netlist.createNestedObject(); - item["id"] = (int)networks[i].getHashId(); + item["id"] = nw.getHashId(); // Copy full string to JSON buffer memory - item["title"] = networks[i].ssid; - item["signal"] = networks[i].rssi; - item["encryption"] = networks[i].getAuthorizationMethodName(); + item["title"] = nw.ssid; + item["signal"] = nw.rssi; + item["encryption"] = nw.getAuthorizationMethodName(); } response.setAllowCrossDomainOrigin("*"); @@ -205,12 +206,18 @@ void startServers() void networkScanCompleted(bool succeeded, BssList& list) { - if(succeeded) { - for(unsigned i = 0; i < list.count(); i++) - if(!list[i].hidden && list[i].ssid.length() > 0) - networks.add(list[i]); + if(!succeeded) { + return; + } + + networks.clear(); + for(auto& nw : list) { + if(!nw.hidden && nw.ssid.length() > 0) { + networks.add(nw); + } } - networks.sort([](const BssInfo& a, const BssInfo& b) { return b.rssi - a.rssi; }); + + networks.sort([](auto& a, auto& b) { return b.rssi - a.rssi; }); } void init() @@ -232,8 +239,9 @@ void init() if(AppSettings.exist()) { WifiStation.config(AppSettings.ssid, AppSettings.password); - if(!AppSettings.dhcp && !AppSettings.ip.isNull()) + if(!AppSettings.dhcp && !AppSettings.ip.isNull()) { WifiStation.setIP(AppSettings.ip, AppSettings.netmask, AppSettings.gateway); + } } WifiStation.startScan(networkScanCompleted); diff --git a/tests/HostTests/modules/Wiring.cpp b/tests/HostTests/modules/Wiring.cpp index 63595ea939..647eccc88a 100644 --- a/tests/HostTests/modules/Wiring.cpp +++ b/tests/HostTests/modules/Wiring.cpp @@ -8,58 +8,47 @@ #include #include -class WiringTest : public TestGroup +namespace { -public: - WiringTest() : TestGroup(_F("Wiring")) - { - } +template Print& operator<<(Print& p, const std::pair& e) +{ + p << e.first << " = " << e.second; + return p; +} - template void println(const E& e) const - { - Serial.print(e.key()); - Serial.print(" = "); - Serial.println(*e); +template void print(const T& list, const char* separator = "\r\n") +{ + for(auto e : list) { + Serial << e << separator; } +} - template void print(const Map& map) const - { - for(auto e : map) { - println(e); - } - } +template void fillMap(T& map) +{ + auto startMem = MallocCount::getCurrent(); + map[MIME_HTML] = os_random() % 0xffff; + map[MIME_TEXT] = os_random() % 0xffff; + map[MIME_JS] = os_random() % 0xffff; + map[MIME_CSS] = os_random() % 0xffff; + map[MIME_XML] = os_random() % 0xffff; + map[MIME_JSON] = os_random() % 0xffff; + map[MIME_JPEG] = os_random() % 0xffff; + map[MIME_GIF] = os_random() % 0xffff; + map[MIME_PNG] = os_random() % 0xffff; + map[MIME_SVG] = os_random() % 0xffff; + map[MIME_ICO] = os_random() % 0xffff; + map[MIME_GZIP] = os_random() % 0xffff; + map[MIME_ZIP] = os_random() % 0xffff; + Serial << "fillMap heap " << MallocCount::getCurrent() - startMem << endl; +} - template void println(const std::pair& e) const - { - Serial.print(e.first); - Serial.print(" = "); - Serial.println(e.second); - } +} // namespace - template void print(const std::map& map) const - { - for(auto e : map) { - println(e); - } - } - - template void fillMap(T& map) +class WiringTest : public TestGroup +{ +public: + WiringTest() : TestGroup(_F("Wiring")) { - auto startMem = MallocCount::getCurrent(); - map[MIME_HTML] = os_random() % 0xffff; - map[MIME_TEXT] = os_random() % 0xffff; - map[MIME_JS] = os_random() % 0xffff; - map[MIME_CSS] = os_random() % 0xffff; - map[MIME_XML] = os_random() % 0xffff; - map[MIME_JSON] = os_random() % 0xffff; - map[MIME_JPEG] = os_random() % 0xffff; - map[MIME_GIF] = os_random() % 0xffff; - map[MIME_PNG] = os_random() % 0xffff; - map[MIME_SVG] = os_random() % 0xffff; - map[MIME_ICO] = os_random() % 0xffff; - map[MIME_GZIP] = os_random() % 0xffff; - map[MIME_ZIP] = os_random() % 0xffff; - Serial << "fillMap heap " << MallocCount::getCurrent() - startMem << endl; } void execute() override @@ -79,13 +68,15 @@ class WiringTest : public TestGroup print(map); for(auto e : map) { - String s = *e; - e->length(); + REQUIRE(e->startsWith("value")); } for(auto e : map) { *e += ": gobbed"; } + for(auto e : map) { + REQUIRE(e->endsWith("gobbed")); + } REQUIRE_EQ(map["b"], "value(b): gobbed"); @@ -143,17 +134,49 @@ class WiringTest : public TestGroup Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; - for(auto& e : vector) { - Serial.println(e); - } + print(vector); for(auto& e : vector) { e += ": gobbed"; } - for(auto& e : vector) { - Serial.println(e); + CHECK(e.length() == 16 && e.endsWith("gobbed")); + } + + vector.setElementAt("potato", 1); + REQUIRE(vector[1] == "potato"); + REQUIRE(vector.count() == 4); + + vector[1] = "cabbage"; + REQUIRE(vector[1] == "cabbage"); + REQUIRE(vector.count() == 4); + + REQUIRE(!vector.insertElementAt("radish", 5)); + REQUIRE(vector.insertElementAt("radish", 4)); + REQUIRE(vector[4] == "radish"); + + REQUIRE(vector.firstElement() == "value(a): gobbed"); + REQUIRE(vector.lastElement() == "radish"); + + REQUIRE(vector.remove(2)); + REQUIRE(vector[2] == "value(d): gobbed"); + + REQUIRE(vector.setSize(3)); + REQUIRE_EQ(vector.count(), 3); + REQUIRE_EQ(vector.capacity(), 14); + + vector.trimToSize(); + REQUIRE_EQ(vector.capacity(), 3); + + String arr[3]; + vector.copyInto(arr); + for(unsigned i = 0; i < vector.count(); ++i) { + REQUIRE_EQ(vector[i], arr[i]); } + + REQUIRE(vector.addElement(new String("banana"))); + REQUIRE_EQ(vector.count(), 4); + REQUIRE_EQ(vector.capacity(), 13); } TEST_CASE("std::vector") @@ -168,17 +191,84 @@ class WiringTest : public TestGroup Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + print(vector); + for(auto& e : vector) { - Serial.println(e); + e += ": gobbed"; + } + + print(vector); + } + + TEST_CASE("Vector") + { + auto startMem = MallocCount::getCurrent(); + + Vector vector(32); + for(unsigned i = 0; i < 32; ++i) { + vector.add(os_random()); } + Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + + print(vector, ","); + Serial.println(); + for(auto& e : vector) { - e += ": gobbed"; + e += 12; } + print(vector, ","); + Serial.println(); + + vector.setElementAt(0, 1); + REQUIRE(vector[1] == 0); + REQUIRE(vector.count() == 32); + REQUIRE(vector.capacity() == 32); + + REQUIRE(!vector.insertElementAt(99, 35)); + REQUIRE(vector.insertElementAt(99, 32)); + REQUIRE(vector[32] == 99); + REQUIRE_EQ(vector.capacity(), 42); + + REQUIRE(vector.setSize(3)); + REQUIRE_EQ(vector.count(), 3); + REQUIRE_EQ(vector.capacity(), 42); + + vector.trimToSize(); + REQUIRE_EQ(vector.capacity(), 3); + + uint8_t arr[3]; + vector.copyInto(arr); + for(unsigned i = 0; i < vector.count(); ++i) { + REQUIRE_EQ(vector[i], arr[i]); + } + } + + TEST_CASE("std::vector") + { + auto startMem = MallocCount::getCurrent(); + + std::vector vector; + for(unsigned i = 0; i < 32; ++i) { + vector.push_back(os_random()); + } + + Serial << "Heap " << MallocCount::getCurrent() - startMem << endl; + + for(auto& e : vector) { + Serial << e << ", "; + } + Serial.println(); + for(auto& e : vector) { - Serial.println(e); + e += 12; } + + for(auto& e : vector) { + Serial << e << ", "; + } + Serial.println(); } TEST_CASE("MacAddress") From 16b33c671ce08527aec230e661a54f4417c3e41e Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 28 Sep 2022 09:45:03 +0100 Subject: [PATCH 32/58] Catch `Range::random()` divide-by-zero condition, fix off-by-1 error (#2559) e.g. min=0, max=10 then range=11 not 10 --- Sming/Core/Data/Range.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index 67f399c185..92168a7c5d 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -100,8 +100,12 @@ template struct TRange { */ T random() const { + auto n = 1 + max - min; + if(n == 0) { + return 0; + } auto value = os_random(); - return min + value % (max - min); + return min + value % n; } Iterator begin() const From 8013fff476370814c67688edd73d6da4164dc2b5 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 29 Sep 2022 10:56:12 +0100 Subject: [PATCH 33/58] Fix `smg_uart_uninit()` from blocking subsequent re-initialisation (#2560) This PR fixes a bug in the Esp8266 and Host uart driver implementations of `smg_uart_uninit` which causes subsequent calls to `smg_uart_init_ex` to fail as it thinks the port is in use. This bug is exposed if a port is opened, closed and then re-opened: ``` Serial.begin(COM_SPEED_SERIAL); ... Serial.end(); // optional - begin() calls this internally anyway Serial.begin(9600); // fails ``` Also add a `bool` return value from `HardwareSerial::begin()` method so caller can check for errors. --- Sming/Arch/Esp8266/Components/driver/uart.cpp | 1 + Sming/Arch/Host/Components/driver/uart.cpp | 1 + Sming/Core/HardwareSerial.cpp | 13 ++++++------- Sming/Core/HardwareSerial.h | 18 +++++++++++------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Sming/Arch/Esp8266/Components/driver/uart.cpp b/Sming/Arch/Esp8266/Components/driver/uart.cpp index 37e2e151ee..be211390ba 100644 --- a/Sming/Arch/Esp8266/Components/driver/uart.cpp +++ b/Sming/Arch/Esp8266/Components/driver/uart.cpp @@ -772,6 +772,7 @@ void smg_uart_uninit(smg_uart_t* uart) break; } + uartInstances[uart->uart_nr] = nullptr; delete uart->rx_buffer; delete uart->tx_buffer; delete uart; diff --git a/Sming/Arch/Host/Components/driver/uart.cpp b/Sming/Arch/Host/Components/driver/uart.cpp index 55a635f93f..d67e386020 100644 --- a/Sming/Arch/Host/Components/driver/uart.cpp +++ b/Sming/Arch/Host/Components/driver/uart.cpp @@ -347,6 +347,7 @@ void smg_uart_uninit(smg_uart_t* uart) smg_uart_set_debug(UART_NO); } + uartInstances[uart->uart_nr] = nullptr; delete uart->rx_buffer; delete uart->tx_buffer; delete uart; diff --git a/Sming/Core/HardwareSerial.cpp b/Sming/Core/HardwareSerial.cpp index de7079eadd..b305cfbe0c 100644 --- a/Sming/Core/HardwareSerial.cpp +++ b/Sming/Core/HardwareSerial.cpp @@ -28,12 +28,13 @@ HardwareSerial::~HardwareSerial() #endif } -void HardwareSerial::begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin) +bool HardwareSerial::begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin) { end(); - if(uartNr < 0) - return; + if(uartNr < 0) { + return false; + } smg_uart_config_t cfg = { .uart_nr = (uint8_t)uartNr, @@ -48,6 +49,8 @@ void HardwareSerial::begin(uint32_t baud, SerialFormat format, SerialMode mode, }; uart = smg_uart_init_ex(cfg); updateUartCallback(); + + return uart != nullptr; } void HardwareSerial::end() @@ -56,10 +59,6 @@ void HardwareSerial::end() return; } - if(smg_uart_get_debug() == uartNr) { - smg_uart_set_debug(UART_NO); - } - smg_uart_uninit(uart); uart = nullptr; } diff --git a/Sming/Core/HardwareSerial.h b/Sming/Core/HardwareSerial.h index ea996aa1a0..055e9e6708 100644 --- a/Sming/Core/HardwareSerial.h +++ b/Sming/Core/HardwareSerial.h @@ -131,10 +131,11 @@ class HardwareSerial : public ReadWriteStream /** @brief Initialise the serial port * @param baud BAUD rate of the serial port (Default: 9600) + * @retval bool true on success */ - void begin(uint32_t baud = 9600) + bool begin(uint32_t baud = 9600) { - begin(baud, SERIAL_8N1, SERIAL_FULL, SERIAL_PIN_DEFAULT); + return begin(baud, SERIAL_8N1, SERIAL_FULL, SERIAL_PIN_DEFAULT); } /** @@ -144,10 +145,11 @@ class HardwareSerial : public ReadWriteStream * even (E), and no (N) parity, and 1 or 2 stop bits. * To set the desired mode, call Serial.begin(baudrate, SERIAL_8N1), * Serial.begin(baudrate, SERIAL_6E2), etc. + * @retval bool true on success */ - void begin(uint32_t baud, SerialFormat format) + bool begin(uint32_t baud, SerialFormat format) { - begin(baud, format, SERIAL_FULL, SERIAL_PIN_DEFAULT); + return begin(baud, format, SERIAL_FULL, SERIAL_PIN_DEFAULT); } /** @@ -158,10 +160,11 @@ class HardwareSerial : public ReadWriteStream * To set the desired mode, call Serial.begin(baudrate, SERIAL_8N1), * Serial.begin(baudrate, SERIAL_6E2), etc. * @param mode specifies if the UART supports receiving (RX), transmitting (TX) or both (FULL) operations + * @retval bool true on success */ - void begin(uint32_t baud, SerialFormat format, SerialMode mode) + bool begin(uint32_t baud, SerialFormat format, SerialMode mode) { - begin(baud, format, mode, 1); + return begin(baud, format, mode, 1); } /** @@ -171,8 +174,9 @@ class HardwareSerial : public ReadWriteStream * @param mode * @param txPin Can specify alternate pin for TX * @param rxPin + * @retval bool true on success */ - void begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin = SERIAL_PIN_DEFAULT); + bool begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin = SERIAL_PIN_DEFAULT); /** * @brief De-inits the current UART if it is already used From abbdbbf1eb238a7c0b86df40664225bda0a53b43 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 1 Oct 2022 06:33:58 +0100 Subject: [PATCH 34/58] Fix minor filesystem bugs (#2563) - Fix return value from Spiffs `fenumxattr()`: Should return number of attributes read. - Fix LittleFS `FileSystem::format()` return value: int not bool - Remove (non-const) `Device::partitions()` method: Partition table is always accessed read-only - Remove `Partition::getDevice()` method: Could be used to bypass protections offered by partitioning API - Fix `IFS::Stat::printTo()` timestamp printing: Shows numeric (time_t) value instead of string --- Sming/Components/IFS | 2 +- Sming/Components/Storage/src/include/Storage/Device.h | 5 ----- Sming/Components/Storage/src/include/Storage/Partition.h | 9 --------- .../Storage/src/include/Storage/PartitionTable.h | 2 +- Sming/Libraries/LittleFS | 2 +- Sming/Libraries/Spiffs/src/FileMeta.cpp | 2 ++ 6 files changed, 5 insertions(+), 17 deletions(-) diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 1aaa86e1e1..2df44074ac 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 1aaa86e1e1ffba3c939c9f32caf91bae63325070 +Subproject commit 2df44074ac0e43b6e7930bb5c20eb39106898077 diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index b8ce634555..0255eb43e8 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -56,11 +56,6 @@ class Device : public LinkedObjectTemplate return getName() == name; } - PartitionTable& partitions() - { - return mPartitions; - } - const PartitionTable& partitions() const { return mPartitions; diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 18eb0930ac..72487fdb93 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -334,15 +334,6 @@ class Partition */ String getDeviceName() const; - /** - * @brief Get storage device containing this partition - * @retval Device* null if device isn't registered - */ - Device* getDevice() const - { - return mDevice; - } - /** * @brief Determine if given address contained within this partition */ diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index a243d803bb..1183f2e5e1 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -77,7 +77,7 @@ class PartitionTable /** * @brief Find the n'th OTA partition */ - Partition findOta(uint8_t index) + Partition findOta(uint8_t index) const { using App = Partition::SubType::App; auto subtype = App(uint8_t(App::ota0) + index); diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 27be7f5b4b..1a30230481 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 27be7f5b4bd59cd4e44d8a1e05f8d9bed740feca +Subproject commit 1a3023048190fc133a9a49bfe208a209eb3f56cf diff --git a/Sming/Libraries/Spiffs/src/FileMeta.cpp b/Sming/Libraries/Spiffs/src/FileMeta.cpp index e7ea32dbe7..f8af99324e 100644 --- a/Sming/Libraries/Spiffs/src/FileMeta.cpp +++ b/Sming/Libraries/Spiffs/src/FileMeta.cpp @@ -59,6 +59,7 @@ int SpiffsMetaBuffer::enumxattr(AttributeEnumCallback callback, void* buffer, si continue; } e.set(tag, value, getAttributeSize(tag)); + ++count; if(!callback(e)) { return count; } @@ -72,6 +73,7 @@ int SpiffsMetaBuffer::enumxattr(AttributeEnumCallback callback, void* buffer, si break; } e.set(AttributeTag(unsigned(AttributeTag::User) + tagIndex), &user[i], tagSize); + ++count; if(!callback(e)) { break; } From e5eccdbcd023193b0e47efb32d1e1b8f8bc99204 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 1 Oct 2022 06:34:48 +0100 Subject: [PATCH 35/58] Add ESP32 task watchdog reset to flash routines (#2562) Like ESP8266, can timeout during lengthy operations --- Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp index 982cd85036..a44ffb7480 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp @@ -12,11 +12,14 @@ #include #include #include +#include #include #include 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); if(r != ESP_OK) { SYSTEM_ERROR("ERROR in flash_write: r=%d at %08X\n", r, toaddr); @@ -28,6 +31,8 @@ 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); if(r != ESP_OK) { SYSTEM_ERROR("ERROR in flash_read: r=%d at %08X\n", r, fromaddr); @@ -39,6 +44,8 @@ uint32_t flashmem_read(void* to, uint32_t fromaddr, uint32_t size) bool flashmem_erase_sector(uint32_t sector_id) { + esp_task_wdt_reset(); + debug_d("flashmem_erase_sector(0x%08x)", sector_id); return spi_flash_erase_sector(sector_id) == SPI_FLASH_RESULT_OK; From 843fab812c4daeff87ab1f4f2b4c304731c739e0 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 4 Oct 2022 07:49:12 +0100 Subject: [PATCH 36/58] Revise Partition in-memory storage mechanism (#2564) This PR makes some changes to the way partition tables are constructed internally. The changes are intended to make the system more intuitive, flexible, and to pave the way for external disk (SD card) storage interfaces. **Use linked list to store partition tables** Currently the partition table is allocated using a fixed array of `Partition::Info` structures. This means any additional information would cause all partition entries to increase in size. This has been changed to a linked list so that future extensions can be accommodated. It also avoids having a fixed limit on the partition table size. **Replace `CustomDevice::createPartition` methods with `partitions().add()`** 'create' was a poor naming choice as it doesn't write anything to storage, just updates the partition table. These methods have been removed in favour of operating on the `partitions()` property directly. The default `Device::partitions()` is read-only (const) but it is overridden in custom devices to support writes, etc. **Add `Partition::FullType` for better type/subtype handling** Partition types consist of a `type` and `subtype` component, however standard subtypes can be referred to using just the subtype as these are defined using strong enums from which the type can be inferred. When explicitly providing both a type and subtype, this must now be provided as a `FullType` structure, e.g. `{`Storage::Partition::Type::Data`, 100}`. This simplifies the API and removes any ambiguity between overloaded method parameters. --- Sming/Components/IFS | 2 +- Sming/Components/Storage/src/CustomDevice.cpp | 42 ----------------- Sming/Components/Storage/src/Iterator.cpp | 34 ++++---------- Sming/Components/Storage/src/Partition.cpp | 5 ++ .../Components/Storage/src/PartitionTable.cpp | 11 +---- Sming/Components/Storage/src/ProgMem.cpp | 6 +-- Sming/Components/Storage/src/SysMem.cpp | 9 ---- .../src/include/Storage/CustomDevice.h | 22 ++++----- .../Storage/src/include/Storage/Device.h | 3 ++ .../Storage/src/include/Storage/Iterator.h | 19 ++++---- .../Storage/src/include/Storage/Partition.h | 33 +++++++++++-- .../src/include/Storage/PartitionTable.h | 40 ++++++++++------ .../Storage/src/include/Storage/ProgMem.h | 47 +++++++++---------- .../Storage/src/include/Storage/SysMem.h | 22 +++++---- Sming/Libraries/LittleFS | 2 +- docs/source/upgrading/4.6-4.7.rst | 41 ++++++++++++++++ docs/source/upgrading/index.rst | 1 + samples/Basic_IFS/app/application.cpp | 2 +- samples/Basic_Storage/app/application.cpp | 6 +-- tests/HostTests/modules/Spiffs.cpp | 4 +- 20 files changed, 180 insertions(+), 171 deletions(-) delete mode 100644 Sming/Components/Storage/src/CustomDevice.cpp create mode 100644 docs/source/upgrading/4.6-4.7.rst diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 2df44074ac..2c04e53140 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 2df44074ac0e43b6e7930bb5c20eb39106898077 +Subproject commit 2c04e5314040b787f2e9b3b619182dec47bae13a diff --git a/Sming/Components/Storage/src/CustomDevice.cpp b/Sming/Components/Storage/src/CustomDevice.cpp deleted file mode 100644 index a960528961..0000000000 --- a/Sming/Components/Storage/src/CustomDevice.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * CustomDevice.cpp - */ - -#include "include/Storage/CustomDevice.h" -#include - -namespace Storage -{ -namespace -{ -static constexpr size_t maxPartitions{16}; ///< Hard limit on partition table size - -class Partitions : public PartitionTable -{ -public: - Partition add(const Partition::Info& info) - { - if(!mEntries) { - mEntries.reset(new Partition::Info[maxPartitions]); - } else - assert(mCount < maxPartitions); - - auto i = mCount++; - mEntries.get()[i] = info; - return operator[](i); - } -}; - -} // namespace - -Partition CustomDevice::createPartition(const Partition::Info& info) -{ - if(mPartitions.count() >= maxPartitions) { - debug_e("Partition table is full for '%s'", getName().c_str()); - return Partition{}; - } - - return reinterpret_cast(mPartitions).add(info); -} - -} // namespace Storage diff --git a/Sming/Components/Storage/src/Iterator.cpp b/Sming/Components/Storage/src/Iterator.cpp index 8abc2a6c5b..e0de8dae21 100644 --- a/Sming/Components/Storage/src/Iterator.cpp +++ b/Sming/Components/Storage/src/Iterator.cpp @@ -18,39 +18,23 @@ Iterator::Iterator(Partition::Type type, uint8_t subtype) : mSearch{nullptr, typ next(); } -bool Iterator::next() +void Iterator::next() { while(mDevice != nullptr) { - while(uint8_t(++mPos) < mDevice->partitions().count()) { - auto entry = mDevice->partitions()[mPos]; - - if(mSearch.type != Partition::Type::any && mSearch.type != entry.type()) { - continue; - } - - if(mSearch.subType != Partition::SubType::any && mSearch.subType != entry.subType()) { - continue; + mInfo = mInfo ? mInfo->getNext() : mDevice->partitions().mEntries.head(); + if(mInfo == nullptr) { + if(mSearch.device != nullptr) { + break; } - - return true; + mDevice = mDevice->getNext(); + mInfo = nullptr; + continue; } - if(mSearch.device != nullptr) { + if(mInfo->match(mSearch.type, mSearch.subType)) { break; } - - mDevice = mDevice->getNext(); - mPos = beforeStart; } - - mDevice = nullptr; - mPos = afterEnd; - return false; -} - -Partition Iterator::operator*() const -{ - return mDevice ? mDevice->partitions()[mPos] : Partition{}; } } // namespace Storage diff --git a/Sming/Components/Storage/src/Partition.cpp b/Sming/Components/Storage/src/Partition.cpp index 0cb6af2554..03761fa929 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -123,6 +123,11 @@ String toLongString(Partition::Type type, uint8_t subType) namespace Storage { +Partition::FullType::operator String() const +{ + return toString(type, subtype); +} + String Partition::typeString() const { return toString(type(), subType()); diff --git a/Sming/Components/Storage/src/PartitionTable.cpp b/Sming/Components/Storage/src/PartitionTable.cpp index 793cd061bf..e62612bf62 100644 --- a/Sming/Components/Storage/src/PartitionTable.cpp +++ b/Sming/Components/Storage/src/PartitionTable.cpp @@ -16,21 +16,14 @@ namespace Storage { void PartitionTable::load(const esp_partition_info_t* entry, unsigned count) { - if(count == 0) { - mEntries.reset(); - mCount = count; - return; - } - - mCount = count; - mEntries.reset(new Partition::Info[count]); + mEntries.clear(); for(unsigned i = 0; i < count; ++i) { auto& e = entry[i]; // name may not be zero-terminated char name[Partition::nameSize + 1]; memcpy(name, e.name, Partition::nameSize); name[Partition::nameSize] = '\0'; - mEntries.get()[i] = Partition::Info{name, e.type, e.subtype, e.offset, e.size, e.flags}; + add(name, {e.type, e.subtype}, e.offset, e.size, e.flags); } } diff --git a/Sming/Components/Storage/src/ProgMem.cpp b/Sming/Components/Storage/src/ProgMem.cpp index 8d95f594cc..16e68e3410 100644 --- a/Sming/Components/Storage/src/ProgMem.cpp +++ b/Sming/Components/Storage/src/ProgMem.cpp @@ -21,15 +21,15 @@ bool ProgMem::read(uint32_t address, void* dst, size_t size) return readCount == size; } -Partition ProgMem::createPartition(const String& name, const void* flashPtr, size_t size, Partition::Type type, - uint8_t subtype) +Partition ProgMem::ProgMemPartitionTable::add(const String& name, const void* flashPtr, size_t size, + Partition::FullType type) { auto addr = flashmem_get_address(flashPtr); if(addr == 0) { return Partition{}; } - return createPartition(name, type, subtype, addr, size, Partition::Flag::readOnly); + return CustomPartitionTable::add(name, type, addr, size, Partition::Flag::readOnly); } } // namespace Storage diff --git a/Sming/Components/Storage/src/SysMem.cpp b/Sming/Components/Storage/src/SysMem.cpp index 5281259f62..730eaa7a24 100644 --- a/Sming/Components/Storage/src/SysMem.cpp +++ b/Sming/Components/Storage/src/SysMem.cpp @@ -9,17 +9,8 @@ ****/ #include "include/Storage/SysMem.h" -#include namespace Storage { SysMem sysMem; - -Partition SysMem::createPartition(const String& name, const FSTR::ObjectBase& fstr, Partition::Type type, - uint8_t subtype) -{ - return createPartition(name, type, subtype, reinterpret_cast(fstr.data()), fstr.size(), - Partition::Flag::readOnly); -} - } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/CustomDevice.h b/Sming/Components/Storage/src/include/Storage/CustomDevice.h index 82222f2667..ff39cb336a 100644 --- a/Sming/Components/Storage/src/include/Storage/CustomDevice.h +++ b/Sming/Components/Storage/src/include/Storage/CustomDevice.h @@ -10,25 +10,23 @@ namespace Storage { /** * @brief Class to support dynamic partitions - * - * Call `createPartition` to add partitions up to a maximum of 16 entries. */ class CustomDevice : public Device { public: - Partition createPartition(const Partition::Info& info); - - Partition createPartition(const String& name, Partition::Type type, uint8_t subtype, uint32_t offset, size_t size, - Partition::Flags flags = 0) + class CustomPartitionTable : public PartitionTable { - return createPartition(Partition::Info{name, type, subtype, offset, size, flags}); - } + public: + using PartitionTable::add; + using PartitionTable::clear; + }; - template - Partition createPartition(const String& name, SubType subtype, uint32_t offset, size_t size, - Partition::Flags flags = 0) + /** + * @brief Provide read/write access to in-memory partition table + */ + CustomPartitionTable& partitions() { - return createPartition(name, Partition::Type(SubType::partitionType), uint8_t(subtype), offset, size, flags); + return static_cast(mPartitions); } }; diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index 0255eb43e8..4802fda5cb 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -56,6 +56,9 @@ class Device : public LinkedObjectTemplate return getName() == name; } + /** + * @brief Provide read-only access to partition table + */ const PartitionTable& partitions() const { return mPartitions; diff --git a/Sming/Components/Storage/src/include/Storage/Iterator.h b/Sming/Components/Storage/src/include/Storage/Iterator.h index 028090278a..c17662693c 100644 --- a/Sming/Components/Storage/src/include/Storage/Iterator.h +++ b/Sming/Components/Storage/src/include/Storage/Iterator.h @@ -32,7 +32,7 @@ class Iterator : public std::iterator explicit operator bool() const { - return (mDevice != nullptr) && (mPos > beforeStart) && (mPos < afterEnd); + return mDevice && mInfo; } Iterator operator++(int) @@ -50,7 +50,7 @@ class Iterator : public std::iterator bool operator==(const Iterator& other) const { - return (mDevice == other.mDevice) && (mPos == other.mPos); + return mInfo == other.mInfo; } bool operator!=(const Iterator& other) const @@ -58,7 +58,10 @@ class Iterator : public std::iterator return !operator==(other); } - Partition operator*() const; + Partition operator*() const + { + return mDevice && mInfo ? Partition(*mDevice, *mInfo) : Partition{}; + } Iterator begin() { @@ -71,15 +74,11 @@ class Iterator : public std::iterator } private: - static constexpr int8_t beforeStart{-1}; - static constexpr int8_t afterEnd{0x7f}; - - Iterator() : mPos(afterEnd) + Iterator() { } - bool seek(uint8_t pos); - bool next(); + void next(); struct Search { Device* device; @@ -88,7 +87,7 @@ class Iterator : public std::iterator }; Search mSearch{}; Device* mDevice{nullptr}; - int8_t mPos{beforeStart}; + const Partition::Info* mInfo{nullptr}; }; } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 72487fdb93..922d044e96 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #define PARTITION_APP_SUBTYPE_MAP(XX) \ @@ -127,10 +127,30 @@ class Partition using Name = char[nameSize]; using Flags = BitSet; + /** + * @brief Express both partition type and subtype together + */ + struct FullType { + Type type; + uint8_t subtype; + + FullType(Type type, uint8_t subtype) : type(type), subtype(subtype) + { + } + + template FullType(T subType) : FullType(Type(T::partitionType), uint8_t(subType)) + { + } + + operator String() const; + }; + /** * @brief Partition information */ - struct Info { + struct Info : public LinkedObjectTemplate { + using OwnedList = OwnedLinkedObjectListTemplate; + CString name; uint32_t offset{0}; uint32_t size{0}; @@ -142,9 +162,14 @@ class Partition { } - Info(const String& name, Type type, uint8_t subtype, uint32_t offset, uint32_t size, Flags flags) - : name(name), offset(offset), size(size), type(type), subtype(subtype), flags(flags) + Info(const String& name, FullType fullType, uint32_t offset, uint32_t size, Flags flags = 0) + : name(name), offset(offset), size(size), type(fullType.type), subtype(fullType.subtype), flags(flags) + { + } + + bool match(Type type, uint8_t subType) const { + return (type == Type::any || type == this->type) && (subType == SubType::any || subType == this->subtype); } }; diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index 1183f2e5e1..b618141d18 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -24,7 +24,7 @@ class PartitionTable explicit operator bool() const { - return mCount != 0; + return mEntries.isEmpty(); } /** @@ -44,10 +44,9 @@ class PartitionTable return Iterator(mDevice, type, subType); } - /// C++ subtype definition provides partition type - template Iterator find(T subType) const + Iterator find(Partition::FullType fullType) const { - return find(Partition::Type(T::partitionType), uint8_t(subType)); + return find(fullType.type, fullType.subtype); } /** @} */ @@ -94,28 +93,39 @@ class PartitionTable return Iterator(mDevice).end(); } - uint8_t count() const + Device& device() const { - return mCount; + return mDevice; } - Device& device() const +protected: + friend Device; + friend Iterator; + + void load(const esp_partition_info_t* entry, unsigned count); + + /** + * @brief Add new partition using given Info + * @param info Must be allocated using `new`: Device will take ownership + * @retval Partition Reference to the partition + */ + Partition add(const Partition::Info* info) { - return mDevice; + return mEntries.add(info) ? Partition(mDevice, *info) : Partition{}; } - Partition operator[](unsigned index) const + template Partition add(const String& name, Partition::FullType type, Args... args) { - return (index < mCount) ? Partition(mDevice, mEntries.get()[index]) : Partition(); + return add(new Partition::Info(name, type, args...)); } -protected: - friend Device; - void load(const esp_partition_info_t* entry, unsigned count); + void clear() + { + mEntries.clear(); + } Device& mDevice; - std::unique_ptr mEntries; - uint8_t mCount{0}; + Partition::Info::OwnedList mEntries; }; } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/ProgMem.h b/Sming/Components/Storage/src/include/Storage/ProgMem.h index d8758244d0..5a149940e2 100644 --- a/Sming/Components/Storage/src/include/Storage/ProgMem.h +++ b/Sming/Components/Storage/src/include/Storage/ProgMem.h @@ -51,36 +51,31 @@ class ProgMem : public CustomDevice return false; } - using CustomDevice::createPartition; - - /** - * @brief Create partition for PROGMEM data access - * @param name Name for partition - * @param flashPtr PROGMEM pointer - * @param size Size of PROGMEM data - * @param type Partition type - * @param subtype Partition sub-type - * @retval Partition Invalid if data is not progmem - */ - Partition createPartition(const String& name, const void* flashPtr, size_t size, Partition::Type type, - uint8_t subtype); - - template Partition createPartition(const String& name, const void* flashPtr, size_t size, T subType) + class ProgMemPartitionTable : public CustomPartitionTable { - return createPartition(name, flashPtr, size, Partition::Type(T::partitionType), uint8_t(subType)); - } + public: + /** + * @brief Add partition entry for PROGMEM data access + * @param name Name for partition + * @param flashPtr PROGMEM pointer + * @param size Size of PROGMEM data + * @param type Partition type and subtype + * @retval Partition Invalid if data is not progmem + */ + Partition add(const String& name, const void* flashPtr, size_t size, Partition::FullType type); - /** - * @brief Create partition for FlashString data access - */ - Partition createPartition(const String& name, const FSTR::ObjectBase& fstr, Partition::Type type, uint8_t subtype) - { - return createPartition(name, fstr.data(), fstr.size(), type, subtype); - } + /** + * @brief Add partition entry for FlashString data access + */ + Partition add(const String& name, const FSTR::ObjectBase& fstr, Partition::FullType type) + { + return add(name, fstr.data(), fstr.size(), type); + } + }; - template Partition createPartition(const String& name, const FSTR::ObjectBase& fstr, T subType) + ProgMemPartitionTable& partitions() { - return createPartition(name, fstr, Partition::Type(T::partitionType), uint8_t(subType)); + return static_cast(mPartitions); } }; diff --git a/Sming/Components/Storage/src/include/Storage/SysMem.h b/Sming/Components/Storage/src/include/Storage/SysMem.h index 9f49a3fa3e..22a623a564 100644 --- a/Sming/Components/Storage/src/include/Storage/SysMem.h +++ b/Sming/Components/Storage/src/include/Storage/SysMem.h @@ -70,16 +70,22 @@ class SysMem : public CustomDevice return true; } - using CustomDevice::createPartition; - - /** - * @brief Create partition for FlashString data access - */ - Partition createPartition(const String& name, const FSTR::ObjectBase& fstr, Partition::Type type, uint8_t subtype); + class SysMemPartitionTable : public CustomPartitionTable + { + public: + /** + * @brief Add partition entry for FlashString data access + */ + Partition add(const String& name, const FSTR::ObjectBase& fstr, Partition::FullType type) + { + return CustomPartitionTable::add(name, type, reinterpret_cast(fstr.data()), fstr.size(), + Partition::Flag::readOnly); + } + }; - template Partition createPartition(const String& name, const FSTR::ObjectBase& fstr, T subType) + SysMemPartitionTable& partitions() { - return createPartition(name, fstr, Partition::Type(T::partitionType), uint8_t(subType)); + return static_cast(mPartitions); } }; diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 1a30230481..62202e935b 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 1a3023048190fc133a9a49bfe208a209eb3f56cf +Subproject commit 62202e935bbb6df127f383698d4c820715353642 diff --git a/docs/source/upgrading/4.6-4.7.rst b/docs/source/upgrading/4.6-4.7.rst new file mode 100644 index 0000000000..b5858ae5a4 --- /dev/null +++ b/docs/source/upgrading/4.6-4.7.rst @@ -0,0 +1,41 @@ +From v4.6 to v4.7 +================= + +.. highlight:: c++ + +Storage Partition methods +------------------------- + +The ``Storage::Partition::getDevice()`` method has been removed. +This could be used to bypass protections offered by the partitioning API. + + +Storage Device Partitions +------------------------- + +The ``Storage::CustomDevice::createPartition()`` methods have been removed. + Instead, use partition table methods. + + For example:: + + part = device->createPartition("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); + + becomes:: + + part = device->partitions().add("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); + + This also applies to derivatives :cpp:class:`Storage::SysMem` and :cpp:class:`Storage::ProgMem`. + + +Creating custom partition types require use of :cpp:struct:`Storage::Partition::FullType`. + + For example:: + + part = device->createPartitions("fs_app", Storage::Partition::Type::data, 100, startOffset, size); + + becomes:: + + part = device->partitions().add("fs_app", {Storage::Partition::Type::data, 100}, startOffset, size); + + Note how the ``type`` and ``subtype`` values are enclosed in braces (instantiating a ``FullType`` struct). + This avoids confusing the subtype value ``100`` with the start offset. diff --git a/docs/source/upgrading/index.rst b/docs/source/upgrading/index.rst index 915fe4dc28..a53c6a896f 100644 --- a/docs/source/upgrading/index.rst +++ b/docs/source/upgrading/index.rst @@ -7,6 +7,7 @@ For newer versions we have dedicated pages. .. toctree:: :maxdepth: 1 + 4.6-4.7 4.5-4.6 4.4-4.5 4.3-4.4 diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 7aff2d69af..79a7f8c25b 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -139,7 +139,7 @@ bool initFileSystem() #ifdef ENABLE_FLASHSTRING_IMAGE // Create a partition wrapping some flashstring data - auto part = Storage::progMem.createPartition(F("fwfsMem"), fwfsImage, Storage::Partition::SubType::Data::fwfs); + auto part = Storage::progMem.partitions().add(F("fwfsMem"), fwfsImage, Storage::Partition::SubType::Data::fwfs); #else auto part = Storage::findDefaultPartition(Storage::Partition::SubType::Data::fwfs); #endif diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index 98bdec0269..de77fcfd56 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -80,19 +80,19 @@ void init() Serial.println(_F("** Reading tests, repeat 3 times to show effect of caching (if any)")); Serial.println(_F("** Reading SysMem device (flash)")); - part = Storage::sysMem.createPartition(F("fs_app"), FS_app, Storage::Partition::Type::data, 100); + part = Storage::sysMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); Serial.println(_F("** Reading SysMem device (RAM)")); - part = Storage::sysMem.createPartition(F("fs_app"), FS_app, Storage::Partition::Type::data, 100); + part = Storage::sysMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); Serial.println(_F("** Reading ProgMem device")); - part = Storage::progMem.createPartition(F("fs_app"), FS_app, Storage::Partition::Type::data, 100); + part = Storage::progMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); diff --git a/tests/HostTests/modules/Spiffs.cpp b/tests/HostTests/modules/Spiffs.cpp index bde78215f3..c2a08997a0 100644 --- a/tests/HostTests/modules/Spiffs.cpp +++ b/tests/HostTests/modules/Spiffs.cpp @@ -113,8 +113,8 @@ class SpiffsTest : public TestGroup } auto dev = new Storage::FileDevice(tag, hfs, f); Storage::registerDevice(dev); - auto part = dev->createPartition(tag, Storage::Partition::SubType::Data::spiffs, 0, dev->getSize(), - Storage::Partition::Flag::readOnly); + auto part = dev->partitions().add(tag, Storage::Partition::SubType::Data::spiffs, 0, dev->getSize(), + Storage::Partition::Flag::readOnly); auto fs = IFS::createSpiffsFilesystem(part); int err = fs->mount(); From 5927375066611c40f29c89f4d8ad95e949c891d7 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 7 Oct 2022 14:00:47 +0100 Subject: [PATCH 37/58] Fix m_printf for signed 64-bit numbers (#2565) --- Sming/System/m_printf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sming/System/m_printf.cpp b/Sming/System/m_printf.cpp index de12db413a..42482fef39 100644 --- a/Sming/System/m_printf.cpp +++ b/Sming/System/m_printf.cpp @@ -215,7 +215,11 @@ int m_vsnprintf(char *buf, size_t maxLen, const char *fmt, va_list args) case 'd': case 'i': - s = ltoa_wp(va_arg(args, int), tempNum, 10, width, pad); + if(length >= 2) { + s = lltoa_wp(va_arg(args, long long int), tempNum, 10, width, pad); + } else { + s = ltoa_wp(va_arg(args, int), tempNum, 10, width, pad); + } break; case 'f': From cacef01fd01b792e135947bc4789d17098ae64a0 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 10 Oct 2022 08:52:46 +0100 Subject: [PATCH 38/58] Translate SPIFFS and LittleFS error codes into standard values (#2566) * Translate SPIFFS and LittleFS error codes into standard values * Fix SPIFFS error codes --- Sming/Libraries/LittleFS | 2 +- Sming/Libraries/Spiffs/src/Error.cpp | 76 ++++++++++--------- Sming/Libraries/Spiffs/src/FileSystem.cpp | 56 +++++++------- .../Spiffs/src/include/IFS/SPIFFS/Error.h | 2 + 4 files changed, 73 insertions(+), 63 deletions(-) diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 62202e935b..55dbf00a0e 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 62202e935bbb6df127f383698d4c820715353642 +Subproject commit 55dbf00a0e992f97d9dd1416f38f13b079e0ce84 diff --git a/Sming/Libraries/Spiffs/src/Error.cpp b/Sming/Libraries/Spiffs/src/Error.cpp index 494c24a335..1269ad7c93 100644 --- a/Sming/Libraries/Spiffs/src/Error.cpp +++ b/Sming/Libraries/Spiffs/src/Error.cpp @@ -21,6 +21,7 @@ ****/ #include "include/IFS/SPIFFS/Error.h" +#include #include namespace IFS @@ -31,19 +32,41 @@ namespace SPIFFS * @todo Return generic FSERR codes wherever possible by mapping from SPIFFS codes */ +/* + * Translate common SPIFFS error codes into the standard one. + * This avoids the need to provide strings for these values. + */ +#define SPIFFS_ERROR_TRANSLATION_MAP(XX) \ + XX(SPIFFS_ERR_NOT_MOUNTED, Error::NotMounted) \ + XX(SPIFFS_ERR_FULL, Error::NoSpace) \ + XX(SPIFFS_ERR_NOT_FOUND, Error::NotFound) \ + XX(SPIFFS_ERR_END_OF_OBJECT, Error::SeekBounds) \ + XX(SPIFFS_ERR_DELETED, Error::InvalidHandle) \ + XX(SPIFFS_ERR_FILE_CLOSED, Error::FileNotOpen) \ + XX(SPIFFS_ERR_OUT_OF_FILE_DESCS, Error::OutOfFileDescs) \ + XX(SPIFFS_ERR_BAD_DESCRIPTOR, Error::InvalidHandle) \ + XX(SPIFFS_ERR_NOT_WRITABLE, Error::ReadOnly) \ + XX(SPIFFS_ERR_NOT_READABLE, Error::Denied) \ + XX(SPIFFS_ERR_CONFLICTING_NAME, Error::Exists) \ + XX(SPIFFS_ERR_NOT_CONFIGURED, Error::BadFileSystem) \ + XX(SPIFFS_ERR_NOT_A_FS, Error::BadFileSystem) \ + XX(SPIFFS_ERR_MOUNTED, Error::Denied) \ + XX(SPIFFS_ERR_ERASE_FAIL, Error::EraseFailure) \ + XX(SPIFFS_ERR_FILE_EXISTS, Error::Exists) \ + XX(SPIFFS_ERR_RO_NOT_IMPL, Error::ReadOnly) \ + XX(SPIFFS_ERR_RO_ABORTED_OPERATION, Error::ReadOnly) \ + XX(SPIFFS_ERR_PROBE_NOT_A_FS, Error::BadFileSystem) \ + XX(SPIFFS_ERR_NAME_TOO_LONG, Error::NameTooLong) \ + XX(SPIFFS_ERR_SEEK_BOUNDS, Error::SeekBounds) + +/* + * All remaining SPIFFS error codes + */ #define SPIFFS_ERROR_MAP(XX) \ - XX(OK, 0) \ - XX(NOT_MOUNTED, -10000) \ - XX(FULL, -10001) \ - XX(NOT_FOUND, -10002) \ - XX(END_OF_OBJECT, -10003) \ - XX(DELETED, -10004) \ XX(NOT_FINALIZED, -10005) \ XX(NOT_INDEX, -10006) \ XX(OUT_OF_FILE_DESCS, -10007) \ - XX(FILE_CLOSED, -10008) \ XX(FILE_DELETED, -10009) \ - XX(BAD_DESCRIPTOR, -10010) \ XX(IS_INDEX, -10011) \ XX(IS_FREE, -10012) \ XX(INDEX_SPAN_MISMATCH, -10013) \ @@ -54,42 +77,16 @@ namespace SPIFFS XX(INDEX_FREE, -10018) \ XX(INDEX_LU, -10019) \ XX(INDEX_INVALID, -10020) \ - XX(NOT_WRITABLE, -10021) \ - XX(NOT_READABLE, -10022) \ - XX(CONFLICTING_NAME, -10023) \ - XX(NOT_CONFIGURED, -10024) \ - \ - XX(NOT_A_FS, -10025) \ - XX(MOUNTED, -10026) \ - XX(ERASE_FAIL, -10027) \ XX(MAGIC_NOT_POSSIBLE, -10028) \ - \ XX(NO_DELETED_BLOCKS, -10029) \ - \ - XX(FILE_EXISTS, -10030) \ - \ XX(NOT_A_FILE, -10031) \ - XX(RO_NOT_IMPL, -10032) \ - XX(RO_ABORTED_OPERATION, -10033) \ XX(PROBE_TOO_FEW_BLOCKS, -10034) \ - XX(PROBE_NOT_A_FS, -10035) \ - XX(NAME_TOO_LONG, -10036) \ - \ XX(IX_MAP_UNMAPPED, -10037) \ XX(IX_MAP_MAPPED, -10038) \ XX(IX_MAP_BAD_RANGE, -10039) \ - \ - XX(SEEK_BOUNDS, -10040) \ - \ XX(INTERNAL, -10050) \ - \ XX(TEST, -10100) -struct spiffs_error_t { - int32_t err; - PGM_P tag; -}; - #define XX(tag, value) DEFINE_FSTR_LOCAL(str_##tag, #tag) SPIFFS_ERROR_MAP(XX) #undef XX @@ -98,6 +95,17 @@ SPIFFS_ERROR_MAP(XX) DEFINE_FSTR_MAP_LOCAL(errorMap, int, FlashString, SPIFFS_ERROR_MAP(XX)) #undef XX +int translateSpiffsError(int spiffs_error) +{ + switch(spiffs_error) { +#define XX(err_spiffs, err_sys) \ + case err_spiffs: \ + return err_sys; + default: + return Error::fromSystem(spiffs_error); + } +} + String spiffsErrorToStr(int err) { return errorMap[std::min(err, 0)].content(); diff --git a/Sming/Libraries/Spiffs/src/FileSystem.cpp b/Sming/Libraries/Spiffs/src/FileSystem.cpp index c17b14cfb2..1184e0bcc2 100644 --- a/Sming/Libraries/Spiffs/src/FileSystem.cpp +++ b/Sming/Libraries/Spiffs/src/FileSystem.cpp @@ -173,7 +173,7 @@ int FileSystem::tryMount(spiffs_config& cfg) nullptr); if(err < 0) { if(isSpiffsError(err)) { - err = Error::fromSystem(err); + err = translateSpiffsError(err); } debug_ifserr(err, "SPIFFS_mount()"); } @@ -191,7 +191,7 @@ int FileSystem::format() SPIFFS_unmount(handle()); int err = SPIFFS_format(handle()); if(err < 0) { - err = Error::fromSystem(err); + err = translateSpiffsError(err); debug_ifserr(err, "format()"); return err; } @@ -209,7 +209,7 @@ int FileSystem::check() }; int err = SPIFFS_check(handle()); - return Error::fromSystem(err); + return translateSpiffsError(err); } int FileSystem::getinfo(Info& info) @@ -273,7 +273,7 @@ FileHandle FileSystem::open(const char* path, OpenFlags flags) auto file = SPIFFS_open(handle(), path, sflags, 0); if(file < 0) { - int err = Error::fromSystem(file); + int err = translateSpiffsError(file); debug_ifserr(err, "open('%s')", path); return err; } @@ -292,7 +292,7 @@ FileHandle FileSystem::open(const char* path, OpenFlags flags) int err = SPIFFS_ftruncate(handle(), file, 0); if(err < 0) { SPIFFS_close(handle(), file); - return Error::fromSystem(err); + return translateSpiffsError(err); } // Update modification timestamp @@ -307,13 +307,13 @@ int FileSystem::close(FileHandle file) CHECK_MOUNTED() if(file < 0) { - return Error::FileNotOpen; + return Error::InvalidHandle; } int res = flushMeta(file); int err = SPIFFS_close(handle(), file); if(err < 0) { - res = Error::fromSystem(err); + res = translateSpiffsError(err); } return res; } @@ -321,19 +321,19 @@ int FileSystem::close(FileHandle file) int FileSystem::eof(FileHandle file) { int res = SPIFFS_eof(handle(), file); - return Error::fromSystem(res); + return translateSpiffsError(res); } int32_t FileSystem::tell(FileHandle file) { int res = SPIFFS_tell(handle(), file); - return Error::fromSystem(res); + return translateSpiffsError(res); } int FileSystem::ftruncate(FileHandle file, size_t new_size) { int res = SPIFFS_ftruncate(handle(), file, new_size); - return Error::fromSystem(res); + return translateSpiffsError(res); } int FileSystem::flush(FileHandle file) @@ -343,7 +343,7 @@ int FileSystem::flush(FileHandle file) int res = flushMeta(file); int err = SPIFFS_fflush(handle(), file); if(err < 0) { - res = Error::fromSystem(err); + res = translateSpiffsError(err); } return res; } @@ -352,7 +352,7 @@ int FileSystem::read(FileHandle file, void* data, size_t size) { int res = SPIFFS_read(handle(), file, data, size); if(res < 0) { - int err = Error::fromSystem(res); + int err = translateSpiffsError(res); debug_ifserr(err, "read()"); return err; } @@ -365,7 +365,7 @@ 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 Error::fromSystem(res); + return translateSpiffsError(res); } touch(file); @@ -376,7 +376,7 @@ int FileSystem::lseek(FileHandle file, int offset, SeekOrigin origin) { int res = SPIFFS_lseek(handle(), file, offset, int(origin)); if(res < 0) { - int err = Error::fromSystem(res); + int err = translateSpiffsError(res); debug_ifserr(err, "lseek()"); return err; } @@ -433,7 +433,7 @@ int FileSystem::flushMeta(FileHandle file) smb->flags[SpiffsMetaBuffer::Flag::dirty] = false; int err = SPIFFS_fupdate_meta(handle(), file, smb); if(err < 0) { - err = Error::fromSystem(err); + err = translateSpiffsError(err); debug_ifserr(err, "fupdate_meta()"); return err; } @@ -458,7 +458,7 @@ int FileSystem::stat(const char* path, Stat* stat) spiffs_stat ss; int err = SPIFFS_stat(handle(), path ?: "", &ss); if(err < 0) { - return Error::fromSystem(err); + return translateSpiffsError(err); } if(stat != nullptr) { @@ -485,7 +485,7 @@ int FileSystem::fstat(FileHandle file, Stat* stat) spiffs_stat ss; int err = SPIFFS_fstat(handle(), file, &ss); if(err < 0) { - return Error::fromSystem(err); + return translateSpiffsError(err); } auto smb = getMetaBuffer(file); @@ -551,7 +551,7 @@ int FileSystem::setxattr(const char* path, AttributeTag tag, const void* data, s spiffs_stat ss; int err = SPIFFS_stat(handle(), path ?: "", &ss); if(err < 0) { - return Error::fromSystem(err); + return translateSpiffsError(err); } SpiffsMetaBuffer smb; smb.assign(ss.meta); @@ -563,7 +563,7 @@ int FileSystem::setxattr(const char* path, AttributeTag tag, const void* data, s return FS_OK; } err = SPIFFS_update_meta(handle(), path, &smb); - return Error::fromSystem(err); + return translateSpiffsError(err); #else return Error::NotSupported; #endif @@ -576,7 +576,7 @@ int FileSystem::getxattr(const char* path, AttributeTag tag, void* buffer, size_ spiffs_stat ss; int err = SPIFFS_stat(handle(), path, &ss); if(err < 0) { - return Error::fromSystem(err); + return translateSpiffsError(err); } SpiffsMetaBuffer smb; smb.assign(ss.meta); @@ -606,7 +606,7 @@ int FileSystem::opendir(const char* path, DirHandle& dir) if(SPIFFS_opendir(handle(), nullptr, &d->d) == nullptr) { int err = SPIFFS_errno(handle()); - err = Error::fromSystem(err); + err = translateSpiffsError(err); debug_ifserr(err, "opendir"); delete d; return err; @@ -630,7 +630,7 @@ int FileSystem::rewinddir(DirHandle dir) d->directories.setLength(0); if(SPIFFS_opendir(handle(), nullptr, &d->d) == nullptr) { int err = SPIFFS_errno(handle()); - return Error::fromSystem(err); + return translateSpiffsError(err); } return FS_OK; @@ -648,7 +648,7 @@ int FileSystem::readdir(DirHandle dir, Stat& stat) return Error::NoMoreFiles; } - return Error::fromSystem(err); + return translateSpiffsError(err); } /* The volume doesn't contain directory objects, so at each level we need @@ -729,7 +729,7 @@ int FileSystem::closedir(DirHandle dir) int err = SPIFFS_closedir(&d->d); delete d; - return Error::fromSystem(err); + return translateSpiffsError(err); } int FileSystem::mkdir(const char* path) @@ -745,7 +745,7 @@ int FileSystem::rename(const char* oldpath, const char* newpath) } int err = SPIFFS_rename(handle(), oldpath, newpath); - return Error::fromSystem(err); + return translateSpiffsError(err); } int FileSystem::remove(const char* path) @@ -767,7 +767,7 @@ int FileSystem::remove(const char* path) } int err = SPIFFS_remove(handle(), path); - err = Error::fromSystem(err); + err = translateSpiffsError(err); debug_ifserr(err, "remove('%s')", path); return err; } @@ -786,7 +786,7 @@ int FileSystem::fremove(FileHandle file) } int err = SPIFFS_fremove(handle(), file); - return Error::fromSystem(err); + return translateSpiffsError(err); } int FileSystem::getFilePath(FileID fileid, NameBuffer& buffer) @@ -805,7 +805,7 @@ int FileSystem::getFilePath(FileID fileid, NameBuffer& buffer) } } - return Error::fromSystem(err); + return translateSpiffsError(err); } } // namespace SPIFFS diff --git a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/Error.h b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/Error.h index f714e59cb3..5a33ea7139 100644 --- a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/Error.h +++ b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/Error.h @@ -33,6 +33,8 @@ inline bool isSpiffsError(int err) return err <= -10000; } +int translateSpiffsError(int spiffs_error); + String spiffsErrorToStr(int err); } // namespace SPIFFS } // namespace IFS From 86aec1f3374abebfd47f3758db4f69016826e5b8 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 17 Oct 2022 08:03:04 +0100 Subject: [PATCH 39/58] Fix Uuid comparison for PROGMEM usage (#2567) even memcmp_P goes pop sometimes. To be safe, compare explicitly as 4 words. --- Sming/Core/Data/Uuid.cpp | 11 +++++++++++ Sming/Core/Data/Uuid.h | 10 +++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Sming/Core/Data/Uuid.cpp b/Sming/Core/Data/Uuid.cpp index fdb8ddc71c..e2577a8bb3 100644 --- a/Sming/Core/Data/Uuid.cpp +++ b/Sming/Core/Data/Uuid.cpp @@ -21,6 +21,17 @@ uint32_t os_random(); void os_get_random(void* buf, size_t n); } +bool Uuid::operator==(const Uuid& other) const +{ + // Ensure these are stricly compared as a set of words to avoid PROGMEM issues + struct S { + uint32_t a, b, c, d; + }; + auto& s1 = reinterpret_cast(*this); + auto& s2 = reinterpret_cast(other); + return s1.a == s2.a && s1.b == s2.b && s1.c == s2.c && s1.d == s2.d; +} + bool Uuid::generate(MacAddress mac) { uint8_t version = 1; // DCE version diff --git a/Sming/Core/Data/Uuid.h b/Sming/Core/Data/Uuid.h index 75a351f721..355a704473 100644 --- a/Sming/Core/Data/Uuid.h +++ b/Sming/Core/Data/Uuid.h @@ -36,7 +36,7 @@ struct Uuid { */ static constexpr size_t stringSize = 36; - Uuid() + constexpr Uuid() { } @@ -69,14 +69,10 @@ struct Uuid { explicit operator bool() const { - Uuid Null{}; - return memcmp(this, &Null, sizeof(Null)) != 0; + return *this != Uuid{}; } - bool operator==(const Uuid& other) const - { - return memcmp(this, &other, sizeof(Uuid)) == 0; - } + bool operator==(const Uuid& other) const; bool operator!=(const Uuid& other) const { From 92a9f9d9293dd9b6a238158a4fdcb7bb3b9f4b5f Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 17 Oct 2022 08:04:12 +0100 Subject: [PATCH 40/58] Fix `make[1]: cc: Command not found` during clean (#2568) --- Sming/Arch/Esp8266/Components/libc/component.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sming/Arch/Esp8266/Components/libc/component.mk b/Sming/Arch/Esp8266/Components/libc/component.mk index 930c83d177..8e5247d0f3 100644 --- a/Sming/Arch/Esp8266/Components/libc/component.mk +++ b/Sming/Arch/Esp8266/Components/libc/component.mk @@ -13,6 +13,8 @@ LIBDIRS += $(COMPONENT_PATH)/lib EXTRA_LIBS += microc microgcc setjmp endif +ifndef MAKE_CLEAN + # build customised libstdc++ # https://github.com/esp8266/Arduino/blob/master/tools/sdk/lib/README.md LIBSTDCPP_SRC = $(call FixPath,$(shell $(CC) -print-file-name=libstdc++.a)) @@ -34,3 +36,5 @@ $(COMPONENT_RULE)$(LIBSTDCPP_DST): $(LIBSTDCPP_SRC) COMPONENT_TARGETS += $(LIBSTDCPP_DST) EXTRA_LIBS += stdc++ + +endif From 8beedbcb57ba79a759d6abfa735639331a1217e2 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 18 Oct 2022 08:52:26 +0100 Subject: [PATCH 41/58] Fix Windows Host github CI workflow, tidy (#2569) This PR makes a few improvements to the CI scripts: - Re-enable Windows Host builds. This was failing because of line endings: system default is core.autocrlf=true, requires override before checkout - Use `checkout@v3`: version 2 is deprecated - Move ninja and python setup code into scripts --- .github/workflows/ci.yml | 39 ++++++++-------- .github/workflows/coverity-scan.yml | 15 +++--- .github/workflows/spelling-check.yml | 2 +- .travis.yml | 63 -------------------------- Tools/ci/install.sh | 8 ++-- Tools/ci/setenv.ps1 | 3 ++ Tools/install.sh | 1 + Tools/travis/build.sh | 35 -------------- Tools/travis/deploy.sh | 47 ------------------- Tools/travis/install.sh | 11 ----- appveyor.yml | 51 --------------------- docs/source/information/develop/ci.rst | 35 ++++---------- 12 files changed, 47 insertions(+), 263 deletions(-) delete mode 100644 .travis.yml delete mode 100755 Tools/travis/build.sh delete mode 100755 Tools/travis/deploy.sh delete mode 100755 Tools/travis/install.sh delete mode 100644 appveyor.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0dc70545a0..170819b125 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,39 +27,42 @@ jobs: - arch: Esp32 variant: esp32c3 os: windows-latest - exclude: - - os: windows-latest - arch: Host - - continue-on-error: ${{ matrix.arch == 'Host' && matrix.os == 'windows-latest' }} - + concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} cancel-in-progress: true - + runs-on: ${{ matrix.os }} steps: + - name: Fix autocrlf setting + run: | + git config --global --add core.autocrlf input + - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - name: Setup SMING_HOME for Ubuntu if: ${{ matrix.os == 'ubuntu-latest' }} run: | echo "CI_BUILD_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV echo "SMING_HOME=$GITHUB_WORKSPACE/Sming" >> $GITHUB_ENV + - name: Setup SMING_HOME for Windows if: ${{ matrix.os == 'windows-latest' }} run: | echo ("CI_BUILD_DIR=" + $env:GITHUB_WORKSPACE) >> $env:GITHUB_ENV $env:SMING_HOME = Join-Path $env:GITHUB_WORKSPACE "Sming" echo ("SMING_HOME=" + $env:SMING_HOME) >> $env:GITHUB_ENV + - name: Install Sming Framework on Ubuntu if: ${{ matrix.os == 'ubuntu-latest' }} - env: + env: SMING_ARCH: ${{matrix.arch}} SMING_SOC: ${{matrix.variant}} - run: | - ./Tools/install.sh $(echo "$SMING_ARCH" | tr '[:upper:]' '[:lower:]') + run: | + Tools/ci/install.sh + - name: Install Sming Framework on Windows if: ${{ matrix.os == 'windows-latest' }} env: @@ -67,26 +70,24 @@ jobs: SMING_SOC: ${{matrix.variant}} run: | Tools/ci/setenv.ps1 - Tools/install.cmd "$env:SMING_ARCH".ToLower() - - name: Install Ninja - uses: seanmiddleditch/gha-setup-ninja@master + Tools/ci/install.cmd + - name: Build and Test for ${{matrix.arch}} on Ubuntu env: SMING_ARCH: ${{matrix.arch}} SMING_SOC: ${{matrix.variant}} CLANG_FORMAT: clang-format-8 - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-latest' }} run: | source $SMING_HOME/../Tools/export.sh $CLANG_FORMAT --version - ./Tools/ci/build.sh + Tools/ci/build.sh + - name: Build and Test for ${{matrix.arch}} on Windows env: SMING_ARCH: ${{matrix.arch}} SMING_SOC: ${{matrix.variant}} - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.os == 'windows-latest' }} run: | - $env:PYTHON_PATH=$(python -c "import sys, os.path; print(os.path.dirname(sys.executable))") Tools/ci/setenv.ps1 Tools/ci/build.cmd - diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index 1d65dd2aaf..26e267d00e 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -17,7 +17,7 @@ jobs: # concurrency: # group: ${{ github.head_ref || github.run_id }} # cancel-in-progress: true - + runs-on: ubuntu-latest steps: @@ -40,24 +40,24 @@ jobs: fi fi fi - + echo "CHECK_SCA=$CHECK_SCA" >> $GITHUB_ENV + - name: Setup SMING_HOME for Ubuntu if: ${{ env.CHECK_SCA == 1 }} run: | echo "CI_BUILD_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV echo "SMING_HOME=$GITHUB_WORKSPACE/Sming" >> $GITHUB_ENV echo "SMING_ARCH=Host" >> $GITHUB_ENV + - name: Install Sming Framework on Ubuntu if: ${{ env.CHECK_SCA == 1 }} run: | - ./Tools/install.sh $(echo "$SMING_ARCH" | tr '[:upper:]' '[:lower:]') - - name: Install Ninja - if: ${{ env.CHECK_SCA == 1 }} - uses: seanmiddleditch/gha-setup-ninja@master + Tools/ci/install.sh + - name: Run Coverity Scan if: ${{ env.CHECK_SCA == 1 }} - env: + env: COVERITY_SCAN_TOKEN: ${{secrets.COVERITY_SCAN_TOKEN}} run: | source $SMING_HOME/../Tools/export.sh @@ -65,6 +65,7 @@ jobs: export COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd $SMING_HOME" cat > /tmp/secrets.sh $SMING_HOME/Arch/Host/Tools/ci/coverity-scan.sh + - name: Archive scan log if: ${{ env.CHECK_SCA == 1 }} uses: actions/upload-artifact@v3 diff --git a/.github/workflows/spelling-check.yml b/.github/workflows/spelling-check.yml index 0edeb0080e..4e8d27e7be 100644 --- a/.github/workflows/spelling-check.yml +++ b/.github/workflows/spelling-check.yml @@ -10,7 +10,7 @@ jobs: name: Check spelling runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: false - name: Get submodules diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b470c2bb35..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,63 +0,0 @@ -language: python -python: 3.9 -os: linux -dist: focal -env: - global: - - SMINGTOOLS=https://github.com/SmingHub/SmingTools/releases/download/1.0 - - secure: D/cPk+sL2MNHLtfuU/rMiVN63+CTFpo9Chqa39LEH5VloGqC5f7RyIi2Maa3C/U2JQfM01HlsNR7E5bB0W8DQYbtzBDTqbZ4C7ppZRU5jCQ+L51ERKJ0EAV3KkaravQCRbWt3tlgOp6Xk6xaRMBaHEGrdbFjHYgEMPVteUQNr0A= - - secure: pc8Yqwmn6AM+iBjLNNnknmOoi+AxoyvcVy128b2WXSdj6Q4bOIXgj4WUg8I52i1fgyh0Rxg19WUB6qSVyykCXVdSRajIU1MsKZI+0q44Q83wnwVeYm7nPWxDqS3FKMajucZCg4p0BTE4T6tpnm7zZNHduHnggua/NpP2h7B/Sqs= - - secure: TX0IxYV3tTocCaJcgIA2xzJyHIzbxo7sAkLLYL+OITgWPD1VDUrEqEe7konQA5NIDJJ0VjoHxpdfti2LHG1fw45vrEMfBIOmZG6nW2gxD8ZS2G8KlYIxFB93oNNB6qJRHps1uIANk2hM+Ju6Pnqfc+lLh8oabs974ziAxoYuAJQ= -jobs: - include: - - stage: test - name: Host - addons: - apt: - packages: - - clang-format-8 - - doxygen - - python3-sphinx - - python3-pip - - python3-setuptools - - python3-cairocffi - - graphviz-dev - - xmlstarlet - - jq - env: - - SMING_ARCH=Host - - stage: build - name: C++17 - env: - - SMING_ARCH=Esp8266 - - SDK_VERSION=3.0.1 - - ESP_HOME=$TRAVIS_BUILD_DIR/opt/esp-quick-toolchain - - - stage: build - name: ESP-IDF - env: - - SMING_ARCH=Esp32 - - -git: - submodules: false -addons: - apt: - update: true - packages: - - xmlstarlet -install: "Tools/travis/install.sh" -script: "Tools/travis/build.sh" -deploy: - provider: script - script: "Tools/travis/deploy.sh $TRAVIS_TAG" - skip_cleanup: true - on: - tags: true - condition: $TRAVIS_BUILD_STAGE_NAME = test -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/c1a5e8bc97d3794a0417 - on_success: always - on_failure: always diff --git a/Tools/ci/install.sh b/Tools/ci/install.sh index 9fe5da5110..fbf7625fe0 100755 --- a/Tools/ci/install.sh +++ b/Tools/ci/install.sh @@ -12,9 +12,11 @@ set -ex if [ -z "$SMING_TOOLS_PREINSTALLED" ]; then # appveyor-specific -export PYTHON=$HOME/venv3.9/bin/python -export ESP32_PYTHON_PATH=$HOME/venv3.9/bin -source "$HOME/venv3.9/bin/activate" +if [ -n "$APPVEYOR" ]; then + export PYTHON=$HOME/venv3.9/bin/python + export ESP32_PYTHON_PATH=$HOME/venv3.9/bin + source "$HOME/venv3.9/bin/activate" +fi if [ "$BUILD_DOCS" = "true" ]; then INSTALL_OPTS="doc" diff --git a/Tools/ci/setenv.ps1 b/Tools/ci/setenv.ps1 index a2c69a3925..bbeb69abbe 100644 --- a/Tools/ci/setenv.ps1 +++ b/Tools/ci/setenv.ps1 @@ -31,6 +31,9 @@ if ($IsWindows) { if ( -not (Test-Path "$env:PYTHON_PATH") ) { $env:PYTHON_PATH = "C:\Python39" } + if ( -not (Test-Path "$env:PYTHON_PATH") ) { + $env:PYTHON_PATH = $(Get-Command python | Split-Path) + } } $env:PATH = "$env:PYTHON_PATH;$env:PYTHON_PATH\Scripts;$env:PATH" diff --git a/Tools/install.sh b/Tools/install.sh index 0fb94d8107..6a5423b46c 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -100,6 +100,7 @@ if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then clang-format-8 \ g++-9-multilib \ python3-setuptools \ + ninja-build \ $EXTRA_PACKAGES sudo update-alternatives --set gcc /usr/bin/gcc-9 diff --git a/Tools/travis/build.sh b/Tools/travis/build.sh deleted file mode 100755 index 6cac7ad533..0000000000 --- a/Tools/travis/build.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -set -ex # exit with nonzero exit code if anything fails - -# Build times benefit from parallel building -export MAKE_PARALLEL="make -j3" - -export SMING_HOME=$TRAVIS_BUILD_DIR/Sming - -# Setup ARCH SDK -cd $SMING_HOME -if [ -f "$SMING_HOME/Arch/$SMING_ARCH/Tools/travis/build.setup.sh" ]; then - source "$SMING_HOME/Arch/$SMING_ARCH/Tools/travis/build.setup.sh" -fi - -env - -# Full compile checks please -export STRICT=1 - -# Move samples and tests into directory outside of the Sming repo. -export SMING_PROJECTS_DIR=$HOME/projects -mkdir $SMING_PROJECTS_DIR -mv ../samples $SMING_PROJECTS_DIR -mv ../tests $SMING_PROJECTS_DIR - -# Diagnostic info -cd $SMING_PROJECTS_DIR/samples/Basic_Blink -make help -make list-config - -# Run ARCH SDK tests -cd $SMING_HOME -if [ -f "$SMING_HOME/Arch/$SMING_ARCH/Tools/travis/build.run.sh" ]; then - source "$SMING_HOME/Arch/$SMING_ARCH/Tools/travis/build.run.sh" -fi diff --git a/Tools/travis/deploy.sh b/Tools/travis/deploy.sh deleted file mode 100755 index 5df806fe84..0000000000 --- a/Tools/travis/deploy.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -set -ex # exit with nonzero exit code if anything fails - -TAG=$1 -if [ -z $TAG ]; then - printf "Usage:\n\t$0 \n"; - exit 1; -fi - -export SMING_HOME=$TRAVIS_BUILD_DIR/Sming - -# [ Create new draft release for this tag] -AUTH_HEADER="Authorization: token ${RELEASE_TOKEN}" -RESPONSE=$(curl -H "Content-Type:application/json" -H "$AUTH_HEADER" \ - -d "{\"tag_name\":\"$TAG\",\"target_commitish\": \"develop\",\"name\": \"$TAG\",\"body\":\"Coming soon\",\"draft\": true,\"prerelease\": true}" \ - https://api.github.com/repos/SmingHub/Sming/releases) - -# Get release id -RELEASE_ID=$(echo "$RESPONSE" | jq -r .id) - -# [Get all submodules used in this release, pack them and add the archive to the release artifacts] -cd $SMING_HOME -make submodules -ALL_SUBMODULE_DIRS=$(find $SMING_HOME -name '.submodule' | xargs dirname | sed 's/^\(.*\)\/\(Sming\/.*\)$/\2/') -FILE=/tmp/sming-submodules.tgz -cd ../ -tar cvzf $FILE $ALL_SUBMODULE_DIRS - -curl -H "$AUTH_HEADER" -H "Content-Type: $(file -b --mime-type $FILE)" --data-binary @$FILE "https://uploads.github.com/repos/SmingHub/Sming/releases/$RELEASE_ID/assets?name=$(basename $FILE)" - -# [Update the documentation] -# On push and release readthedocs webhook should update the documentation automatically. -# See: https://buildmedia.readthedocs.org/media/pdf/docs/stable/docs.pdf Webhooks - -# [ Update the choco packages ] -cd /tmp -git clone https://github.com/slaff/chocolatey-packages.git -cd chocolatey-packages -FILES_TO_CHANGE="packages/sming/sming.nuspec packages/sming.upgrade/sming.upgrade.nuspec packages/sming.examples/sming.examples.nuspec packages/sming.core/sming.core.nuspec" - -for FILE in $FILES_TO_CHANGE; -do - xmlstarlet ed --inplace -N "ns=http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" -u "/ns:package/ns:metadata/ns:version" -v "$TAG" $FILE; -done - -git commit -a -m "Updated chocolatey packages to latest stable $TAG version." || 1 -git push https://${SMING_TOKEN}@github.com/slaff/chocolatey-packages.git master diff --git a/Tools/travis/install.sh b/Tools/travis/install.sh deleted file mode 100755 index 099ee34e94..0000000000 --- a/Tools/travis/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -ex # exit with nonzero exit code if anything fails - -sudo dpkg --add-architecture i386 -sudo apt update -sudo apt install software-properties-common -sudo aptitude install -y libc6-dev=2.31-0ubuntu9.2 libc6=2.31-0ubuntu9.2 g++-9-multilib linux-libc-dev:i386 - -if [ -f "$TRAVIS_BUILD_DIR/Sming/Arch/$SMING_ARCH/Tools/travis/install.sh" ]; then - source "$TRAVIS_BUILD_DIR/Sming/Arch/$SMING_ARCH/Tools/travis/install.sh" -fi diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index fb4c571ef5..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,51 +0,0 @@ -image: -- Visual Studio 2019 - -environment: - SMING_SECRET: - secure: rCs19uNvDR07w1d2pfwJIzewiEQ2zpKXdqFp5BqHQAA= - - matrix: - - SMING_ARCH: Host - -install: - - ps: | - # Set up environment variables for all environments and build types - $env:CI_REPO_NAME = $env:APPVEYOR_REPO_NAME - if ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME) { - $env:CI_PULL_REQUEST = "true" - } - Tools/ci/setenv.ps1 - - - cmd: | - Tools\ci\install.cmd - - - sh: | - . Tools/ci/install.sh - -before_build: - - sh: | - # Check if we could run static code analysis - export CHECK_SCA=0 - if [[ $APPVEYOR_REPO_TAG_NAME != "" || ( $APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED == *"[scan:coverity]"* && $CI_PULL_REQUEST == "" ) ]]; then - export CHECK_SCA=1 - fi - -build_script: - - cmd: Tools\ci\build.cmd - - sh: Tools/ci/build.sh - -after_build: - - ps: | - if ($env:BUILD_DOCS) { - $docFile = "sming-docs.zip" - Compress-Archive -Path $env:CI_BUILD_DIR/docs/build/html -DestinationPath $docFile - Push-AppveyorArtifact $docFile - } - - -deploy_script: - - sh: | - if [[ $APPVEYOR_REPO_TAG_NAME != "" && $APPVEYOR_BUILD_WORKER_IMAGE == "Ubuntu2004" && $SMING_ARCH == "Host" ]]; then - Tools/ci/deploy.sh $APPVEYOR_REPO_TAG_NAME - fi diff --git a/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index c149a33a70..76910fad46 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -19,43 +19,26 @@ are supported on all architectures. It also provides a mechanism for logging test results. -Appveyor --------- +Github Actions +-------------- -We use `appveyor `__ to manage all test builds. +We use Github Actions to manage all test builds. This service is free of charge for open-source projects. -Note: We used to use `Travis `__ but this is no longer free of charge. +.. note:: + + Appveyor has been removed in favour of GitHub Actions. + + We used to use `Travis `__ but this is no longer free of charge. -The build is controlled via the ``appveyor.yml`` file in the sming root directory. Sming performs the build and test logic is handled using scripts, which are intended to be easily portable to other CI services if necessary. Mostly batch scripts (.cmd) are used for Windows, and bash scripts (.sh) for GNU/Linux but where practical powershell core is used as this runs on either. - .. note:: - Appveyor also supports macOS but at present Sming doesn't perform CI builds on that platform. - - -Configuration -~~~~~~~~~~~~~ - -Sming developers may use integration testing for their own projects, libraries or framework changes. - -Configure as follows: - -- Visit https://www.appveyor.com/ and create an account. It's usually easiest to sign up using the ``GitHub`` link. -- Select ``Projects`` from the toolbar and click on ``New Project``. If there are no projects listed make sure - AppVeyor has been authorised as a GitHub App. -- You can now click ``New Build`` to build the default branch. - This may not be what you require so visit the project settings page and configure as necessary. - -By default, pull requests are built automatically. - -The `Rolling builds `__ -setting ensures that only the most recent commit to a branch is built, so should usually be enabled. + Sming doesn't perform CI builds for MacOS. Library CI support From ee934e456cbc2dea5a3dacb8b451a62d01d60474 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 24 Oct 2022 09:51:48 +0100 Subject: [PATCH 42/58] Fix "fatal: transport 'file' not allowed" error during CI builds (#2570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CVE-2022-39253 Git has changed the default value of protocol.file.allow to “user”, meaning that file:// clones are considered unsafe by default. --- tests/SharedComponent/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SharedComponent/Makefile b/tests/SharedComponent/Makefile index ea6948bf30..b246327d31 100644 --- a/tests/SharedComponent/Makefile +++ b/tests/SharedComponent/Makefile @@ -63,7 +63,7 @@ $(REPO_DIR)/.git: # Add shared-test.repo as a submodule to the shared-test Component, but leave it un-initialised $(SHARED_COMPONENT_DIR)/.gitmodules: | $(SHARED_COMPONENT_DIR)/.git $(Q) cd $(@D)/$(COMPONENT_NAME) && \ - git submodule add $(CURDIR)/$(REPO_DIR) $(SUBMODULE_NAME) && \ + git -c protocol.file.allow=always submodule add $(CURDIR)/$(REPO_DIR) $(SUBMODULE_NAME) && \ git submodule deinit -f $(SUBMODULE_NAME) $(SHARED_COMPONENT_DIR)/.git: From 0a0478f51d12a9d2604ac0dd9650e4b4831020b3 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 24 Oct 2022 14:21:45 +0100 Subject: [PATCH 43/58] Fix SPIFFS error translation (#2571) --- Sming/Components/IFS | 2 +- Sming/Libraries/Spiffs/src/Error.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Sming/Components/IFS b/Sming/Components/IFS index 2c04e53140..a29817b8e8 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 2c04e5314040b787f2e9b3b619182dec47bae13a +Subproject commit a29817b8e8578e0709091ddfb204206ab1749fe0 diff --git a/Sming/Libraries/Spiffs/src/Error.cpp b/Sming/Libraries/Spiffs/src/Error.cpp index 1269ad7c93..c7b321b8c1 100644 --- a/Sming/Libraries/Spiffs/src/Error.cpp +++ b/Sming/Libraries/Spiffs/src/Error.cpp @@ -23,6 +23,7 @@ #include "include/IFS/SPIFFS/Error.h" #include #include +#include "../spiffs/src/spiffs.h" namespace IFS { @@ -101,6 +102,8 @@ int translateSpiffsError(int spiffs_error) #define XX(err_spiffs, err_sys) \ case err_spiffs: \ return err_sys; + SPIFFS_ERROR_TRANSLATION_MAP(XX) +#undef XX default: return Error::fromSystem(spiffs_error); } From 5a2f49a268b69b7dd0d77ce4aa35f3e2f0dc071a Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Oct 2022 10:43:02 +0100 Subject: [PATCH 44/58] Remove CustomDevice, use `editablePartitions()` method (#2572) This PR tidies up how device in-memory partition tables are updated. The Device `partitions()` method returns a read-only (const) reference to the device's `PartitionTable` suitable for general application use. A new `editablePartitions()` method has been added which provides a non-const version so the table can be updated. This removes the need for the `CustomDevice` class, which has been removed. For example: part = device->createPartition("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); becomes: part = device->editablePartitions().add("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); --- Sming/Components/IFS | 2 +- Sming/Components/Storage/README.rst | 10 ++--- Sming/Components/Storage/src/ProgMem.cpp | 2 +- .../src/include/Storage/CustomDevice.h | 33 ---------------- .../Storage/src/include/Storage/Device.h | 8 ++++ .../src/include/Storage/PartitionTable.h | 12 +++--- .../Storage/src/include/Storage/ProgMem.h | 8 ++-- .../src/include/Storage/StreamDevice.h | 6 +-- .../Storage/src/include/Storage/SysMem.h | 12 +++--- Sming/Libraries/LittleFS | 2 +- docs/source/upgrading/4.6-4.7.rst | 38 +++++++++++-------- samples/Basic_IFS/app/application.cpp | 3 +- samples/Basic_Storage/app/application.cpp | 7 ++-- tests/HostTests/modules/Spiffs.cpp | 4 +- 14 files changed, 65 insertions(+), 82 deletions(-) delete mode 100644 Sming/Components/Storage/src/include/Storage/CustomDevice.h diff --git a/Sming/Components/IFS b/Sming/Components/IFS index a29817b8e8..e69049e93b 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit a29817b8e8578e0709091ddfb204206ab1749fe0 +Subproject commit e69049e93bc6efa4b6fe0d4dd07209fac450a0e1 diff --git a/Sming/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index ef4a5cccd9..56a0dce5ad 100644 --- a/Sming/Components/Storage/README.rst +++ b/Sming/Components/Storage/README.rst @@ -332,19 +332,19 @@ This is a C++ interface. Some examples:: Storage::Partition part = Storage::findPartition("spiffs0"); // Find by name if(part) { - debugf("Partition '%s' found", part.name().c_str()); + Serial << part << endl; } else { - debugf("Partition NOT found"); + Serial << "spiffs0 partition NOT Found" << endl; } // Enumerate all partitions for(auto part: Storage::findPartition()) { - debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); + Serial << part << endl; } // Enumerate all SPIFFS partitions for(auto part: Storage::findPartition(Storage::Partition::SubType::Data::spiffs)) { - debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); + Serial << part << endl; } @@ -361,7 +361,7 @@ You can query partition entries from a Storage object directly, for example:: #include for(auto part: Storage::spiFlash->partitions()) { - debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); + Serial << part << endl; } diff --git a/Sming/Components/Storage/src/ProgMem.cpp b/Sming/Components/Storage/src/ProgMem.cpp index 16e68e3410..34b4f25df0 100644 --- a/Sming/Components/Storage/src/ProgMem.cpp +++ b/Sming/Components/Storage/src/ProgMem.cpp @@ -29,7 +29,7 @@ Partition ProgMem::ProgMemPartitionTable::add(const String& name, const void* fl return Partition{}; } - return CustomPartitionTable::add(name, type, addr, size, Partition::Flag::readOnly); + return PartitionTable::add(name, type, addr, size, Partition::Flag::readOnly); } } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/CustomDevice.h b/Sming/Components/Storage/src/include/Storage/CustomDevice.h deleted file mode 100644 index ff39cb336a..0000000000 --- a/Sming/Components/Storage/src/include/Storage/CustomDevice.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * CustomDevice.h - */ - -#pragma once - -#include "Device.h" - -namespace Storage -{ -/** - * @brief Class to support dynamic partitions - */ -class CustomDevice : public Device -{ -public: - class CustomPartitionTable : public PartitionTable - { - public: - using PartitionTable::add; - using PartitionTable::clear; - }; - - /** - * @brief Provide read/write access to in-memory partition table - */ - CustomPartitionTable& partitions() - { - return static_cast(mPartitions); - } -}; - -} // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index 4802fda5cb..71b4987408 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -64,6 +64,14 @@ class Device : public LinkedObjectTemplate return mPartitions; } + /** + * @brief Provide full access to partition table + */ + PartitionTable& editablePartitions() + { + return mPartitions; + } + /** * @brief Load partition table entries * @tableOffset Location of partition table to read diff --git a/Sming/Components/Storage/src/include/Storage/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index b618141d18..b54fcee3f3 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionTable.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionTable.h @@ -98,12 +98,6 @@ class PartitionTable return mDevice; } -protected: - friend Device; - friend Iterator; - - void load(const esp_partition_info_t* entry, unsigned count); - /** * @brief Add new partition using given Info * @param info Must be allocated using `new`: Device will take ownership @@ -124,6 +118,12 @@ class PartitionTable mEntries.clear(); } +protected: + friend Device; + friend Iterator; + + void load(const esp_partition_info_t* entry, unsigned count); + Device& mDevice; Partition::Info::OwnedList mEntries; }; diff --git a/Sming/Components/Storage/src/include/Storage/ProgMem.h b/Sming/Components/Storage/src/include/Storage/ProgMem.h index 5a149940e2..a9d74580f2 100644 --- a/Sming/Components/Storage/src/include/Storage/ProgMem.h +++ b/Sming/Components/Storage/src/include/Storage/ProgMem.h @@ -9,14 +9,14 @@ ****/ #pragma once -#include "CustomDevice.h" +#include "Device.h" namespace Storage { /** * @brief Storage device to access PROGMEM using flash API */ -class ProgMem : public CustomDevice +class ProgMem : public Device { public: String getName() const override @@ -51,7 +51,7 @@ class ProgMem : public CustomDevice return false; } - class ProgMemPartitionTable : public CustomPartitionTable + class ProgMemPartitionTable : public PartitionTable { public: /** @@ -73,7 +73,7 @@ class ProgMem : public CustomDevice } }; - ProgMemPartitionTable& partitions() + ProgMemPartitionTable& editablePartitions() { return static_cast(mPartitions); } diff --git a/Sming/Components/Storage/src/include/Storage/StreamDevice.h b/Sming/Components/Storage/src/include/Storage/StreamDevice.h index 18ca2d64cf..ebca8bfc2f 100644 --- a/Sming/Components/Storage/src/include/Storage/StreamDevice.h +++ b/Sming/Components/Storage/src/include/Storage/StreamDevice.h @@ -2,7 +2,7 @@ * StreamDevice.h */ -#include "CustomDevice.h" +#include "Device.h" #include namespace Storage @@ -11,10 +11,10 @@ namespace Storage * @brief Read-only partition on a stream object * @note Writes not possible as streams always append data, cannot do random writes */ -class StreamDevice : public CustomDevice +class StreamDevice : public Device { public: - StreamDevice(IDataSourceStream* stream, size_t size) : CustomDevice(nameOf(stream), size), mStream(stream) + StreamDevice(IDataSourceStream* stream, size_t size) : Device(nameOf(stream), size), mStream(stream) { } diff --git a/Sming/Components/Storage/src/include/Storage/SysMem.h b/Sming/Components/Storage/src/include/Storage/SysMem.h index 22a623a564..aa26598df1 100644 --- a/Sming/Components/Storage/src/include/Storage/SysMem.h +++ b/Sming/Components/Storage/src/include/Storage/SysMem.h @@ -10,14 +10,14 @@ #pragma once -#include "CustomDevice.h" +#include "Device.h" namespace Storage { /** * @brief Storage device to access system memory, e.g. RAM */ -class SysMem : public CustomDevice +class SysMem : public Device { public: String getName() const override @@ -70,7 +70,7 @@ class SysMem : public CustomDevice return true; } - class SysMemPartitionTable : public CustomPartitionTable + class SysMemPartitionTable : public PartitionTable { public: /** @@ -78,12 +78,12 @@ class SysMem : public CustomDevice */ Partition add(const String& name, const FSTR::ObjectBase& fstr, Partition::FullType type) { - return CustomPartitionTable::add(name, type, reinterpret_cast(fstr.data()), fstr.size(), - Partition::Flag::readOnly); + return PartitionTable::add(name, type, reinterpret_cast(fstr.data()), fstr.size(), + Partition::Flag::readOnly); } }; - SysMemPartitionTable& partitions() + SysMemPartitionTable& editablePartitions() { return static_cast(mPartitions); } diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 55dbf00a0e..d64b6bc0f7 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 55dbf00a0e992f97d9dd1416f38f13b079e0ce84 +Subproject commit d64b6bc0f7a9bfb20b843cf4181bc9f9cb6de762 diff --git a/docs/source/upgrading/4.6-4.7.rst b/docs/source/upgrading/4.6-4.7.rst index b5858ae5a4..466d2940ec 100644 --- a/docs/source/upgrading/4.6-4.7.rst +++ b/docs/source/upgrading/4.6-4.7.rst @@ -6,36 +6,42 @@ From v4.6 to v4.7 Storage Partition methods ------------------------- -The ``Storage::Partition::getDevice()`` method has been removed. -This could be used to bypass protections offered by the partitioning API. +The ``Storage::Partition::getDevice()`` method has been removed because +it could be used to bypass protections offered by the partitioning API. Storage Device Partitions ------------------------- -The ``Storage::CustomDevice::createPartition()`` methods have been removed. - Instead, use partition table methods. +The ``CustomDevice`` class has been removed as it is simpler and more flexible to instead use PartitionTable methods. - For example:: +The :cpp:func:`Storage::Device::partitions` method returns a read-only (const) :cpp:class:`Storage::PartitionTable` object +for general use to avoid inadvertent modification. - part = device->createPartition("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); +Use the :cpp:func:`Storage::Device::editablePartitions` method to make partition table changes. - becomes:: +For example:: - part = device->partitions().add("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); + part = device->createPartition("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); - This also applies to derivatives :cpp:class:`Storage::SysMem` and :cpp:class:`Storage::ProgMem`. +becomes:: + part = device->editablePartitions().add("archive", Storage::Partition::SubType::Data::fwfs, startOffset, size); -Creating custom partition types require use of :cpp:struct:`Storage::Partition::FullType`. - For example:: - part = device->createPartitions("fs_app", Storage::Partition::Type::data, 100, startOffset, size); +Custom Partition Types +---------------------- - becomes:: +Creating custom partition types now require use of :cpp:struct:`Storage::Partition::FullType`. - part = device->partitions().add("fs_app", {Storage::Partition::Type::data, 100}, startOffset, size); +For example:: - Note how the ``type`` and ``subtype`` values are enclosed in braces (instantiating a ``FullType`` struct). - This avoids confusing the subtype value ``100`` with the start offset. + part = device->createPartition("fs_app", Storage::Partition::Type::data, 100, startOffset, size); + +becomes:: + + part = device->editablePartitions().add("fs_app", {Storage::Partition::Type::data, 100}, startOffset, size); + +Note how the ``type`` and ``subtype`` values are enclosed in braces (instantiating a ``FullType`` struct). +This avoids confusing the subtype value ``100`` with the start offset. diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 79a7f8c25b..5c92b3ddab 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -139,7 +139,8 @@ bool initFileSystem() #ifdef ENABLE_FLASHSTRING_IMAGE // Create a partition wrapping some flashstring data - auto part = Storage::progMem.partitions().add(F("fwfsMem"), fwfsImage, Storage::Partition::SubType::Data::fwfs); + auto part = + Storage::progMem.editablePartitions().add(F("fwfsMem"), fwfsImage, Storage::Partition::SubType::Data::fwfs); #else auto part = Storage::findDefaultPartition(Storage::Partition::SubType::Data::fwfs); #endif diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index de77fcfd56..7c2aa6fa7c 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -80,19 +80,20 @@ void init() Serial.println(_F("** Reading tests, repeat 3 times to show effect of caching (if any)")); Serial.println(_F("** Reading SysMem device (flash)")); - part = Storage::sysMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); + part = Storage::sysMem.editablePartitions().add(F("fs_app FLASH"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); Serial.println(_F("** Reading SysMem device (RAM)")); - part = Storage::sysMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); + part = Storage::sysMem.editablePartitions().add(F("fs_app RAM"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); Serial.println(_F("** Reading ProgMem device")); - part = Storage::progMem.partitions().add(F("fs_app"), FS_app, {Storage::Partition::Type::data, 100}); + part = + Storage::progMem.editablePartitions().add(F("fs_app PROGMEM"), FS_app, {Storage::Partition::Type::data, 100}); printPart(part); printPart(part); printPart(part); diff --git a/tests/HostTests/modules/Spiffs.cpp b/tests/HostTests/modules/Spiffs.cpp index c2a08997a0..03e6e9e03b 100644 --- a/tests/HostTests/modules/Spiffs.cpp +++ b/tests/HostTests/modules/Spiffs.cpp @@ -113,8 +113,8 @@ class SpiffsTest : public TestGroup } auto dev = new Storage::FileDevice(tag, hfs, f); Storage::registerDevice(dev); - auto part = dev->partitions().add(tag, Storage::Partition::SubType::Data::spiffs, 0, dev->getSize(), - Storage::Partition::Flag::readOnly); + auto part = dev->editablePartitions().add(tag, Storage::Partition::SubType::Data::spiffs, 0, dev->getSize(), + Storage::Partition::Flag::readOnly); auto fs = IFS::createSpiffsFilesystem(part); int err = fs->mount(); From 0c01a88b5c3170470c6514f5b367e2260fc8b891 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 27 Oct 2022 10:15:55 +0100 Subject: [PATCH 45/58] Fix LittleFS error code translation (#2573) --- Sming/Libraries/LittleFS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index d64b6bc0f7..9af1d3bd27 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit d64b6bc0f7a9bfb20b843cf4181bc9f9cb6de762 +Subproject commit 9af1d3bd27915b0180ba7f73fe553a06ad7d9d94 From ebd8feb9f308579ed6d09835c7e79be7016b9ec3 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 31 Oct 2022 08:12:50 +0000 Subject: [PATCH 46/58] Add Github actions support for library CI testing (#2577) This PR adds a re-usable `library` workflow for Github actions so that Sming libraries can be independently tested. It also tidies up the main ``ci.yml`` file and fixes a couple of minor related issues. The ``library.yml`` re-useable workflow is provided, which takes care of these tasks: - Checking in the library to test - Checking in the Sming framework - Installing build tools - Builds all applications within the library's ``samples`` directory, for all supported architectures - If a test application is provided then that should be located in a ``test`` directory. This is built for all architectures, and also executed for Host. Builds are handled using :source:`Tools/ci/library/Makefile`. See also https://docs.github.com/en/actions/using-workflows/reusing-workflows. To use this in a project, add a suitable workflow to the ``.github/workflows`` directory. Templates are provided in the ``.github/workflows/library`` directory. Here is the basic ``push`` scenario: ``` name: CI Push on: [push] jobs: build: uses: SmingHub/Sming/.github/workflows/library.yml@develop # Inputs are all optional, defaults are shown with: # Repository to fetch Sming from sming_repo: 'https://github.com/SmingHub/Sming' # Sming branch to run against sming_branch: 'develop' # Library alias alias: '' ``` The ``sming_repo`` and ``sming_branch`` inputs are provided if your library requires modifications to Sming which are not (yet) in the main repository. The ``alias`` input is required where the library repository name does not correspond with the working title. For example, the ``jerryscript`` library is in a repository called ``Sming-jerryscript``, so must be checked out using a different name. If Sming contains a library (or Component) with the same name then it will be overridden, with a warning ``Multiple matches found for Component 'jerryscript'`` in the build log. The ``ci-dispatch.yml`` example demonstrates manual triggering, which allows these inputs to be easily changed. See https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow. Note that the workflow must be available in the library's default branch, or it will not appear in the github web page. --- .github/workflows/ci.yml | 67 +++++-------- .github/workflows/library.yml | 97 +++++++++++++++++++ .github/workflows/library/ci-dispatch.yml | 18 ++++ .github/workflows/library/ci-push.yml | 7 ++ .../Storage/Tools/hwconfig/common.py | 2 +- Tools/ci/install.sh | 2 +- Tools/install.sh | 1 + docs/source/information/develop/ci.rst | 62 ++++++++++++ 8 files changed, 212 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/library.yml create mode 100644 .github/workflows/library/ci-dispatch.yml create mode 100644 .github/workflows/library/ci-push.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 170819b125..a75033856e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,22 +11,21 @@ jobs: strategy: fail-fast: false matrix: - arch: [Esp8266, Host, Esp32, Rp2040] - variant: [""] os: [ubuntu-latest, windows-latest] + variant: [esp8266, host, esp32, esp32s2, esp32c3, rp2040] include: - - arch: Esp32 - variant: esp32s2 - os: ubuntu-latest - - arch: Esp32 - variant: esp32s2 - os: windows-latest - - arch: Esp32 - variant: esp32c3 - os: ubuntu-latest - - arch: Esp32 - variant: esp32c3 - os: windows-latest + - variant: esp8266 + arch: Esp8266 + - variant: host + arch: Host + - variant: esp32 + arch: Esp32 + - variant: esp32s2 + arch: Esp32 + - variant: esp32c3 + arch: Esp32 + - variant: rp2040 + arch: Rp2040 concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} @@ -42,40 +41,27 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Setup SMING_HOME for Ubuntu - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - echo "CI_BUILD_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV - echo "SMING_HOME=$GITHUB_WORKSPACE/Sming" >> $GITHUB_ENV - - - name: Setup SMING_HOME for Windows - if: ${{ matrix.os == 'windows-latest' }} + - name: Configure environment + shell: pwsh run: | - echo ("CI_BUILD_DIR=" + $env:GITHUB_WORKSPACE) >> $env:GITHUB_ENV - $env:SMING_HOME = Join-Path $env:GITHUB_WORKSPACE "Sming" - echo ("SMING_HOME=" + $env:SMING_HOME) >> $env:GITHUB_ENV + "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 Sming Framework on Ubuntu + - name: Install build tools for Ubuntu if: ${{ matrix.os == 'ubuntu-latest' }} - env: - SMING_ARCH: ${{matrix.arch}} - SMING_SOC: ${{matrix.variant}} run: | Tools/ci/install.sh - - name: Install Sming Framework on Windows + - name: Install build tools for Windows if: ${{ matrix.os == 'windows-latest' }} - env: - SMING_ARCH: ${{matrix.arch}} - SMING_SOC: ${{matrix.variant}} run: | - Tools/ci/setenv.ps1 + . Tools/ci/setenv.ps1 Tools/ci/install.cmd - - name: Build and Test for ${{matrix.arch}} on Ubuntu + - name: Build and test for ${{matrix.arch}} on Ubuntu env: - SMING_ARCH: ${{matrix.arch}} - SMING_SOC: ${{matrix.variant}} CLANG_FORMAT: clang-format-8 if: ${{ matrix.os == 'ubuntu-latest' }} run: | @@ -83,11 +69,8 @@ jobs: $CLANG_FORMAT --version Tools/ci/build.sh - - name: Build and Test for ${{matrix.arch}} on Windows - env: - SMING_ARCH: ${{matrix.arch}} - SMING_SOC: ${{matrix.variant}} + - name: Build and test for ${{matrix.arch}} on Windows if: ${{ matrix.os == 'windows-latest' }} run: | - Tools/ci/setenv.ps1 + . Tools/ci/setenv.ps1 Tools/ci/build.cmd diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml new file mode 100644 index 0000000000..cb247ad98d --- /dev/null +++ b/.github/workflows/library.yml @@ -0,0 +1,97 @@ +name: Continuous Integration (CI) + +on: + workflow_call: + inputs: + sming_repo: + description: 'Full URL for Sming repository' + default: 'https://github.com/SmingHub/Sming' + type: string + sming_branch: + description: 'Sming branch to run against' + default: 'develop' + type: string + alias: + description: 'Library alias' + default: '' + type: string + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + variant: [esp8266, host, esp32, esp32s2, esp32c3, 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 + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ toJson(matrix) }} + cancel-in-progress: true + + runs-on: ${{ matrix.os }} + + steps: + - name: Fix autocrlf setting + run: | + git config --global --add core.autocrlf input + + - name: Checkout code + uses: actions/checkout@v3 + + - name: Create library alias + if: ${{ inputs.alias }} + shell: pwsh + run: | + New-Item -ItemType SymbolicLink -Path "../${{ inputs.alias }}" -Target (Resolve-Path ".").path + + - name: Checkout sming + run: | + git clone ${{ inputs.sming_repo }} -b ${{ inputs.sming_branch }} --depth 1 ../../sming + + - name: Configure environment + shell: pwsh + run: | + "SMING_HOME=" + (Resolve-Path "../../sming/Sming").path >> $env:GITHUB_ENV + "COMPONENT_SEARCH_DIRS=" + (Resolve-Path "..").path >> $env:GITHUB_ENV + "CI_MAKEFILE=" + (Resolve-Path "../../sming/Tools/ci/library/Makefile") >> $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-latest' }} + run: | + . $SMING_HOME/../Tools/export.sh + $SMING_HOME/../Tools/ci/install.sh $SMING_ARCH + + - name: Install build tools for Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + . "$env:SMING_HOME/../Tools/ci/setenv.ps1" + . "$env:SMING_HOME/../Tools/ci/install.cmd" + + - name: Build and Test for ${{matrix.arch}} on Ubuntu + env: + CLANG_FORMAT: clang-format-8 + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + . $SMING_HOME/../Tools/export.sh + make -j$(nproc) -f $CI_MAKEFILE + + - name: Build and Test for ${{matrix.arch}} on Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + . "$env:SMING_HOME/../Tools/ci/setenv.ps1" + make -j $env:NUMBER_OF_PROCESSORS -f $env:CI_MAKEFILE diff --git a/.github/workflows/library/ci-dispatch.yml b/.github/workflows/library/ci-dispatch.yml new file mode 100644 index 0000000000..9c56780fc3 --- /dev/null +++ b/.github/workflows/library/ci-dispatch.yml @@ -0,0 +1,18 @@ +name: CI Dispatch + +on: + workflow_dispatch: + inputs: + sming_repo: + description: 'Full URL for Sming repository' + default: 'https://github.com/SmingHub/Sming' + sming_branch: + description: 'Sming branch to run against' + default: 'develop' + +jobs: + build: + uses: SmingHub/Sming/.github/workflows/library.yml@develop + with: + sming_repo: ${{ inputs.sming_repo }} + sming_branch: ${{ inputs.sming_branch }} diff --git a/.github/workflows/library/ci-push.yml b/.github/workflows/library/ci-push.yml new file mode 100644 index 0000000000..ba9475e787 --- /dev/null +++ b/.github/workflows/library/ci-push.yml @@ -0,0 +1,7 @@ +name: CI Push + +on: [push] + +jobs: + build: + uses: SmingHub/Sming/.github/workflows/library.yml@develop diff --git a/Sming/Components/Storage/Tools/hwconfig/common.py b/Sming/Components/Storage/Tools/hwconfig/common.py index af10921d7c..d0b30932d8 100644 --- a/Sming/Components/Storage/Tools/hwconfig/common.py +++ b/Sming/Components/Storage/Tools/hwconfig/common.py @@ -24,7 +24,7 @@ def critical(msg): def fixpath(path): """Paths in Windows can get a little weird """ - if len(path) > 2 and path[1] != ':' and platform.system() == 'Windows' and path[2] == '/': + if path[0] == '/' and platform.system() == 'Windows': return path[1] + ':' + path[2:] return path diff --git a/Tools/ci/install.sh b/Tools/ci/install.sh index fbf7625fe0..e95c2a6d45 100755 --- a/Tools/ci/install.sh +++ b/Tools/ci/install.sh @@ -24,6 +24,6 @@ else INSTALL_OPTS="fonts" fi -"$SMING_HOME/../Tools/install.sh" ${SMING_ARCH,,} $INSTALL_OPTS +"$SMING_HOME/../Tools/install.sh" $SMING_ARCH $INSTALL_OPTS fi diff --git a/Tools/install.sh b/Tools/install.sh index 6a5423b46c..fcbbb411ea 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -17,6 +17,7 @@ err=0 FONT_PACKAGES="fonts-ubuntu fonts-noto-mono xfonts-base fonts-urw-base35 fonts-droid-fallback" for opt in "$@"; do + opt=$(echo "$opt" | tr '[:upper:]' '[:lower:]') case $opt in all) inst_host=1 diff --git a/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index 76910fad46..8dabb8f159 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -44,6 +44,68 @@ where practical powershell core is used as this runs on either. Library CI support ------------------ +Sming libraries may be separately built and tested whether or not they are included as part of +the Sming repository (or a fork). + +There are two mechanisms avaiable. + +GitHub Actions +~~~~~~~~~~~~~~ + +The ``library.yml`` re-useable workflow is provided, which takes care of these tasks: + +- Checking in the library to test +- Checking in the Sming framework +- Installing build tools +- Builds all applications within the library's ``samples`` directory, for all supported architectures +- If a test application is provided then that should be located in a ``test`` directory. + This is built for all architectures, and also executed for Host. + +Builds are handled using :source:`Tools/ci/library/Makefile`. + +See also https://docs.github.com/en/actions/using-workflows/reusing-workflows. + +To use this in a project, add a suitable workflow to the ``.github/workflows`` directory. +Templates are provided in the ``.github/workflows/library`` directory. + +Here is the basic ``push`` scenario: + +.. code-block:: yaml + + name: CI Push + on: [push] + jobs: + build: + uses: SmingHub/Sming/.github/workflows/library.yml@develop + # Inputs are all optional, defaults are shown + with: + # Repository to fetch Sming from + sming_repo: 'https://github.com/SmingHub/Sming' + # Sming branch to run against + sming_branch: 'develop' + # Library alias + alias: '' + +The ``sming_repo`` and ``sming_branch`` inputs are provided if your library requires modifications +to Sming which are not (yet) in the main repository. + +The ``alias`` input is required where the library repository name does not correspond with +the working title. +For example, the ``jerryscript`` library is in a repository called ``Sming-jerryscript``, +so must be checked out using a different name. +If Sming contains a library (or Component) with the same name then it will be overridden, +with a warning ``Multiple matches found for Component 'jerryscript'`` in the build log. + +The ``ci-dispatch.yml`` example demonstrates manual triggering, which allows these inputs to be easily changed. +See https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow. + +Note that the workflow must be available in the library's default branch, or it will +not appear in the github web page. + + +Appveyor +~~~~~~~~ + Appveyor may be configured to test a Sming library separately. Steps to enable: Add project to appveyor account From c40f7e362c5c9002d99bce70ad0f2f694cd45fc7 Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 10 Nov 2022 13:05:23 +0100 Subject: [PATCH 47/58] Fix issue with esp32 paths. (#2580) --- Sming/Arch/Esp32/build.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sming/Arch/Esp32/build.mk b/Sming/Arch/Esp32/build.mk index 2524b411cd..9e102d8088 100644 --- a/Sming/Arch/Esp32/build.mk +++ b/Sming/Arch/Esp32/build.mk @@ -100,8 +100,8 @@ endif DEBUG_VARS += NINJA NINJA := $(if $(ESP32_NINJA_PATH),$(ESP32_NINJA_PATH)/,)ninja -space := -space += +empty:= +space:= $(empty) $(empty) export PATH := $(subst $(space),:,$(IDF_PATH_LIST)):$(PATH) From 82fb1f651c31efa26cbeb80c1fbb79b98d5579a8 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 14 Nov 2022 08:00:08 +0000 Subject: [PATCH 48/58] Fix ObjectList inheritance (#2582) --- Sming/Core/Data/LinkedObject.h | 9 ++------- Sming/Core/Data/LinkedObjectList.h | 14 ++++++++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Sming/Core/Data/LinkedObject.h b/Sming/Core/Data/LinkedObject.h index 95bd20379e..14d58d8cd0 100644 --- a/Sming/Core/Data/LinkedObject.h +++ b/Sming/Core/Data/LinkedObject.h @@ -30,11 +30,6 @@ class LinkedObject return mNext; } - LinkedObject* getNext() const - { - return mNext; - } - bool insertAfter(LinkedObject* object) { if(object == nullptr) { @@ -84,7 +79,7 @@ template class LinkedObjectTemplate : public LinkedObject IteratorTemplate& operator++() { - mObject = mObject->getNext(); + this->mObject = static_cast(this->mObject->next()); return *this; } @@ -129,7 +124,7 @@ template class LinkedObjectTemplate : public LinkedObject ObjectType* getNext() const { - return reinterpret_cast(this->next()); + return static_cast(this->next()); } bool insertAfter(ObjectType* object) diff --git a/Sming/Core/Data/LinkedObjectList.h b/Sming/Core/Data/LinkedObjectList.h index b9f5e75767..b194efa681 100644 --- a/Sming/Core/Data/LinkedObjectList.h +++ b/Sming/Core/Data/LinkedObjectList.h @@ -89,6 +89,12 @@ class LinkedObjectList template class LinkedObjectListTemplate : public LinkedObjectList { public: + using Iterator = + typename LinkedObjectTemplate::template IteratorTemplate; + using ConstIterator = + typename LinkedObjectTemplate::template IteratorTemplate; + LinkedObjectListTemplate() = default; LinkedObjectListTemplate(ObjectType* object) : LinkedObjectList(object) @@ -105,22 +111,22 @@ template class LinkedObjectListTemplate : public LinkedObj return reinterpret_cast(mHead); } - typename ObjectType::Iterator begin() + Iterator begin() { return head(); } - typename ObjectType::Iterator end() + Iterator end() { return nullptr; } - typename ObjectType::ConstIterator begin() const + ConstIterator begin() const { return head(); } - typename ObjectType::ConstIterator end() const + ConstIterator end() const { return nullptr; } From 71983c59b4de7cf18831c8d5e96cdd5ad1ed39cf Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 15 Nov 2022 13:08:06 +0000 Subject: [PATCH 49/58] Add disk storage support (SD cards) (#2584) This PR extends the Storage system to support block-based devices such as SD cards. Storage sizes have been changed from `uint32_t` to `storage_size_t`. Default operation is unchanged, but this allows 64-bit offsets to be used to support devices greater than about 4GB. The existing `SDCard` library has been taken and reworked extensively with added GNU/Linux source code to handle MBR/GPT partitioning. The result is the `DiskStorage` base library, which is then used by the `SdStorage` library to provide specific SD card support, currently using SPI. Optional buffering for block devices is included to support other filing systems. LittleFS appears to work but Spiffs doesn't - it requires erased sectors to be 0xFF which is fundamentally incompatible. Finally, the `FatIFS` library has been added, using the current version of Chan's fatfs library. There are some minor modifications in the code to fix time handling and simplify use. Testing for these libraries has been implemented by verifying generated filesystem images using standard GNU/Linux tools. --- .gitmodules | 20 ++- .../Esp8266/Components/esp8266/startup.cpp | 35 ++++-- .../Host/Components/spi_flash/component.mk | 2 + .../Rp2040/Components/rp2040/component.mk | 3 +- Sming/Components/IFS | 2 +- Sming/Components/Storage/README.rst | 17 +++ Sming/Components/Storage/component.mk | 5 + Sming/Components/Storage/src/.cs | 0 Sming/Components/Storage/src/Debug.cpp | 9 ++ Sming/Components/Storage/src/Device.cpp | 6 +- Sming/Components/Storage/src/Partition.cpp | 64 ++++++---- Sming/Components/Storage/src/ProgMem.cpp | 2 +- Sming/Components/Storage/src/SpiFlash.cpp | 8 +- .../Storage/src/include/Storage/Debug.h | 1 + .../Storage/src/include/Storage/Device.h | 45 ++++++- .../Storage/src/include/Storage/Partition.h | 115 +++++++++++++++--- .../src/include/Storage/PartitionStream.h | 4 +- .../Storage/src/include/Storage/ProgMem.h | 8 +- .../Storage/src/include/Storage/SpiFlash.h | 8 +- .../src/include/Storage/StreamDevice.h | 8 +- .../Storage/src/include/Storage/SysMem.h | 8 +- .../Storage/src/include/Storage/Types.h | 66 ++++++++++ Sming/Core/FileSystem.h | 16 +-- Sming/Libraries/DiskStorage | 1 + Sming/Libraries/FatIFS | 1 + Sming/Libraries/LittleFS | 2 +- .../Ota/src/include/Ota/UpgradeOutputStream.h | 2 +- Sming/Libraries/SdStorage | 1 + Sming/Libraries/SmingTest | 2 +- Sming/Libraries/Spiffs/component.mk | 1 + Sming/Libraries/Spiffs/src/FileSystem.cpp | 19 ++- .../src/include/IFS/SPIFFS/FileSystem.h | 7 +- Tools/install.sh | 2 + docs/source/information/index.rst | 1 + docs/source/information/storage.rst | 28 +++++ samples/Basic_IFS/README.rst | 6 + samples/Basic_IFS/app/application.cpp | 43 +++++++ samples/Basic_IFS/basic_ifs_Esp8266.hw | 2 +- samples/Basic_IFS/component.mk | 11 +- samples/Basic_IFS/fsimage.fwfs | 5 +- samples/Basic_Storage/app/application.cpp | 2 +- tests/HostTests/modules/Storage.cpp | 10 +- 42 files changed, 482 insertions(+), 116 deletions(-) create mode 100644 Sming/Components/Storage/src/.cs create mode 100644 Sming/Components/Storage/src/include/Storage/Types.h create mode 160000 Sming/Libraries/DiskStorage create mode 160000 Sming/Libraries/FatIFS create mode 160000 Sming/Libraries/SdStorage create mode 100644 docs/source/information/storage.rst diff --git a/.gitmodules b/.gitmodules index c828c2366a..c4ac5e4caf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -213,10 +213,6 @@ path = Sming/Libraries/CS5460/CS5460 url = https://github.com/xxzl0130/CS5460.git ignore = dirty -[submodule "Libraries.DIAL"] - path = Sming/Libraries/DIAL - url = https://github.com/slaff/Sming-DIAL.git - ignore = dirty [submodule "Libraries.DFRobotDFPlayerMini"] path = Sming/Libraries/DFRobotDFPlayerMini url = https://github.com/DFRobot/DFRobotDFPlayerMini.git @@ -225,6 +221,18 @@ path = Sming/Libraries/DHTesp url = https://github.com/beegee-tokyo/DHTesp.git ignore = dirty +[submodule "Libraries.DIAL"] + path = Sming/Libraries/DIAL + url = https://github.com/slaff/Sming-DIAL.git + ignore = dirty +[submodule "Libraries.DiskStorage"] + path = Sming/Libraries/DiskStorage + url = https://github.com/mikee47/DiskStorage + ignore = dirty +[submodule "Libraries.FatIFS"] + path = Sming/Libraries/FatIFS + url = https://github.com/mikee47/FatIFS + ignore = dirty [submodule "Libraries.flatbuffers"] path = Sming/Libraries/flatbuffers/src url = https://github.com/google/flatbuffers.git @@ -313,6 +321,10 @@ path = Sming/Libraries/RingTone url = https://github.com/mikee47/RingTone ignore = dirty +[submodule "Libraries.SdStorage"] + path = Sming/Libraries/SdStorage + url = https://github.com/mikee47/SdStorage + ignore = dirty [submodule "Libraries.SignalGenerator"] path = Sming/Libraries/SignalGenerator url = https://github.com/mikee47/SignalGenerator diff --git a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp index facaec0a26..79d1d9794b 100644 --- a/Sming/Arch/Esp8266/Components/esp8266/startup.cpp +++ b/Sming/Arch/Esp8266/Components/esp8266/startup.cpp @@ -48,22 +48,39 @@ extern "C" void ICACHE_FLASH_ATTR WEAK_ATTR user_pre_init(void) { Storage::initialize(); - auto sysParam = *Storage::findPartition(Storage::Partition::SubType::Data::sysParam); - auto rfCal = *Storage::findPartition(Storage::Partition::SubType::Data::rfCal); - auto phy = *Storage::findPartition(Storage::Partition::SubType::Data::phy); + using PartType = Storage::Partition::SubType::Data; + auto sysParam = *Storage::findPartition(PartType::sysParam); + auto rfCal = *Storage::findPartition(PartType::rfCal); + auto phy = *Storage::findPartition(PartType::phy); - static const partition_item_t partitions[] = { - {SYSTEM_PARTITION_BOOTLOADER, 0, SPI_FLASH_SEC_SIZE}, - {SYSTEM_PARTITION_PHY_DATA, phy.address(), phy.size()}, - {SYSTEM_PARTITION_SYSTEM_PARAMETER, sysParam.address(), sysParam.size()}, - {SYSTEM_PARTITION_RF_CAL, rfCal.address(), rfCal.size()}, + static const partition_item_t partitions[]{ + { + SYSTEM_PARTITION_BOOTLOADER, + 0, + SPI_FLASH_SEC_SIZE, + }, + { + SYSTEM_PARTITION_PHY_DATA, + uint32_t(phy.address()), + uint32_t(phy.size()), + }, + { + SYSTEM_PARTITION_SYSTEM_PARAMETER, + uint32_t(sysParam.address()), + uint32_t(sysParam.size()), + }, + { + SYSTEM_PARTITION_RF_CAL, + uint32_t(rfCal.address()), + uint32_t(rfCal.size()), + }, }; enum flash_size_map sizeMap = system_get_flash_size_map(); if(!system_partition_table_regist(partitions, ARRAY_SIZE(partitions), sizeMap)) { os_printf("system_partition_table_regist: failed\n"); os_printf("size_map = %u\n", sizeMap); - for (unsigned i = 0; i < ARRAY_SIZE(partitions); ++i) { + for(unsigned i = 0; i < ARRAY_SIZE(partitions); ++i) { auto& part = partitions[i]; os_printf("partition[%u]: %u, 0x%08x, 0x%08x\n", i, part.type, part.addr, part.size); } diff --git a/Sming/Arch/Host/Components/spi_flash/component.mk b/Sming/Arch/Host/Components/spi_flash/component.mk index 510aaa7e76..0aa8fcafcc 100644 --- a/Sming/Arch/Host/Components/spi_flash/component.mk +++ b/Sming/Arch/Host/Components/spi_flash/component.mk @@ -1 +1,3 @@ COMPONENT_INCDIRS += $(ESP8266_COMPONENTS)/spi_flash/include + +COMPONENT_DEPENDS := IFS diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index ebbe18cfa1..670b13ba31 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -91,7 +91,8 @@ LIBDIRS += \ EXTRA_LIBS += \ pico \ m \ - stdc++ + stdc++ \ + gcc RP2040_CMAKE_OPTIONS := \ -G Ninja \ diff --git a/Sming/Components/IFS b/Sming/Components/IFS index e69049e93b..1767d7020e 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit e69049e93bc6efa4b6fe0d4dd07209fac450a0e1 +Subproject commit 1767d7020e18c8ffa0c58b31a5650a5275ee47c6 diff --git a/Sming/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index 56a0dce5ad..6cd6ac162f 100644 --- a/Sming/Components/Storage/README.rst +++ b/Sming/Components/Storage/README.rst @@ -304,6 +304,20 @@ Configuration Set this to adjust the hardware profile using option fragments. See :ref:`hwconfig_options`. +.. envvar:: ENABLE_STORAGE_SIZE64 + + Build with ``ENABLE_STORAGE_SIZE64=1`` to enable support for storage devices of more than 4GB capacity. + + Device and partition addresses and sizes use the :cpp:type:`storage_size_t` type, which by default is ``uint32_t``. + Setting this value changes it to ``uint64_t``. + + When enabling this setting, care must be taken in code especially with ``printf`` style format strings such + as in debug statements. The safest way to handle both cases is like this:: + + debug_i("Partition size: %llu", uint64_t(part.size())); + + + Binary partition table ---------------------- @@ -379,6 +393,9 @@ you can take advantage of the partition API to manage them as follows: in your ``init()`` function (or elsewhere if more appropriate). +See :library:`DiskStorage` for how devices such as SD flash cards are managed. + + API --- diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index 24967d8da7..13b96ee8f1 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -2,6 +2,11 @@ COMPONENT_INCDIRS := src/include COMPONENT_SRCDIRS := src COMPONENT_DOXYGEN_INPUT := src/include +COMPONENT_VARS := ENABLE_STORAGE_SIZE64 +ifeq ($(ENABLE_STORAGE_SIZE64),1) +GLOBAL_CFLAGS += -DENABLE_STORAGE_SIZE64 +endif + COMPONENT_RELINK_VARS := PARTITION_TABLE_OFFSET CONFIG_VARS += HWCONFIG HWCONFIG_OPTS diff --git a/Sming/Components/Storage/src/.cs b/Sming/Components/Storage/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Components/Storage/src/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp index 1ff281190b..531cbfec7c 100644 --- a/Sming/Components/Storage/src/Debug.cpp +++ b/Sming/Components/Storage/src/Debug.cpp @@ -16,6 +16,15 @@ void listPartitions(Print& out) out.println(); } +void listPartitions(Print& out, const Device& device) +{ + out << device.getName() << _F(" partitions:") << endl; + for(auto part : device.partitions()) { + out << "- " << part << endl; + } + out.println(); +} + void listDevices(Print& out, bool fullPartitionInfo) { out.println(); diff --git a/Sming/Components/Storage/src/Device.cpp b/Sming/Components/Storage/src/Device.cpp index d7aaa49d71..a1d5560f0f 100644 --- a/Sming/Components/Storage/src/Device.cpp +++ b/Sming/Components/Storage/src/Device.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * Device.h - external storage device API + * Device.cpp * ****/ @@ -89,8 +89,8 @@ bool Device::loadPartitions(Device& source, uint32_t tableOffset) toString(Device::Type(entry->subtype)).c_str(), toString(getType()).c_str()); } if(entry->size != getSize()) { - debug_w("[Device] '%s' size mismatch, 0x%08x in partition table but device reports 0x%08x", - getName().c_str(), entry->size, getSize()); + debug_w("[Device] '%s' size mismatch, 0x%08x in partition table but device reports 0x%08llx", + getName().c_str(), entry->size, uint64_t(getSize())); } // Skip the storage entry, not required diff --git a/Sming/Components/Storage/src/Partition.cpp b/Sming/Components/Storage/src/Partition.cpp index 03761fa929..d9f4bd13f5 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -4,7 +4,7 @@ * http://github.com/SmingHub/Sming * All files of the Sming Core are provided under the LGPL v3 license. * - * Partition.cpp - Partition support for all architectures + * Partition.cpp * ****/ @@ -158,7 +158,7 @@ bool Partition::verify(Partition::Type type, uint8_t subtype) const return true; } -bool Partition::getDeviceAddress(uint32_t& address, size_t size) const +bool Partition::getDeviceAddress(storage_size_t& address, storage_size_t size) const { if(mDevice == nullptr || mPart == nullptr) { debug_e("[Partition] Invalid"); @@ -166,7 +166,7 @@ bool Partition::getDeviceAddress(uint32_t& address, size_t size) const } if(address >= mPart->size || (address + size - 1) >= mPart->size) { - debug_e("[Partition] Invalid range, address: 0x%08x, size: 0x%08x", address, size); + debug_e("[Partition] Invalid range, address: 0x%08llx, size: 0x%08llx", uint64_t(address), uint64_t(size)); return false; } @@ -212,66 +212,82 @@ bool Partition::allowWrite() return true; } -bool Partition::read(uint32_t offset, void* dst, size_t size) +bool Partition::read(storage_size_t offset, void* dst, size_t size) { if(!allowRead()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->read(addr, dst, size) : false; + return mDevice->read(addr, dst, size); } -bool Partition::write(uint32_t offset, const void* src, size_t size) +bool Partition::write(storage_size_t offset, const void* src, size_t size) { if(!allowWrite()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->write(addr, src, size) : false; + return mDevice->write(addr, src, size); } -bool Partition::erase_range(uint32_t offset, size_t size) +bool Partition::erase_range(storage_size_t offset, storage_size_t size) { if(!allowWrite()) { return false; } - uint32_t addr = offset; + auto addr = offset; if(!getDeviceAddress(addr, size)) { return false; } - return mDevice ? mDevice->erase_range(addr, size) : false; + return mDevice->erase_range(addr, size); } -size_t Partition::printTo(Print& p) const +uint16_t Partition::getSectorSize() const +{ + return mDevice ? mDevice->getSectorSize() : Device::defaultSectorSize; +} + +bool Partition::sync() +{ + return mDevice ? mDevice->sync() : false; +} + +size_t Partition::Info::printTo(Print& p) const { size_t n{0}; + n += p.print(name.length() == 0 ? _F("(NO NAME)") : name.c_str()); + n += p.print(", "); + n += p.print(fullType()); + n += p.print(" @ 0x"); + n += p.print(offset, HEX); + n += p.print(_F(", size 0x")); + n += p.print(size, HEX); + return n; +} + +size_t Partition::printTo(Print& p) const +{ if(*this) { + size_t n{0}; n += p.print(getDeviceName()); n += p.print('/'); - n += p.print(name()); - n += p.print(" ("); - n += p.print(typeString()); - n += p.print(" @ 0x"); - n += p.print(address(), HEX); - n += p.print(_F(", size 0x")); - n += p.print(size(), HEX); - n += p.print(')'); - } else { - n += p.print(_F("(none)")); + n += p.print(*mPart); + return n; } - return n; + + return p.print(_F("(none)")); } } // namespace Storage diff --git a/Sming/Components/Storage/src/ProgMem.cpp b/Sming/Components/Storage/src/ProgMem.cpp index 34b4f25df0..78c3ebd2af 100644 --- a/Sming/Components/Storage/src/ProgMem.cpp +++ b/Sming/Components/Storage/src/ProgMem.cpp @@ -15,7 +15,7 @@ namespace Storage { ProgMem progMem; -bool ProgMem::read(uint32_t address, void* dst, size_t size) +bool ProgMem::read(storage_size_t address, void* dst, size_t size) { size_t readCount = flashmem_read(dst, address, size); return readCount == size; diff --git a/Sming/Components/Storage/src/SpiFlash.cpp b/Sming/Components/Storage/src/SpiFlash.cpp index 62a764600b..7aa0368699 100644 --- a/Sming/Components/Storage/src/SpiFlash.cpp +++ b/Sming/Components/Storage/src/SpiFlash.cpp @@ -33,24 +33,24 @@ size_t SpiFlash::getBlockSize() const return SPI_FLASH_SEC_SIZE; } -size_t SpiFlash::getSize() const +storage_size_t SpiFlash::getSize() const { return flashmem_get_size_bytes(); } -bool SpiFlash::read(uint32_t address, void* dst, size_t size) +bool SpiFlash::read(storage_size_t address, void* dst, size_t size) { size_t readCount = flashmem_read(dst, address, size); return readCount == size; } -bool SpiFlash::write(uint32_t address, const void* src, size_t size) +bool SpiFlash::write(storage_size_t address, const void* src, size_t size) { size_t writeCount = flashmem_write(src, address, size); return writeCount == size; } -bool SpiFlash::erase_range(uint32_t address, size_t size) +bool SpiFlash::erase_range(storage_size_t address, storage_size_t size) { if(address % SPI_FLASH_SEC_SIZE != 0 || size % SPI_FLASH_SEC_SIZE != 0) { debug_e("[Partition] erase address/size misaligned: 0x%08x / 0x%08x", address, size); diff --git a/Sming/Components/Storage/src/include/Storage/Debug.h b/Sming/Components/Storage/src/include/Storage/Debug.h index 113a1dd19e..659ddca3b3 100644 --- a/Sming/Components/Storage/src/include/Storage/Debug.h +++ b/Sming/Components/Storage/src/include/Storage/Debug.h @@ -8,6 +8,7 @@ namespace Storage namespace Debug { void listPartitions(Print& out); +void listPartitions(Print& out, const Device& device); void listDevices(Print& out, bool fullPartitionInfo = true); } // namespace Debug diff --git a/Sming/Components/Storage/src/include/Storage/Device.h b/Sming/Components/Storage/src/include/Storage/Device.h index 71b4987408..7ebaa32df8 100644 --- a/Sming/Components/Storage/src/include/Storage/Device.h +++ b/Sming/Components/Storage/src/include/Storage/Device.h @@ -111,9 +111,9 @@ class Device : public LinkedObjectTemplate /** * @brief Obtain addressable size of this device - * @retval size_t Must be at least as large as the value declared in the partition table + * @retval storage_size_t Must be at least as large as the value declared in the hardware configuration */ - virtual size_t getSize() const = 0; + virtual storage_size_t getSize() const = 0; /** * @brief Obtain device type @@ -127,7 +127,7 @@ class Device : public LinkedObjectTemplate * @param size Size of data to be read, in bytes. * @retval bool true on success, false on error */ - virtual bool read(uint32_t address, void* dst, size_t size) = 0; + virtual bool read(storage_size_t address, void* dst, size_t size) = 0; /** * @brief Write data to the storage device @@ -136,7 +136,7 @@ class Device : public LinkedObjectTemplate * @param size Size of data to be written, in bytes. * @retval bool true on success, false on error */ - virtual bool write(uint32_t address, const void* src, size_t size) = 0; + virtual bool write(storage_size_t address, const void* src, size_t size) = 0; /** * @brief Erase a region of storage in preparation for writing @@ -144,7 +144,42 @@ class Device : public LinkedObjectTemplate * @param size Size of region to erase, in bytes * @retval bool true on success, false on error */ - virtual bool erase_range(uint32_t address, size_t size) = 0; + virtual bool erase_range(storage_size_t address, storage_size_t size) = 0; + + /** + * @brief Get sector size, the unit of allocation for block-access devices + * + * Override this method only if the device does not support standard 512-byte sector access. + * For example, 'Advanced-Format' drives use 4096-byte sectors. + */ + virtual uint16_t getSectorSize() const + { + return defaultSectorSize; + } + + /** + * @brief Obtain total number of sectors on this device + */ + virtual storage_size_t getSectorCount() const + { + return getSize() / getSectorSize(); + } + + /** + * @brief Flush any pending writes to the physical media + * @retval bool Return false if sync operation failed. + * + * Devices with intermediate buffering should implement this method. + */ + virtual bool sync() + { + return true; + } + + /** + * @name Default sector size for block-based devices + */ + static constexpr uint16_t defaultSectorSize{512}; size_t printTo(Print& p) const; diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 922d044e96..1dc96822a9 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -31,6 +31,7 @@ #include #include #include +#include "Types.h" #define PARTITION_APP_SUBTYPE_MAP(XX) \ XX(factory, 0x00, "Factory application") \ @@ -73,6 +74,11 @@ class Device; class PartitionTable; struct esp_partition_info_t; +namespace Disk +{ +class DiskPart; +} + /** * @brief Represents a flash partition */ @@ -134,12 +140,36 @@ class Partition Type type; uint8_t subtype; - FullType(Type type, uint8_t subtype) : type(type), subtype(subtype) + constexpr FullType() : type(Type::invalid), subtype(SubType::invalid) + { + } + + constexpr FullType(Type type, uint8_t subtype) : type(type), subtype(subtype) + { + } + + explicit operator bool() const + { + return type != Type::invalid && subtype != uint8_t(SubType::invalid); + } + + template constexpr FullType(T subType) : FullType(Type(T::partitionType), uint8_t(subType)) { } - template FullType(T subType) : FullType(Type(T::partitionType), uint8_t(subType)) + bool operator==(const FullType& other) const { + return type == other.type && subtype == other.subtype; + } + + bool operator!=(const FullType& other) const + { + return !operator==(other); + } + + constexpr uint16_t value() const + { + return uint8_t(type) << 8 | subtype; } operator String() const; @@ -148,12 +178,12 @@ class Partition /** * @brief Partition information */ - struct Info : public LinkedObjectTemplate { + struct Info : public LinkedObjectTemplate, public Printable { using OwnedList = OwnedLinkedObjectListTemplate; CString name; - uint32_t offset{0}; - uint32_t size{0}; + storage_size_t offset{0}; + storage_size_t size{0}; Type type{Type::invalid}; uint8_t subtype{SubType::invalid}; Flags flags; @@ -162,15 +192,27 @@ class Partition { } - Info(const String& name, FullType fullType, uint32_t offset, uint32_t size, Flags flags = 0) + Info(const String& name, FullType fullType, storage_size_t offset, storage_size_t size, Flags flags = 0) : name(name), offset(offset), size(size), type(fullType.type), subtype(fullType.subtype), flags(flags) { } + FullType fullType() const + { + return {type, subtype}; + } + bool match(Type type, uint8_t subType) const { return (type == Type::any || type == this->type) && (subType == SubType::any || subType == this->subtype); } + + virtual const Disk::DiskPart* diskpart() const + { + return nullptr; + } + + size_t printTo(Print& p) const override; }; Partition() @@ -235,9 +277,10 @@ class Partition * @param size Size of data to be read, in bytes. * @retval bool true on success, false on error */ - bool read(uint32_t offset, void* dst, size_t size); + bool read(storage_size_t offset, void* dst, size_t size); - template typename std::enable_if::value, bool>::type read(uint32_t offset, T& value) + template + typename std::enable_if::value, bool>::type read(storage_size_t offset, T& value) { return read(offset, &value, sizeof(value)); } @@ -250,7 +293,7 @@ class Partition * @retval bool true on success, false on error * @note Flash region must be erased first */ - bool write(uint32_t offset, const void* src, size_t size); + bool write(storage_size_t offset, const void* src, size_t size); /** * @brief Erase part of the partition @@ -259,7 +302,7 @@ class Partition * @retval bool true on success, false on error * @note Both offset and size must be aligned to flash sector size (4Kbytes) */ - bool erase_range(uint32_t offset, size_t size); + bool erase_range(storage_size_t offset, storage_size_t size); /** * @brief Obtain partition type @@ -277,29 +320,37 @@ class Partition return mPart ? mPart->subtype : SubType::invalid; } + /** + * @brief Obtain both type and subtype + */ + FullType fullType() const + { + return mPart ? mPart->fullType() : FullType{}; + } + /** * @brief Obtain partition starting address - * @param uint32_t Device address + * @retval storage_size_t Device address */ - uint32_t address() const + storage_size_t address() const { return (mPart && mPart->type != Partition::Type::storage) ? mPart->offset : 0; } /** * @brief Obtain address of last byte in this this partition - * @param uint32_t Device address + * @retval storage_size_t Device address */ - uint32_t lastAddress() const + storage_size_t lastAddress() const { return mPart ? (mPart->offset + mPart->size - 1) : 0; } /** * @brief Obtain partition size - * @retval size_t Size in bytes + * @retval storage_size_t Size in bytes */ - size_t size() const + storage_size_t size() const { return mPart ? mPart->size : 0; } @@ -351,7 +402,7 @@ class Partition * @retval bool true on success, false on failure * Fails if the given offset/size combination is out of range, or the partition is undefined. */ - bool getDeviceAddress(uint32_t& address, size_t size) const; + bool getDeviceAddress(storage_size_t& address, storage_size_t size) const; /** * @brief Get name of storage device for this partition @@ -362,7 +413,7 @@ class Partition /** * @brief Determine if given address contained within this partition */ - bool contains(uint32_t addr) const + bool contains(storage_size_t addr) const { return mPart ? (addr >= mPart->offset && addr <= lastAddress()) : false; } @@ -387,6 +438,34 @@ class Partition */ size_t getBlockSize() const; + /** + * @brief Get sector size for block-addressable devices + * @see See `Storage::Device::getSectorSize` + */ + uint16_t getSectorSize() const; + + /** + * @brief Obtain total number of sectors in this partition + */ + storage_size_t getSectorCount() const + { + return size() / getSectorSize(); + } + + /** + * @brief Flush any pending writes to the physical media + * @see See `Storage::Device::sync` + */ + bool sync(); + + /** + * @brief If this is a disk partition, return pointer to the additional information + */ + const Disk::DiskPart* diskpart() const + { + return mPart ? mPart->diskpart() : nullptr; + } + size_t printTo(Print& p) const; protected: diff --git a/Sming/Components/Storage/src/include/Storage/PartitionStream.h b/Sming/Components/Storage/src/include/Storage/PartitionStream.h index 09d19570f8..af0b02ddd5 100644 --- a/Sming/Components/Storage/src/include/Storage/PartitionStream.h +++ b/Sming/Components/Storage/src/include/Storage/PartitionStream.h @@ -34,7 +34,7 @@ class PartitionStream : public ReadWriteStream * * If blockErase is false then region must be pre-erased before writing. */ - PartitionStream(Partition partition, uint32_t offset, size_t size, bool blockErase = false) + PartitionStream(Partition partition, storage_size_t offset, size_t size, bool blockErase = false) : partition(partition), startOffset(offset), size(size), blockErase(blockErase) { } @@ -69,7 +69,7 @@ class PartitionStream : public ReadWriteStream private: Partition partition; - uint32_t startOffset; + storage_size_t startOffset; size_t size; uint32_t writePos{0}; uint32_t readPos{0}; diff --git a/Sming/Components/Storage/src/include/Storage/ProgMem.h b/Sming/Components/Storage/src/include/Storage/ProgMem.h index a9d74580f2..0f43003f3b 100644 --- a/Sming/Components/Storage/src/include/Storage/ProgMem.h +++ b/Sming/Components/Storage/src/include/Storage/ProgMem.h @@ -29,7 +29,7 @@ class ProgMem : public Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -39,14 +39,14 @@ class ProgMem : public Device return Type::flash; } - bool read(uint32_t address, void* dst, size_t size) override; + bool read(storage_size_t address, void* dst, size_t size) override; - bool write(uint32_t address, const void* src, size_t size) override + bool write(storage_size_t address, const void* src, size_t size) override { return false; } - bool erase_range(uint32_t address, size_t size) override + bool erase_range(storage_size_t address, storage_size_t size) override { return false; } diff --git a/Sming/Components/Storage/src/include/Storage/SpiFlash.h b/Sming/Components/Storage/src/include/Storage/SpiFlash.h index bed0050cb4..b99a1b53f9 100644 --- a/Sming/Components/Storage/src/include/Storage/SpiFlash.h +++ b/Sming/Components/Storage/src/include/Storage/SpiFlash.h @@ -23,7 +23,7 @@ class SpiFlash : public Device public: String getName() const override; size_t getBlockSize() const override; - size_t getSize() const override; + storage_size_t getSize() const override; Type getType() const override { @@ -32,9 +32,9 @@ class SpiFlash : public Device uint32_t getId() const override; - bool read(uint32_t address, void* dst, size_t size) override; - bool write(uint32_t address, const void* src, size_t size) override; - bool erase_range(uint32_t address, size_t size) override; + bool read(storage_size_t address, void* dst, size_t size) override; + bool write(storage_size_t address, const void* src, size_t size) override; + bool erase_range(storage_size_t address, storage_size_t size) override; }; } // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/StreamDevice.h b/Sming/Components/Storage/src/include/Storage/StreamDevice.h index ebca8bfc2f..7e9bd08906 100644 --- a/Sming/Components/Storage/src/include/Storage/StreamDevice.h +++ b/Sming/Components/Storage/src/include/Storage/StreamDevice.h @@ -39,23 +39,23 @@ class StreamDevice : public Device return Type::stream; } - bool read(uint32_t address, void* buffer, size_t len) override + bool read(storage_size_t address, void* buffer, size_t len) override { if(mStream == nullptr) { return false; } - if(mStream->seekFrom(address, SeekOrigin::Start) != int(address)) { + if(storage_size_t(mStream->seekFrom(address, SeekOrigin::Start)) != address) { return false; } return mStream->readBytes(static_cast(buffer), len) == len; } - bool write(uint32_t address, const void* data, size_t len) override + bool write(storage_size_t address, const void* data, size_t len) override { return false; } - bool erase_range(uint32_t address, size_t len) override + bool erase_range(storage_size_t address, storage_size_t len) override { return false; } diff --git a/Sming/Components/Storage/src/include/Storage/SysMem.h b/Sming/Components/Storage/src/include/Storage/SysMem.h index aa26598df1..d2d333f1d2 100644 --- a/Sming/Components/Storage/src/include/Storage/SysMem.h +++ b/Sming/Components/Storage/src/include/Storage/SysMem.h @@ -30,7 +30,7 @@ class SysMem : public Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -40,7 +40,7 @@ class SysMem : public Device return Type::sysmem; } - bool read(uint32_t address, void* buffer, size_t len) override + bool read(storage_size_t address, void* buffer, size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { memcpy_P(buffer, reinterpret_cast(address), len); @@ -50,7 +50,7 @@ class SysMem : public Device return true; } - bool write(uint32_t address, const void* data, size_t len) override + bool write(storage_size_t address, const void* data, size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { return false; @@ -60,7 +60,7 @@ class SysMem : public Device return true; } - bool erase_range(uint32_t address, size_t len) override + bool erase_range(storage_size_t address, storage_size_t len) override { if(isFlashPtr(reinterpret_cast(address))) { return false; diff --git a/Sming/Components/Storage/src/include/Storage/Types.h b/Sming/Components/Storage/src/include/Storage/Types.h new file mode 100644 index 0000000000..846ce55b59 --- /dev/null +++ b/Sming/Components/Storage/src/include/Storage/Types.h @@ -0,0 +1,66 @@ +/**** + * 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. + * + * Types.h + * + ****/ +#pragma once + +#include + +#ifdef ENABLE_STORAGE_SIZE64 +using storage_size_t = uint64_t; +#else +using storage_size_t = uint32_t; +#endif + +namespace Storage +{ +/** + * @brief Determine if a value requires 64-bits to store + */ +inline bool isSize64(uint64_t value) +{ + using Lim = std::numeric_limits; + return value < Lim::min() || value > Lim::max(); +} + +/** + * @brief Determine if a value requires 64-bits to store + */ +inline bool isSize64(int64_t value) +{ + using Lim = std::numeric_limits; + return value < Lim::min() || value > Lim::max(); +} + +/** + * @name Get power of 2 for given value + * @param value Must be an exact power of 2 + * @retval uint8_t Result n such that `value == 1 << n` + * @see Use `isLog2()` to confirm value is power of 2 + * @{ + */ +template constexpr typename std::enable_if<(sizeof(T) <= 4), uint8_t>::type getSizeBits(T value) +{ + return __builtin_ffs(value) - 1; +} + +template constexpr typename std::enable_if<(sizeof(T) > 4), uint8_t>::type getSizeBits(T value) +{ + return __builtin_ffsll(value) - 1; +} +/** @} */ + +/** + * @brief Determine if a value is an exact power of 2 + */ +template constexpr bool isLog2(T value) +{ + return value == (T(1U) << getSizeBits(value)); +} + +} // namespace Storage diff --git a/Sming/Core/FileSystem.h b/Sming/Core/FileSystem.h index 572c1950a9..211813000f 100644 --- a/Sming/Core/FileSystem.h +++ b/Sming/Core/FileSystem.h @@ -170,9 +170,9 @@ inline int fileRead(FileHandle file, void* data, size_t size) * @param file File handle * @param offset Quantity of bytes to move cursor * @param origin Position from where to move cursor - * @retval int Offset within file or negative error code + * @retval file_offset_t Offset within file or negative error code */ -inline int fileSeek(FileHandle file, int offset, SeekOrigin origin) +inline file_offset_t fileSeek(FileHandle file, file_offset_t offset, SeekOrigin origin) { CHECK_FS(seek) return fileSystem->lseek(file, offset, origin); @@ -190,9 +190,9 @@ inline bool fileIsEOF(FileHandle file) /** @brief Get position in file * @param file File handle - * @retval int32_t Read / write cursor position or error code + * @retval file_offset_t Read / write cursor position or error code */ -inline int fileTell(FileHandle file) +inline file_offset_t fileTell(FileHandle file) { CHECK_FS(tell) return fileSystem->tell(file); @@ -243,9 +243,9 @@ template inline int fileSetContent(const /** @brief Get size of file * @param fileName Name of file - * @retval uint32_t Size of file in bytes, 0 on error + * @retval file_size_t Size of file in bytes, 0 on error */ -template inline uint32_t fileGetSize(const TFileName& fileName) +template inline file_size_t fileGetSize(const TFileName& fileName) { auto fileSystem = getFileSystem(); return fileSystem ? fileSystem->getSize(fileName) : 0; @@ -258,7 +258,7 @@ template inline uint32_t fileGetSize(const TFileName& fileN * @note In POSIX `ftruncate()` can also make the file bigger, however SPIFFS can only * reduce the file size and will return an error if newSize > fileSize */ -inline int fileTruncate(FileHandle file, size_t newSize) +inline int fileTruncate(FileHandle file, file_size_t newSize) { CHECK_FS(truncate); return fileSystem->ftruncate(file, newSize); @@ -281,7 +281,7 @@ inline int fileTruncate(FileHandle file) * @note In POSIX `truncate()` can also make the file bigger, however SPIFFS can only * reduce the file size and will return an error if newSize > fileSize */ -template int fileTruncate(const TFileName& fileName, size_t newSize) +template int fileTruncate(const TFileName& fileName, file_size_t newSize) { CHECK_FS(truncate); return fileSystem->truncate(fileName, newSize); diff --git a/Sming/Libraries/DiskStorage b/Sming/Libraries/DiskStorage new file mode 160000 index 0000000000..c467f3f0f9 --- /dev/null +++ b/Sming/Libraries/DiskStorage @@ -0,0 +1 @@ +Subproject commit c467f3f0f9f504aecf134ec45780971da1595399 diff --git a/Sming/Libraries/FatIFS b/Sming/Libraries/FatIFS new file mode 160000 index 0000000000..b4c11f4f28 --- /dev/null +++ b/Sming/Libraries/FatIFS @@ -0,0 +1 @@ +Subproject commit b4c11f4f28deb99fe48c25a16f0f72915202c05d diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 9af1d3bd27..f5fc23fbb3 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 9af1d3bd27915b0180ba7f73fe553a06ad7d9d94 +Subproject commit f5fc23fbb3112460dbd595ddf03b7ec2d45c8cb0 diff --git a/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h b/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h index fa3a6157c3..bbbf47b6ee 100644 --- a/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h +++ b/Sming/Libraries/Ota/src/include/Ota/UpgradeOutputStream.h @@ -30,7 +30,7 @@ class UpgradeOutputStream : public ReadWriteStream * @param partition */ UpgradeOutputStream(Partition partition, size_t maxLength = 0) - : partition(partition), maxLength(maxLength != 0 ? std::min(maxLength, partition.size()) : partition.size()) + : partition(partition), maxLength(std::min(storage_size_t(maxLength ?: 0x1000000), partition.size())) { } diff --git a/Sming/Libraries/SdStorage b/Sming/Libraries/SdStorage new file mode 160000 index 0000000000..99826990a4 --- /dev/null +++ b/Sming/Libraries/SdStorage @@ -0,0 +1 @@ +Subproject commit 99826990a46c3a509ec9c33bbe1572b3b50e663d diff --git a/Sming/Libraries/SmingTest b/Sming/Libraries/SmingTest index a6c7f94341..25a7e24411 160000 --- a/Sming/Libraries/SmingTest +++ b/Sming/Libraries/SmingTest @@ -1 +1 @@ -Subproject commit a6c7f9434135fc6350da72b7e226a825f0092356 +Subproject commit 25a7e2441148cd0805ab7b7ab2d4648a0131b092 diff --git a/Sming/Libraries/Spiffs/component.mk b/Sming/Libraries/Spiffs/component.mk index a482d6ff1f..7ed51e9991 100644 --- a/Sming/Libraries/Spiffs/component.mk +++ b/Sming/Libraries/Spiffs/component.mk @@ -1,4 +1,5 @@ ## SPIFFS library +COMPONENT_DEPENDS := IFS COMPONENT_SUBMODULES := spiffs COMPONENT_SRCDIRS := src spiffs/src COMPONENT_INCDIRS := src/include diff --git a/Sming/Libraries/Spiffs/src/FileSystem.cpp b/Sming/Libraries/Spiffs/src/FileSystem.cpp index 1184e0bcc2..267e961800 100644 --- a/Sming/Libraries/Spiffs/src/FileSystem.cpp +++ b/Sming/Libraries/Spiffs/src/FileSystem.cpp @@ -134,12 +134,18 @@ int FileSystem::mount() return Error::BadPartition; } + auto partSize = partition.size(); + if(partSize > MAX_PARTITION_SIZE) { + debug_e("[SPIFFS] Partition too large"); + return Error::BadPartition; + } + fs.user_data = this; spiffs_config cfg{ .hal_read_f = f_read, .hal_write_f = f_write, .hal_erase_f = f_erase, - .phys_size = partition.size(), + .phys_size = uint32_t(partSize), .phys_addr = 0, .phys_erase_block = partition.getBlockSize(), .log_block_size = logicalBlockSize, @@ -315,6 +321,7 @@ int FileSystem::close(FileHandle file) if(err < 0) { res = translateSpiffsError(err); } + partition.sync(); return res; } @@ -324,13 +331,13 @@ int FileSystem::eof(FileHandle file) return translateSpiffsError(res); } -int32_t FileSystem::tell(FileHandle file) +file_offset_t FileSystem::tell(FileHandle file) { int res = SPIFFS_tell(handle(), file); return translateSpiffsError(res); } -int FileSystem::ftruncate(FileHandle file, size_t new_size) +int FileSystem::ftruncate(FileHandle file, file_size_t new_size) { int res = SPIFFS_ftruncate(handle(), file, new_size); return translateSpiffsError(res); @@ -345,6 +352,7 @@ int FileSystem::flush(FileHandle file) if(err < 0) { res = translateSpiffsError(err); } + partition.sync(); return res; } @@ -372,7 +380,7 @@ int FileSystem::write(FileHandle file, const void* data, size_t size) return res; } -int FileSystem::lseek(FileHandle file, int offset, SeekOrigin origin) +file_offset_t FileSystem::lseek(FileHandle file, file_offset_t offset, SeekOrigin origin) { int res = SPIFFS_lseek(handle(), file, offset, int(origin)); if(res < 0) { @@ -563,6 +571,7 @@ int FileSystem::setxattr(const char* path, AttributeTag tag, const void* data, s return FS_OK; } err = SPIFFS_update_meta(handle(), path, &smb); + partition.sync(); return translateSpiffsError(err); #else return Error::NotSupported; @@ -745,6 +754,7 @@ int FileSystem::rename(const char* oldpath, const char* newpath) } int err = SPIFFS_rename(handle(), oldpath, newpath); + partition.sync(); return translateSpiffsError(err); } @@ -769,6 +779,7 @@ int FileSystem::remove(const char* path) int err = SPIFFS_remove(handle(), path); err = translateSpiffsError(err); debug_ifserr(err, "remove('%s')", path); + partition.sync(); return err; } diff --git a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h index ed9279218e..8afa6305fe 100644 --- a/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h +++ b/Sming/Libraries/Spiffs/src/include/IFS/SPIFFS/FileSystem.h @@ -84,10 +84,10 @@ class FileSystem : public IFileSystem int close(FileHandle file) override; int read(FileHandle file, void* data, size_t size) override; int write(FileHandle file, const void* data, size_t size) override; - int lseek(FileHandle file, int offset, SeekOrigin origin) override; + file_offset_t lseek(FileHandle file, file_offset_t offset, SeekOrigin origin) override; int eof(FileHandle file) override; - int32_t tell(FileHandle file) override; - int ftruncate(FileHandle file, size_t new_size) override; + file_offset_t tell(FileHandle file) override; + int ftruncate(FileHandle file, file_size_t new_size) override; int flush(FileHandle file) override; int rename(const char* oldpath, const char* newpath) override; int remove(const char* path) override; @@ -126,6 +126,7 @@ class FileSystem : public IFileSystem static s32_t f_write(struct spiffs_t* spiffs, u32_t addr, u32_t size, u8_t* src); static s32_t f_erase(struct spiffs_t* spiffs, u32_t addr, u32_t size); + static constexpr uint32_t MAX_PARTITION_SIZE{256 * 1024 * 1024}; static constexpr size_t CACHE_PAGES{8}; static constexpr size_t LOG_PAGE_SIZE{256}; static constexpr size_t MIN_BLOCKSIZE{256}; diff --git a/Tools/install.sh b/Tools/install.sh index fcbbb411ea..499f887a04 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -102,6 +102,8 @@ if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then g++-9-multilib \ python3-setuptools \ ninja-build \ + exfat-fuse \ + exfat-utils \ $EXTRA_PACKAGES sudo update-alternatives --set gcc /usr/bin/gcc-9 diff --git a/docs/source/information/index.rst b/docs/source/information/index.rst index 58620c197e..0b360e0604 100644 --- a/docs/source/information/index.rst +++ b/docs/source/information/index.rst @@ -9,6 +9,7 @@ Information events memory flash + storage strings interrupts tasks diff --git a/docs/source/information/storage.rst b/docs/source/information/storage.rst new file mode 100644 index 0000000000..5084b555c6 --- /dev/null +++ b/docs/source/information/storage.rst @@ -0,0 +1,28 @@ +Bulk Storage and Filing Systems +=============================== + +Sming uses a class-based layered approach to bulk storage. + +The :component:`Storage` Component defines the :cpp:class:`Storage::Device` abstract class, +which devices such as SPI flash implement to provide raw read/write/erase access. +Devices are partitioned into areas for specific uses which applications +access using a :cpp:class:`Storage::Partition` object. + +The :library:`DiskStorage` library provides support for block-access devices +which use standard partitioning schemes (MBR, GPT). +SD cards are supported via the :library:`SdStorage` library. + +Sming uses an installable (virtual) filing system mechanism based on :cpp:class:`IFS::IFileSystem`. +This is managed by the :component:`IFS` Component and contains the FWFS lightweight read-only filing system. + +Additional filing system implementations are provided in separate libraries: + +- :library:`Spiffs` +- :library:`LittleFS` +- :library:`FatIFS` + +Note that when using bulk storage of more than about 4GB in size applications should be built with +:cpp:envvar:`ENABLE_STORAGE_SIZE64` =1. This changes all sizes and offsets to 64-bit. + +If manipulating files greated than about 2GB (signed 32-bit value) then the :cpp:envvar:`ENABLE_FILE_SIZE64` +setting should also be enabled. diff --git a/samples/Basic_IFS/README.rst b/samples/Basic_IFS/README.rst index d607593f02..2d01da92bb 100644 --- a/samples/Basic_IFS/README.rst +++ b/samples/Basic_IFS/README.rst @@ -29,3 +29,9 @@ This sample also demonstrates how to store the data in a :cpp:type:`FlashString` Because the data is linked into the program image this is only suitable for small filesystem images. This could be used to store default recovery data, especially with OTA updates because each program image is self-contained. + +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. diff --git a/samples/Basic_IFS/app/application.cpp b/samples/Basic_IFS/app/application.cpp index 5c92b3ddab..68b4f817c1 100644 --- a/samples/Basic_IFS/app/application.cpp +++ b/samples/Basic_IFS/app/application.cpp @@ -19,6 +19,22 @@ #define WIFI_PWD "PleaseEnterPass" #endif +#ifdef ENABLE_SDCARD +#include +#include + +// Chip selects independent of SPI controller in use +#ifdef ARCH_ESP32 +#define PIN_CARD_CS 21 +#else +// Esp8266 cannot use GPIO15 as this affects boot mode +#define PIN_CARD_CS 5 +#endif + +#define SPI_FREQ_LIMIT 0 //2000000 + +#endif + namespace { #ifdef ENABLE_FLASHSTRING_IMAGE @@ -194,6 +210,33 @@ bool initFileSystem() delete spiffs; } +#ifdef ENABLE_SDCARD + auto card = new Storage::SD::Card("card1", SPI); + Storage::registerDevice(card); + + // Buffering allows byte read/write + card.allocateBuffers(2); + + if(card->begin(PIN_CARD_CS, SPI_FREQ_LIMIT)) { + Serial << "CSD" << endl << card->csd << endl; + Serial << "CID" << endl << card->cid; + + auto part = *card->partitions().begin(); + auto fatfs = IFS::createFatFilesystem(part); + if(fatfs != nullptr) { + if(fatfs->mount() == FS_OK) { + fs->setVolume(2, fatfs); + } else { + delete fatfs; + delete card; + } + } + } else { + delete card; + } + +#endif + debug_i("File system initialised"); return true; } diff --git a/samples/Basic_IFS/basic_ifs_Esp8266.hw b/samples/Basic_IFS/basic_ifs_Esp8266.hw index a174c30a45..301edd0a72 100644 --- a/samples/Basic_IFS/basic_ifs_Esp8266.hw +++ b/samples/Basic_IFS/basic_ifs_Esp8266.hw @@ -3,7 +3,7 @@ "arch": "Esp8266", "partitions": { "rom0": { - "size": "480K" + "size": "600K" } } } \ No newline at end of file diff --git a/samples/Basic_IFS/component.mk b/samples/Basic_IFS/component.mk index feec6c667e..50140848dd 100644 --- a/samples/Basic_IFS/component.mk +++ b/samples/Basic_IFS/component.mk @@ -1,4 +1,8 @@ -COMPONENT_DEPENDS := LittleFS +COMPONENT_DEPENDS := \ + Spiffs \ + LittleFS \ + FatIFS \ + SdStorage # Empty SPIFFS partition please SPIFF_FILES := @@ -12,3 +16,8 @@ HWCONFIG := spiffs else HWCONFIG := basic_ifs_$(SMING_ARCH) endif + +CONFIG_VARS += ENABLE_SDCARD +ifeq ($(ENABLE_SDCARD),1) +COMPONENT_CXXFLAGS += -DENABLE_SDCARD +endif diff --git a/samples/Basic_IFS/fsimage.fwfs b/samples/Basic_IFS/fsimage.fwfs index 40051d1e23..cc8b6bfb88 100644 --- a/samples/Basic_IFS/fsimage.fwfs +++ b/samples/Basic_IFS/fsimage.fwfs @@ -11,10 +11,11 @@ "sming.png": "${SMING_HOME}/../docs/api-logo.png", "Data": "${SMING_HOME}/Core/Data" }, - // Directories to mount other object stores + // Directories to mount other filesystems "mountpoints": { "littlefs": 0, - "spiffs": 1 + "spiffs": 1, + "fat": 2 }, // Rules for file metadata. All rules are evaluated in sequence for every file "rules": [ diff --git a/samples/Basic_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index 7c2aa6fa7c..e9fa62b362 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -27,7 +27,7 @@ void listSpiffsPartitions() void printPart(Storage::Partition part) { - size_t bufSize = std::min(4096U, part.size()); + size_t bufSize = std::min(storage_size_t(4096), part.size()); char buf[bufSize]; OneShotFastUs timer; if(!part.read(0, buf, bufSize)) { diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index fc329e7586..4c47578f91 100644 --- a/tests/HostTests/modules/Storage.cpp +++ b/tests/HostTests/modules/Storage.cpp @@ -15,7 +15,7 @@ class TestDevice : public Storage::Device return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x40000000; } @@ -25,7 +25,7 @@ class TestDevice : public Storage::Device return Type::unknown; } - bool read(uint32_t address, void* dst, size_t size) override + bool read(storage_size_t address, void* dst, size_t size) override { for(unsigned i = 0; i < size; ++i) { static_cast(dst)[i] = address + i; @@ -33,12 +33,12 @@ class TestDevice : public Storage::Device return true; } - bool write(uint32_t address, const void* src, size_t size) override + bool write(storage_size_t address, const void* src, size_t size) override { return false; } - bool erase_range(uint32_t address, size_t size) override + bool erase_range(storage_size_t address, storage_size_t size) override { return false; } @@ -54,7 +54,7 @@ class PartitionTest : public TestGroup void execute() override { auto dev = new TestDevice; - Storage::registerDevice(dev); + REQUIRE(Storage::registerDevice(dev)); listPartitions(); From 1f1f6b4ee73074e0cfcb80a6206b7fbce341558a Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 16 Nov 2022 07:52:39 +0000 Subject: [PATCH 50/58] Partition method fixes (#2585) Fix error calling Storage::findPartition with const char*, e.g. findPartition("rom0") Add Partition != operator --- Sming/Components/Storage/src/include/Storage.h | 2 +- Sming/Components/Storage/src/include/Storage/Partition.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Sming/Components/Storage/src/include/Storage.h b/Sming/Components/Storage/src/include/Storage.h index a43fa8a24f..80ceda5bb3 100644 --- a/Sming/Components/Storage/src/include/Storage.h +++ b/Sming/Components/Storage/src/include/Storage.h @@ -54,7 +54,7 @@ inline Iterator findPartition(Partition::Type type = Partition::Type::any, uint8 return Iterator(type, subType); } -template Iterator findPartition(T subType) +template typename std::enable_if::value, Iterator>::type findPartition(T subType) { return Iterator(Partition::Type(T::partitionType), uint8_t(subType)); } diff --git a/Sming/Components/Storage/src/include/Storage/Partition.h b/Sming/Components/Storage/src/include/Storage/Partition.h index 1dc96822a9..535b0fd4cf 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -433,6 +433,11 @@ class Partition return mPart ? mPart->name.equals(name) : false; } + template bool operator!=(const T& other) const + { + return !operator==(other); + } + /** * @brief Obtain smallest allocation unit for erase operations */ From 2552a4c69fae4497405605af3b5d7d14c6a281a1 Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 1 Dec 2022 16:05:31 +0100 Subject: [PATCH 51/58] Newer version of GCC complain about usage of printf(string-or-var) without formatting arguments. (#2586) Example: ``` error: format not a string literal and no format arguments [-Werror=format-security] 320 | printf("Error: Invalid base64\n"); TTY_FLUSH(); ``` This PR fixes the compilation issues. --- .../.patches/axtls-8266/ssl/os_port.h | 5 +- Sming/Components/axtls-8266/axtls-8266.patch | 1659 +++++++++++++---- 2 files changed, 1348 insertions(+), 316 deletions(-) diff --git a/Sming/Components/axtls-8266/.patches/axtls-8266/ssl/os_port.h b/Sming/Components/axtls-8266/.patches/axtls-8266/ssl/os_port.h index 2f85609401..743f0d1a1a 100644 --- a/Sming/Components/axtls-8266/.patches/axtls-8266/ssl/os_port.h +++ b/Sming/Components/axtls-8266/.patches/axtls-8266/ssl/os_port.h @@ -86,7 +86,10 @@ extern void system_soft_wdt_feed(void); #define get_random(num_rand_bytes, rand_data) os_get_random(rand_data, num_rand_bytes) -#define printf(fmt, ...) m_printf(_F(fmt), ##__VA_ARGS__) +#define printf(fmt, ...) m_printf(_F(fmt), ##__VA_ARGS__) +#define puts(str) m_puts(_F(str)) +#define putc(c) m_putc(c) +#define vprintf(fmt, ...) m_vprintf(fmt, ##__VA_ARGS__) #undef strcpy_P #define strcpy_P(a, str) strcpy(a, _F(str)) diff --git a/Sming/Components/axtls-8266/axtls-8266.patch b/Sming/Components/axtls-8266/axtls-8266.patch index 35e032998e..dd20ab83dd 100644 --- a/Sming/Components/axtls-8266/axtls-8266.patch +++ b/Sming/Components/axtls-8266/axtls-8266.patch @@ -1,5 +1,101 @@ +diff --git a/crypto/bigint.c b/crypto/bigint.c +index d90b093..9eebb72 100644 +--- a/crypto/bigint.c ++++ b/crypto/bigint.c +@@ -180,7 +180,7 @@ void bi_permanent(bigint *bi) + if (bi->refs != 1) + { + #ifdef CONFIG_SSL_FULL_MODE +- printf("bi_permanent: refs was not 1\n"); ++ puts("bi_permanent: refs was not 1\n"); + #endif + abort(); + } +@@ -198,7 +198,7 @@ void bi_depermanent(bigint *bi) + if (bi->refs != PERMANENT) + { + #ifdef CONFIG_SSL_FULL_MODE +- printf("bi_depermanent: bigint was not permanent\n"); ++ puts("bi_depermanent: bigint was not permanent\n"); + #endif + abort(); + } +@@ -233,7 +233,7 @@ void bi_free(BI_CTX *ctx, bigint *bi) + if (--ctx->active_count < 0) + { + #ifdef CONFIG_SSL_FULL_MODE +- printf("bi_free: active_count went negative " ++ puts("bi_free: active_count went negative " + "- double-freed bigint?\n"); + #endif + abort(); +@@ -688,11 +688,11 @@ void bi_print(const char *label, bigint *x) + { + comp mask = 0x0f << (j*4); + comp num = (x->comps[i] & mask) >> (j*4); +- putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); ++ putc((num <= 9) ? (num + '0') : (num + 'A' - 10)); + } + } + +- printf("\n"); ++ puts("\n"); + } + #endif + +@@ -1098,7 +1098,7 @@ static bigint *alloc(BI_CTX *ctx, int size) + if (biR->refs != 0) + { + #ifdef CONFIG_SSL_FULL_MODE +- printf("alloc: refs was not 0\n"); ++ puts("alloc: refs was not 0\n"); + #endif + abort(); /* create a stack trace from a core dump */ + } +@@ -1174,13 +1174,13 @@ static void check(const bigint *bi) + { + if (bi->refs <= 0) + { +- printf("check: zero or negative refs in bigint\n"); ++ puts("check: zero or negative refs in bigint\n"); + abort(); + } + + if (bi->next != NULL) + { +- printf("check: attempt to use a bigint from " ++ puts("check: attempt to use a bigint from " + "the free list\n"); + abort(); + } +diff --git a/crypto/crypto.h b/crypto/crypto.h +index da24d31..4de139b 100644 +--- a/crypto/crypto.h ++++ b/crypto/crypto.h +@@ -196,6 +196,10 @@ EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); + /************************************************************************** + * HMAC declarations + **************************************************************************/ ++#define hmac_md5 ax_hmac_md5 ++#define hmac_sha1 ax_hmac_sha1 ++#define hmac_sha256 ax_hmac_sha256 ++ + void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, + int key_len, uint8_t *digest); + void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, +@@ -206,6 +210,10 @@ void hmac_sha256(const uint8_t *msg, int length, const uint8_t *key, + /************************************************************************** + * HMAC functions operating on vectors + **************************************************************************/ ++#define hmac_md5_v ax_hmac_md5_v ++#define hmac_sha1_v ax_hmac_sha1_v ++#define hmac_sha256_v ax_hmac_sha256_v ++ + void hmac_md5_v(const uint8_t **msg, int* length, int count, const uint8_t *key, + int key_len, uint8_t *digest); + void hmac_sha1_v(const uint8_t **msg, int* length, int count, const uint8_t *key, diff --git a/crypto/crypto_misc.c b/crypto/crypto_misc.c -index dca7e5f..5f4ec51 100644 +index dca7e5f..b028750 100644 --- a/crypto/crypto_misc.c +++ b/crypto/crypto_misc.c @@ -44,7 +44,6 @@ @@ -73,16 +169,56 @@ index dca7e5f..5f4ec51 100644 /** * Set a series of bytes with a random number. Individual bytes are not zero. */ -@@ -289,7 +232,7 @@ EXP_FUNC void STDCALL print_blob(const char *format, +@@ -257,17 +200,17 @@ static void print_hex(uint8_t hex) + printf("%02x ", hex); + if (++column == 8) + { +- printf(": "); ++ puts(": "); + } + else if (column >= 16) + { +- printf("\n"); ++ puts("\n"); + column = 0; + } - va_start(ap, size); - snprintf(tmp, sizeof(tmp), "SSL: %s\n", format); -- vprintf(tmp, ap); -+ m_vprintf(tmp, ap); - print_hex_init(size); - for (i = 0; i < size; i++) + if (++hex_index >= hex_finish && column > 0) { - +- printf("\n"); ++ puts("\n"); + } + } + +@@ -374,7 +317,7 @@ EXP_FUNC int STDCALL base64_decode(const char *in, int len, + error: + #ifdef CONFIG_SSL_FULL_MODE + if (ret < 0) +- printf("Error: Invalid base64\n"); TTY_FLUSH(); ++ puts("Error: Invalid base64\n"); TTY_FLUSH(); + #endif + TTY_FLUSH(); + return ret; +diff --git a/crypto/rsa.c b/crypto/rsa.c +index 53509d0..25c568d 100644 +--- a/crypto/rsa.c ++++ b/crypto/rsa.c +@@ -236,11 +236,11 @@ void RSA_print(const RSA_CTX *rsa_ctx) + if (rsa_ctx == NULL) + return; + +- printf("----------------- RSA DEBUG ----------------\n"); ++ puts("----------------- RSA DEBUG ----------------\n"); + printf("Size:\t%d\n", rsa_ctx->num_octets); +- printf("Modulus"); bi_print("", rsa_ctx->m); +- printf("Public Key"); bi_print("", rsa_ctx->e); +- printf("Private Key"); bi_print("", rsa_ctx->d); ++ puts("Modulus"); bi_print("", rsa_ctx->m); ++ puts("Public Key"); bi_print("", rsa_ctx->e); ++ puts("Private Key"); bi_print("", rsa_ctx->d); + } + #endif + diff --git a/replacements/time.c b/replacements/time.c index 4972119..3e7e407 100644 --- a/replacements/time.c @@ -219,137 +355,628 @@ index 4972119..3e7e407 100644 } return 0; } - -diff --git a/ssl/tls1.c b/ssl/tls1.c -index 8f0fbfb..35ad4f3 100644 ---- a/ssl/tls1.c -+++ b/ssl/tls1.c -@@ -85,7 +85,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = - 16, /* block padding size */ - SHA1_SIZE, /* digest size */ - 2*(SHA1_SIZE+16+16), /* key block size */ -- hmac_sha1_v, /* hmac algorithm */ -+ crypto_sha1_hmac_v, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - }, -@@ -96,7 +96,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = - 16, /* block padding size */ - SHA1_SIZE, /* digest size */ - 2*(SHA1_SIZE+32+16), /* key block size */ -- hmac_sha1_v, /* hmac algorithm */ -+ crypto_sha1_hmac_v, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - }, -@@ -107,7 +107,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = - 16, /* block padding size */ - SHA256_SIZE, /* digest size */ - 2*(SHA256_SIZE+32+16), /* key block size */ -- hmac_sha256_v, /* hmac algorithm */ -+ crypto_sha256_hmac_v, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - }, -@@ -118,7 +118,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = - 16, /* block padding size */ - SHA256_SIZE, /* digest size */ - 2*(SHA256_SIZE+32+16), /* key block size */ -- hmac_sha256_v, /* hmac algorithm */ -+ crypto_sha256_hmac_v, /* hmac algorithm */ - (crypt_func)AES_cbc_encrypt, /* encrypt */ - (crypt_func)AES_cbc_decrypt /* decrypt */ - } -@@ -843,15 +843,15 @@ void add_packet(SSL *ssl, const uint8_t *pkt, int len) - // TLS1.2+ - if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2 || ssl->version == 0) - { -- SHA256_Update(&ssl->dc->sha256_ctx, pkt, len); -+ crypto_sha256_update(&ssl->dc->sha256_ctx, pkt, len); - } - - if (ssl->version < SSL_PROTOCOL_VERSION_TLS1_2 || - ssl->next_state == HS_SERVER_HELLO || - ssl->next_state == 0) +diff --git a/ssl/asn1.c b/ssl/asn1.c +index a08a618..3c64064 100644 +--- a/ssl/asn1.c ++++ b/ssl/asn1.c +@@ -271,7 +271,7 @@ int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) + if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ { -- MD5_Update(&ssl->dc->md5_ctx, pkt, len); -- SHA1_Update(&ssl->dc->sha1_ctx, pkt, len); -+ crypto_md5_update(&ssl->dc->md5_ctx, pkt, len); -+ crypto_sha1_update(&ssl->dc->sha1_ctx, pkt, len); + #ifdef CONFIG_SSL_FULL_MODE +- printf("Error: This is not a valid ASN.1 file\n"); ++ puts("Error: This is not a valid ASN.1 file\n"); + #endif + return X509_INVALID_PRIV_KEY; } +@@ -405,7 +405,7 @@ static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) + int asn1_version(const uint8_t *cert, int *offset, int *val) + { + (*offset) += 2; /* get past explicit tag */ +- return asn1_get_int(cert, offset, val); ++ return asn1_get_int(cert, offset, (int32_t*)val); } -@@ -864,9 +864,9 @@ static void p_hash_md5(const uint8_t *sec, int sec_len, - uint8_t a1[MD5_SIZE+77]; + /** +@@ -766,12 +766,12 @@ int asn1_signature_type(const uint8_t *cert, + { + #ifdef CONFIG_SSL_FULL_MODE + int i; +- printf("invalid digest: "); ++ puts("invalid digest: "); - /* A(1) */ -- hmac_md5(seed, seed_len, sec, sec_len, a1); -+ crypto_md5_hmac(seed, seed_len, sec, sec_len, a1); - memcpy(&a1[MD5_SIZE], seed, seed_len); -- hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); -+ crypto_md5_hmac(a1, MD5_SIZE+seed_len, sec, sec_len, out); + for (i = 0; i < len; i++) + printf("%02x ", cert[*offset + i]); - while (olen > MD5_SIZE) - { -@@ -875,11 +875,11 @@ static void p_hash_md5(const uint8_t *sec, int sec_len, - olen -= MD5_SIZE; +- printf("\n"); ++ puts("\n"); + #endif + goto end_check_sig; /* unrecognised cert type */ + } +diff --git a/ssl/crypto_misc.h b/ssl/crypto_misc.h +index 02d9306..63423c2 100644 +--- a/ssl/crypto_misc.h ++++ b/ssl/crypto_misc.h +@@ -39,8 +39,11 @@ + extern "C" { + #endif - /* A(N) */ -- hmac_md5(a1, MD5_SIZE, sec, sec_len, a2); -+ crypto_md5_hmac(a1, MD5_SIZE, sec, sec_len, a2); - memcpy(a1, a2, MD5_SIZE); +-#include "crypto.h" +-#include "bigint.h" ++#include "../crypto/crypto.h" ++#include "../crypto/bigint.h" ++#include ++#include ++#include - /* work out the actual hash */ -- hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); -+ crypto_md5_hmac(a1, MD5_SIZE+seed_len, sec, sec_len, out); - } - } + /************************************************************************** + * X509 declarations +diff --git a/ssl/gen_cert.c b/ssl/gen_cert.c +index 093ae9c..d611ab0 100644 +--- a/ssl/gen_cert.c ++++ b/ssl/gen_cert.c +@@ -314,7 +314,7 @@ static int gen_tbs_cert(const char * dn[], + uint8_t *sha_dgst) + { + int ret = X509_OK; +- SHA1_CTX sha_ctx; ++ crypto_sha1_context_t sha_ctx; + int seq_offset; + int begin_tbs = *offset; + int seq_size = pre_adjust_with_size( +@@ -336,9 +336,9 @@ static int gen_tbs_cert(const char * dn[], + gen_pub_key(rsa_ctx, buf, offset); + adjust_with_size(seq_size, seq_offset, buf, offset); -@@ -892,9 +892,9 @@ static void p_hash_sha1(const uint8_t *sec, int sec_len, - uint8_t a1[SHA1_SIZE+77]; +- SHA1_Init(&sha_ctx); +- SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); +- SHA1_Final(sha_dgst, &sha_ctx); ++ crypto_sha1_init(&sha_ctx); ++ crypto_sha1_update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); ++ crypto_sha1_final(sha_dgst, &sha_ctx); - /* A(1) */ -- hmac_sha1(seed, seed_len, sec, sec_len, a1); -+ crypto_sha1_hmac(seed, seed_len, sec, sec_len, a1); - memcpy(&a1[SHA1_SIZE], seed, seed_len); -- hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); -+ crypto_sha1_hmac(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + error: + return ret; +diff --git a/ssl/loader.c b/ssl/loader.c +index 6e41f40..874e5fd 100644 +--- a/ssl/loader.c ++++ b/ssl/loader.c +@@ -155,7 +155,7 @@ static int do_obj(SSL_CTX *ssl_ctx, int obj_type, + #endif + default: + #ifdef CONFIG_SSL_FULL_MODE +- printf(unsupported_str); ++ printf("%s", unsupported_str); + #endif + ret = SSL_ERROR_NOT_SUPPORTED; + break; +@@ -222,14 +222,14 @@ static int pem_decrypt(const char *where, const char *end, + char *start = NULL; + uint8_t iv[IV_SIZE]; + int i, pem_size; +- MD5_CTX md5_ctx; ++ crypto_md5_context_t md5_ctx; + AES_CTX aes_ctx; + uint8_t key[32]; /* AES256 size */ - while (olen > SHA1_SIZE) + if (password == NULL || strlen(password) == 0) { -@@ -903,11 +903,11 @@ static void p_hash_sha1(const uint8_t *sec, int sec_len, - olen -= SHA1_SIZE; - - /* A(N) */ -- hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2); -+ crypto_sha1_hmac(a1, SHA1_SIZE, sec, sec_len, a2); - memcpy(a1, a2, SHA1_SIZE); - - /* work out the actual hash */ -- hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); -+ crypto_sha1_hmac(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + #ifdef CONFIG_SSL_FULL_MODE +- printf("Error: Need a password for this PEM file\n"); ++ puts("Error: Need a password for this PEM file\n"); + #endif + goto error; } - } - -@@ -920,9 +920,9 @@ static void p_hash_sha256(const uint8_t *sec, int sec_len, - uint8_t a1[SHA256_SIZE+77]; - - /* A(1) */ -- hmac_sha256(seed, seed_len, sec, sec_len, a1); -+ crypto_sha256_hmac(seed, seed_len, sec, sec_len, a1); - memcpy(&a1[SHA256_SIZE], seed, seed_len); -- hmac_sha256(a1, SHA256_SIZE+seed_len, sec, sec_len, out); -+ crypto_sha256_hmac(a1, SHA256_SIZE+seed_len, sec, sec_len, out); - - while (olen > SHA256_SIZE) +@@ -246,7 +246,7 @@ static int pem_decrypt(const char *where, const char *end, + else { -@@ -931,11 +931,11 @@ static void p_hash_sha256(const uint8_t *sec, int sec_len, - olen -= SHA256_SIZE; + #ifdef CONFIG_SSL_FULL_MODE +- printf("Error: Unsupported password cipher\n"); ++ puts("Error: Unsupported password cipher\n"); + #endif + goto error; + } +@@ -269,18 +269,18 @@ static int pem_decrypt(const char *where, const char *end, + goto error; - // A(N) -- hmac_sha256(a1, SHA256_SIZE, sec, sec_len, a2); -+ crypto_sha256_hmac(a1, SHA256_SIZE, sec, sec_len, a2); - memcpy(a1, a2, SHA256_SIZE); + /* work out the key */ +- MD5_Init(&md5_ctx); +- MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); +- MD5_Update(&md5_ctx, iv, SALT_SIZE); +- MD5_Final(key, &md5_ctx); ++ crypto_md5_init(&md5_ctx); ++ crypto_md5_update(&md5_ctx, (const uint8_t*)password, strlen(password)); ++ crypto_md5_update(&md5_ctx, iv, SALT_SIZE); ++ crypto_md5_final(key, &md5_ctx); + + if (is_aes_256) + { +- MD5_Init(&md5_ctx); +- MD5_Update(&md5_ctx, key, MD5_SIZE); +- MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); +- MD5_Update(&md5_ctx, iv, SALT_SIZE); +- MD5_Final(&key[MD5_SIZE], &md5_ctx); ++ crypto_md5_init(&md5_ctx); ++ crypto_md5_update(&md5_ctx, key, MD5_SIZE); ++ crypto_md5_update(&md5_ctx, (const uint8_t*)password, strlen(password)); ++ crypto_md5_update(&md5_ctx, iv, SALT_SIZE); ++ crypto_md5_final(&key[MD5_SIZE], &md5_ctx); + } + + /* decrypt using the key/iv */ +@@ -481,7 +481,7 @@ error: + #ifdef CONFIG_SSL_FULL_MODE + if (ret) + { +- printf("Error: Certificate or key not loaded\n"); ++ puts("Error: Certificate or key not loaded\n"); + } + #endif + +diff --git a/ssl/os_port.h b/ssl/os_port.h +index e0b9e46..743f0d1 100644 +--- a/ssl/os_port.h ++++ b/ssl/os_port.h +@@ -43,31 +43,20 @@ extern "C" { + + #include "os_int.h" + #include "config.h" +-#include ++#include + +-#ifdef WIN32 +-#define STDCALL __stdcall +-#define EXP_FUNC __declspec(dllexport) +-#else +-#define STDCALL +-#define EXP_FUNC +-#endif +- +-#if defined(_WIN32_WCE) + #undef WIN32 +-#define WIN32 ++#ifndef ESP8266 ++#define ESP8266 + #endif + +-#if defined(ESP8266) ++#define STDCALL ++#define EXP_FUNC + +-#include "util/time.h" ++#include "../util/time.h" + #include +-#define alloca(size) __builtin_alloca(size) + #define TTY_FLUSH() +-#ifdef putc + #undef putc +-#endif +-#define putc(x, f) ets_putc(x) + + #define SOCKET_READ(A,B,C) ax_port_read(A,B,C) + #define SOCKET_WRITE(A,B,C) ax_port_write(A,B,C) +@@ -75,10 +64,6 @@ extern "C" { + #define get_file ax_get_file + #define EWOULDBLOCK EAGAIN + +-#define hmac_sha1 ax_hmac_sha1 +-#define hmac_sha256 ax_hmac_sha256 +-#define hmac_md5 ax_hmac_md5 +- + #ifndef be64toh + # define __bswap_constant_64(x) \ + ((((x) & 0xff00000000000000ull) >> 56) \ +@@ -92,175 +77,35 @@ extern "C" { + #define be64toh(x) __bswap_constant_64(x) + #endif + +-void ax_wdt_feed(); +- +-#ifndef PROGMEM +-#define PROGMEM __attribute__((aligned(4))) __attribute__((section(".irom.text"))) +-#endif +- +-#ifndef WITH_PGM_READ_HELPER +-#define ax_array_read_u8(x, y) x[y] +-#else +- +-static inline uint8_t pgm_read_byte(const void* addr) { +- register uint32_t res; +- __asm__("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ +- "sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ +- "l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ +- "slli %0, %0, 3\n" /* Multiply offset by 8, yielding an offset in bits */ +- "ssr %0\n" /* Prepare to shift by offset (in bits) */ +- "srl %0, %1\n" /* Shift right; now the requested byte is the first one */ +- :"=r"(res), "=r"(addr) +- :"1"(addr) +- :); +- return (uint8_t) res; /* This masks the lower byte from the returned word */ +-} ++extern void system_soft_wdt_feed(void); ++#define ax_wdt_feed system_soft_wdt_feed + + #define ax_array_read_u8(x, y) pgm_read_byte((x)+(y)) +-#endif //WITH_PGM_READ_HELPER + +-#ifdef printf +-#undef printf +-#endif +-//#define printf(...) ets_printf(__VA_ARGS__) +-#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) +-#define PGM_VOID_P const void * +-static inline void* memcpy_P(void* dest, PGM_VOID_P src, size_t count) { +- const uint8_t* read = (const uint8_t*)(src); +- uint8_t* write = (uint8_t*)(dest); ++#ifdef AXTLS_BUILD + +- while (count) +- { +- *write++ = pgm_read_byte(read++); +- count--; +- } ++#define get_random(num_rand_bytes, rand_data) os_get_random(rand_data, num_rand_bytes) + +- return dest; +-} +-static inline int strlen_P(const char *str) { +- int cnt = 0; +- while (pgm_read_byte(str++)) cnt++; +- return cnt; +-} +-static inline int memcmp_P(const void *a1, const void *b1, size_t len) { +- const uint8_t* a = (const uint8_t*)(a1); +- uint8_t* b = (uint8_t*)(b1); +- for (size_t i=0; i? ++// Not ANSI C so prototype required + extern char *strdup(const char *orig); + +-#elif defined(WIN32) +- +-/* Windows CE stuff */ +-#if defined(_WIN32_WCE) +-#include +-#define abort() exit(1) +-#else +-#include +-#include +-#include +-#include +-#endif /* _WIN32_WCE */ +- +-#include +-#include +-#undef getpid +-#undef open +-#undef close +-#undef sleep +-#undef gettimeofday +-#undef dup2 +-#undef unlink +- +-#define SOCKET_READ(A,B,C) recv(A,B,C,0) +-#define SOCKET_WRITE(A,B,C) send(A,B,C,0) +-#define SOCKET_CLOSE(A) closesocket(A) +-#define srandom(A) srand(A) +-#define random() rand() +-#define getpid() _getpid() +-#define snprintf _snprintf +-#define open(A,B) _open(A,B) +-#define dup2(A,B) _dup2(A,B) +-#define unlink(A) _unlink(A) +-#define close(A) _close(A) +-#define read(A,B,C) _read(A,B,C) +-#define write(A,B,C) _write(A,B,C) +-#define sleep(A) Sleep(A*1000) +-#define usleep(A) Sleep(A/1000) +-#define strdup(A) _strdup(A) +-#define chroot(A) _chdir(A) +-#define chdir(A) _chdir(A) +-#define alloca(A) _alloca(A) +-#ifndef lseek +-#define lseek(A,B,C) _lseek(A,B,C) +-#endif +- +-/* This fix gets around a problem where a win32 application on a cygwin xterm +- doesn't display regular output (until a certain buffer limit) - but it works +- fine under a normal DOS window. This is a hack to get around the issue - +- see http://www.khngai.com/emacs/tty.php */ +-#define TTY_FLUSH() if (!_isatty(_fileno(stdout))) fflush(stdout); +- +-/* +- * automatically build some library dependencies. +- */ +-#pragma comment(lib, "WS2_32.lib") +-#pragma comment(lib, "AdvAPI32.lib") +- +-typedef int socklen_t; +- +-EXP_FUNC void STDCALL gettimeofday(struct timeval* t,void* timezone); +-EXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2); +-EXP_FUNC int STDCALL getdomainname(char *buf, int buf_size); +- +-#else /* Not Win32 */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define SOCKET_READ(A,B,C) read(A,B,C) +-#define SOCKET_WRITE(A,B,C) write(A,B,C) +-#define SOCKET_CLOSE(A) if (A >= 0) close(A) +-#define TTY_FLUSH() +- +-#ifndef be64toh +-#define be64toh(x) __be64_to_cpu(x) +-#endif +- +-#endif /* Not Win32 */ +- + /* some functions to mutate the way these work */ +-inline uint32_t htonl(uint32_t n){ ++#ifndef ntohl ++static inline uint32_t htonl(uint32_t n){ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000UL) >> 8) | +@@ -268,41 +113,14 @@ inline uint32_t htonl(uint32_t n){ + } + + #define ntohl htonl +- +-EXP_FUNC int STDCALL ax_open(const char *pathname, int flags); +- +-#ifdef CONFIG_PLATFORM_LINUX +-void exit_now(const char *format, ...) __attribute((noreturn)); +-#else +-void exit_now(const char *format, ...); ++#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS + #endif + + /* Mutexing definitions */ +-#if defined(CONFIG_SSL_CTX_MUTEXING) +-#if defined(WIN32) +-#define SSL_CTX_MUTEX_TYPE HANDLE +-#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0) +-#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A) +-#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE) +-#define SSL_CTX_UNLOCK(A) ReleaseMutex(A) +-#else +-#include +-#define SSL_CTX_MUTEX_TYPE pthread_mutex_t +-#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL) +-#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A) +-#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A) +-#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A) +-#endif +-#else /* no mutexing */ + #define SSL_CTX_MUTEX_INIT(A) + #define SSL_CTX_MUTEX_DESTROY(A) + #define SSL_CTX_LOCK(A) + #define SSL_CTX_UNLOCK(A) +-#endif +- +-#ifndef PROGMEM +-#define PROGMEM +-#endif + + #ifdef __cplusplus + } +diff --git a/ssl/p12.c b/ssl/p12.c +index 5bd2394..5363d22 100644 +--- a/ssl/p12.c ++++ b/ssl/p12.c +@@ -190,7 +190,7 @@ static int p8_decrypt(const char *uni_pass, int uni_pass_len, + uint8_t p[BLOCK_SIZE*2]; + uint8_t d[BLOCK_SIZE]; + uint8_t Ai[SHA1_SIZE]; +- SHA1_CTX sha_ctx; ++ crypto_sha1_context_t sha_ctx; + RC4_CTX rc4_ctx; + int i; + +@@ -202,16 +202,16 @@ static int p8_decrypt(const char *uni_pass, int uni_pass_len, + } + + /* get the key - no IV since we are using RC4 */ +- SHA1_Init(&sha_ctx); +- SHA1_Update(&sha_ctx, d, sizeof(d)); +- SHA1_Update(&sha_ctx, p, sizeof(p)); +- SHA1_Final(Ai, &sha_ctx); ++ crypto_sha1_init(&sha_ctx); ++ crypto_sha1_update(&sha_ctx, d, sizeof(d)); ++ crypto_sha1_update(&sha_ctx, p, sizeof(p)); ++ crypto_sha1_final(Ai, &sha_ctx); + + for (i = 1; i < iter; i++) + { +- SHA1_Init(&sha_ctx); +- SHA1_Update(&sha_ctx, Ai, SHA1_SIZE); +- SHA1_Final(Ai, &sha_ctx); ++ crypto_sha1_init(&sha_ctx); ++ crypto_sha1_update(&sha_ctx, Ai, SHA1_SIZE); ++ crypto_sha1_final(Ai, &sha_ctx); + } + + /* do the decryption */ +@@ -409,7 +409,7 @@ int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) + key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) + goto error; + +- hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); ++ crypto_sha1_hmac(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); + + if (memcmp(mac, orig_mac, SHA1_SIZE)) + { +diff --git a/ssl/tls1.c b/ssl/tls1.c +index 8f0fbfb..b2dcddd 100644 +--- a/ssl/tls1.c ++++ b/ssl/tls1.c +@@ -85,7 +85,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + 2*(SHA1_SIZE+16+16), /* key block size */ +- hmac_sha1_v, /* hmac algorithm */ ++ crypto_sha1_hmac_v, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, +@@ -96,7 +96,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = + 16, /* block padding size */ + SHA1_SIZE, /* digest size */ + 2*(SHA1_SIZE+32+16), /* key block size */ +- hmac_sha1_v, /* hmac algorithm */ ++ crypto_sha1_hmac_v, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, +@@ -107,7 +107,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = + 16, /* block padding size */ + SHA256_SIZE, /* digest size */ + 2*(SHA256_SIZE+32+16), /* key block size */ +- hmac_sha256_v, /* hmac algorithm */ ++ crypto_sha256_hmac_v, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + }, +@@ -118,7 +118,7 @@ static const cipher_info_t cipher_info[NUM_PROTOCOLS] = + 16, /* block padding size */ + SHA256_SIZE, /* digest size */ + 2*(SHA256_SIZE+32+16), /* key block size */ +- hmac_sha256_v, /* hmac algorithm */ ++ crypto_sha256_hmac_v, /* hmac algorithm */ + (crypt_func)AES_cbc_encrypt, /* encrypt */ + (crypt_func)AES_cbc_decrypt /* decrypt */ + } +@@ -843,15 +843,15 @@ void add_packet(SSL *ssl, const uint8_t *pkt, int len) + // TLS1.2+ + if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2 || ssl->version == 0) + { +- SHA256_Update(&ssl->dc->sha256_ctx, pkt, len); ++ crypto_sha256_update(&ssl->dc->sha256_ctx, pkt, len); + } + + if (ssl->version < SSL_PROTOCOL_VERSION_TLS1_2 || + ssl->next_state == HS_SERVER_HELLO || + ssl->next_state == 0) + { +- MD5_Update(&ssl->dc->md5_ctx, pkt, len); +- SHA1_Update(&ssl->dc->sha1_ctx, pkt, len); ++ crypto_md5_update(&ssl->dc->md5_ctx, pkt, len); ++ crypto_sha1_update(&ssl->dc->sha1_ctx, pkt, len); + } + } + +@@ -864,9 +864,9 @@ static void p_hash_md5(const uint8_t *sec, int sec_len, + uint8_t a1[MD5_SIZE+77]; + + /* A(1) */ +- hmac_md5(seed, seed_len, sec, sec_len, a1); ++ crypto_md5_hmac(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[MD5_SIZE], seed, seed_len); +- hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); ++ crypto_md5_hmac(a1, MD5_SIZE+seed_len, sec, sec_len, out); + + while (olen > MD5_SIZE) + { +@@ -875,11 +875,11 @@ static void p_hash_md5(const uint8_t *sec, int sec_len, + olen -= MD5_SIZE; + + /* A(N) */ +- hmac_md5(a1, MD5_SIZE, sec, sec_len, a2); ++ crypto_md5_hmac(a1, MD5_SIZE, sec, sec_len, a2); + memcpy(a1, a2, MD5_SIZE); + + /* work out the actual hash */ +- hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out); ++ crypto_md5_hmac(a1, MD5_SIZE+seed_len, sec, sec_len, out); + } + } + +@@ -892,9 +892,9 @@ static void p_hash_sha1(const uint8_t *sec, int sec_len, + uint8_t a1[SHA1_SIZE+77]; + + /* A(1) */ +- hmac_sha1(seed, seed_len, sec, sec_len, a1); ++ crypto_sha1_hmac(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[SHA1_SIZE], seed, seed_len); +- hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); ++ crypto_sha1_hmac(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + + while (olen > SHA1_SIZE) + { +@@ -903,11 +903,11 @@ static void p_hash_sha1(const uint8_t *sec, int sec_len, + olen -= SHA1_SIZE; + + /* A(N) */ +- hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2); ++ crypto_sha1_hmac(a1, SHA1_SIZE, sec, sec_len, a2); + memcpy(a1, a2, SHA1_SIZE); + + /* work out the actual hash */ +- hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out); ++ crypto_sha1_hmac(a1, SHA1_SIZE+seed_len, sec, sec_len, out); + } + } + +@@ -920,9 +920,9 @@ static void p_hash_sha256(const uint8_t *sec, int sec_len, + uint8_t a1[SHA256_SIZE+77]; + + /* A(1) */ +- hmac_sha256(seed, seed_len, sec, sec_len, a1); ++ crypto_sha256_hmac(seed, seed_len, sec, sec_len, a1); + memcpy(&a1[SHA256_SIZE], seed, seed_len); +- hmac_sha256(a1, SHA256_SIZE+seed_len, sec, sec_len, out); ++ crypto_sha256_hmac(a1, SHA256_SIZE+seed_len, sec, sec_len, out); + + while (olen > SHA256_SIZE) + { +@@ -931,11 +931,11 @@ static void p_hash_sha256(const uint8_t *sec, int sec_len, + olen -= SHA256_SIZE; + + // A(N) +- hmac_sha256(a1, SHA256_SIZE, sec, sec_len, a2); ++ crypto_sha256_hmac(a1, SHA256_SIZE, sec, sec_len, a2); + memcpy(a1, a2, SHA256_SIZE); // work out the actual hash - hmac_sha256(a1, SHA256_SIZE+seed_len, sec, sec_len, out); @@ -388,59 +1015,382 @@ index 8f0fbfb..35ad4f3 100644 int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); uint8_t *buf = ssl->bm_data; -+ if (ssl->can_free_certificates) { -+ certificate_free(ssl); -+ } -+ - if (IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY)) - return SSL_CLOSE_NOTIFY; ++ if (ssl->can_free_certificates) { ++ certificate_free(ssl); ++ } ++ + if (IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY)) + return SSL_CLOSE_NOTIFY; + +@@ -1411,7 +1415,7 @@ int basic_read(SSL *ssl, uint8_t **in_data) + if ((buf[0] & 0x80) && buf[2] == 1) + { + #ifdef CONFIG_SSL_FULL_MODE +- printf("Error: no SSLv23 handshaking allowed\n"); ++ puts("Error: no SSLv23 handshaking allowed\n"); + #endif + ret = SSL_ERROR_NOT_SUPPORTED; + goto error; /* not an error - just get out of here */ +@@ -1562,7 +1566,7 @@ int increase_bm_data_size(SSL *ssl, size_t size) + required = (required < RT_MAX_PLAIN_LENGTH) ? required : RT_MAX_PLAIN_LENGTH; + uint8_t* new_bm_all_data = (uint8_t*) realloc(ssl->bm_all_data, required + RT_EXTRA); + if (!new_bm_all_data) { +- printf("failed to grow plain buffer\r\n"); ++ puts("failed to grow plain buffer\r\n"); + ssl->hs_status = SSL_ERROR_DEAD; + return SSL_ERROR_CONN_LOST; + } +@@ -1845,9 +1849,9 @@ void disposable_new(SSL *ssl) + if (ssl->dc == NULL) + { + ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX)); +- SHA256_Init(&ssl->dc->sha256_ctx); +- MD5_Init(&ssl->dc->md5_ctx); +- SHA1_Init(&ssl->dc->sha1_ctx); ++ crypto_sha256_init(&ssl->dc->sha256_ctx); ++ crypto_md5_init(&ssl->dc->md5_ctx); ++ crypto_sha1_init(&ssl->dc->sha1_ctx); + } + } + +@@ -2248,15 +2252,15 @@ EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp) + return 1; + int res = memcmp(ssl->x509_ctx->fingerprint, fp, SHA1_SIZE); + if (res != 0) { +- printf("cert FP: "); ++ puts("cert FP: "); + for (int i = 0; i < SHA1_SIZE; ++i) { + printf("%02X ", ssl->x509_ctx->fingerprint[i]); + } +- printf("\r\ntest FP: "); ++ puts("\r\ntest FP: "); + for (int i = 0; i < SHA1_SIZE; ++i) { + printf("%02X ", fp[i]); + } +- printf("\r\n"); ++ puts("\r\n"); + } + return res; + } +@@ -2267,15 +2271,15 @@ EXP_FUNC int STDCALL ssl_match_spki_sha256(const SSL *ssl, const uint8_t* hash) + return 1; + int res = memcmp(ssl->x509_ctx->spki_sha256, hash, SHA256_SIZE); + if (res != 0) { +- printf("cert SPKI SHA-256 hash: "); ++ puts("cert SPKI SHA-256 hash: "); + for (int i = 0; i < SHA256_SIZE; ++i) { + printf("%02X ", ssl->x509_ctx->spki_sha256[i]); + } +- printf("\r\ntest hash: "); ++ puts("\r\ntest hash: "); + for (int i = 0; i < SHA256_SIZE; ++i) { + printf("%02X ", hash[i]); + } +- printf("\r\n"); ++ puts("\r\n"); + } + return res; + } +@@ -2294,55 +2298,55 @@ void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok) + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + +- if (not_ok) printf("Error - invalid State:\t"); +- else printf("State:\t"); +- if (is_send) printf("sending "); +- else printf("receiving "); ++ if (not_ok) puts("Error - invalid State:\t"); ++ else puts("State:\t"); ++ if (is_send) puts("sending "); ++ else puts("receiving "); + + switch (state) + { + case HS_HELLO_REQUEST: +- printf("Hello Request (0)\n"); ++ puts("Hello Request (0)\n"); + break; + + case HS_CLIENT_HELLO: +- printf("Client Hello (1)\n"); ++ puts("Client Hello (1)\n"); + break; + + case HS_SERVER_HELLO: +- printf("Server Hello (2)\n"); ++ puts("Server Hello (2)\n"); + break; + + case HS_CERTIFICATE: +- printf("Certificate (11)\n"); ++ puts("Certificate (11)\n"); + break; + + case HS_SERVER_KEY_XCHG: +- printf("Certificate Request (12)\n"); ++ puts("Certificate Request (12)\n"); + break; + + case HS_CERT_REQ: +- printf("Certificate Request (13)\n"); ++ puts("Certificate Request (13)\n"); + break; + + case HS_SERVER_HELLO_DONE: +- printf("Server Hello Done (14)\n"); ++ puts("Server Hello Done (14)\n"); + break; + + case HS_CERT_VERIFY: +- printf("Certificate Verify (15)\n"); ++ puts("Certificate Verify (15)\n"); + break; + + case HS_CLIENT_KEY_XCHG: +- printf("Client Key Exchange (16)\n"); ++ puts("Client Key Exchange (16)\n"); + break; + + case HS_FINISHED: +- printf("Finished (16)\n"); ++ puts("Finished (16)\n"); + break; + + default: +- printf("Error (Unknown)\n"); ++ puts("Error (Unknown)\n"); + break; + } + } +@@ -2389,7 +2393,7 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code) + if (error_code == SSL_OK) + return; + +- printf("Error: "); ++ puts("Error: "); + + /* X509 error? */ + if (error_code < SSL_X509_OFFSET) +@@ -2409,67 +2413,67 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code) + switch (error_code) + { + case SSL_ERROR_DEAD: +- printf("connection dead"); ++ puts("connection dead"); + break; + + case SSL_ERROR_RECORD_OVERFLOW: +- printf("record overflow"); ++ puts("record overflow"); + break; + + case SSL_ERROR_INVALID_HANDSHAKE: +- printf("invalid handshake"); ++ puts("invalid handshake"); + break; + + case SSL_ERROR_INVALID_PROT_MSG: +- printf("invalid protocol message"); ++ puts("invalid protocol message"); + break; + + case SSL_ERROR_INVALID_HMAC: +- printf("invalid mac"); ++ puts("invalid mac"); + break; + + case SSL_ERROR_INVALID_VERSION: +- printf("invalid version"); ++ puts("invalid version"); + break; + + case SSL_ERROR_INVALID_SESSION: +- printf("invalid session"); ++ puts("invalid session"); + break; + + case SSL_ERROR_NO_CIPHER: +- printf("no cipher"); ++ puts("no cipher"); + break; + + case SSL_ERROR_INVALID_CERT_HASH_ALG: +- printf("invalid cert hash algorithm"); ++ puts("invalid cert hash algorithm"); + break; + + case SSL_ERROR_CONN_LOST: +- printf("connection lost"); ++ puts("connection lost"); + break; + + case SSL_ERROR_BAD_CERTIFICATE: +- printf("bad certificate"); ++ puts("bad certificate"); + break; + + case SSL_ERROR_INVALID_KEY: +- printf("invalid key"); ++ puts("invalid key"); + break; + + case SSL_ERROR_FINISHED_INVALID: +- printf("finished invalid"); ++ puts("finished invalid"); + break; + + case SSL_ERROR_NO_CERT_DEFINED: +- printf("no certificate defined"); ++ puts("no certificate defined"); + break; + + case SSL_ERROR_NO_CLIENT_RENOG: +- printf("client renegotiation not supported"); ++ puts("client renegotiation not supported"); + break; + + case SSL_ERROR_NOT_SUPPORTED: +- printf("Option not supported"); ++ puts("Option not supported"); + break; + + default: +@@ -2477,7 +2481,7 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code) + break; + } + +- printf("\n"); ++ puts("\n"); + } + + /** +@@ -2488,68 +2492,68 @@ void DISPLAY_ALERT(SSL *ssl, int alert) + if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) + return; + +- printf("Alert: "); ++ puts("Alert: "); + + switch (alert) + { + case SSL_ALERT_CLOSE_NOTIFY: +- printf("close notify"); ++ puts("close notify"); + break; + + case SSL_ALERT_UNEXPECTED_MESSAGE: +- printf("unexpected message"); ++ puts("unexpected message"); + break; + + case SSL_ALERT_BAD_RECORD_MAC: +- printf("bad record mac"); ++ puts("bad record mac"); + break; + + case SSL_ALERT_RECORD_OVERFLOW: +- printf("record overlow"); ++ puts("record overlow"); + break; + + case SSL_ALERT_HANDSHAKE_FAILURE: +- printf("handshake failure"); ++ puts("handshake failure"); + break; + + case SSL_ALERT_BAD_CERTIFICATE: +- printf("bad certificate"); ++ puts("bad certificate"); + break; + + case SSL_ALERT_UNSUPPORTED_CERTIFICATE: +- printf("unsupported certificate"); ++ puts("unsupported certificate"); + break; + + case SSL_ALERT_CERTIFICATE_EXPIRED: +- printf("certificate expired"); ++ puts("certificate expired"); + break; + + case SSL_ALERT_CERTIFICATE_UNKNOWN: +- printf("certificate unknown"); ++ puts("certificate unknown"); + break; + + case SSL_ALERT_ILLEGAL_PARAMETER: +- printf("illegal parameter"); ++ puts("illegal parameter"); + break; + + case SSL_ALERT_UNKNOWN_CA: +- printf("unknown ca"); ++ puts("unknown ca"); + break; + + case SSL_ALERT_DECODE_ERROR: +- printf("decode error"); ++ puts("decode error"); + break; + + case SSL_ALERT_DECRYPT_ERROR: +- printf("decrypt error"); ++ puts("decrypt error"); + break; + + case SSL_ALERT_INVALID_VERSION: +- printf("invalid version"); ++ puts("invalid version"); + break; -@@ -1845,9 +1849,9 @@ void disposable_new(SSL *ssl) - if (ssl->dc == NULL) - { - ssl->dc = (DISPOSABLE_CTX *)calloc(1, sizeof(DISPOSABLE_CTX)); -- SHA256_Init(&ssl->dc->sha256_ctx); -- MD5_Init(&ssl->dc->md5_ctx); -- SHA1_Init(&ssl->dc->sha1_ctx); -+ crypto_sha256_init(&ssl->dc->sha256_ctx); -+ crypto_md5_init(&ssl->dc->md5_ctx); -+ crypto_sha1_init(&ssl->dc->sha1_ctx); + case SSL_ALERT_NO_RENEGOTIATION: +- printf("no renegotiation"); ++ puts("no renegotiation"); + break; + + default: +@@ -2557,7 +2561,7 @@ void DISPLAY_ALERT(SSL *ssl, int alert) + break; } - } - -diff --git a/crypto/bigint.c b/crypto/bigint.c -index d90b093..f18fbd5 100644 ---- a/crypto/bigint.c -+++ b/crypto/bigint.c -@@ -688,7 +688,7 @@ void bi_print(const char *label, bigint *x) - { - comp mask = 0x0f << (j*4); - comp num = (x->comps[i] & mask) >> (j*4); -- putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); -+ m_putc((num <= 9) ? (num + '0') : (num + 'A' - 10)); - } - } +- printf("\n"); ++ puts("\n"); + } -diff --git a/ssl/crypto_misc.h b/ssl/crypto_misc.h -index 02d9306..3590c1d 100644 ---- a/ssl/crypto_misc.h -+++ b/ssl/crypto_misc.h -@@ -39,8 +39,11 @@ - extern "C" { + #endif /* CONFIG_SSL_FULL_MODE */ +@@ -2584,7 +2588,7 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code) {} + EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + uint8_t *session_id, uint8_t sess_id_size) + { +- printf(unsupported_str); ++ printf("%s", unsupported_str); + return NULL; + } #endif +@@ -2592,20 +2596,20 @@ EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const + #if !defined(CONFIG_SSL_CERT_VERIFICATION) + EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) + { +- printf(unsupported_str); ++ printf("%s", unsupported_str); + return -1; + } --#include "crypto.h" --#include "bigint.h" -+#include "../crypto/crypto.h" -+#include "../crypto/bigint.h" -+#include -+#include -+#include - /************************************************************************** - * X509 declarations - + EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) + { +- printf(unsupported_str); ++ printf("%s", unsupported_str); + return NULL; + } + + EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index) + { +- printf(unsupported_str); ++ printf("%s", unsupported_str); + return NULL; + } + diff --git a/ssl/tls1.h b/ssl/tls1.h index dac63b9..bf79c9e 100644 --- a/ssl/tls1.h @@ -466,51 +1416,21 @@ index dac63b9..bf79c9e 100644 uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */ uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */ uint8_t final_finish_mac[128]; - -diff --git a/ssl/loader.c b/ssl/loader.c -index 6e41f40..8e4055b 100644 ---- a/ssl/loader.c -+++ b/ssl/loader.c -@@ -222,7 +222,7 @@ static int pem_decrypt(const char *where, const char *end, - char *start = NULL; - uint8_t iv[IV_SIZE]; - int i, pem_size; -- MD5_CTX md5_ctx; -+ crypto_md5_context_t md5_ctx; - AES_CTX aes_ctx; - uint8_t key[32]; /* AES256 size */ - -@@ -269,18 +269,18 @@ static int pem_decrypt(const char *where, const char *end, - goto error; - - /* work out the key */ -- MD5_Init(&md5_ctx); -- MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); -- MD5_Update(&md5_ctx, iv, SALT_SIZE); -- MD5_Final(key, &md5_ctx); -+ crypto_md5_init(&md5_ctx); -+ crypto_md5_update(&md5_ctx, (const uint8_t*)password, strlen(password)); -+ crypto_md5_update(&md5_ctx, iv, SALT_SIZE); -+ crypto_md5_final(key, &md5_ctx); - - if (is_aes_256) - { -- MD5_Init(&md5_ctx); -- MD5_Update(&md5_ctx, key, MD5_SIZE); -- MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); -- MD5_Update(&md5_ctx, iv, SALT_SIZE); -- MD5_Final(&key[MD5_SIZE], &md5_ctx); -+ crypto_md5_init(&md5_ctx); -+ crypto_md5_update(&md5_ctx, key, MD5_SIZE); -+ crypto_md5_update(&md5_ctx, (const uint8_t*)password, strlen(password)); -+ crypto_md5_update(&md5_ctx, iv, SALT_SIZE); -+ crypto_md5_final(&key[MD5_SIZE], &md5_ctx); - } +diff --git a/ssl/tls1_svr.c b/ssl/tls1_svr.c +index 6df91b5..dab6def 100644 +--- a/ssl/tls1_svr.c ++++ b/ssl/tls1_svr.c +@@ -63,7 +63,7 @@ EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd) + + #ifdef CONFIG_SSL_FULL_MODE + if (ssl_ctx->chain_length == 0) +- printf("Warning - no server certificate defined\n"); TTY_FLUSH(); ++ puts("Warning - no server certificate defined\n"); TTY_FLUSH(); + #endif - /* decrypt using the key/iv */ - + return ssl; diff --git a/ssl/x509.c b/ssl/x509.c -index a51b948..8e10d85 100644 +index a51b948..ae626b4 100644 --- a/ssl/x509.c +++ b/ssl/x509.c @@ -109,76 +109,52 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) @@ -624,118 +1544,227 @@ index a51b948..8e10d85 100644 { ret = X509_NOT_OK; } +@@ -673,36 +649,36 @@ void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) + char critical[16]; + strcpy_P(critical, "critical, "); + +- printf("=== CERTIFICATE ISSUED TO ===\n"); +- printf("Common Name (CN):\t\t"); ++ puts("=== CERTIFICATE ISSUED TO ===\n"); ++ puts("Common Name (CN):\t\t"); + printf("%s\n", cert->cert_dn[X509_COMMON_NAME] ? + cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); + +- printf("Organization (O):\t\t"); ++ puts("Organization (O):\t\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATION] ? + cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + if (cert->cert_dn[X509_ORGANIZATIONAL_UNIT]) + { +- printf("Organizational Unit (OU):\t"); ++ puts("Organizational Unit (OU):\t"); + printf("%s\n", cert->cert_dn[X509_ORGANIZATIONAL_UNIT]); + } -diff --git a/ssl/gen_cert.c b/ssl/gen_cert.c -index 093ae9c..d611ab0 100644 ---- a/ssl/gen_cert.c -+++ b/ssl/gen_cert.c -@@ -314,7 +314,7 @@ static int gen_tbs_cert(const char * dn[], - uint8_t *sha_dgst) - { - int ret = X509_OK; -- SHA1_CTX sha_ctx; -+ crypto_sha1_context_t sha_ctx; - int seq_offset; - int begin_tbs = *offset; - int seq_size = pre_adjust_with_size( -@@ -336,9 +336,9 @@ static int gen_tbs_cert(const char * dn[], - gen_pub_key(rsa_ctx, buf, offset); - adjust_with_size(seq_size, seq_offset, buf, offset); + if (cert->cert_dn[X509_LOCATION]) + { +- printf("Location (L):\t\t\t"); ++ puts("Location (L):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_LOCATION]); + } -- SHA1_Init(&sha_ctx); -- SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); -- SHA1_Final(sha_dgst, &sha_ctx); -+ crypto_sha1_init(&sha_ctx); -+ crypto_sha1_update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs); -+ crypto_sha1_final(sha_dgst, &sha_ctx); + if (cert->cert_dn[X509_COUNTRY]) + { +- printf("Country (C):\t\t\t"); ++ puts("Country (C):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_COUNTRY]); + } - error: - return ret; - -diff --git a/ssl/p12.c b/ssl/p12.c -index 5bd2394..5363d22 100644 ---- a/ssl/p12.c -+++ b/ssl/p12.c -@@ -190,7 +190,7 @@ static int p8_decrypt(const char *uni_pass, int uni_pass_len, - uint8_t p[BLOCK_SIZE*2]; - uint8_t d[BLOCK_SIZE]; - uint8_t Ai[SHA1_SIZE]; -- SHA1_CTX sha_ctx; -+ crypto_sha1_context_t sha_ctx; - RC4_CTX rc4_ctx; - int i; + if (cert->cert_dn[X509_STATE]) + { +- printf("State (ST):\t\t\t"); ++ puts("State (ST):\t\t\t"); + printf("%s\n", cert->cert_dn[X509_STATE]); + } -@@ -202,16 +202,16 @@ static int p8_decrypt(const char *uni_pass, int uni_pass_len, +@@ -723,83 +699,83 @@ void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DIGITAL_SIGNATURE)) + { +- printf("Digital Signature"); ++ puts("Digital Signature"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_NON_REPUDIATION)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Non Repudiation"); ++ puts("Non Repudiation"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_ENCIPHERMENT)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Key Encipherment"); ++ puts("Key Encipherment"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DATA_ENCIPHERMENT)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Data Encipherment"); ++ puts("Data Encipherment"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_AGREEMENT)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Key Agreement"); ++ puts("Key Agreement"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Key Cert Sign"); ++ puts("Key Cert Sign"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_CRL_SIGN)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("CRL Sign"); ++ puts("CRL Sign"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_ENCIPHER_ONLY)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Encipher Only"); ++ puts("Encipher Only"); + has_started = true; + } + + if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DECIPHER_ONLY)) + { + if (has_started) +- printf(", "); ++ puts(", "); + +- printf("Decipher Only"); ++ puts("Decipher Only"); + has_started = true; + } + +- printf("\n"); ++ puts("\n"); } - /* get the key - no IV since we are using RC4 */ -- SHA1_Init(&sha_ctx); -- SHA1_Update(&sha_ctx, d, sizeof(d)); -- SHA1_Update(&sha_ctx, p, sizeof(p)); -- SHA1_Final(Ai, &sha_ctx); -+ crypto_sha1_init(&sha_ctx); -+ crypto_sha1_update(&sha_ctx, d, sizeof(d)); -+ crypto_sha1_update(&sha_ctx, p, sizeof(p)); -+ crypto_sha1_final(Ai, &sha_ctx); + if (cert->subject_alt_name_present) +@@ -813,63 +789,63 @@ void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) + while (cert->subject_alt_dnsnames[i]) + printf("%s ", cert->subject_alt_dnsnames[i++]); + } +- printf("\n"); ++ puts("\n"); - for (i = 1; i < iter; i++) + } + +- printf("=== CERTIFICATE ISSUED BY ===\n"); +- printf("Common Name (CN):\t\t"); ++ puts("=== CERTIFICATE ISSUED BY ===\n"); ++ puts("Common Name (CN):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_COMMON_NAME] ? + cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); + +- printf("Organization (O):\t\t"); ++ puts("Organization (O):\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATION] ? + cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); + + if (cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]) { -- SHA1_Init(&sha_ctx); -- SHA1_Update(&sha_ctx, Ai, SHA1_SIZE); -- SHA1_Final(Ai, &sha_ctx); -+ crypto_sha1_init(&sha_ctx); -+ crypto_sha1_update(&sha_ctx, Ai, SHA1_SIZE); -+ crypto_sha1_final(Ai, &sha_ctx); +- printf("Organizational Unit (OU):\t"); ++ puts("Organizational Unit (OU):\t"); + printf("%s\n", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]); } - /* do the decryption */ -@@ -409,7 +409,7 @@ int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) - key, SHA1_SIZE, PKCS12_MAC_ID)) < 0) - goto error; + if (cert->ca_cert_dn[X509_LOCATION]) + { +- printf("Location (L):\t\t\t"); ++ puts("Location (L):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_LOCATION]); + } -- hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); -+ crypto_sha1_hmac(auth_safes, auth_safes_len, key, SHA1_SIZE, mac); + if (cert->ca_cert_dn[X509_COUNTRY]) + { +- printf("Country (C):\t\t\t"); ++ puts("Country (C):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_COUNTRY]); + } - if (memcmp(mac, orig_mac, SHA1_SIZE)) + if (cert->ca_cert_dn[X509_STATE]) { - -diff --git a/crypto/crypto.h b/crypto/crypto.h -index da24d31..4de139b 100644 ---- a/crypto/crypto.h -+++ b/crypto/crypto.h -@@ -196,6 +196,10 @@ EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); - /************************************************************************** - * HMAC declarations - **************************************************************************/ -+#define hmac_md5 ax_hmac_md5 -+#define hmac_sha1 ax_hmac_sha1 -+#define hmac_sha256 ax_hmac_sha256 -+ - void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, - int key_len, uint8_t *digest); - void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, -@@ -206,6 +210,10 @@ void hmac_sha256(const uint8_t *msg, int length, const uint8_t *key, - /************************************************************************** - * HMAC functions operating on vectors - **************************************************************************/ -+#define hmac_md5_v ax_hmac_md5_v -+#define hmac_sha1_v ax_hmac_sha1_v -+#define hmac_sha256_v ax_hmac_sha256_v -+ - void hmac_md5_v(const uint8_t **msg, int* length, int count, const uint8_t *key, - int key_len, uint8_t *digest); - void hmac_sha1_v(const uint8_t **msg, int* length, int count, const uint8_t *key, - -diff --git a/ssl/asn1.c b/ssl/asn1.c -index a08a618..273d08b 100644 ---- a/ssl/asn1.c -+++ b/ssl/asn1.c -@@ -405,7 +405,7 @@ static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) - int asn1_version(const uint8_t *cert, int *offset, int *val) - { - (*offset) += 2; /* get past explicit tag */ -- return asn1_get_int(cert, offset, val); -+ return asn1_get_int(cert, offset, (int32_t*)val); - } +- printf("State (ST):\t\t\t"); ++ puts("State (ST):\t\t\t"); + printf("%s\n", cert->ca_cert_dn[X509_STATE]); + } - /** + printf("Not Before:\t\t\t%s", ctime(&cert->not_before)); + printf("Not After:\t\t\t%s", ctime(&cert->not_after)); + printf("RSA bitsize:\t\t\t%d\n", cert->rsa_ctx->num_octets*8); +- printf("Sig Type:\t\t\t"); ++ puts("Sig Type:\t\t\t"); + switch (cert->sig_type) + { + case SIG_TYPE_MD5: +- printf("MD5\n"); ++ puts("MD5\n"); + break; + case SIG_TYPE_SHA1: +- printf("SHA1\n"); ++ puts("SHA1\n"); + break; + case SIG_TYPE_SHA256: +- printf("SHA256\n"); ++ puts("SHA256\n"); + break; + case SIG_TYPE_SHA384: +- printf("SHA384\n"); ++ puts("SHA384\n"); + break; + case SIG_TYPE_SHA512: +- printf("SHA512\n"); ++ puts("SHA512\n"); + break; + default: + printf("Unrecognized: %d\n", cert->sig_type); From 78516ad9dc5317577c0cf3fe09762c2a4f3908e7 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 2 Dec 2022 10:23:49 +0100 Subject: [PATCH 52/58] Fix to typos reported by codespell. (#2587) * Use also Ubuntu 20.04 in CI - otherwise build fails due to missing clang-format-8. --- .github/workflows/ci.yml | 6 +++--- .github/workflows/coverity-scan.yml | 2 +- Sming/Core/Data/CsvReader.h | 2 +- Sming/Core/Data/Stream/TemplateStream.h | 2 +- Sming/Core/Data/Uuid.cpp | 2 +- Sming/Core/Data/Uuid.h | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a75033856e..128a33f77b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,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 @@ -50,7 +50,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: | Tools/ci/install.sh @@ -63,7 +63,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: | source $SMING_HOME/../Tools/export.sh $CLANG_FORMAT --version diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index 26e267d00e..10287b0e53 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -18,7 +18,7 @@ jobs: # group: ${{ github.head_ref || github.run_id }} # cancel-in-progress: true - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: Checkout code diff --git a/Sming/Core/Data/CsvReader.h b/Sming/Core/Data/CsvReader.h index b257596acf..a8aa9cc151 100644 --- a/Sming/Core/Data/CsvReader.h +++ b/Sming/Core/Data/CsvReader.h @@ -99,7 +99,7 @@ class CsvReader } /** - * @brief Get index of columnn given its name + * @brief Get index of column given its name * @param name Column name to find * @retval int -1 if name is not found */ diff --git a/Sming/Core/Data/Stream/TemplateStream.h b/Sming/Core/Data/Stream/TemplateStream.h index 5e8839efab..22fb3b79f4 100644 --- a/Sming/Core/Data/Stream/TemplateStream.h +++ b/Sming/Core/Data/Stream/TemplateStream.h @@ -159,7 +159,7 @@ class TemplateStream : public IDataSourceStream * * Called internally and an opening brace ("{" or "{{") has been found. * Default behaviour is to locate the closing brace(s) and interpret the - * bounded text as a variable name, which is passsed to `getValue`. + * bounded text as a variable name, which is passed to `getValue`. * * This method is overridden by SectionTemplate to support more complex expressions. */ diff --git a/Sming/Core/Data/Uuid.cpp b/Sming/Core/Data/Uuid.cpp index e2577a8bb3..4b4b157ad8 100644 --- a/Sming/Core/Data/Uuid.cpp +++ b/Sming/Core/Data/Uuid.cpp @@ -23,7 +23,7 @@ void os_get_random(void* buf, size_t n); bool Uuid::operator==(const Uuid& other) const { - // Ensure these are stricly compared as a set of words to avoid PROGMEM issues + // Ensure these are strictly compared as a set of words to avoid PROGMEM issues struct S { uint32_t a, b, c, d; }; diff --git a/Sming/Core/Data/Uuid.h b/Sming/Core/Data/Uuid.h index 355a704473..46a38421ee 100644 --- a/Sming/Core/Data/Uuid.h +++ b/Sming/Core/Data/Uuid.h @@ -95,7 +95,7 @@ struct Uuid { bool generate(); /** - * @name Decompse string into UUID + * @name Decompose string into UUID * @{ */ bool decompose(const char* s, size_t len); From 74c7a9cb4b7a2c9a83f929d740fcf15ad78b562d Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 2 Dec 2022 10:10:22 +0000 Subject: [PATCH 53/58] Add Host stubs for RTC mem read/write (#2588) This PR adds stubs for the `system_rtc_mem_read` and `system_rtc_mem_write` functions so that code compiles for the `Host` arch. No immediate use-cases fo this, but for future consideration it might be useful to make these functional using a backing file, similar to how flash memory is handled. One area where this might be useful is improving `System.restart()` behaviour, perhaps by forking a separate process which can be restarted. --- .../Host/Components/esp_hal/include/esp_system.h | 3 +++ Sming/Arch/Host/Components/esp_hal/system.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_system.h b/Sming/Arch/Host/Components/esp_hal/include/esp_system.h index e3e22bcc25..a436fad478 100644 --- a/Sming/Arch/Host/Components/esp_hal/include/esp_system.h +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_system.h @@ -59,6 +59,9 @@ const char* system_get_sdk_version(void); uint32 system_get_chip_id(void); +bool system_rtc_mem_read(uint8_t src_addr, void* des_addr, uint16_t load_size); +bool system_rtc_mem_write(uint8_t des_addr, const void* src_addr, uint16_t save_size); + #ifdef __cplusplus } #endif diff --git a/Sming/Arch/Host/Components/esp_hal/system.cpp b/Sming/Arch/Host/Components/esp_hal/system.cpp index 3249c9cc43..114cc751a0 100644 --- a/Sming/Arch/Host/Components/esp_hal/system.cpp +++ b/Sming/Arch/Host/Components/esp_hal/system.cpp @@ -122,3 +122,15 @@ void xt_enable_interrupts() { ets_intr_unlock(); } + +/* RTC */ + +bool system_rtc_mem_read(uint8_t src_addr, void* des_addr, uint16_t load_size) +{ + return false; +} + +bool system_rtc_mem_write(uint8_t des_addr, const void* src_addr, uint16_t save_size) +{ + return false; +} From 8b48f24f77c5938d0a3c231d7a2994e1f34d36b5 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 2 Dec 2022 11:11:29 +0100 Subject: [PATCH 54/58] Ignore changes from bulk change commits related to: (#2589) * Added .git-blame-ignore-revs file * Updated the ignore list in this file to include commits that were made for spell checking and coding style changes only. For more information see here: https://www.moxio.com/blog/43/ignoring-bulk-change-commits-with-git-blame --- .git-blame-ignore-revs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..5a3a3d70cc --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,10 @@ +# Spell Check Commits +90a99e8dc09f01baa594ab37c41b5d7a34c9bb72 +78516ad9dc5317577c0cf3fe09762c2a4f3908e7 + +# Coding Style Commits +54231b9e43b751b2ccfb906a73510230364509be +97268eee7680d962d2c6d532a19b4b6713771be7 +302745184fd96ed8a587c4310316c5f41d2e9d79 +e2f8736b4f08530a082fbf40db966a6d37b569d7 +95c5c8c2d5a87269acd963aae7402e2b835580f1 From bc863c134154a833bc965bb6740c942a0e083629 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 7 Dec 2022 11:35:26 +0100 Subject: [PATCH 55/58] Fix to issues reported by codespell. (#2591) --- docs/source/framework/core/data/streams/templates.rst | 2 +- docs/source/information/develop/ci.rst | 2 +- docs/source/information/storage.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/framework/core/data/streams/templates.rst b/docs/source/framework/core/data/streams/templates.rst index 152052c4e8..7b98ee9624 100644 --- a/docs/source/framework/core/data/streams/templates.rst +++ b/docs/source/framework/core/data/streams/templates.rst @@ -57,7 +57,7 @@ One such implementation is the :cpp:class:`IFS::DirectoryTemplate` class. The :sample:`Basic_IFS` sample demonstrates how it can be used to provide a formatted directory listing in multiple formats, using a different template for each format. -The :sample:`Basic_Templates` sample illustrates a similar appraoch using data from CSV data files. +The :sample:`Basic_Templates` sample illustrates a similar approach using data from CSV data files. If the output format requires escaping, create an instance of the appropriate :cpp:class:`Format::Formatter` and call :cpp:func:`SectionTemplate::setFormatter`. diff --git a/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index 8dabb8f159..74581accd6 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -47,7 +47,7 @@ Library CI support Sming libraries may be separately built and tested whether or not they are included as part of the Sming repository (or a fork). -There are two mechanisms avaiable. +There are two mechanisms available. GitHub Actions ~~~~~~~~~~~~~~ diff --git a/docs/source/information/storage.rst b/docs/source/information/storage.rst index 5084b555c6..6ff416ef49 100644 --- a/docs/source/information/storage.rst +++ b/docs/source/information/storage.rst @@ -24,5 +24,5 @@ Additional filing system implementations are provided in separate libraries: Note that when using bulk storage of more than about 4GB in size applications should be built with :cpp:envvar:`ENABLE_STORAGE_SIZE64` =1. This changes all sizes and offsets to 64-bit. -If manipulating files greated than about 2GB (signed 32-bit value) then the :cpp:envvar:`ENABLE_FILE_SIZE64` +If manipulating files greater than about 2GB (signed 32-bit value) then the :cpp:envvar:`ENABLE_FILE_SIZE64` setting should also be enabled. From 394d1e092271ac00f14b07e49100eecc26fddc18 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 7 Dec 2022 16:06:42 +0100 Subject: [PATCH 56/58] Fix to print debug filename. (#2590) * Better fix thanks to @mike47. --- Sming/component.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/component.mk b/Sming/component.mk index 16059d289e..c0e95cf705 100644 --- a/Sming/component.mk +++ b/Sming/component.mk @@ -76,7 +76,7 @@ CONFIG_VARS += DEBUG_PRINT_FILENAME_AND_LINE DEBUG_PRINT_FILENAME_AND_LINE ?= 0 GLOBAL_CFLAGS += -DDEBUG_PRINT_FILENAME_AND_LINE=$(DEBUG_PRINT_FILENAME_AND_LINE) # When rules are created make will see '$*' so substitute the filename -GLOBAL_CFLAGS += -DCUST_FILE_BASE=$$* +GLOBAL_CFLAGS += -DCUST_FILE_BASE=$$$$(subst $$(SMING_HOME)/,,$$$$<) # Default debug verbose level is INFO, where DEBUG=3 INFO=2 WARNING=1 ERROR=0 CONFIG_VARS += DEBUG_VERBOSE_LEVEL From bf6b1974c78d25a5f3bbf1de5cf4946eaa9a15ff Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 8 Dec 2022 15:50:18 +0100 Subject: [PATCH 57/58] Installer: Remove download directory. (#2593) --- Tools/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/install.sh b/Tools/install.sh index 499f887a04..5e65f6480f 100755 --- a/Tools/install.sh +++ b/Tools/install.sh @@ -194,7 +194,7 @@ if [ $inst_rp2040 -eq 1 ]; then fi if [ -z "$KEEP_DOWNLOADS" ]; then - rm -f "$DOWNLOADS/*" + rm -rf "$DOWNLOADS/*" fi From c3684aba275263c44be827bf9016ab5beb814afc Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 19 Dec 2022 09:37:21 +0100 Subject: [PATCH 58/58] Preparation for release 4.7.0. (#2592) --- README.md | 12 ++---------- Sming/Core/SmingVersion.h | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c659b0941d..d0de9ab4bb 100644 --- a/README.md +++ b/README.md @@ -29,21 +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.6.0**](https://sming.readthedocs.io/en/stable) - current stable version. -- [Documentation for version 4.2.x](https://sming.readthedocs.io/en/4.2.2) - Long Term Support (LTS) version. +- [**Documentation for version 4.7.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.6.0](https://github.com/SmingHub/Sming/releases/tag/4.6.0) - great new features, performance and stability improvements. - - -### Long Term Support (LTS) - -- Sming V4.2.x is our LTS version which will be supported until the end of 2021. - +- [Sming V4.7.0](https://github.com/SmingHub/Sming/releases/tag/4.7.0) - great new features, performance and stability improvements. ### Development @@ -54,7 +47,6 @@ git clone https://github.com/SmingHub/Sming.git ``` - ## Examples The examples are a great way to learn the API and brush up your C/C++ knowledge. Once you have completed the installation of the development tools, you can get the latest source code. diff --git a/Sming/Core/SmingVersion.h b/Sming/Core/SmingVersion.h index ffbf7ba418..80d5d95189 100644 --- a/Sming/Core/SmingVersion.h +++ b/Sming/Core/SmingVersion.h @@ -6,7 +6,7 @@ */ #define SMING_MAJOR_VERSION 4 -#define SMING_MINOR_VERSION 6 +#define SMING_MINOR_VERSION 7 #define SMING_PATCH_VERSION 0 #define SMING_PRE_RELEASE ""