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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0dc70545a0..128a33f77b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,82 +11,66 @@ jobs: strategy: fail-fast: false matrix: - arch: [Esp8266, Host, Esp32, Rp2040] - variant: [""] - os: [ubuntu-latest, windows-latest] + os: [ubuntu-20.04, 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 - exclude: - - os: windows-latest - arch: Host - - continue-on-error: ${{ matrix.arch == 'Host' && matrix.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) }} 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 - - name: Setup SMING_HOME for Ubuntu - if: ${{ matrix.os == 'ubuntu-latest' }} + uses: actions/checkout@v3 + + - name: Configure environment + shell: pwsh 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' }} + "CI_BUILD_DIR=" + (Resolve-Path ".").path >> $env:GITHUB_ENV + "SMING_HOME=" + (Resolve-Path "Sming").path >> $env:GITHUB_ENV + "SMING_ARCH=${{ matrix.arch }}" >> $env:GITHUB_ENV + "SMING_SOC=${{ matrix.variant }}" >> $env:GITHUB_ENV + + - name: Install build tools for Ubuntu + if: ${{ matrix.os == 'ubuntu-20.04' }} 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: - SMING_ARCH: ${{matrix.arch}} - SMING_SOC: ${{matrix.variant}} - run: | - ./Tools/install.sh $(echo "$SMING_ARCH" | tr '[:upper:]' '[:lower:]') - - name: Install Sming Framework on Windows + Tools/ci/install.sh + + - 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/install.cmd "$env:SMING_ARCH".ToLower() - - name: Install Ninja - uses: seanmiddleditch/gha-setup-ninja@master - - name: Build and Test for ${{matrix.arch}} on Ubuntu + . Tools/ci/setenv.ps1 + 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-20.04' }} run: | source $SMING_HOME/../Tools/export.sh $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}} - if: ${{ matrix.os == 'windows-latest' }} + Tools/ci/build.sh + + - name: Build and test for ${{matrix.arch}} on Windows + 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/setenv.ps1 Tools/ci/build.cmd - diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index 1d65dd2aaf..10287b0e53 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -17,8 +17,8 @@ jobs: # concurrency: # group: ${{ github.head_ref || github.run_id }} # cancel-in-progress: true - - runs-on: ubuntu-latest + + runs-on: ubuntu-20.04 steps: - name: Checkout code @@ -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/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/.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" 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/.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/.gitmodules b/.gitmodules index 7607e1ac02..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 @@ -377,8 +389,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/.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/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/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..0015310cc3 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 { @@ -57,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 @@ -727,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; } @@ -757,14 +761,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/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 affffe905e..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 @@ -17,11 +21,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 @@ -39,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 \ @@ -71,6 +87,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 +194,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 +217,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/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/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/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 8633b37252..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(); @@ -13,27 +14,47 @@ 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; } 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 */ 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/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 \ 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; 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/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) 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/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/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/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..8e5247d0f3 100644 --- a/Sming/Arch/Esp8266/Components/libc/component.mk +++ b/Sming/Arch/Esp8266/Components/libc/component.mk @@ -12,3 +12,29 @@ COMPONENT_SRCDIRS += src/oldlib 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)) +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++ + +endif 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/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/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/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/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/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/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/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; +} 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/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 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/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 diff --git a/Sming/Arch/Rp2040/Components/rp2040/component.mk b/Sming/Arch/Rp2040/Components/rp2040/component.mk index fc87b4cd6a..670b13ba31 100644 --- a/Sming/Arch/Rp2040/Components/rp2040/component.mk +++ b/Sming/Arch/Rp2040/Components/rp2040/component.mk @@ -90,7 +90,9 @@ LIBDIRS += \ EXTRA_LIBS += \ pico \ - m + m \ + stdc++ \ + gcc RP2040_CMAKE_OPTIONS := \ -G Ninja \ 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/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/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 9dbc293071..1767d7020e 160000 --- a/Sming/Components/IFS +++ b/Sming/Components/IFS @@ -1 +1 @@ -Subproject commit 9dbc29307169c426ab5c9e6eab1b8cf0dcedfa4a +Subproject commit 1767d7020e18c8ffa0c58b31a5650a5275ee47c6 diff --git a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp index 744b595e12..4609bed48c 100644 --- a/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp +++ b/Sming/Components/Network/Arch/Esp32/Platform/StationImpl.cpp @@ -165,27 +165,38 @@ 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; + } + + // 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; - if(save) { - setAutoConnect(autoConnectOnStartup); + enable(true, cfg.save); + + 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 +339,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 +493,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/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/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/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/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/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/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 */ 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/Components/Storage/README.rst b/Sming/Components/Storage/README.rst index 4b86403ff0..6cd6ac162f 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:: @@ -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 ---------------------- @@ -332,20 +346,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 it = Storage::findPartition(); it; ++it) { - auto part = *it; - debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); + for(auto part: Storage::findPartition()) { + Serial << part << endl; } // 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)) { + Serial << part << endl; } @@ -362,7 +375,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; } @@ -380,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/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/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..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 @@ -39,6 +44,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/.cs b/Sming/Components/Storage/src/.cs new file mode 100644 index 0000000000..e69de29bb2 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/Debug.cpp b/Sming/Components/Storage/src/Debug.cpp index 37d261ecea..531cbfec7c 100644 --- a/Sming/Components/Storage/src/Debug.cpp +++ b/Sming/Components/Storage/src/Debug.cpp @@ -6,29 +6,21 @@ namespace Storage { namespace Debug { -void printPartition(Print& out, Partition part, bool includeDevice) +void listPartitions(Print& out) { - out.print(part.name()); - if(includeDevice) { - out.print(" on "); - out.print(part.getDeviceName()); + out.println(); + out.println(_F("Registered partitions:")); + for(auto part : Storage::findPartition()) { + out << "- " << part << endl; } - 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(")"); + out.println(); } -void listPartitions(Print& out) +void listPartitions(Print& out, const Device& device) { - out.println(); - out.println(_F("Registered partitions:")); - for(auto it = Storage::findPartition(); it; ++it) { - out.print("- "); - printPartition(out, *it); + out << device.getName() << _F(" partitions:") << endl; + for(auto part : device.partitions()) { + out << "- " << part << endl; } out.println(); } @@ -38,14 +30,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 +39,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..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 * ****/ @@ -12,6 +12,7 @@ #include "include/Storage/Device.h" #include "include/Storage/partition_info.h" #include +#include #include namespace @@ -88,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 @@ -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/Iterator.cpp b/Sming/Components/Storage/src/Iterator.cpp index e7a4e2a2ab..e0de8dae21 100644 --- a/Sming/Components/Storage/src/Iterator.cpp +++ b/Sming/Components/Storage/src/Iterator.cpp @@ -13,55 +13,28 @@ namespace Storage { -Iterator::Iterator(Device& device, uint8_t partitionIndex) - : mSearch{&device, Partition::Type::any, Partition::SubType::any}, mDevice(&device), mPos(partitionIndex) - +Iterator::Iterator(Partition::Type type, uint8_t subtype) : mSearch{nullptr, type, subtype}, mDevice(spiFlash) { - if(partitionIndex >= device.partitions().count()) { - mDevice = nullptr; - mPos = afterEnd; - } -} - -Iterator::Iterator(Partition::Type type, uint8_t subtype) : mSearch{nullptr, type, subtype} -{ - mDevice = spiFlash; 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; } - mPos = afterEnd; - if(mSearch.device != nullptr) { - mDevice = nullptr; + if(mInfo->match(mSearch.type, mSearch.subType)) { break; } - - mDevice = mDevice->getNext(); - mPos = beforeStart; } - - 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 d66c128fbb..d9f4bd13f5 100644 --- a/Sming/Components/Storage/src/Partition.cpp +++ b/Sming/Components/Storage/src/Partition.cpp @@ -4,13 +4,14 @@ * 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 * ****/ #include "include/Storage/Partition.h" #include "include/Storage/Device.h" #include +#include #include using namespace Storage; @@ -122,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()); @@ -152,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"); @@ -160,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; } @@ -206,46 +212,82 @@ bool Partition::allowWrite() return true; } -bool Partition::read(size_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(size_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(size_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); +} + +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(*mPart); + return n; + } + + return p.print(_F("(none)")); } } // namespace Storage 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..78c3ebd2af 100644 --- a/Sming/Components/Storage/src/ProgMem.cpp +++ b/Sming/Components/Storage/src/ProgMem.cpp @@ -15,21 +15,21 @@ 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; } -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 PartitionTable::add(name, type, addr, size, Partition::Flag::readOnly); } } // namespace Storage 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/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.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/CustomDevice.h b/Sming/Components/Storage/src/include/Storage/CustomDevice.h deleted file mode 100644 index 82222f2667..0000000000 --- a/Sming/Components/Storage/src/include/Storage/CustomDevice.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * CustomDevice.h - */ - -#pragma once - -#include "Device.h" - -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) - { - return createPartition(Partition::Info{name, type, subtype, offset, size, flags}); - } - - template - Partition createPartition(const String& name, SubType subtype, uint32_t offset, size_t size, - Partition::Flags flags = 0) - { - return createPartition(name, Partition::Type(SubType::partitionType), uint8_t(subtype), offset, size, flags); - } -}; - -} // namespace Storage diff --git a/Sming/Components/Storage/src/include/Storage/Debug.h b/Sming/Components/Storage/src/include/Storage/Debug.h index 74c99c3b57..659ddca3b3 100644 --- a/Sming/Components/Storage/src/include/Storage/Debug.h +++ b/Sming/Components/Storage/src/include/Storage/Debug.h @@ -7,8 +7,8 @@ namespace Storage { namespace Debug { -void printPartition(Print& out, Partition part, bool includeDevice = true); 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 c6100e1561..7ebaa32df8 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" @@ -55,12 +56,18 @@ class Device : public LinkedObjectTemplate return getName() == name; } - PartitionTable& partitions() + /** + * @brief Provide read-only access to partition table + */ + const PartitionTable& partitions() const { return mPartitions; } - const PartitionTable& partitions() const + /** + * @brief Provide full access to partition table + */ + PartitionTable& editablePartitions() { return mPartitions; } @@ -104,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 @@ -120,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 @@ -129,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 @@ -137,7 +144,44 @@ 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; protected: PartitionTable mPartitions; diff --git a/Sming/Components/Storage/src/include/Storage/Iterator.h b/Sming/Components/Storage/src/include/Storage/Iterator.h index dcd3b7ca88..c17662693c 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(); } @@ -30,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) @@ -48,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 @@ -56,14 +58,27 @@ class Iterator : public std::iterator return !operator==(other); } - Partition operator*() const; + Partition operator*() const + { + return mDevice && mInfo ? Partition(*mDevice, *mInfo) : Partition{}; + } + + 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() + { + } - bool seek(uint8_t pos); - bool next(); + void next(); struct Search { Device* device; @@ -72,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 d0f26c36e1..535b0fd4cf 100644 --- a/Sming/Components/Storage/src/include/Storage/Partition.h +++ b/Sming/Components/Storage/src/include/Storage/Partition.h @@ -26,10 +26,12 @@ ****/ #pragma once +#include #include #include -#include +#include #include +#include "Types.h" #define PARTITION_APP_SUBTYPE_MAP(XX) \ XX(factory, 0x00, "Factory application") \ @@ -72,6 +74,11 @@ class Device; class PartitionTable; struct esp_partition_info_t; +namespace Disk +{ +class DiskPart; +} + /** * @brief Represents a flash partition */ @@ -126,13 +133,57 @@ class Partition using Name = char[nameSize]; using Flags = BitSet; + /** + * @brief Express both partition type and subtype together + */ + struct FullType { + Type type; + uint8_t 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)) + { + } + + 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; + }; + /** * @brief Partition information */ - struct Info { + 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; @@ -141,10 +192,27 @@ 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, 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() @@ -209,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(size_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(size_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)); } @@ -224,7 +293,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(storage_size_t offset, const void* src, size_t size); /** * @brief Erase part of the partition @@ -233,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(size_t offset, size_t size); + bool erase_range(storage_size_t offset, storage_size_t size); /** * @brief Obtain partition type @@ -251,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; } @@ -325,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 @@ -333,26 +410,17 @@ 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 */ - bool contains(uint32_t addr) const + bool contains(storage_size_t addr) const { return mPart ? (addr >= mPart->offset && addr <= lastAddress()) : false; } bool operator==(const Partition& other) const { - return this == &other; + return mDevice == other.mDevice && mPart == other.mPart; } bool operator==(const char* name) const @@ -365,11 +433,46 @@ 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 */ 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: Device* mDevice{nullptr}; const Info* mPart{nullptr}; 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/PartitionTable.h b/Sming/Components/Storage/src/include/Storage/PartitionTable.h index 49cd59bf10..b54fcee3f3 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 mEntries.isEmpty(); + } + /** * @name Partition search * @{ @@ -39,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); } /** @} */ @@ -72,7 +76,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); @@ -81,36 +85,47 @@ 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 + Device& device() const { - return mCount; + return mDevice; } - Device& device() const + /** + * @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{}; + } + + template Partition add(const String& name, Partition::FullType type, Args... args) + { + return add(new Partition::Info(name, type, args...)); } - Partition operator[](unsigned index) const + void clear() { - return (index < mCount) ? Partition(mDevice, mEntries.get()[index]) : Partition(); + mEntries.clear(); } protected: friend Device; + friend Iterator; + void load(const esp_partition_info_t* entry, unsigned count); 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..0f43003f3b 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 @@ -29,7 +29,7 @@ class ProgMem : public CustomDevice return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -39,48 +39,43 @@ class ProgMem : public CustomDevice 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; } - 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 PartitionTable { - 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& editablePartitions() { - return createPartition(name, fstr, Partition::Type(T::partitionType), uint8_t(subType)); + return static_cast(mPartitions); } }; 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 18ca2d64cf..7e9bd08906 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) { } @@ -39,23 +39,23 @@ class StreamDevice : public CustomDevice 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 9f49a3fa3e..d2d333f1d2 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 @@ -30,7 +30,7 @@ class SysMem : public CustomDevice return sizeof(uint32_t); } - size_t getSize() const override + storage_size_t getSize() const override { return 0x80000000; } @@ -40,7 +40,7 @@ class SysMem : public CustomDevice 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 CustomDevice 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 CustomDevice 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; @@ -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 PartitionTable + { + public: + /** + * @brief Add partition entry for FlashString data access + */ + Partition add(const String& name, const FSTR::ObjectBase& fstr, Partition::FullType type) + { + return PartitionTable::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& editablePartitions() { - return createPartition(name, fstr, Partition::Type(T::partitionType), uint8_t(subType)); + return static_cast(mPartitions); } }; 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/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/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); 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 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/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/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/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/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/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; } diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index 56fed9ee55..92168a7c5d 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -8,6 +8,8 @@ * ****/ +#pragma once + #include #include @@ -80,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); } @@ -88,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; } @@ -98,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 @@ -120,6 +126,11 @@ template struct TRange { s += max; return s; } + + operator String() const + { + return toString(); + } }; template inline String toString(TRange range) 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/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 new file mode 100644 index 0000000000..4b4b157ad8 --- /dev/null +++ b/Sming/Core/Data/Uuid.cpp @@ -0,0 +1,151 @@ +/**** + * 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::operator==(const Uuid& other) const +{ + // Ensure these are strictly 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 + 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..46a38421ee --- /dev/null +++ b/Sming/Core/Data/Uuid.h @@ -0,0 +1,162 @@ +/**** + * 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; + + constexpr 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 + { + return *this != Uuid{}; + } + + bool operator==(const Uuid& other) const; + + 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 Decompose 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/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/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/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..211813000f 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. */ @@ -188,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); @@ -208,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); @@ -261,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; @@ -276,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); @@ -299,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/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 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) { 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 "" 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/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/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 diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 804705b99f..f5fc23fbb3 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 804705b99f95e5297fa193ad3c5aff12f32f1ec0 +Subproject commit f5fc23fbb3112460dbd595ddf03b7ec2d45c8cb0 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/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; 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/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/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/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 1a25cc1ea7..25a7e24411 160000 --- a/Sming/Libraries/SmingTest +++ b/Sming/Libraries/SmingTest @@ -1 +1 @@ -Subproject commit 1a25cc1ea71b68139fbccbd4e66afc5db8b89846 +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/Error.cpp b/Sming/Libraries/Spiffs/src/Error.cpp index 494c24a335..c7b321b8c1 100644 --- a/Sming/Libraries/Spiffs/src/Error.cpp +++ b/Sming/Libraries/Spiffs/src/Error.cpp @@ -21,7 +21,9 @@ ****/ #include "include/IFS/SPIFFS/Error.h" +#include #include +#include "../spiffs/src/spiffs.h" namespace IFS { @@ -31,19 +33,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 +78,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 +96,19 @@ 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; + SPIFFS_ERROR_TRANSLATION_MAP(XX) +#undef XX + default: + return Error::fromSystem(spiffs_error); + } +} + String spiffsErrorToStr(int err) { return errorMap[std::min(err, 0)].content(); 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; } diff --git a/Sming/Libraries/Spiffs/src/FileSystem.cpp b/Sming/Libraries/Spiffs/src/FileSystem.cpp index c17b14cfb2..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, @@ -173,7 +179,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 +197,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 +215,7 @@ int FileSystem::check() }; int err = SPIFFS_check(handle()); - return Error::fromSystem(err); + return translateSpiffsError(err); } int FileSystem::getinfo(Info& info) @@ -273,7 +279,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 +298,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,33 +313,34 @@ 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); } + partition.sync(); return res; } int FileSystem::eof(FileHandle file) { int res = SPIFFS_eof(handle(), file); - return Error::fromSystem(res); + return translateSpiffsError(res); } -int32_t FileSystem::tell(FileHandle file) +file_offset_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 FileSystem::ftruncate(FileHandle file, 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,8 +350,9 @@ 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); } + partition.sync(); return res; } @@ -352,7 +360,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,18 +373,18 @@ 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); 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) { - int err = Error::fromSystem(res); + int err = translateSpiffsError(res); debug_ifserr(err, "lseek()"); return err; } @@ -433,7 +441,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 +466,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 +493,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 +559,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 +571,8 @@ 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); + partition.sync(); + return translateSpiffsError(err); #else return Error::NotSupported; #endif @@ -576,7 +585,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 +615,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 +639,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 +657,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 +738,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 +754,8 @@ int FileSystem::rename(const char* oldpath, const char* newpath) } int err = SPIFFS_rename(handle(), oldpath, newpath); - return Error::fromSystem(err); + partition.sync(); + return translateSpiffsError(err); } int FileSystem::remove(const char* path) @@ -767,8 +777,9 @@ 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); + partition.sync(); return err; } @@ -786,7 +797,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 +816,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 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/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 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/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); } 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) { 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/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/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..42482fef39 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++) { @@ -190,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': @@ -202,8 +231,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 +250,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/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/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..f9ca622aee 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(long num, uint8_t base = DEC) + { + if(base == 0) { + return write(num); + } else { + return printNumber(num, base); + } + } - size_t print(const long long&, int base = DEC); + template size_t print(long num, Args... args) + { + return printNumber(num, args...); + } + + template size_t print(const long long& num, Args... args) + { + return printNumber(num, args...); + } - size_t print(unsigned int num, int base = DEC) + template size_t print(unsigned int num, Args... args) { - return print((unsigned long)num, base); + return print((unsigned long)num, args...); } - size_t print(unsigned char num, int base = DEC) + template size_t print(unsigned char num, Args... args) { - return print((unsigned long)num, base); + return print((unsigned long)num, args...); } - size_t print(int num, int base = DEC) + template size_t print(int num, Args... args) { - return print((long)num, base); + return printNumber((long)num, args...); } /** @} */ @@ -159,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 @@ -177,101 +211,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) + /** + * @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, base) + println(); + extern String toString(E e); + return print(toString(value)); } - 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) - { - return print(num, digits) + println(); - } - - /** @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 write("\r\n", 2); } - /** @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 +247,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 +260,30 @@ class Print } }; +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; +} + +// 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/WHashMap.h b/Sming/Wiring/WHashMap.h index 790e530356..1b1de76155 100644 --- a/Sming/Wiring/WHashMap.h +++ b/Sming/Wiring/WHashMap.h @@ -31,6 +31,8 @@ #include #include #include +#include "WiringList.h" +#include "Print.h" /** * @brief HashMap class template @@ -39,8 +41,6 @@ template class HashMap { public: - using Comparator = bool (*)(const K&, const K&); - template struct BaseElement { public: using Value = typename std::conditional::type; @@ -90,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; @@ -156,6 +165,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 +195,6 @@ template class HashMap { } - ~HashMap() - { - clear(); - } - /* || @description || | Get the size of this HashMap @@ -207,7 +221,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *keys[idx]; + return keys[idx]; } K& keyAt(unsigned int idx) @@ -215,7 +229,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *keys[idx]; + return keys[idx]; } /* @@ -232,7 +246,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *values[idx]; + return values[idx]; } V& valueAt(unsigned int idx) @@ -240,7 +254,7 @@ template class HashMap if(idx >= count()) { abort(); } - return *values[idx]; + return values[idx]; } /* @@ -263,7 +277,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 +293,15 @@ template class HashMap */ V& operator[](const K& key); - void allocate(unsigned int newSize); + bool allocate(unsigned int newSize) + { + return keys.allocate(newSize) && values.allocate(newSize); + } + + /** + * @brief Sort map entries + */ + void sort(SortCompare compare); /* || @description @@ -290,7 +312,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 +347,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 +374,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 +414,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 +431,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/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..054065b1bd 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,15 +331,29 @@ 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); + + template + constexpr typename std::enable_if::value && !std::is_convertible::value, bool>::type + concat(E value) + { + extern String toString(E); + return concat(toString(value)); + } /** @} */ /** @@ -359,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) - { - concat(num); - return (*this); - } - String& operator+=(float num) - { - concat(num); - return (*this); - } - String& operator+=(double num) + template String& operator+=(T value) { - concat(num); - return (*this); + concat(value); + return *this; } /** @} */ @@ -794,6 +769,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/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 new file mode 100644 index 0000000000..d799215cc4 --- /dev/null +++ b/Sming/Wiring/WiringList.h @@ -0,0 +1,184 @@ +/**** + * 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 scalar values + */ +template struct ScalarList { + T* values{nullptr}; + size_t size{0}; + + ~ScalarList() + { + clear(); + } + + bool allocate(size_t newSize); + + void clear() + { + 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) + { + memmove(&values[index], &values[index + 1], (size - index - 1) * sizeof(T)); + } + + void trim(size_t newSize, bool reallocate) + { + if(!reallocate) { + return; + } + + auto newmem = realloc(values, sizeof(T) * newSize); + if(newmem == nullptr) { + return; + } + + values = static_cast(newmem); + size = newSize; + } + + T& operator[](unsigned index) + { + return values[index]; + } + + const T& operator[](unsigned index) const + { + return const_cast(*this)[index]; + } +}; + +/** + * @brief List of object pointers + */ +template struct ObjectList : public ScalarList { + struct Element { + T*& value; + + Element& operator=(T* v) + { + delete value; + value = v; + return *this; + } + + 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); + + void clear() + { + 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) + { + delete this->values[index]; + ScalarList::remove(index); + this->values[this->size - 1] = nullptr; + } + + void trim(size_t newSize, bool reallocate) + { + 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 *this->values[index]; + } +}; + +template bool ScalarList::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); + size = newSize; + return true; +} + +template bool ObjectList::allocate(size_t newSize) +{ + auto curSize = this->size; + if(!ScalarList::allocate(newSize)) { + return false; + } + + std::fill_n(&this->values[curSize], newSize - curSize, nullptr); + return true; +} + +template +using List = typename std::conditional::value, ScalarList, ObjectList>::type; + +} // namespace wiring_private 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 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/ci/install.sh b/Tools/ci/install.sh index 9fe5da5110..e95c2a6d45 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" @@ -22,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/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 26f1c72939..5e65f6480f 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 @@ -76,10 +77,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 @@ -100,6 +101,9 @@ if [ -n "$APPVEYOR" ] || [ -n "$GITHUB_ACTION" ]; then clang-format-8 \ g++-9-multilib \ python3-setuptools \ + ninja-build \ + exfat-fuse \ + exfat-utils \ $EXTRA_PACKAGES sudo update-alternatives --set gcc /usr/bin/gcc-9 @@ -190,7 +194,7 @@ if [ $inst_rp2040 -eq 1 ]; then fi if [ -z "$KEEP_DOWNLOADS" ]; then - rm -f "$DOWNLOADS/*" + rm -rf "$DOWNLOADS/*" fi 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 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/requirements.txt b/docs/requirements.txt index 4ee83e6283..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==0.8.4 # 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 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/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/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/docs/source/information/develop/ci.rst b/docs/source/information/develop/ci.rst index c149a33a70..74581accd6 100644 --- a/docs/source/information/develop/ci.rst +++ b/docs/source/information/develop/ci.rst @@ -19,47 +19,92 @@ 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. + Sming doesn't perform CI builds for MacOS. -Configuration -~~~~~~~~~~~~~ +Library CI support +------------------ -Sming developers may use integration testing for their own projects, libraries or framework changes. +Sming libraries may be separately built and tested whether or not they are included as part of +the Sming repository (or a fork). -Configure as follows: +There are two mechanisms available. -- 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. +GitHub Actions +~~~~~~~~~~~~~~ -By default, pull requests are built automatically. +The ``library.yml`` re-useable workflow is provided, which takes care of these tasks: -The `Rolling builds `__ -setting ensures that only the most recent commit to a branch is built, so should usually be enabled. +- 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`. -Library CI support ------------------- +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: 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/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/docs/source/information/storage.rst b/docs/source/information/storage.rst new file mode 100644 index 0000000000..6ff416ef49 --- /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 greater than about 2GB (signed 32-bit value) then the :cpp:envvar:`ENABLE_FILE_SIZE64` +setting should also be enabled. 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..466d2940ec --- /dev/null +++ b/docs/source/upgrading/4.6-4.7.rst @@ -0,0 +1,47 @@ +From v4.6 to v4.7 +================= + +.. highlight:: c++ + +Storage Partition methods +------------------------- + +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 ``CustomDevice`` class has been removed as it is simpler and more flexible to instead use PartitionTable methods. + +The :cpp:func:`Storage::Device::partitions` method returns a read-only (const) :cpp:class:`Storage::PartitionTable` object +for general use to avoid inadvertent modification. + +Use the :cpp:func:`Storage::Device::editablePartitions` method to make partition table changes. + +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); + + + +Custom Partition Types +---------------------- + +Creating custom partition types now require use of :cpp:struct:`Storage::Partition::FullType`. + +For example:: + + 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/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/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/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 0a7163bbb2..228601605b 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -77,10 +77,11 @@ 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.printf("vid = [%X] pid = [%X]\n", vid, pid); - } else - Serial.println("OV2640 detected"); + Serial.println(_F("Can't find OV2640 module!")); + Serial << "vid = [" << String(vid, HEX) << "], pid = [" << String(pid, HEX) << "]" << endl; + } else { + Serial.println(_F("OV2640 detected")); + } // initialize SPI: pinMode(CAM_CS, OUTPUT); @@ -93,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(); } @@ -167,7 +169,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 +180,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 +192,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 +230,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/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(); } 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_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 7aff2d69af..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 @@ -139,7 +155,8 @@ 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.editablePartitions().add(F("fwfsMem"), fwfsImage, Storage::Partition::SubType::Data::fwfs); #else auto part = Storage::findDefaultPartition(Storage::Partition::SubType::Data::fwfs); #endif @@ -193,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_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 7d8283b18a..53e8a3a0b0 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()); @@ -27,14 +27,14 @@ Storage::Partition findSpiffsPartition(Storage::Partition partition) 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_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_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_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..6c89546433 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) { @@ -58,11 +46,10 @@ int onDownload(HttpConnection& connection, bool success) auto ssl = connection.getSsl(); if(ssl != nullptr) { - ssl->printTo(Serial); + Serial.print(*ssl); } - 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_Storage/app/application.cpp b/samples/Basic_Storage/app/application.cpp index a1ba039d47..e9fa62b362 100644 --- a/samples/Basic_Storage/app/application.cpp +++ b/samples/Basic_Storage/app/application.cpp @@ -8,11 +8,9 @@ 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) { - Serial.print(F(">> Mounting '")); - Serial.print((*it).name()); - Serial.println("' ..."); - bool ok = spiffs_mount(*it); + for(auto part : Storage::findPartition(Storage::Partition::SubType::Data::spiffs)) { + Serial << _F(">> Mounting '") << part.name() << "' ..." << endl; + bool ok = spiffs_mount(part); Serial.println(ok ? "OK, listing files:" : "Mount failed!"); if(ok) { Directory dir; @@ -22,29 +20,27 @@ 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; } } } 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)) { - 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); } @@ -84,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.createPartition(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.createPartition(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.createPartition(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/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..e20a08de7e 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_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/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); 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/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(); } 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); 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/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/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/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/Spiffs.cpp b/tests/HostTests/modules/Spiffs.cpp index bde78215f3..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->createPartition(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(); diff --git a/tests/HostTests/modules/Storage.cpp b/tests/HostTests/modules/Storage.cpp index 06cd99c4cd..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(); @@ -63,10 +63,8 @@ class PartitionTest : public TestGroup void listPartitions() { - for(auto it = Storage::findPartition(); it; ++it) { - auto part = *it; - Serial.print("* "); - Storage::Debug::printPartition(Serial, part); + for(auto part : Storage::findPartition()) { + Serial << "* " << part << endl; testRead(part, 0xE0, 0x20, true); testRead(part, 10, 20, true); 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); 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(); } 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(); +} diff --git a/tests/HostTests/modules/Wiring.cpp b/tests/HostTests/modules/Wiring.cpp index c66e3cfa50..647eccc88a 100644 --- a/tests/HostTests/modules/Wiring.cpp +++ b/tests/HostTests/modules/Wiring.cpp @@ -3,73 +3,272 @@ #include #include #include +#include +#include +#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 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; +} + +} // namespace - template void print(const Map& map) const +class WiringTest : public TestGroup +{ +public: + WiringTest() : TestGroup(_F("Wiring")) { - for(auto e : map) { - println(e); - } } 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) { - 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"); print(map); } - TEST_CASE("Vector(String)") + TEST_CASE("HashMap") + { + 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") { - Vector 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; + + print(vector); + for(auto& e : vector) { - Serial.println(e); + e += ": gobbed"; + } + for(auto& e : vector) { + 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") + { + 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; + + print(vector); + for(auto& e : vector) { 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 += 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) { + e += 12; + } + for(auto& e : vector) { - Serial.println(e); + Serial << e << ", "; } + Serial.println(); } TEST_CASE("MacAddress") 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: