Compare commits
1 commit
master
...
add-cpu-12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
294af1c384 |
1200 changed files with 20408 additions and 306941 deletions
42
.github/workflows/build-libpico.yml
vendored
42
.github/workflows/build-libpico.yml
vendored
|
|
@ -1,42 +0,0 @@
|
||||||
# Run whenever it is manually triggered, a pull request or a push is done that modifes the libpico configuration
|
|
||||||
|
|
||||||
name: libpico Builder
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- tools/libpico/**
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- tools/libpico/**
|
|
||||||
jobs:
|
|
||||||
build-libpico:
|
|
||||||
name: Build libpico precompiled libraries
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: false
|
|
||||||
- name: Get submodules for pico-sdk
|
|
||||||
run: cd pico-sdk && git submodule update --init --recursive
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install cmake make build-essential wget
|
|
||||||
# Automatically get correct toolchain
|
|
||||||
cd tools && python3 get.py && cd ..
|
|
||||||
# add to PATH
|
|
||||||
echo "$GITHUB_WORKSPACE/system/riscv32-unknown-elf/bin" >> "$GITHUB_PATH"
|
|
||||||
echo "$GITHUB_WORKSPACE/system/arm-none-eabi/bin" >> "$GITHUB_PATH"
|
|
||||||
- name: Build libpico
|
|
||||||
run: |
|
|
||||||
cd tools/libpico
|
|
||||||
./make-libpico.sh
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: libpico
|
|
||||||
path: |
|
|
||||||
tools/libpico/build-rp2040/*.a
|
|
||||||
tools/libpico/build-rp2350/*.a
|
|
||||||
tools/libpico/build-rp2350-riscv/*.a
|
|
||||||
261
.github/workflows/pull-request.yml
vendored
261
.github/workflows/pull-request.yml
vendored
|
|
@ -6,21 +6,34 @@ name: Arduino-Pico CI
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
# Consistent style, spelling
|
# Me no spell so good
|
||||||
astyle:
|
code-spell:
|
||||||
name: Spelling, Style, Boards, Package, PIO
|
name: Check spelling
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Run codespell
|
||||||
|
uses: codespell-project/actions-codespell@master
|
||||||
|
with:
|
||||||
|
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
|
||||||
|
ignore_words_list: ser,dout
|
||||||
|
|
||||||
|
# Consistent style
|
||||||
|
astyle:
|
||||||
|
name: Style, Boards, Package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: false
|
submodules: false
|
||||||
- name: Run codespell
|
- name: Check package references
|
||||||
uses: codespell-project/actions-codespell@v2
|
run: |
|
||||||
with:
|
./tests/ci/pkgrefs_test.sh
|
||||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h
|
|
||||||
ignore_words_list: ser,dout,shiftIn,acount,froms
|
|
||||||
- name: Check boards.txt was not edited after makeboards.py
|
- name: Check boards.txt was not edited after makeboards.py
|
||||||
run: |
|
run: |
|
||||||
./tools/makeboards.py
|
./tools/makeboards.py
|
||||||
|
|
@ -33,15 +46,10 @@ jobs:
|
||||||
./tests/restyle.sh
|
./tests/restyle.sh
|
||||||
# If anything changed, GIT should return an error and fail the test
|
# If anything changed, GIT should return an error and fail the test
|
||||||
git diff --exit-code
|
git diff --exit-code
|
||||||
- name: Check compiled PIO files
|
# - name: Check Arduino API copy is clean
|
||||||
run: |
|
# run: |
|
||||||
(cd ./tools && ./get.py)
|
# git submodule update --init ./ArduinoCore-API
|
||||||
./tools/makepio.py
|
# diff -r ./cores/rp2040/api ./ArduinoCore-API/api
|
||||||
# If anything changed, GIT should return an error and fail the test
|
|
||||||
git diff -w --exit-code
|
|
||||||
- name: Check package references
|
|
||||||
run: |
|
|
||||||
./tests/ci/pkgrefs_test.sh
|
|
||||||
|
|
||||||
# Build all examples on linux (core and Arduino IDE)
|
# Build all examples on linux (core and Arduino IDE)
|
||||||
build-linux:
|
build-linux:
|
||||||
|
|
@ -49,24 +57,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
chunk: [0, 1, 2, 3, 4, 5]
|
chunk: [0, 1, 2, 3]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Cache Linux toolchain
|
- name: Cache Linux toolchain
|
||||||
id: cache-linux
|
id: cache-linux
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ./tools/dist
|
path: ./tools/dist
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
- name: Build Sketches
|
- name: Build Sketches
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
|
TRAVIS_TAG: ${{ github.ref }}
|
||||||
BUILD_PARITY: custom
|
BUILD_PARITY: custom
|
||||||
mod: 6
|
mod: 4
|
||||||
rem: ${{ matrix.chunk }}
|
rem: ${{ matrix.chunk }}
|
||||||
run: |
|
run: |
|
||||||
cd pico-sdk
|
cd pico-sdk
|
||||||
|
|
@ -74,87 +84,27 @@ jobs:
|
||||||
cd ..
|
cd ..
|
||||||
bash ./tests/build.sh
|
bash ./tests/build.sh
|
||||||
|
|
||||||
# Build all rp2350 examples on linux (core and Arduino IDE)
|
|
||||||
build-rp2350-linux:
|
|
||||||
name: Build RP2350 ${{ matrix.chunk }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
chunk: [0, 1, 2, 3, 4, 5]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Cache Linux toolchain
|
|
||||||
id: cache-linux
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ./tools/dist
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
|
||||||
- name: Build Sketches
|
|
||||||
env:
|
|
||||||
BUILD_PARITY: custom
|
|
||||||
mod: 6
|
|
||||||
rem: ${{ matrix.chunk }}
|
|
||||||
run: |
|
|
||||||
cd pico-sdk
|
|
||||||
git submodule update --init
|
|
||||||
cd ..
|
|
||||||
bash ./tests/build-rp2350.sh
|
|
||||||
|
|
||||||
# Build all rp2350-riscv examples on linux (core and Arduino IDE)
|
|
||||||
build-rp2350-riscv-linux:
|
|
||||||
name: Build RP2350-RISCV ${{ matrix.chunk }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
chunk: [0, 1, 2, 3, 4, 5]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Cache Linux toolchain
|
|
||||||
id: cache-linux
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ./tools/dist
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
|
||||||
- name: Build Sketches
|
|
||||||
env:
|
|
||||||
BUILD_PARITY: custom
|
|
||||||
mod: 6
|
|
||||||
rem: ${{ matrix.chunk }}
|
|
||||||
run: |
|
|
||||||
cd pico-sdk
|
|
||||||
git submodule update --init
|
|
||||||
cd ..
|
|
||||||
bash ./tests/build-rp2350-riscv.sh
|
|
||||||
|
|
||||||
# Build TinyUSB examples, requires custom build command line
|
# Build TinyUSB examples, requires custom build command line
|
||||||
build-tinyusb:
|
build-tinyusb:
|
||||||
name: Build TinyUSB Examples
|
name: Build TinyUSB Examples
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Cache Linux toolchain
|
- name: Cache Linux toolchain
|
||||||
id: cache-linux
|
id: cache-linux
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ./tools/dist
|
path: ./tools/dist
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
- name: Build Sketches
|
- name: Build Sketches
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
|
TRAVIS_TAG: ${{ github.ref }}
|
||||||
BUILD_PARITY: custom
|
BUILD_PARITY: custom
|
||||||
run: |
|
run: |
|
||||||
cd pico-sdk
|
cd pico-sdk
|
||||||
|
|
@ -167,20 +117,22 @@ jobs:
|
||||||
name: Windows
|
name: Windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Cache Windows toolchain
|
- name: Cache Windows toolchain
|
||||||
id: cache-windows
|
id: cache-windows
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ./tools/dist
|
path: ./tools/dist
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
- name: Build Sketch
|
- name: Build Sketch
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
|
TRAVIS_TAG: ${{ github.ref }}
|
||||||
WINDOWS: 1
|
WINDOWS: 1
|
||||||
BUILD_PARITY: custom
|
BUILD_PARITY: custom
|
||||||
mod: 500
|
mod: 500
|
||||||
|
|
@ -198,144 +150,31 @@ jobs:
|
||||||
# Single build under macOS to ensure the Mac toolchain is good.
|
# Single build under macOS to ensure the Mac toolchain is good.
|
||||||
build-mac:
|
build-mac:
|
||||||
name: Mac
|
name: Mac
|
||||||
strategy:
|
runs-on: macOS-latest
|
||||||
matrix:
|
|
||||||
os: [macOS-13, macOS-14]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Cache Mac toolchain
|
- name: Cache Mac toolchain
|
||||||
id: cache-mac
|
id: cache-mac
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ./tools/dist
|
path: ./tools/dist
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
- name: Build Sketch
|
- name: Build Sketch
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
|
TRAVIS_TAG: ${{ github.ref }}
|
||||||
MACOSX: 1
|
MACOSX: 1
|
||||||
BUILD_PARITY: custom
|
BUILD_PARITY: custom
|
||||||
mod: 500
|
mod: 500
|
||||||
rem: 1
|
rem: 1
|
||||||
run: |
|
run: |
|
||||||
brew update
|
|
||||||
brew install bash
|
|
||||||
/usr/bin/env bash --version
|
|
||||||
uname -a
|
|
||||||
cd pico-sdk
|
cd pico-sdk
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
cd ..
|
cd ..
|
||||||
/usr/bin/env bash ./tests/build.sh
|
bash ./tests/build.sh
|
||||||
./system/picotool/picotool version
|
|
||||||
otool -L ./system/picotool/picotool
|
|
||||||
|
|
||||||
# Build a few examples with PlatformIO to test if integration works
|
|
||||||
build-platformio:
|
|
||||||
name: Build PlatformIO Examples
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Initialize needed submodules
|
|
||||||
run: |
|
|
||||||
cd pico-sdk
|
|
||||||
git submodule update --init
|
|
||||||
cd ../libraries/Adafruit_TinyUSB_Arduino
|
|
||||||
git submodule update --init
|
|
||||||
cd ../..
|
|
||||||
- name: Cache pip
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.cache/pip
|
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pip-
|
|
||||||
- name: Cache PlatformIO
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.platformio
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install PlatformIO
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install --upgrade platformio
|
|
||||||
rm -rf ~/.platformio/platforms/raspberrypi*
|
|
||||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
|
||||||
pio pkg install --global --tool symlink://.
|
|
||||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
|
||||||
- name: Build Multicore Example
|
|
||||||
run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
|
||||||
- name: Build Multicore Example (RISC-V)
|
|
||||||
run: pio ci -v --board=rpipico2 -O "board_build.mcu = rp2350-riscv" -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
|
||||||
- name: Build Fade Example
|
|
||||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
|
||||||
- name: Build TinyUSB Example
|
|
||||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
|
|
||||||
- name: Build WiFi Example
|
|
||||||
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino
|
|
||||||
- name: Build Signed OTA Example
|
|
||||||
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
|
|
||||||
- name: Build Bluetooth Example
|
|
||||||
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DPIO_FRAMEWORK_ARDUINO_ENABLE_BLUETOOTH" libraries/MouseBLE/examples/BLECircle/BLECircle.ino
|
|
||||||
|
|
||||||
# Build every variant using PIO for simplicity
|
|
||||||
build-variants:
|
|
||||||
name: Build Every Variant ${{ matrix.chunk }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
chunk: [0, 1]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Initialize needed submodules
|
|
||||||
run: |
|
|
||||||
cd pico-sdk
|
|
||||||
git submodule update --init
|
|
||||||
cd ../libraries/Adafruit_TinyUSB_Arduino
|
|
||||||
git submodule update --init
|
|
||||||
cd ../..
|
|
||||||
- name: Cache pip
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.cache/pip
|
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pip-
|
|
||||||
- name: Cache PlatformIO
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.platformio
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install PlatformIO
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install --upgrade platformio
|
|
||||||
rm -rf ~/.platformio/platforms/raspberrypi*
|
|
||||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
|
||||||
pio pkg install --global --tool symlink://.
|
|
||||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
|
||||||
- name: Build Every Variant
|
|
||||||
run: |
|
|
||||||
cnt=0
|
|
||||||
for b in $(cut -f1 -d. /home/runner/work/arduino-pico/arduino-pico/boards.txt | sed 's/#.*//' | sed 's/^menu$//' | sort -u); do
|
|
||||||
cnt=$((cnt + 1))
|
|
||||||
rem=$((cnt % 2))
|
|
||||||
if [ $rem == ${{ matrix.chunk }} ]; then
|
|
||||||
pio ci --board=$b -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Bootsel/Bootsel.ino
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
|
||||||
30
.github/workflows/release-to-publish.yml
vendored
30
.github/workflows/release-to-publish.yml
vendored
|
|
@ -9,38 +9,24 @@ jobs:
|
||||||
name: Update master JSON file
|
name: Update master JSON file
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Cache pip
|
- uses: actions/setup-python@v2
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
python-version: '3.x'
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pip-
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
# - name: Cache PlatformIO
|
|
||||||
# uses: actions/cache@v4
|
|
||||||
# with:
|
|
||||||
# path: ~/.platformio
|
|
||||||
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
||||||
# - name: Install PlatformIO
|
|
||||||
# run: |
|
|
||||||
# python -m pip install --upgrade pip
|
|
||||||
# pip install --upgrade platformio
|
|
||||||
- name: Deploy updated JSON
|
- name: Deploy updated JSON
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
BUILD_TYPE: package
|
BUILD_TYPE: package
|
||||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
|
||||||
run: |
|
run: |
|
||||||
pip3 install PyGithub
|
pip3 install PyGithub
|
||||||
TAG=$(git describe --exact-match --tags)
|
TAG=$(git describe --exact-match --tags)
|
||||||
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
||||||
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
||||||
# Upload to Platform.IO
|
# Upload to Platform.IO
|
||||||
# curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
apt-get install -y python3-pip
|
||||||
# pio package publish rp2040-$TAG.zip --non-interactive
|
pip3 install platformio
|
||||||
|
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||||
|
pio package publish rp2040-$TAG.zip --non-interactive
|
||||||
|
|
|
||||||
5
.github/workflows/tag-to-draft-release.yml
vendored
5
.github/workflows/tag-to-draft-release.yml
vendored
|
|
@ -15,15 +15,16 @@ jobs:
|
||||||
name: Package
|
name: Package
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
- name: Build package JSON
|
- name: Build package JSON
|
||||||
env:
|
env:
|
||||||
|
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||||
BUILD_TYPE: package
|
BUILD_TYPE: package
|
||||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -1,12 +1,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
system
|
system
|
||||||
tools/dist
|
tools/dist
|
||||||
docs/_build
|
|
||||||
ota/build
|
|
||||||
ota/build-rp2350
|
|
||||||
ota/build-rp2350-riscv
|
|
||||||
tools/libpico/boot
|
|
||||||
tools/libpico/build-rp2040
|
|
||||||
tools/libpico/build-rp2350
|
|
||||||
tools/libpico/build-rp2350-riscv
|
|
||||||
platform.local.txt
|
|
||||||
|
|
|
||||||
38
.gitmodules
vendored
38
.gitmodules
vendored
|
|
@ -10,42 +10,18 @@
|
||||||
[submodule "libraries/LittleFS/lib/littlefs"]
|
[submodule "libraries/LittleFS/lib/littlefs"]
|
||||||
path = libraries/LittleFS/lib/littlefs
|
path = libraries/LittleFS/lib/littlefs
|
||||||
url = https://github.com/littlefs-project/littlefs.git
|
url = https://github.com/littlefs-project/littlefs.git
|
||||||
|
[submodule "libraries/SdFat"]
|
||||||
|
path = libraries/ESP8266SdFat
|
||||||
|
url = https://github.com/earlephilhower/ESP8266SdFat.git
|
||||||
[submodule "libraries/Keyboard"]
|
[submodule "libraries/Keyboard"]
|
||||||
path = libraries/HID_Keyboard
|
path = libraries/Keyboard
|
||||||
url = https://github.com/earlephilhower/Keyboard.git
|
url = https://github.com/earlephilhower/Keyboard
|
||||||
[submodule "libraries/Mouse"]
|
[submodule "libraries/Mouse"]
|
||||||
path = libraries/HID_Mouse
|
path = libraries/Mouse
|
||||||
url = https://github.com/earlephilhower/Mouse.git
|
url = https://github.com/earlephilhower/Mouse
|
||||||
[submodule "libraries/Joystick"]
|
|
||||||
path = libraries/HID_Joystick
|
|
||||||
url = https://github.com/earlephilhower/Joystick.git
|
|
||||||
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
|
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
|
||||||
path = libraries/Adafruit_TinyUSB_Arduino
|
path = libraries/Adafruit_TinyUSB_Arduino
|
||||||
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
|
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
|
||||||
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
|
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
|
||||||
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
|
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
|
||||||
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
|
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
|
||||||
[submodule "tools/libbearssl/bearssl"]
|
|
||||||
path = tools/libbearssl/bearssl
|
|
||||||
url = https://github.com/earlephilhower/bearssl-esp8266.git
|
|
||||||
[submodule "ota/uzlib"]
|
|
||||||
path = ota/uzlib
|
|
||||||
url = https://github.com/pfalcon/uzlib.git
|
|
||||||
[submodule "libraries/http_parser/lib/http-parser"]
|
|
||||||
path = libraries/http-parser/lib/http-parser
|
|
||||||
url = https://github.com/nodejs/http-parser.git
|
|
||||||
[submodule "libraries/FatFS/lib/SPIFTL"]
|
|
||||||
path = libraries/FatFS/lib/SPIFTL
|
|
||||||
url = https://github.com/earlephilhower/SPIFTL.git
|
|
||||||
[submodule "libraries/AsyncUDP"]
|
|
||||||
path = libraries/AsyncUDP
|
|
||||||
url = https://github.com/earlephilhower/AsyncUDP.git
|
|
||||||
[submodule "cores/rp2040/tlsf"]
|
|
||||||
path = lib/tlsf
|
|
||||||
url = https://github.com/earlephilhower/tlsf.git
|
|
||||||
[submodule "libraries/ESPHost"]
|
|
||||||
path = libraries/ESPHost
|
|
||||||
url = https://github.com/Networking-for-Arduino/ESPHost.git
|
|
||||||
[submodule "libraries/SdFat"]
|
|
||||||
path = libraries/SdFat
|
|
||||||
url = https://github.com/greiman/SdFat.git
|
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
# Read the Docs configuration file for Sphinx projects
|
|
||||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
||||||
|
|
||||||
# Required
|
|
||||||
version: 2
|
|
||||||
|
|
||||||
# Set the OS, Python version and other tools you might need
|
|
||||||
|
|
||||||
build:
|
|
||||||
os: ubuntu-22.04
|
|
||||||
tools:
|
|
||||||
python: "3.12"
|
|
||||||
jobs:
|
|
||||||
post_create_environment:
|
|
||||||
- python -m pip install sphinx_rtd_theme
|
|
||||||
# You can also specify other tool versions:
|
|
||||||
# nodejs: "20"
|
|
||||||
# rust: "1.70"
|
|
||||||
# golang: "1.20"
|
|
||||||
|
|
||||||
|
|
||||||
# Build documentation in the "docs/" directory with Sphinx
|
|
||||||
|
|
||||||
sphinx:
|
|
||||||
configuration: docs/conf.py
|
|
||||||
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
|
||||||
# builder: "dirhtml"
|
|
||||||
# Fail on all warnings to avoid broken references
|
|
||||||
# fail_on_warning: true
|
|
||||||
|
|
||||||
# Optionally build your docs in additional formats such as PDF and ePub
|
|
||||||
formats:
|
|
||||||
- pdf
|
|
||||||
# - epub
|
|
||||||
|
|
||||||
# Optional but recommended, declare the Python requirements required
|
|
||||||
# to build your documentation
|
|
||||||
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
|
||||||
# python:
|
|
||||||
# install:
|
|
||||||
# - requirements: docs/requirements.txt
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 82928635c893189343cf8eb78569f0c4136fded0
|
Subproject commit ff01bb620e0c3386e39e032e209d9a07ad799d25
|
||||||
236
README.md
236
README.md
|
|
@ -2,190 +2,52 @@
|
||||||
[](https://github.com/earlephilhower/arduino-pico/releases)
|
[](https://github.com/earlephilhower/arduino-pico/releases)
|
||||||
[](https://gitter.im/arduino-pico/community)
|
[](https://gitter.im/arduino-pico/community)
|
||||||
|
|
||||||
Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
|
Raspberry Pi Pico Arduino core, for all RP2040 boards
|
||||||
|
|
||||||
This is a port of Arduino to the RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2 processor). It uses the bare Raspberry Pi Pico SDK and a custom GCC 14.2/Newlib 4.3 toolchain and supports ARM and RISC-V cores.
|
This is a port of the RP2040 (Raspberry Pi Pico processor) to the Arduino ecosystem. It uses the bare Raspberry Pi Pico SDK and a custom GCC 10.3/Newlib 4.0 toolchain.
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
||||||
|
|
||||||
# Contributing
|
|
||||||
Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blob/master/docs/contrib.rst) for more information on submitting pull requests and porting libraries or sketches to this core.
|
|
||||||
|
|
||||||
# Supported Boards
|
# Supported Boards
|
||||||
* Raspberry Pi Pico
|
* Raspberry Pi Pico
|
||||||
* Raspberry Pi Pico W
|
|
||||||
* Raspberry Pi Pico 2
|
|
||||||
* Raspberry Pi Pico 2W
|
|
||||||
* 0xCB Helios
|
|
||||||
* Adafruit Feather RP2040
|
* Adafruit Feather RP2040
|
||||||
* Adafruit Feather RP2040 SCORPIO
|
|
||||||
* Adafruit Floppsy RP2040
|
|
||||||
* Adafruit ItsyBitsy RP2040
|
* Adafruit ItsyBitsy RP2040
|
||||||
* Adafruit KB2040
|
* Adafruit KB2040
|
||||||
* Adafruit Macropad RP2040
|
* Adafruit Macropad RP2040
|
||||||
* Adafruit Metro RP2040
|
|
||||||
* Adafruit Metro RP2350
|
|
||||||
* Adafruit QTPy RP2040
|
* Adafruit QTPy RP2040
|
||||||
* Adafruit STEMMA Friend RP2040
|
* Adafruit STEMMA Friend RP2040
|
||||||
* Adafruit Trinkey RP2040 QT
|
* Adafruit Trinkey RP2040 QT
|
||||||
* Amken Bunny
|
|
||||||
* Amken Revelop
|
|
||||||
* Amken Revelop Plus
|
|
||||||
* Amken Revelop eS
|
|
||||||
* Architeuthis Flux Jumperless
|
|
||||||
* Architeuthis Flux Jumperless V5
|
|
||||||
* Arduino Nano RP2040 Connect
|
* Arduino Nano RP2040 Connect
|
||||||
* ArtronShop RP2 Nano
|
|
||||||
* Breadstick Raspberry
|
|
||||||
* BridgeTek IDM2040-7A
|
|
||||||
* BridgeTek IDM2040-43A
|
|
||||||
* Cytron IRIV IO Controller
|
|
||||||
* Cytron Maker Pi RP2040
|
* Cytron Maker Pi RP2040
|
||||||
* Cytron Maker Nano RP2040
|
* Cytron Maker Nano RP2040
|
||||||
* Cytron Maker Uno RP2040
|
|
||||||
* Cytron Motion 2350 Pro
|
|
||||||
* Datanoise PicoADK v1
|
|
||||||
* Datanoise PicoADK v2 (RP2350)
|
|
||||||
* Degz Suibo RP2040
|
|
||||||
* DeRuiLab FlyBoard2040 Core
|
* DeRuiLab FlyBoard2040 Core
|
||||||
* DFRobot Beetle RP2040
|
* DFRobot Beetle RP2040
|
||||||
* ElectronicCats Hunter Cat NFC
|
|
||||||
* EVN Alpha
|
|
||||||
* ExtremeElectronics RC2040
|
|
||||||
* GroundStudio Marble Pico
|
|
||||||
* Invector Labs Challenger RP2040 WiFi
|
* Invector Labs Challenger RP2040 WiFi
|
||||||
* Invector Labs Challenger RP2040 WiFi/BLE
|
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||||
* Invector Labs Challenger RP2040 WiFi6/BLE
|
|
||||||
* Invector Labs Challenger NB RP2040 WiFi
|
* Invector Labs Challenger NB RP2040 WiFi
|
||||||
* Invector Labs Challenger RP2040 LTE
|
* Invector Labs Challenger RP2040 LTE
|
||||||
* Invector Labs Challenger RP2040 LoRa
|
* Invector Labs Challenger RP2040 LoRa
|
||||||
* Invector Labs Challenger RP2040 SubGHz
|
|
||||||
* Invector Labs Challenger RP2040 SD/RTC
|
|
||||||
* Invector Labs Challenger RP2040 UWB
|
|
||||||
* Invector Labs Challenger RP2350 BConnect
|
|
||||||
* Invector Labs Challenger RP2350 WiFi/BLE
|
|
||||||
* Invector Labs RPICO32
|
* Invector Labs RPICO32
|
||||||
* Melopero Cookie RP2040
|
|
||||||
* Melopero Shake RP2040
|
* Melopero Shake RP2040
|
||||||
* METE HOCA Akana R1
|
|
||||||
* Makerbase MKSTHR36
|
|
||||||
* Makerbase MKSTHR42
|
|
||||||
* MyMakers RP2040
|
|
||||||
* Neko Systems BL2040 Mini
|
|
||||||
* Newsan Archi
|
|
||||||
* nullbits Bit-C PRO
|
|
||||||
* Olimex Pico2XL
|
|
||||||
* Olimex Pico2XXL
|
|
||||||
* Olimex RP2040-Pico30
|
|
||||||
* Pimoroni PGA2040
|
|
||||||
* Pimoroni Pico Plus 2
|
|
||||||
* Pimoroni Pico Plus 2W
|
|
||||||
* Pimoroni Plasma2040
|
|
||||||
* Pimoroni Plasma2350
|
|
||||||
* Pimoroni Servo2040
|
|
||||||
* Pimoroni Tiny2040
|
|
||||||
* Pimoroni Tiny2350
|
|
||||||
* Pintronix PinMax
|
|
||||||
* RAKwireless RAK11300
|
|
||||||
* Redscorp RP2040-Eins
|
|
||||||
* Redscorp RP2040-ProMini
|
|
||||||
* Sea-Picro
|
|
||||||
* Seeed Indicator RP2040
|
|
||||||
* Seeed XIAO RP2040
|
* Seeed XIAO RP2040
|
||||||
* Seeed XIAO RP2350
|
|
||||||
* Silicognition RP2040-Shim
|
|
||||||
* Solder Party RP2040 Stamp
|
* Solder Party RP2040 Stamp
|
||||||
* Solder Party RP2350 Stamp
|
|
||||||
* Solder Party RP2350 Stamp XL
|
|
||||||
* SparkFun IoT RedBoard RP2350
|
|
||||||
* SparkFun MicroMod RP2040
|
|
||||||
* SparkFun ProMicro RP2040
|
* SparkFun ProMicro RP2040
|
||||||
* SparkFun ProMicro RP2350
|
|
||||||
* SparkFun Thing Plus RP2040
|
* SparkFun Thing Plus RP2040
|
||||||
* SparkFun Thing Plus RP2350
|
|
||||||
* SparkFun XRP Controller
|
|
||||||
* uPesy RP2040 DevKit
|
* uPesy RP2040 DevKit
|
||||||
* VCC-GND YD-RP2040
|
|
||||||
* Viyalab Mizu RP2040
|
|
||||||
* Waveshare RP2040 Zero
|
|
||||||
* Waveshare RP2040 One
|
|
||||||
* Waveshare RP2040 Plus
|
|
||||||
* Waveshare RP2040 LCD 0.96
|
|
||||||
* Waveshare RP2040 LCD 1.28
|
|
||||||
* Waveshare RP2040 Matrix
|
|
||||||
* Waveshare RP2040 PiZero
|
|
||||||
* WIZnet W5100S-EVB-Pico
|
* WIZnet W5100S-EVB-Pico
|
||||||
* WIZnet W5100S-EVB-Pico2
|
|
||||||
* WIZnet W5500-EVB-Pico
|
* WIZnet W5500-EVB-Pico
|
||||||
* WIZnet W5500-EVB-Pico2
|
|
||||||
* WIZnet W55RP20-EVB-Pico
|
|
||||||
* WIZnet WizFi360-EVB-Pico
|
* WIZnet WizFi360-EVB-Pico
|
||||||
* Generic RP2040 (configurable flash, I/O pins)
|
* Generic (configurable flash, I/O pins)
|
||||||
* Generic RP2350 (configurable flash, I/O pins)
|
|
||||||
|
|
||||||
# Features
|
|
||||||
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
|
||||||
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
|
|
||||||
* Bluetooth Classic and BLE HID master mode (connect to BT keyboard, mouse, or joystick)
|
|
||||||
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
|
|
||||||
* WiFi (Pico W, ESP32-based ESPHost, Atmel WINC1500)
|
|
||||||
* Ethernet (Wired WizNet W6100, WizNet W5500, WizNet W5100, ENC28J60)
|
|
||||||
* HTTP client and server (WebServer)
|
|
||||||
* SSL/TLS/HTTPS
|
|
||||||
* Over-the-Air (OTA) upgrades
|
|
||||||
* Filesystems (LittleFS and SD/SDFS)
|
|
||||||
* Multicore support (setup1() and loop1())
|
|
||||||
* FreeRTOS SMP support
|
|
||||||
* Overclocking and underclocking from the menus
|
|
||||||
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
|
||||||
* Analog stereo audio in using DMA and the built-in ADC
|
|
||||||
* Analog stereo audio out using PWM hardware
|
|
||||||
* Bluetooth A2DP audio source (output) and sink (input) on the PicoW
|
|
||||||
* USB drive mode for data loggers (SingleFileDrive, FatFSUSB)
|
|
||||||
* Peripherals: SPI master/slave, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input/output, Servo
|
|
||||||
* printf (i.e. debug) output over USB serial
|
|
||||||
* Transparent use of PSRAM globals and heap (RP2350 only)
|
|
||||||
* ARM or RISC-V (Hazard3) support for the RP2350
|
|
||||||
* Semihosted serial and file system access
|
|
||||||
* GPROF profiling support
|
|
||||||
|
|
||||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
|
||||||
* Servos
|
|
||||||
* Tones
|
|
||||||
* I2S Input
|
|
||||||
* I2S Output
|
|
||||||
* Software UARTs (Serial ports)
|
|
||||||
* Software SPIs
|
|
||||||
|
|
||||||
# Installing via Arduino Boards Manager
|
# Installing via Arduino Boards Manager
|
||||||
## Windows-specific Notes
|
**Windows Users**: Please do not use the Windows Store version of the actual Arduino application
|
||||||
Please do not use the Windows Store version of the actual Arduino application
|
|
||||||
because it has issues detecting attached Pico boards. Use the "Windows ZIP" or plain "Windows"
|
because it has issues detecting attached Pico boards. Use the "Windows ZIP" or plain "Windows"
|
||||||
executable (EXE) download direct from https://arduino.cc. and allow it to install any device
|
executable (EXE) download direct from https://arduino.cc. and allow it to install any device
|
||||||
drivers it suggests. Otherwise the Pico board may not be detected. Also, if trying out the
|
drivers it suggests. Otherwise the Pico board may not be detected. Also, if trying out the
|
||||||
2.0 beta Arduino please install the release 1.8 version beforehand to ensure needed device drivers
|
2.0 beta Arduino please install the release 1.8 version beforehand to ensure needed device drivers
|
||||||
are present. (See #20 for more details.)
|
are present. (See #20 for more details.)
|
||||||
|
|
||||||
## Linux-specific Notes
|
|
||||||
Installing Arduino using flatpak (often used by "App Stores" in various Linux
|
|
||||||
distributions) will mean it has restricted access to the host. This might cause uploads to fail
|
|
||||||
with error messages such as the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
Scanning for RP2040 devices
|
|
||||||
...
|
|
||||||
No drive to deploy.
|
|
||||||
```
|
|
||||||
|
|
||||||
If you encounter this, you will need to either install Arduino in a different manner, or override
|
|
||||||
the flatpak sandboxing feature using the following command, then restarting Arduino.
|
|
||||||
|
|
||||||
```
|
|
||||||
flatpak override --user --filesystem=host:ro cc.arduino.IDE2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
Open up the Arduino IDE and go to File->Preferences.
|
Open up the Arduino IDE and go to File->Preferences.
|
||||||
|
|
||||||
In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field:
|
In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field:
|
||||||
|
|
@ -203,12 +65,6 @@ Type "pico" in the search box and select "Add":
|
||||||

|

|
||||||
|
|
||||||
# Installing via GIT
|
# Installing via GIT
|
||||||
|
|
||||||
**Windows Users:** Before installing via `git` on Windows, please read and follow the directions in
|
|
||||||
[this link](https://arduino-pico.readthedocs.io/en/latest/platformio.html#important-steps-for-windows-users-before-installing).
|
|
||||||
If Win32 long paths are not enabled, and `git` not configured to use them then there
|
|
||||||
may be errors when attempting to clone the submodules.
|
|
||||||
|
|
||||||
To install via GIT (for latest and greatest versions):
|
To install via GIT (for latest and greatest versions):
|
||||||
````
|
````
|
||||||
mkdir -p ~/Arduino/hardware/pico
|
mkdir -p ~/Arduino/hardware/pico
|
||||||
|
|
@ -221,6 +77,11 @@ cd ../tools
|
||||||
python3 ./get.py
|
python3 ./get.py
|
||||||
`````
|
`````
|
||||||
|
|
||||||
|
# Installing both Arduino and CMake
|
||||||
|
Tom's Hardware presented a very nice writeup on installing `arduino-pico` on both Windows and Linux, available at https://www.tomshardware.com/how-to/program-raspberry-pi-pico-with-arduino-ide
|
||||||
|
|
||||||
|
If you follow Les' step-by-step you will also have a fully functional `CMake`-based environment to build Pico apps on if you outgrow the Arduino ecosystem.
|
||||||
|
|
||||||
# Uploading Sketches
|
# Uploading Sketches
|
||||||
To upload your first sketch, you will need to hold the BOOTSEL button down while plugging in the Pico to your computer.
|
To upload your first sketch, you will need to hold the BOOTSEL button down while plugging in the Pico to your computer.
|
||||||
Then hit the upload button and the sketch should be transferred and start to run.
|
Then hit the upload button and the sketch should be transferred and start to run.
|
||||||
|
|
@ -241,30 +102,70 @@ To install, follow the directions in
|
||||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||||
|
|
||||||
For detailed usage information, please check the ESP8266 repo documentation (ignore SPIFFS related notes) available at
|
For detailed usage information, please check the ESP8266 repo documentation (ignore SPIFFS related notes) available at
|
||||||
* https://arduino-pico.readthedocs.io/en/latest/fs.html
|
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
||||||
|
|
||||||
# Uploading Sketches with Picoprobe/Debugprobe
|
# Uploading Sketches with Picoprobe
|
||||||
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
|
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
|
||||||
|
|
||||||
Under Windows a local admin user should be able to access the Picoprobe port automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
Under Windows a local admin user should be able to access the Picoprobe port automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||||
|
|
||||||
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
||||||
````
|
````
|
||||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="660", GROUP-"plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", GROUP="users", MODE="0666"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
|
||||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000f", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
sudo udevadm trigger -w -s usb
|
|
||||||
````
|
````
|
||||||
|
|
||||||
The first line creates a device file in `/dev` matching the USB vendor and product ID of the Picoprobe, and it enables global read+write permissions. The second line causes `udev` to load this new rule. The third line requests the kernel generate "device change" events that will cause our new `udev` rule to run.
|
The first line creates a file with the USB vendor and ID of the Picoprobe and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
||||||
|
|
||||||
If for some reason the device file does not appear, manually unplug and re-plug the USB connection and check again. The output from `dmesg` can reveal useful diagnostics if the device file remains absent.
|
|
||||||
|
|
||||||
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
||||||
|
|
||||||
# Debugging with Picoprobe, OpenOCD, and GDB
|
# Uploading Sketches with pico-debug
|
||||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. Use the command line `./system/openocd/bin/openocd -f ./lib/rp2040/picoprobe_cmsis_dap.tcl` or `./system/openocd/bin/openocd -f ./lib/rp2350/picoprobe_cmsis_dap.tcl` from the `git` installation directory.
|
[pico-debug](https://github.com/majbthrd/pico-debug/) differs from Picoprobe in that pico-debug is a virtual debug pod that runs side-by-side on the same RP2040 that you run your code on; so, you only need one RP2040 board instead of two. pico-debug also differs from Picoprobe in that pico-debug is standards-based; it uses the CMSIS-DAP protocol, which means even software not specially written for the Raspberry Pi Pico can support it. pico-debug uses OpenOCD to handle your sketch uploads, and debugging can be accomplished with CMSIS-DAP capable debuggers including GDB.
|
||||||
|
|
||||||
|
Under Windows and macOS, any user should be able to access pico-debug automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||||
|
|
||||||
|
To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes which use `udev`):
|
||||||
|
````
|
||||||
|
echo 'ATTRS{product}=="*CMSIS-DAP*", MODE="664", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-CMSIS-DAP.rules
|
||||||
|
sudo udevadm control --reload
|
||||||
|
````
|
||||||
|
|
||||||
|
The first line creates a file that recognizes all CMSIS-DAP adapters and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
||||||
|
|
||||||
|
Once CMSIS-DAP permissions are set up properly, then select the board "Raspberry Pi Pico (pico-debug)" in the Tools menu.
|
||||||
|
|
||||||
|
When first connecting the USB port to your PC, you must copy [pico-debug-gimmecache.uf2](https://github.com/majbthrd/pico-debug/releases/) to the Pi Pico to load pico-debug into RAM; after this, upload as normal.
|
||||||
|
|
||||||
|
# Debugging with Picoprobe/pico-debug, OpenOCD, and GDB
|
||||||
|
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. For [pico-debug](https://github.com/majbthrd/pico-debug/), replace the raspberrypi-swd and picoprobe example OpenOCD arguments of "-f interface/raspberrypi-swd.cfg -f target/rp2040.cfg" or "-f interface/picoprobe.cfg -f target/rp2040.cfg" respectively in the Pico Getting Started manual with "-f board/pico-debug.cfg".
|
||||||
|
|
||||||
|
# Features
|
||||||
|
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
||||||
|
* Generic Arduino USB Serial, Keyboard, and Mouse emulation
|
||||||
|
* Filesystems (LittleFS and SD/SDFS)
|
||||||
|
* Multicore support (setup1() and loop1())
|
||||||
|
* Overclocking and underclocking from the menus
|
||||||
|
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
||||||
|
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
|
||||||
|
* printf (i.e. debug) output over USB serial
|
||||||
|
|
||||||
|
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||||
|
* Servos
|
||||||
|
* Tones
|
||||||
|
* I2S Input
|
||||||
|
* I2S Output
|
||||||
|
* Software UARTs (Serial ports)
|
||||||
|
|
||||||
|
# Tutorials from Across the Web
|
||||||
|
Here are some links to coverage and additional tutorials for using `arduino-pico`
|
||||||
|
* The File:: class is taken from the ESP8266. See https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
||||||
|
* Arduino Support for the Pi Pico available! And how fast is the Pico? - https://youtu.be/-XHh17cuH5E
|
||||||
|
* Pre-release Adafruit QT Py RP2040 - https://www.youtube.com/watch?v=sfC1msqXX0I
|
||||||
|
* Adafruit Feather RP2040 running LCD + TMP117 - https://www.youtube.com/watch?v=fKDeqZiIwHg
|
||||||
|
* Demonstration of Servos and I2C in Korean - https://cafe.naver.com/arduinoshield/1201
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
If you want to contribute or have bugfixes, drop me a note at <earlephilhower@yahoo.com> or open an issue/PR here.
|
||||||
|
|
||||||
# Licensing and Credits
|
# Licensing and Credits
|
||||||
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
||||||
|
|
@ -273,19 +174,8 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
|
||||||
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
|
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
|
||||||
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
|
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
|
||||||
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
|
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
|
||||||
* Networking and filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
|
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
|
||||||
* DHCP server for AP host mode from the [Micropython Project](https://micropython.org), distributed under the MIT License.
|
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
|
||||||
* [FreeRTOS](https://freertos.org) is copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
|
|
||||||
* [lwIP](https://savannah.nongnu.org/projects/lwip/) is (c) the Swedish Institute of Computer Science and licenced under the BSD license.
|
|
||||||
* [BearSSL](https://bearssl.org) library written by Thomas Pornin, is distributed under the [MIT License](https://bearssl.org/#legal-details).
|
|
||||||
* [UZLib](https://github.com/pfalcon/uzlib) is copyright (c) 2003 Joergen Ibsen and distributed under the zlib license.
|
|
||||||
* [LEAmDNS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
|
|
||||||
* [http-parser](https://github.com/nodejs/http-parser) is copyright Joyent, Inc. and other Node contributors.
|
|
||||||
* WebServer code modified from the [ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and is copyright (c) 2015 Ivan Grokhotkov and others.
|
|
||||||
* [Xoshiro-cpp](https://github.com/Reputeless/Xoshiro-cpp) is copyright (c) 2020 Ryo Suzuki and distributed under the MIT license.
|
|
||||||
* [FatFS low-level filesystem](http://elm-chan.org/fsw/ff/) code is Copyright (C) 2024, ChaN, all rights reserved.
|
|
||||||
* [TLSF memory manager for PSRAM from Espressif fork](https://github.com/espressif/tlsf) of [original](https://github.com/mattconte/tlsf) by Matthew Conte is copyright Matthew Conte and licensed under the MIT license.
|
|
||||||
* [ESPHost library](https://github.com/Networking-for-Arduino/ESPHost) is LGPL licensed by its maintainers.
|
|
||||||
|
|
||||||
-Earle F. Philhower, III
|
-Earle F. Philhower, III
|
||||||
earlephilhower@yahoo.com
|
earlephilhower@yahoo.com
|
||||||
|
|
|
||||||
43322
boards.txt
43322
boards.txt
File diff suppressed because it is too large
Load diff
|
|
@ -1,23 +0,0 @@
|
||||||
// Padded and checksummed version of: generated\Winbond\W25Q32JVxQ\boot2.bin
|
|
||||||
|
|
||||||
.cpu cortex-m0plus
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x25, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
|
||||||
.byte 0x9a, 0x68, 0x01, 0x26, 0xaa, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x00, 0x23
|
|
||||||
.byte 0x64, 0x05, 0xa3, 0x60, 0x04, 0x33, 0x63, 0x61, 0x22, 0x4b, 0x28, 0x00, 0x1e, 0x60, 0xe0, 0x23
|
|
||||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa6, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
|
||||||
.byte 0xc0, 0xb2, 0xa8, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x30, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
|
||||||
.byte 0x31, 0x23, 0x28, 0x00, 0x23, 0x66, 0x25, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x35, 0x25, 0x66
|
|
||||||
.byte 0x02, 0x20, 0x25, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x30, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
|
||||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
|
||||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
|
||||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
|
||||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
|
||||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x23, 0x02, 0x00, 0x04, 0x21, 0x5b, 0x05, 0x98, 0x6a, 0x08, 0x42
|
|
||||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x18, 0x6e, 0x01, 0x2a, 0x00, 0xd0
|
|
||||||
.byte 0x18, 0x6e, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2d, 0x68, 0xca
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// Padded and checksummed version of: generated\Winbond\W25Q128JVxQ\boot2.bin by @maxgerhardt
|
|
||||||
|
|
||||||
.cpu cortex-m0plus
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x26, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
|
||||||
.byte 0x9a, 0x68, 0x00, 0x27, 0xb2, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x04, 0x23
|
|
||||||
.byte 0x01, 0x25, 0x64, 0x05, 0xa7, 0x60, 0x63, 0x61, 0x22, 0x4b, 0x30, 0x00, 0x1d, 0x60, 0xe0, 0x23
|
|
||||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa5, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
|
||||||
.byte 0xc0, 0xb2, 0xb0, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x28, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
|
||||||
.byte 0x25, 0x66, 0x03, 0x20, 0x27, 0x66, 0x26, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x36, 0x26, 0x66
|
|
||||||
.byte 0x02, 0x20, 0x26, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x28, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
|
||||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
|
||||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
|
||||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
|
||||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
|
||||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x22, 0x03, 0x00, 0x04, 0x21, 0x52, 0x05, 0x90, 0x6a, 0x08, 0x42
|
|
||||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x90, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x01, 0x3b, 0xdb, 0xb2, 0x10, 0x6e
|
|
||||||
.byte 0x00, 0x2b, 0xfa, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xa0, 0xf0, 0x2f
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// Padded and checksummed version of: generated\Winbond\W25Q16JVxQ\boot2.bin
|
|
||||||
|
|
||||||
.cpu cortex-m0plus
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x26, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
|
||||||
.byte 0x9a, 0x68, 0x00, 0x27, 0xb2, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x04, 0x23
|
|
||||||
.byte 0x01, 0x25, 0x64, 0x05, 0xa7, 0x60, 0x63, 0x61, 0x22, 0x4b, 0x30, 0x00, 0x1d, 0x60, 0xe0, 0x23
|
|
||||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa5, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
|
||||||
.byte 0xc0, 0xb2, 0xb0, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x28, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
|
||||||
.byte 0x25, 0x66, 0x03, 0x20, 0x27, 0x66, 0x26, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x36, 0x26, 0x66
|
|
||||||
.byte 0x02, 0x20, 0x26, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x28, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
|
||||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
|
||||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
|
||||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
|
||||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
|
||||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x22, 0x03, 0x00, 0x04, 0x21, 0x52, 0x05, 0x90, 0x6a, 0x08, 0x42
|
|
||||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x90, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x01, 0x3b, 0xdb, 0xb2, 0x10, 0x6e
|
|
||||||
.byte 0x00, 0x2b, 0xfa, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xa0, 0xf0, 0x2f
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// Padded and checksummed version of: boot2_w25q64jv.4.bin
|
|
||||||
|
|
||||||
.cpu cortex-m0plus
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x25, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
|
||||||
.byte 0x9a, 0x68, 0x01, 0x26, 0xaa, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x00, 0x23
|
|
||||||
.byte 0x64, 0x05, 0xa3, 0x60, 0x04, 0x33, 0x63, 0x61, 0x22, 0x4b, 0x28, 0x00, 0x1e, 0x60, 0xe0, 0x23
|
|
||||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa6, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
|
||||||
.byte 0xc0, 0xb2, 0xa8, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x30, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
|
||||||
.byte 0x31, 0x23, 0x28, 0x00, 0x23, 0x66, 0x25, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x35, 0x25, 0x66
|
|
||||||
.byte 0x02, 0x20, 0x25, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x30, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
|
||||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
|
||||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
|
||||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
|
||||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
|
||||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
|
||||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x23, 0x02, 0x00, 0x04, 0x21, 0x5b, 0x05, 0x98, 0x6a, 0x08, 0x42
|
|
||||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x18, 0x6e, 0x01, 0x2a, 0x00, 0xd0
|
|
||||||
.byte 0x18, 0x6e, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2d, 0x68, 0xca
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.global __boot2_entry_point
|
|
||||||
__boot2_entry_point:
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
.section .boot2, "ax"
|
|
||||||
|
|
||||||
.global __boot2_entry_point
|
|
||||||
__boot2_entry_point:
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef Arduino_h
|
||||||
|
#define Arduino_h
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -27,22 +28,10 @@
|
||||||
#include "RP2040Version.h"
|
#include "RP2040Version.h"
|
||||||
#include "api/ArduinoAPI.h"
|
#include "api/ArduinoAPI.h"
|
||||||
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
||||||
#include <pico.h>
|
|
||||||
#undef PICO_RP2350A // Set in the RP2350 SDK boards file, overridden in the variant pins_arduino.h
|
|
||||||
#include <pins_arduino.h>
|
#include <pins_arduino.h>
|
||||||
#include <hardware/gpio.h> // Required for the port*Register macros
|
#include "hardware/gpio.h" // Required for the port*Register macros
|
||||||
#include "debug_internal.h"
|
#include "debug_internal.h"
|
||||||
|
#include <RP2040.h> // CMSIS
|
||||||
// Chip sanity checking. SDK uses interesting way of separating 2350A from 2350B, see https://github.com/raspberrypi/pico-sdk/issues/2364
|
|
||||||
#if (!defined(PICO_RP2040) && !defined(PICO_RP2350)) || defined(PICO_RP2040) && defined(PICO_RP2350)
|
|
||||||
#error Invalid core definition. Either PICO_RP2040 or PICO_RP2350 must be defined.
|
|
||||||
#endif
|
|
||||||
#if defined(PICO_RP2350) && !defined(PICO_RP2350A)
|
|
||||||
#error Invalid RP2350 definition. Need to set PICO_RP2350A=0/1 for A/B variant
|
|
||||||
#endif
|
|
||||||
#if defined(PICO_RP2350B)
|
|
||||||
#error Do not define PICO_RP2350B. Use PICO_RP2350A=0 to indicate RP2350B. See the SDK for more details
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Try and make the best of the old Arduino abs() macro. When in C++, use
|
// Try and make the best of the old Arduino abs() macro. When in C++, use
|
||||||
// the sane std::abs() call, but for C code use their macro since stdlib abs()
|
// the sane std::abs() call, but for C code use their macro since stdlib abs()
|
||||||
|
|
@ -50,7 +39,7 @@
|
||||||
#ifdef abs
|
#ifdef abs
|
||||||
#undef abs
|
#undef abs
|
||||||
#endif // abs
|
#endif // abs
|
||||||
#if defined(__cplusplus) && !defined(__riscv)
|
#ifdef __cplusplus
|
||||||
using std::abs;
|
using std::abs;
|
||||||
using std::round;
|
using std::round;
|
||||||
#else
|
#else
|
||||||
|
|
@ -71,66 +60,39 @@ extern "C" {
|
||||||
void interrupts();
|
void interrupts();
|
||||||
void noInterrupts();
|
void noInterrupts();
|
||||||
|
|
||||||
// Only implemented on some RP2350 boards, not the OG Pico 2
|
|
||||||
#ifdef RP2350_PSRAM_CS
|
|
||||||
void *pmalloc(size_t size);
|
|
||||||
void *pcalloc(size_t count, size_t size);
|
|
||||||
#else
|
|
||||||
[[deprecated("This chip does not have PSRAM, pmalloc will always fail")]] void *pmalloc(size_t size);
|
|
||||||
[[deprecated("This chip does not have PSRAM, pcalloc will always fail")]] void *pcalloc(size_t count, size_t size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// AVR compatibility macros...naughty and accesses the HW directly
|
// AVR compatibility macros...naughty and accesses the HW directly
|
||||||
#define digitalPinToPort(pin) (0)
|
#define digitalPinToPort(pin) (0)
|
||||||
#define digitalPinToBitMask(pin) (1UL << (pin))
|
#define digitalPinToBitMask(pin) (1UL << (pin))
|
||||||
#define digitalPinToTimer(pin) (0)
|
#define digitalPinToTimer(pin) (0)
|
||||||
#define digitalPinToInterrupt(pin) (pin)
|
#define digitalPinToInterrupt(pin) (pin)
|
||||||
#define NOT_AN_INTERRUPT (-1)
|
#define NOT_AN_INTERRUPT (-1)
|
||||||
#define portOutputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_out))
|
#define portOutputRegister(port) ((volatile uint32_t*) sio_hw->gpio_out)
|
||||||
#define portInputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_in))
|
#define portInputRegister(port) ((volatile uint32_t*) sio_hw->gpio_in)
|
||||||
#define portModeRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_oe))
|
#define portModeRegister(port) ((volatile uint32_t*) sio_hw->gpio_oe)
|
||||||
#define digitalWriteFast(pin, val) (val ? sio_hw->gpio_set = (1 << pin) : sio_hw->gpio_clr = (1 << pin))
|
|
||||||
#define digitalReadFast(pin) ((1 << pin) & sio_hw->gpio_in)
|
|
||||||
#define sei() interrupts()
|
|
||||||
#define cli() noInterrupts()
|
|
||||||
|
|
||||||
// ADC RP2040-specific calls
|
// ADC RP2040-specific calls
|
||||||
void analogReadResolution(int bits);
|
void analogReadResolution(int bits);
|
||||||
#ifdef __cplusplus
|
float analogReadTemp(); // Returns core temp in Centigrade
|
||||||
float analogReadTemp(float vref = 3.3); // Returns core temp in Centigrade
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// PWM RP2040-specific calls
|
// PWM RP2040-specific calls
|
||||||
void analogWriteFreq(uint32_t freq);
|
void analogWriteFreq(uint32_t freq);
|
||||||
void analogWriteRange(uint32_t range);
|
void analogWriteRange(uint32_t range);
|
||||||
void analogWriteResolution(int res);
|
void analogWriteResolution(int res);
|
||||||
|
|
||||||
|
// FreeRTOS potential calls
|
||||||
|
extern bool __isFreeRTOS;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// FreeRTOS potential calls
|
|
||||||
extern bool __isFreeRTOS;
|
|
||||||
|
|
||||||
// Ancient AVR defines
|
// Ancient AVR defines
|
||||||
#define HAVE_HWSERIAL0
|
#define HAVE_HWSERIAL0
|
||||||
#define HAVE_HWSERIAL1
|
#define HAVE_HWSERIAL1
|
||||||
#define HAVE_HWSERIAL2
|
#define HAVE_HWSERIAL2
|
||||||
|
|
||||||
// PSTR/etc.
|
|
||||||
#ifndef FPSTR
|
|
||||||
#define FPSTR (const char *)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PGM_VOID_P
|
|
||||||
#define PGM_VOID_P const void *
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
// emptyString is an ESP-ism, a constant string with ""
|
|
||||||
extern const String emptyString;
|
|
||||||
|
|
||||||
#ifdef USE_TINYUSB
|
#ifdef USE_TINYUSB
|
||||||
// Needed for declaring Serial
|
// Needed for declaring Serial
|
||||||
#include "Adafruit_USBD_CDC.h"
|
#include "Adafruit_USBD_CDC.h"
|
||||||
|
|
@ -139,7 +101,6 @@ extern const String emptyString;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "SerialUART.h"
|
#include "SerialUART.h"
|
||||||
#include "SerialSemi.h"
|
|
||||||
#include "RP2040Support.h"
|
#include "RP2040Support.h"
|
||||||
#include "SerialPIO.h"
|
#include "SerialPIO.h"
|
||||||
#include "Bootsel.h"
|
#include "Bootsel.h"
|
||||||
|
|
@ -147,32 +108,9 @@ extern const String emptyString;
|
||||||
// Template which will evaluate at *compile time* to a single 32b number
|
// Template which will evaluate at *compile time* to a single 32b number
|
||||||
// with the specified bits set.
|
// with the specified bits set.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
|
constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||||
return i < N ? (1LL << a[i]) | __bitset(a, i + 1) : 0;
|
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Warn users trying to use Pico SDK's STDIO implementation
|
#endif // Arduino_h
|
||||||
#include <pico/stdio.h> // Ensure it won't be re-included elsewhere
|
|
||||||
#undef stdio_uart_init
|
|
||||||
#define stdio_uart_init(...) static_assert(0, "stdio_uart_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
|
||||||
#undef stdio_init_all
|
|
||||||
#define stdio_init_all(...) static_assert(0, "stdio_init_all is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
|
||||||
#undef stdio_usb_init
|
|
||||||
#define stdio_usb_init(...) static_assert(0, "stdio_usb_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
|
||||||
|
|
||||||
// PSRAM decorator
|
|
||||||
#define PSRAM __attribute__((section("\".psram\"")))
|
|
||||||
|
|
||||||
// General GPIO/ADC layout info
|
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A
|
|
||||||
#define __GPIOCNT 48
|
|
||||||
#define __FIRSTANALOGGPIO 40
|
|
||||||
#else
|
|
||||||
#define __GPIOCNT 30
|
|
||||||
#define __FIRSTANALOGGPIO 26
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
using namespace arduino;
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// Abstract class for audio output devices to allow easy swapping between output devices
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Print.h>
|
|
||||||
|
|
||||||
class AudioOutputBase : public Print {
|
|
||||||
public:
|
|
||||||
virtual ~AudioOutputBase() { }
|
|
||||||
virtual bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0) = 0;
|
|
||||||
virtual bool setBitsPerSample(int bps) = 0;
|
|
||||||
virtual bool setFrequency(int freq) = 0;
|
|
||||||
virtual bool setStereo(bool stereo = true) = 0;
|
|
||||||
virtual bool begin() = 0;
|
|
||||||
virtual bool end() = 0;
|
|
||||||
virtual bool getUnderflow() = 0;
|
|
||||||
virtual void onTransmit(void(*)(void *), void *) = 0;
|
|
||||||
// From Print
|
|
||||||
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
|
||||||
virtual int availableForWrite() = 0;
|
|
||||||
};
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
Enable BTStack debugging to a Print-able object
|
|
||||||
|
|
||||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ENABLE_CLASSIC) || defined(ENABLE_BLE)
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <btstack.h>
|
|
||||||
#include <hci_dump.h>
|
|
||||||
|
|
||||||
static Print *_print;
|
|
||||||
|
|
||||||
static void _log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
|
|
||||||
if (!_print) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_print->printf("[BT @%lu] ", millis());
|
|
||||||
|
|
||||||
switch (packet_type) {
|
|
||||||
case HCI_COMMAND_DATA_PACKET:
|
|
||||||
_print->printf("CMD => ");
|
|
||||||
break;
|
|
||||||
case HCI_EVENT_PACKET:
|
|
||||||
_print->printf("EVT <= ");
|
|
||||||
break;
|
|
||||||
case HCI_ACL_DATA_PACKET:
|
|
||||||
_print->printf("ACL %s ", in ? "<=" : "=>");
|
|
||||||
break;
|
|
||||||
case HCI_SCO_DATA_PACKET:
|
|
||||||
_print->printf("SCO %s ", in ? "<=" : "=>");
|
|
||||||
break;
|
|
||||||
case HCI_ISO_DATA_PACKET:
|
|
||||||
_print->printf("ISO %s ", in ? "<=" : "=>");
|
|
||||||
break;
|
|
||||||
case LOG_MESSAGE_PACKET:
|
|
||||||
_print->printf("LOG -- %s\n", (char*) packet);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
_print->printf("UNK(%x) %s ", packet_type, in ? "<=" : "=>");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < len; i++) {
|
|
||||||
_print->printf("%02X ", packet[i]);
|
|
||||||
}
|
|
||||||
_print->printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _log_message(int log_level, const char * format, va_list argptr) {
|
|
||||||
(void)log_level;
|
|
||||||
char log_message_buffer[HCI_DUMP_MAX_MESSAGE_LEN];
|
|
||||||
if (!_print) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
|
|
||||||
_print->printf("[BT @%lu] LOG -- %s\n", millis(), log_message_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const hci_dump_t hci_dump_instance = {
|
|
||||||
NULL,
|
|
||||||
_log_packet,
|
|
||||||
_log_message
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void __EnableBluetoothDebug(Print &print) {
|
|
||||||
_print = &print;
|
|
||||||
hci_dump_init(&hci_dump_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
SPDX-License-Identifier: BSD-3-Clause
|
SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <pico/stdlib.h>
|
#include "pico/stdlib.h"
|
||||||
#include <hardware/gpio.h>
|
#include "hardware/gpio.h"
|
||||||
#include <hardware/sync.h>
|
#include "hardware/sync.h"
|
||||||
#include <hardware/structs/ioqspi.h>
|
#include "hardware/structs/ioqspi.h"
|
||||||
#include <hardware/structs/sio.h>
|
#include "hardware/structs/sio.h"
|
||||||
|
|
||||||
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
||||||
//
|
//
|
||||||
|
|
@ -26,9 +26,7 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
|
|
||||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||||
// are about to temporarily disable flash access!
|
// are about to temporarily disable flash access!
|
||||||
if (!__isFreeRTOS) {
|
noInterrupts();
|
||||||
noInterrupts();
|
|
||||||
}
|
|
||||||
rp2040.idleOtherCore();
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
// Set chip select to Hi-Z
|
// Set chip select to Hi-Z
|
||||||
|
|
@ -41,12 +39,7 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
|
|
||||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||||
// Note the button pulls the pin *low* when pressed.
|
// Note the button pulls the pin *low* when pressed.
|
||||||
#if PICO_RP2040
|
bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
||||||
#define CS_BIT (1u << 1)
|
|
||||||
#else
|
|
||||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
|
||||||
#endif
|
|
||||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
|
||||||
|
|
||||||
// Need to restore the state of chip select, else we are going to have a
|
// Need to restore the state of chip select, else we are going to have a
|
||||||
// bad time when we return to code in flash!
|
// bad time when we return to code in flash!
|
||||||
|
|
@ -55,9 +48,7 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||||
|
|
||||||
rp2040.resumeOtherCore();
|
rp2040.resumeOtherCore();
|
||||||
if (!__isFreeRTOS) {
|
interrupts();
|
||||||
interrupts();
|
|
||||||
}
|
|
||||||
|
|
||||||
return button_state;
|
return button_state;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Wrapper class for polling the BOOTSEL button
|
|
||||||
*/
|
|
||||||
class __Bootsel {
|
class __Bootsel {
|
||||||
public:
|
public:
|
||||||
__Bootsel() { }
|
__Bootsel() { }
|
||||||
/**
|
|
||||||
@brief Get state of the BOOTSEL pin
|
|
||||||
|
|
||||||
@returns True if BOOTSEL pushed
|
|
||||||
*/
|
|
||||||
operator bool();
|
operator bool();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
@brief BOOTSEL accessor instance
|
|
||||||
*/
|
|
||||||
extern __Bootsel BOOTSEL;
|
extern __Bootsel BOOTSEL;
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
CoreMutex for the Raspberry Pi Pico RP2040
|
|
||||||
|
|
||||||
Implements a deadlock-safe multicore mutex for sharing things like the
|
|
||||||
USB or UARTs.
|
|
||||||
|
|
||||||
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "CoreMutex.h"
|
|
||||||
|
|
||||||
CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
|
|
||||||
_mutex = mutex;
|
|
||||||
_acquired = false;
|
|
||||||
_option = option;
|
|
||||||
_pxHigherPriorityTaskWoken = 0; // pdFALSE
|
|
||||||
if (__isFreeRTOS) {
|
|
||||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
|
||||||
|
|
||||||
if (__freertos_check_if_in_isr()) {
|
|
||||||
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// At this point we have the mutex in ISR
|
|
||||||
} else {
|
|
||||||
// Grab the mutex normally, possibly waking other tasks to get it
|
|
||||||
__freertos_mutex_take(m);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t owner;
|
|
||||||
if (!mutex_try_enter(_mutex, &owner)) {
|
|
||||||
if (owner == get_core_num()) { // Deadlock!
|
|
||||||
if (_option & DebugEnable) {
|
|
||||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutex_enter_blocking(_mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_acquired = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreMutex::~CoreMutex() {
|
|
||||||
if (_acquired) {
|
|
||||||
if (__isFreeRTOS) {
|
|
||||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
|
||||||
if (__freertos_check_if_in_isr()) {
|
|
||||||
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
|
|
||||||
} else {
|
|
||||||
__freertos_mutex_give(m);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mutex_exit(_mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -23,17 +23,29 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pico/mutex.h>
|
#include "pico/mutex.h"
|
||||||
#include "_freertos.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DebugEnable = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
class CoreMutex {
|
class CoreMutex {
|
||||||
public:
|
public:
|
||||||
CoreMutex(mutex_t *mutex, uint8_t option = DebugEnable);
|
CoreMutex(mutex_t *mutex) {
|
||||||
~CoreMutex();
|
uint32_t owner;
|
||||||
|
_mutex = mutex;
|
||||||
|
_acquired = false;
|
||||||
|
if (!mutex_try_enter(_mutex, &owner)) {
|
||||||
|
if (owner == get_core_num()) { // Deadlock!
|
||||||
|
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_enter_blocking(_mutex);
|
||||||
|
}
|
||||||
|
_acquired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CoreMutex() {
|
||||||
|
if (_acquired) {
|
||||||
|
mutex_exit(_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
return _acquired;
|
return _acquired;
|
||||||
|
|
@ -42,6 +54,4 @@ public:
|
||||||
private:
|
private:
|
||||||
mutex_t *_mutex;
|
mutex_t *_mutex;
|
||||||
bool _acquired;
|
bool _acquired;
|
||||||
uint8_t _option;
|
|
||||||
BaseType_t _pxHigherPriorityTaskWoken;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -192,12 +192,13 @@ File File::openNextFile() {
|
||||||
String File::readString() {
|
String File::readString() {
|
||||||
String ret;
|
String ret;
|
||||||
ret.reserve(size() - position());
|
ret.reserve(size() - position());
|
||||||
uint8_t temp[256];
|
char temp[256 + 1];
|
||||||
int countRead;
|
int countRead = readBytes(temp, sizeof(temp) - 1);
|
||||||
do {
|
while (countRead > 0) {
|
||||||
countRead = read(temp, sizeof(temp));
|
temp[countRead] = 0;
|
||||||
ret.concat(temp, countRead);
|
ret += temp;
|
||||||
} while (countRead > 0);
|
countRead = readBytes(temp, sizeof(temp) - 1);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,21 +226,6 @@ void File::setTimeCallback(time_t (*cb)(void)) {
|
||||||
_timeCallback = cb;
|
_timeCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::stat(FSStat *st) {
|
|
||||||
if (!_p) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t pos = position();
|
|
||||||
seek(0, SeekEnd);
|
|
||||||
st->size = position() - pos;
|
|
||||||
seek(pos, SeekSet);
|
|
||||||
st->blocksize = 0; // Not set here
|
|
||||||
st->ctime = getCreationTime();
|
|
||||||
st->atime = getLastWrite();
|
|
||||||
st->isDir = isDirectory();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
File Dir::openFile(const char* mode) {
|
File Dir::openFile(const char* mode) {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return File();
|
return File();
|
||||||
|
|
@ -381,6 +367,13 @@ bool FS::info(FSInfo& info) {
|
||||||
return _impl->info(info);
|
return _impl->info(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FS::info64(FSInfo64& info) {
|
||||||
|
if (!_impl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _impl->info64(info);
|
||||||
|
}
|
||||||
|
|
||||||
File FS::open(const String& path, const char* mode) {
|
File FS::open(const String& path, const char* mode) {
|
||||||
return open(path.c_str(), mode);
|
return open(path.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
@ -470,17 +463,6 @@ bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::stat(const char *path, FSStat *st) {
|
|
||||||
if (!_impl) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _impl->stat(path, st);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FS::stat(const String& path, FSStat *st) {
|
|
||||||
return stat(path.c_str(), st);
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t FS::getCreationTime() {
|
time_t FS::getCreationTime() {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef FS_H
|
||||||
|
#define FS_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
@ -48,19 +49,9 @@ enum SeekMode {
|
||||||
SeekEnd = 2
|
SeekEnd = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FSStat {
|
|
||||||
size_t size;
|
|
||||||
size_t blocksize;
|
|
||||||
time_t ctime;
|
|
||||||
time_t atime;
|
|
||||||
bool isDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
class File : public Stream {
|
class File : public Stream {
|
||||||
public:
|
public:
|
||||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
|
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }
|
||||||
_startMillis = millis(); /* workaround -O3 spurious warning #768 */
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print methods:
|
// Print methods:
|
||||||
size_t write(uint8_t) override;
|
size_t write(uint8_t) override;
|
||||||
|
|
@ -100,8 +91,9 @@ public:
|
||||||
uint8_t obuf[256];
|
uint8_t obuf[256];
|
||||||
size_t doneLen = 0;
|
size_t doneLen = 0;
|
||||||
size_t sentLen;
|
size_t sentLen;
|
||||||
|
int i;
|
||||||
|
|
||||||
while ((size_t)src.available() > sizeof(obuf)) {
|
while (src.available() > sizeof(obuf)) {
|
||||||
src.read(obuf, sizeof(obuf));
|
src.read(obuf, sizeof(obuf));
|
||||||
sentLen = write(obuf, sizeof(obuf));
|
sentLen = write(obuf, sizeof(obuf));
|
||||||
doneLen = doneLen + sentLen;
|
doneLen = doneLen + sentLen;
|
||||||
|
|
@ -127,8 +119,6 @@ public:
|
||||||
time_t getCreationTime();
|
time_t getCreationTime();
|
||||||
void setTimeCallback(time_t (*cb)(void));
|
void setTimeCallback(time_t (*cb)(void));
|
||||||
|
|
||||||
bool stat(FSStat *st);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileImplPtr _p;
|
FileImplPtr _p;
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
|
|
@ -162,8 +152,18 @@ protected:
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Support > 4GB filesystems (SD, etc.)
|
// Backwards compatible, <4GB filesystem usage
|
||||||
struct FSInfo {
|
struct FSInfo {
|
||||||
|
size_t totalBytes;
|
||||||
|
size_t usedBytes;
|
||||||
|
size_t blockSize;
|
||||||
|
size_t pageSize;
|
||||||
|
size_t maxOpenFiles;
|
||||||
|
size_t maxPathLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Support > 4GB filesystems (SD, etc.)
|
||||||
|
struct FSInfo64 {
|
||||||
uint64_t totalBytes;
|
uint64_t totalBytes;
|
||||||
uint64_t usedBytes;
|
uint64_t usedBytes;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
|
|
@ -172,6 +172,7 @@ struct FSInfo {
|
||||||
size_t maxPathLength;
|
size_t maxPathLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class FSConfig {
|
class FSConfig {
|
||||||
public:
|
public:
|
||||||
static constexpr uint32_t FSId = 0x00000000;
|
static constexpr uint32_t FSId = 0x00000000;
|
||||||
|
|
@ -200,6 +201,7 @@ public:
|
||||||
|
|
||||||
bool format();
|
bool format();
|
||||||
bool info(FSInfo& info);
|
bool info(FSInfo& info);
|
||||||
|
bool info64(FSInfo64& info);
|
||||||
|
|
||||||
File open(const char* path, const char* mode);
|
File open(const char* path, const char* mode);
|
||||||
File open(const String& path, const char* mode);
|
File open(const String& path, const char* mode);
|
||||||
|
|
@ -222,9 +224,6 @@ public:
|
||||||
bool rmdir(const char* path);
|
bool rmdir(const char* path);
|
||||||
bool rmdir(const String& path);
|
bool rmdir(const String& path);
|
||||||
|
|
||||||
bool stat(const char *path, FSStat *st);
|
|
||||||
bool stat(const String& path, FSStat *st);
|
|
||||||
|
|
||||||
// Low-level FS routines, not needed by most applications
|
// Low-level FS routines, not needed by most applications
|
||||||
bool gc();
|
bool gc();
|
||||||
bool check();
|
bool check();
|
||||||
|
|
@ -241,7 +240,7 @@ protected:
|
||||||
}
|
}
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
static time_t _defaultTimeCB(void) {
|
static time_t _defaultTimeCB(void) {
|
||||||
return time(nullptr);
|
return time(NULL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -265,3 +264,5 @@ using fs::SeekEnd;
|
||||||
using fs::FSInfo;
|
using fs::FSInfo;
|
||||||
using fs::FSConfig;
|
using fs::FSConfig;
|
||||||
#endif //FS_NO_GLOBALS
|
#endif //FS_NO_GLOBALS
|
||||||
|
|
||||||
|
#endif //FS_H
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
#ifndef FSIMPL_H
|
||||||
#pragma once
|
#define FSIMPL_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -119,6 +119,7 @@ public:
|
||||||
virtual void end() = 0;
|
virtual void end() = 0;
|
||||||
virtual bool format() = 0;
|
virtual bool format() = 0;
|
||||||
virtual bool info(FSInfo& info) = 0;
|
virtual bool info(FSInfo& info) = 0;
|
||||||
|
virtual bool info64(FSInfo64& info) = 0;
|
||||||
virtual FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) = 0;
|
virtual FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) = 0;
|
||||||
virtual bool exists(const char* path) = 0;
|
virtual bool exists(const char* path) = 0;
|
||||||
virtual DirImplPtr openDir(const char* path) = 0;
|
virtual DirImplPtr openDir(const char* path) = 0;
|
||||||
|
|
@ -126,7 +127,6 @@ public:
|
||||||
virtual bool remove(const char* path) = 0;
|
virtual bool remove(const char* path) = 0;
|
||||||
virtual bool mkdir(const char* path) = 0;
|
virtual bool mkdir(const char* path) = 0;
|
||||||
virtual bool rmdir(const char* path) = 0;
|
virtual bool rmdir(const char* path) = 0;
|
||||||
virtual bool stat(const char *path, FSStat *st) = 0;
|
|
||||||
virtual bool gc() {
|
virtual bool gc() {
|
||||||
return true; // May not be implemented in all file systems.
|
return true; // May not be implemented in all file systems.
|
||||||
}
|
}
|
||||||
|
|
@ -149,3 +149,5 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
|
#endif //FSIMPL_H
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
#include "api/IPAddress.h"
|
#include "api/IPAddress.h"
|
||||||
using arduino::IPAddress;
|
|
||||||
|
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
/*
|
|
||||||
RP2040 PIO utility class
|
|
||||||
|
|
||||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "PIOProgram.h"
|
|
||||||
#include <map>
|
|
||||||
#include <hardware/claim.h>
|
|
||||||
|
|
||||||
#if defined(PICO_RP2350)
|
|
||||||
#define PIOS pio0, pio1, pio2
|
|
||||||
#define PIOCNT 3
|
|
||||||
#elif defined(PICO_RP2040)
|
|
||||||
#define PIOS pio0, pio1
|
|
||||||
#define PIOCNT 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static std::map<const pio_program_t *, int> __pioMap[PIOCNT];
|
|
||||||
static bool __pioAllocated[PIOCNT];
|
|
||||||
auto_init_mutex(_pioMutex);
|
|
||||||
|
|
||||||
PIOProgram::PIOProgram(const pio_program_t *pgm) {
|
|
||||||
_pgm = pgm;
|
|
||||||
_pio = nullptr;
|
|
||||||
_sm = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We leave the INSN loaded in INSN RAM
|
|
||||||
PIOProgram::~PIOProgram() {
|
|
||||||
if (_pio) {
|
|
||||||
pio_sm_unclaim(_pio, _sm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possibly load into a PIO and allocate a SM
|
|
||||||
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
|
|
||||||
CoreMutex m(&_pioMutex);
|
|
||||||
PIO pi[PIOCNT] = { PIOS };
|
|
||||||
|
|
||||||
uint gpioBaseNeeded = ((start + cnt) >= 32) ? 16 : 0;
|
|
||||||
DEBUGV("PIOProgram %p: Searching for base=%d, pins %d-%d\n", _pgm, gpioBaseNeeded, start, start + cnt - 1);
|
|
||||||
|
|
||||||
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
|
|
||||||
for (int o = 0; o < PIOCNT; o++) {
|
|
||||||
auto p = __pioMap[o].find(_pgm);
|
|
||||||
if ((p != __pioMap[o].end()) && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
|
|
||||||
int idx = pio_claim_unused_sm(pi[o], false);
|
|
||||||
if (idx >= 0) {
|
|
||||||
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
|
||||||
_pio = pi[o];
|
|
||||||
_sm = idx;
|
|
||||||
*pio = pi[o];
|
|
||||||
*sm = idx;
|
|
||||||
*offset = p->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not in any PIO IRAM, so try and add
|
|
||||||
for (int o = 0; o < PIOCNT; o++) {
|
|
||||||
if (__pioAllocated[o] && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
|
|
||||||
DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]);
|
|
||||||
if (pio_can_add_program(pi[o], _pgm)) {
|
|
||||||
int idx = pio_claim_unused_sm(pi[o], false);
|
|
||||||
if (idx >= 0) {
|
|
||||||
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
|
||||||
int off = pio_add_program(pi[o], _pgm);
|
|
||||||
__pioMap[o].insert({_pgm, off});
|
|
||||||
_pio = pi[o];
|
|
||||||
_sm = idx;
|
|
||||||
*pio = pi[o];
|
|
||||||
*sm = idx;
|
|
||||||
*offset = off;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
DEBUGV("PIOProgram: can't claim unused SM\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUGV("PIOProgram: can't add program\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUGV("PIOProgram: Skipping PIO %p, wrong allocated/needhi\n", pi[o]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No existing PIOs can meet, is there an unallocated one we can allocate?
|
|
||||||
PIO p;
|
|
||||||
uint idx;
|
|
||||||
uint off;
|
|
||||||
auto rc = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, &p, &idx, &off, start, cnt, true);
|
|
||||||
if (rc) {
|
|
||||||
int o = 0;
|
|
||||||
while (p != pi[o]) {
|
|
||||||
o++;
|
|
||||||
}
|
|
||||||
assert(!__pioAllocated[o]);
|
|
||||||
__pioAllocated[o] = true;
|
|
||||||
DEBUGV("PIOProgram %p: Allocating new PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
|
||||||
__pioMap[o].insert({_pgm, off});
|
|
||||||
_pio = pi[o];
|
|
||||||
_sm = idx;
|
|
||||||
*pio = pi[o];
|
|
||||||
*sm = idx;
|
|
||||||
*offset = off;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nope, no room either for SMs or INSNs
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
RP2040 PIO utility class
|
|
||||||
|
|
||||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hardware/pio.h>
|
|
||||||
|
|
||||||
// Wrapper class for PIO programs, abstracting common operations out
|
|
||||||
class PIOProgram {
|
|
||||||
public:
|
|
||||||
PIOProgram(const pio_program_t *pgm);
|
|
||||||
~PIOProgram();
|
|
||||||
// Possibly load into a PIO and allocate a SM
|
|
||||||
bool prepare(PIO *pio, int *sm, int *offset, int gpio_start = 0, int gpio_cnt = 1);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const pio_program_t *_pgm;
|
|
||||||
PIO _pio;
|
|
||||||
int _sm;
|
|
||||||
};
|
|
||||||
|
|
@ -1,290 +0,0 @@
|
||||||
/*
|
|
||||||
PolledTimeout.h - Encapsulation of a polled Timeout
|
|
||||||
|
|
||||||
Copyright (c) 2018 Daniel Salazar. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <limits> // std::numeric_limits
|
|
||||||
#include <type_traits> // std::is_unsigned
|
|
||||||
|
|
||||||
#define IRAM_ATTR
|
|
||||||
|
|
||||||
namespace esp8266 {
|
|
||||||
|
|
||||||
|
|
||||||
namespace polledTimeout {
|
|
||||||
|
|
||||||
namespace YieldPolicy {
|
|
||||||
|
|
||||||
struct DoNothing {
|
|
||||||
static void execute() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct YieldOrSkip {
|
|
||||||
static void execute() {} //{esp_yield();}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <unsigned long delayMs>
|
|
||||||
struct YieldAndDelayMs {
|
|
||||||
static void execute() {
|
|
||||||
delay(delayMs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} //YieldPolicy
|
|
||||||
|
|
||||||
namespace TimePolicy {
|
|
||||||
|
|
||||||
struct TimeSourceMillis {
|
|
||||||
// time policy in milli-seconds based on millis()
|
|
||||||
|
|
||||||
using timeType = decltype(millis());
|
|
||||||
static timeType time() {
|
|
||||||
return millis();
|
|
||||||
}
|
|
||||||
static constexpr timeType ticksPerSecond = 1000;
|
|
||||||
static constexpr timeType ticksPerSecondMax = 1000;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TimeSourceCycles {
|
|
||||||
// time policy based on esp_get_cycle_count()
|
|
||||||
// this particular time measurement is intended to be called very often
|
|
||||||
// (every loop, every yield)
|
|
||||||
|
|
||||||
using timeType = decltype(rp2040.getCycleCount());
|
|
||||||
static timeType time() {
|
|
||||||
return rp2040.getCycleCount();
|
|
||||||
}
|
|
||||||
static constexpr timeType ticksPerSecond = F_CPU;
|
|
||||||
static constexpr timeType ticksPerSecondMax = F_CPU;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TimeSourceType, unsigned long long second_th>
|
|
||||||
// "second_th" units of timeType for one second
|
|
||||||
struct TimeUnit {
|
|
||||||
using timeType = typename TimeSourceType::timeType;
|
|
||||||
|
|
||||||
#if __GNUC__ < 5
|
|
||||||
// gcc-4.8 cannot compile the constexpr-only version of this function
|
|
||||||
// using #defines instead luckily works
|
|
||||||
static constexpr timeType computeRangeCompensation() {
|
|
||||||
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
|
|
||||||
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
|
|
||||||
|
|
||||||
return ({
|
|
||||||
fractional == 0 ?
|
|
||||||
1 : // no need for compensation
|
|
||||||
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
|
||||||
});
|
|
||||||
|
|
||||||
#undef number_of_secondTh_in_one_tick
|
|
||||||
#undef fractional
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static constexpr timeType computeRangeCompensation() {
|
|
||||||
return ({
|
|
||||||
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
|
|
||||||
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
|
|
||||||
fractional == 0 ?
|
|
||||||
1 : // no need for compensation
|
|
||||||
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
|
|
||||||
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
|
|
||||||
static constexpr timeType rangeCompensate = computeRangeCompensation();
|
|
||||||
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
|
|
||||||
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
|
|
||||||
static constexpr timeType user2UnitDivider = rangeCompensate;
|
|
||||||
// std::numeric_limits<timeType>::max() is reserved
|
|
||||||
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
|
||||||
|
|
||||||
static timeType toTimeTypeUnit(const timeType userUnit) {
|
|
||||||
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
|
|
||||||
}
|
|
||||||
static timeType toUserUnit(const timeType internalUnit) {
|
|
||||||
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
|
|
||||||
}
|
|
||||||
static timeType time() {
|
|
||||||
return TimeSourceType::time();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using TimeMillis = TimeUnit < TimeSourceMillis, 1'000 >;
|
|
||||||
using TimeFastMillis = TimeUnit < TimeSourceCycles, 1'000 >;
|
|
||||||
using TimeFastMicros = TimeUnit < TimeSourceCycles, 1'000'000 >;
|
|
||||||
using TimeFastNanos = TimeUnit < TimeSourceCycles, 1'000'000'000 >;
|
|
||||||
|
|
||||||
} //TimePolicy
|
|
||||||
|
|
||||||
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
|
|
||||||
class timeoutTemplate {
|
|
||||||
public:
|
|
||||||
using timeType = typename TimePolicyT::timeType;
|
|
||||||
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
|
|
||||||
|
|
||||||
static constexpr timeType alwaysExpired = 0;
|
|
||||||
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
|
|
||||||
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
|
|
||||||
|
|
||||||
timeoutTemplate(const timeType userTimeout) {
|
|
||||||
reset(userTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
IRAM_ATTR // fast
|
|
||||||
bool expired() {
|
|
||||||
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
|
||||||
if (PeriodicT) { //in case of false: gets optimized away
|
|
||||||
return expiredRetrigger();
|
|
||||||
}
|
|
||||||
return expiredOneShot();
|
|
||||||
}
|
|
||||||
|
|
||||||
IRAM_ATTR // fast
|
|
||||||
operator bool() {
|
|
||||||
return expired();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canExpire() const {
|
|
||||||
return !_neverExpires;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canWait() const {
|
|
||||||
return _timeout != alwaysExpired;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets, will trigger after this new timeout.
|
|
||||||
IRAM_ATTR // called from ISR
|
|
||||||
void reset(const timeType newUserTimeout) {
|
|
||||||
reset();
|
|
||||||
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
|
|
||||||
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets, will trigger after the timeout previously set.
|
|
||||||
IRAM_ATTR // called from ISR
|
|
||||||
void reset() {
|
|
||||||
_start = TimePolicyT::time();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets to just expired so that on next poll the check will immediately trigger for the user,
|
|
||||||
// also change timeout (after next immediate trigger).
|
|
||||||
IRAM_ATTR // called from ISR
|
|
||||||
void resetAndSetExpired(const timeType newUserTimeout) {
|
|
||||||
reset(newUserTimeout);
|
|
||||||
_start -= _timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets to just expired so that on next poll the check will immediately trigger for the user.
|
|
||||||
IRAM_ATTR // called from ISR
|
|
||||||
void resetAndSetExpired() {
|
|
||||||
reset();
|
|
||||||
_start -= _timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetToNeverExpires() {
|
|
||||||
_timeout = alwaysExpired + 1; // because canWait() has precedence
|
|
||||||
_neverExpires = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeType getTimeout() const {
|
|
||||||
return TimePolicyT::toUserUnit(_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr timeType timeMax() {
|
|
||||||
return TimePolicyT::timeMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
IRAM_ATTR // fast
|
|
||||||
bool checkExpired(const timeType internalUnit) const {
|
|
||||||
// canWait() is not checked here
|
|
||||||
// returns "can expire" and "time expired"
|
|
||||||
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
IRAM_ATTR // fast
|
|
||||||
bool expiredRetrigger() {
|
|
||||||
if (!canWait()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeType current = TimePolicyT::time();
|
|
||||||
if (checkExpired(current)) {
|
|
||||||
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
|
|
||||||
_start += n * _timeout;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IRAM_ATTR // fast
|
|
||||||
bool expiredOneShot() const {
|
|
||||||
// returns "always expired" or "has expired"
|
|
||||||
return !canWait() || checkExpired(TimePolicyT::time());
|
|
||||||
}
|
|
||||||
|
|
||||||
timeType _timeout;
|
|
||||||
timeType _start;
|
|
||||||
bool _neverExpires;
|
|
||||||
};
|
|
||||||
|
|
||||||
// legacy type names, deprecated (unit is milliseconds)
|
|
||||||
|
|
||||||
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
|
|
||||||
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
|
|
||||||
|
|
||||||
// standard versions (based on millis())
|
|
||||||
// timeMax() is 49.7 days ((2^32)-2 ms)
|
|
||||||
|
|
||||||
using oneShotMs = polledTimeout::timeoutTemplate<false>;
|
|
||||||
using periodicMs = polledTimeout::timeoutTemplate<true>;
|
|
||||||
|
|
||||||
// Time policy based on esp_get_cycle_count(), and intended to be called very often:
|
|
||||||
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
|
|
||||||
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (esp_get_cycle_count()))
|
|
||||||
// timeMax() values:
|
|
||||||
// Ms: max is 26843 ms (26.8 s)
|
|
||||||
// Us: max is 26843545 us (26.8 s)
|
|
||||||
// Ns: max is 1073741823 ns ( 1.07 s)
|
|
||||||
// (time policy based on esp_get_cycle_count() is intended to be called very often)
|
|
||||||
|
|
||||||
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
|
||||||
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
|
||||||
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
|
||||||
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
|
||||||
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
|
||||||
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
|
||||||
|
|
||||||
} //polledTimeout
|
|
||||||
|
|
||||||
|
|
||||||
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
|
|
||||||
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
|
|
||||||
|
|
||||||
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
}//esp8266
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
RP2040 utility class
|
|
||||||
|
|
||||||
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <pico/runtime.h>
|
|
||||||
|
|
||||||
#ifdef PICO_RP2040
|
|
||||||
|
|
||||||
#include <hardware/structs/psm.h>
|
|
||||||
|
|
||||||
extern "C" void boot_double_tap_check();
|
|
||||||
|
|
||||||
// The following check will never actually execute, but it will cause the boot reset
|
|
||||||
// checker to be linked in as part of the constructors.
|
|
||||||
|
|
||||||
void RP2040::enableDoubleResetBootloader() {
|
|
||||||
if (psm_hw->done == 0) {
|
|
||||||
boot_double_tap_check();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __PROFILE
|
|
||||||
Stream *__profileFile;
|
|
||||||
int __writeProfileCB(const void *data, int len) {
|
|
||||||
return __profileFile->write((const char *)data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __PROFILE
|
|
||||||
extern "C" void runtime_init_setup_profiling();
|
|
||||||
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
|
|
||||||
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -18,42 +18,19 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hardware/clocks.h>
|
#include <hardware/clocks.h>
|
||||||
#include <hardware/irq.h>
|
#include <hardware/irq.h>
|
||||||
#include <hardware/pio.h>
|
#include <hardware/pio.h>
|
||||||
#include <pico/unique_id.h>
|
|
||||||
#ifdef PICO_RP2350
|
|
||||||
#include <hardware/regs/powman.h>
|
|
||||||
#else
|
|
||||||
#include <hardware/regs/vreg_and_chip_reset.h>
|
|
||||||
#endif
|
|
||||||
#include <hardware/exception.h>
|
#include <hardware/exception.h>
|
||||||
#include <hardware/watchdog.h>
|
|
||||||
#include <hardware/structs/rosc.h>
|
|
||||||
#include <hardware/structs/systick.h>
|
#include <hardware/structs/systick.h>
|
||||||
#include <pico/multicore.h>
|
#include <pico/multicore.h>
|
||||||
#include <hardware/dma.h>
|
|
||||||
#include <pico/rand.h>
|
|
||||||
#include <pico/util/queue.h>
|
#include <pico/util/queue.h>
|
||||||
#include <pico/bootrom.h>
|
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
#include "PIOProgram.h"
|
|
||||||
#include "ccount.pio.h"
|
#include "ccount.pio.h"
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
#include "_freertos.h"
|
|
||||||
|
|
||||||
extern "C" volatile bool __otherCoreIdled;
|
extern "C" volatile bool __otherCoreIdled;
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#ifdef __PROFILE
|
|
||||||
typedef int (*profileWriteCB)(const void *data, int len);
|
|
||||||
extern void _writeProfile(profileWriteCB writeCB);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MFIFO {
|
class _MFIFO {
|
||||||
public:
|
public:
|
||||||
_MFIFO() { /* noop */ };
|
_MFIFO() { /* noop */ };
|
||||||
|
|
@ -74,13 +51,8 @@ public:
|
||||||
void registerCore() {
|
void registerCore() {
|
||||||
if (!__isFreeRTOS) {
|
if (!__isFreeRTOS) {
|
||||||
multicore_fifo_clear_irq();
|
multicore_fifo_clear_irq();
|
||||||
#ifdef PICO_RP2350
|
|
||||||
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
|
|
||||||
irq_set_enabled(SIO_IRQ_FIFO, true);
|
|
||||||
#else
|
|
||||||
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
|
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
|
||||||
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
// FreeRTOS port.c will handle the IRQ hooking
|
// FreeRTOS port.c will handle the IRQ hooking
|
||||||
}
|
}
|
||||||
|
|
@ -113,14 +85,10 @@ public:
|
||||||
if (!_multicore) {
|
if (!_multicore) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (__isFreeRTOS) {
|
mutex_enter_blocking(&_idleMutex);
|
||||||
__freertos_idle_other_core();
|
__otherCoreIdled = false;
|
||||||
} else {
|
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||||
mutex_enter_blocking(&_idleMutex);
|
while (!__otherCoreIdled) { /* noop */ }
|
||||||
__otherCoreIdled = false;
|
|
||||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
|
||||||
while (!__otherCoreIdled) { /* noop */ }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resumeOtherCore() {
|
void resumeOtherCore() {
|
||||||
|
|
@ -129,10 +97,6 @@ public:
|
||||||
}
|
}
|
||||||
mutex_exit(&_idleMutex);
|
mutex_exit(&_idleMutex);
|
||||||
__otherCoreIdled = false;
|
__otherCoreIdled = false;
|
||||||
if (__isFreeRTOS) {
|
|
||||||
__freertos_resume_other_core();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other core will exit busy-loop and return to operation
|
// Other core will exit busy-loop and return to operation
|
||||||
// once __otherCoreIdled == false.
|
// once __otherCoreIdled == false.
|
||||||
}
|
}
|
||||||
|
|
@ -175,505 +139,146 @@ private:
|
||||||
class RP2040;
|
class RP2040;
|
||||||
extern RP2040 rp2040;
|
extern RP2040 rp2040;
|
||||||
extern "C" void main1();
|
extern "C" void main1();
|
||||||
extern "C" char __StackLimit;
|
class PIOProgram;
|
||||||
extern "C" char __bss_end__;
|
|
||||||
extern "C" void setup1() __attribute__((weak));
|
// Wrapper class for PIO programs, abstracting common operations out
|
||||||
extern "C" void loop1() __attribute__((weak));
|
// TODO - Add unload/destructor
|
||||||
extern "C" bool core1_separate_stack;
|
class PIOProgram {
|
||||||
extern "C" uint32_t* core1_separate_stack_address;
|
public:
|
||||||
|
PIOProgram(const pio_program_t *pgm) {
|
||||||
|
_pgm = pgm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly load into a PIO and allocate a SM
|
||||||
|
bool prepare(PIO *pio, int *sm, int *offset) {
|
||||||
|
extern mutex_t _pioMutex;
|
||||||
|
CoreMutex m(&_pioMutex);
|
||||||
|
// Is there an open slot to run in, first?
|
||||||
|
if (!_findFreeSM(pio, sm)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Is it loaded on that PIO?
|
||||||
|
if (_offset[pio_get_index(*pio)] < 0) {
|
||||||
|
// Nope, need to load it
|
||||||
|
if (!pio_can_add_program(*pio, _pgm)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_offset[pio_get_index(*pio)] = pio_add_program(*pio, _pgm);
|
||||||
|
}
|
||||||
|
// Here it's guaranteed loaded, return values
|
||||||
|
// PIO and SM already set
|
||||||
|
*offset = _offset[pio_get_index(*pio)];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Find an unused PIO state machine to grab, returns false when none available
|
||||||
|
static bool _findFreeSM(PIO *pio, int *sm) {
|
||||||
|
int idx = pio_claim_unused_sm(pio0, false);
|
||||||
|
if (idx >= 0) {
|
||||||
|
*pio = pio0;
|
||||||
|
*sm = idx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
idx = pio_claim_unused_sm(pio1, false);
|
||||||
|
if (idx >= 0) {
|
||||||
|
*pio = pio1;
|
||||||
|
*sm = idx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _offset[2] = { -1, -1 };
|
||||||
|
const pio_program_t *_pgm;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
@brief RP2040/RP2350 helper function for HW-specific features
|
|
||||||
*/
|
|
||||||
class RP2040 {
|
class RP2040 {
|
||||||
public:
|
public:
|
||||||
RP2040() { /* noop */ }
|
RP2040() { /* noop */ }
|
||||||
~RP2040() { /* noop */ }
|
~RP2040() { /* noop */ }
|
||||||
|
|
||||||
void begin(int cpuid) {
|
void begin() {
|
||||||
_epoch[cpuid] = 0;
|
_epoch = 0;
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
if (!__isFreeRTOS) {
|
if (!__isFreeRTOS) {
|
||||||
// Enable SYSTICK exception
|
// Enable SYSTICK exception
|
||||||
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
|
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
|
||||||
systick_hw->csr = 0x7;
|
systick_hw->csr = 0x7;
|
||||||
systick_hw->rvr = 0x00FFFFFF;
|
systick_hw->rvr = 0x00FFFFFF;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
int off = 0;
|
||||||
// Only start 1 instance of the PIO SM
|
_ccountPgm = new PIOProgram(&ccount_program);
|
||||||
if (cpuid == 0) {
|
_ccountPgm->prepare(&_pio, &_sm, &off);
|
||||||
int off = 0;
|
ccount_program_init(_pio, _sm, off);
|
||||||
_ccountPgm = new PIOProgram(&ccount_program);
|
pio_sm_set_enabled(_pio, _sm, true);
|
||||||
_ccountPgm->prepare(&_pio, &_sm, &off);
|
|
||||||
ccount_program_init(_pio, _sm, off);
|
|
||||||
pio_sm_set_enabled(_pio, _sm, true);
|
|
||||||
}
|
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Convert from microseconds to PIO clock cycles
|
||||||
@brief Convert from microseconds to PIO clock cycles
|
|
||||||
|
|
||||||
@returns the PIO cycles for a given microsecond delay
|
|
||||||
*/
|
|
||||||
static int usToPIOCycles(int us) {
|
static int usToPIOCycles(int us) {
|
||||||
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
|
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
|
||||||
return (us * (clock_get_hz(clk_sys) / 1'000'000));
|
return (us * (clock_get_hz(clk_sys) / 1000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Get current clock frequency
|
||||||
@brief Gets the active CPU speed (may differ from F_CPU
|
|
||||||
|
|
||||||
@returns CPU frequency in Hz
|
|
||||||
*/
|
|
||||||
static int f_cpu() {
|
static int f_cpu() {
|
||||||
return clock_get_hz(clk_sys);
|
return clock_get_hz(clk_sys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
|
||||||
@brief Get the core ID that is currently executing this code
|
volatile uint64_t _epoch = 0;
|
||||||
|
|
||||||
@returns 0 for Core 0, 1 for Core 1
|
|
||||||
*/
|
|
||||||
static int cpuid() {
|
|
||||||
return sio_hw->cpuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief CPU cycle counter epoch (24-bit cycle). For internal use
|
|
||||||
*/
|
|
||||||
volatile uint64_t _epoch[2] = {};
|
|
||||||
/**
|
|
||||||
@brief Get the count of CPU clock cycles since power on.
|
|
||||||
|
|
||||||
@details
|
|
||||||
The 32-bit count will overflow every 4 billion cycles, so consider using ``getCycleCount64`` for
|
|
||||||
longer measurements
|
|
||||||
|
|
||||||
@returns CPU clock cycles since power up
|
|
||||||
*/
|
|
||||||
inline uint32_t getCycleCount() {
|
inline uint32_t getCycleCount() {
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
// Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
|
|
||||||
if (!__isFreeRTOS) {
|
if (!__isFreeRTOS) {
|
||||||
uint32_t epoch;
|
uint32_t epoch;
|
||||||
uint32_t ctr;
|
uint32_t ctr;
|
||||||
do {
|
do {
|
||||||
epoch = (uint32_t)_epoch[sio_hw->cpuid];
|
epoch = (uint32_t)_epoch;
|
||||||
ctr = systick_hw->cvr;
|
ctr = systick_hw->cvr;
|
||||||
} while (epoch != (uint32_t)_epoch[sio_hw->cpuid]);
|
} while (epoch != (uint32_t)_epoch);
|
||||||
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
|
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
|
||||||
} else {
|
} else {
|
||||||
#endif
|
|
||||||
return ccount_read(_pio, _sm);
|
return ccount_read(_pio, _sm);
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
@brief Get the count of CPU clock cycles since power on as a 64-bit quantrity
|
|
||||||
|
|
||||||
@returns CPU clock cycles since power up
|
|
||||||
*/
|
|
||||||
inline uint64_t getCycleCount64() {
|
inline uint64_t getCycleCount64() {
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
if (!__isFreeRTOS) {
|
if (!__isFreeRTOS) {
|
||||||
uint64_t epoch;
|
uint64_t epoch;
|
||||||
uint64_t ctr;
|
uint64_t ctr;
|
||||||
do {
|
do {
|
||||||
epoch = _epoch[sio_hw->cpuid];
|
epoch = _epoch;
|
||||||
ctr = systick_hw->cvr;
|
ctr = systick_hw->cvr;
|
||||||
} while (epoch != _epoch[sio_hw->cpuid]);
|
} while (epoch != _epoch);
|
||||||
return epoch + (1LL << 24) - ctr;
|
return epoch + (1LL << 24) - ctr;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
|
||||||
return ccount_read(_pio, _sm);
|
return ccount_read(_pio, _sm);
|
||||||
#if !defined(__riscv) && !defined(__PROFILE)
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Gets total unused heap (dynamic memory)
|
|
||||||
|
|
||||||
@details
|
|
||||||
Note that the allocations of the size of the total free heap may fail due to fragmentation.
|
|
||||||
For example, ``getFreeHeap`` can report 100KB available, but an allocation of 90KB may fail
|
|
||||||
because there may not be a contiguous 90KB space available
|
|
||||||
|
|
||||||
@returns Free heap in bytes
|
|
||||||
*/
|
|
||||||
inline int getFreeHeap() {
|
|
||||||
return getTotalHeap() - getUsedHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Gets total used heap (dynamic memory)
|
|
||||||
|
|
||||||
@returns Used heap in bytes
|
|
||||||
*/
|
|
||||||
inline int getUsedHeap() {
|
|
||||||
struct mallinfo m = mallinfo();
|
|
||||||
return m.uordblks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Gets total heap (dynamic memory) compiled into the program
|
|
||||||
|
|
||||||
@returns Total heap size in bytes
|
|
||||||
*/
|
|
||||||
inline int getTotalHeap() {
|
|
||||||
return &__StackLimit - &__bss_end__;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief On the RP2350, returns the amount of heap (dynamic memory) available in PSRAM
|
|
||||||
|
|
||||||
@returns Total free heap in PSRAM, or 0 if no PSRAM present
|
|
||||||
*/
|
|
||||||
inline int getFreePSRAMHeap() {
|
|
||||||
return getTotalPSRAMHeap() - getUsedPSRAMHeap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief On the RP2350, returns the total amount of PSRAM heap (dynamic memory) used
|
|
||||||
|
|
||||||
@returns Bytes used in PSRAM, or 0 if no PSRAM present
|
|
||||||
*/
|
|
||||||
inline int getUsedPSRAMHeap() {
|
|
||||||
#if defined(RP2350_PSRAM_CS)
|
|
||||||
extern size_t __psram_total_used();
|
|
||||||
return __psram_total_used();
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief On the RP2350, gets total heap (dynamic memory) compiled into the program
|
|
||||||
|
|
||||||
@returns Total PSRAM heap size in bytes, or 0 if no PSRAM present
|
|
||||||
*/
|
|
||||||
inline int getTotalPSRAMHeap() {
|
|
||||||
#if defined(RP2350_PSRAM_CS)
|
|
||||||
extern size_t __psram_total_space();
|
|
||||||
return __psram_total_space();
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Gets the current stack pointer in a ARM/RISC-V safe manner
|
|
||||||
|
|
||||||
@returns Current SP
|
|
||||||
*/
|
|
||||||
inline uint32_t getStackPointer() {
|
|
||||||
uint32_t *sp;
|
|
||||||
#if defined(__riscv)
|
|
||||||
asm volatile("mv %0, sp" : "=r"(sp));
|
|
||||||
#else
|
|
||||||
asm volatile("mov %0, sp" : "=r"(sp));
|
|
||||||
#endif
|
|
||||||
return (uint32_t)sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Calculates approximately how much stack space is still available for the running core. Handles multiprocessing and separate stacks.
|
|
||||||
|
|
||||||
@details
|
|
||||||
Not valid in FreeRTOS. Use the FreeRTOS internal functions to access this information.
|
|
||||||
|
|
||||||
@returns Approximation of the amount of stack available for use on the specific core
|
|
||||||
*/
|
|
||||||
inline int getFreeStack() {
|
|
||||||
const unsigned int sp = getStackPointer();
|
|
||||||
uint32_t ref = 0x20040000;
|
|
||||||
if (setup1 || loop1) {
|
|
||||||
if (core1_separate_stack) {
|
|
||||||
ref = cpuid() ? (unsigned int)core1_separate_stack_address : 0x20040000;
|
|
||||||
} else {
|
|
||||||
ref = cpuid() ? 0x20040000 : 0x20041000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sp - ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief On the RP2350, gets the size of attached PSRAM
|
|
||||||
|
|
||||||
@returns PSRAM size in bytes, or 0 if no PSRAM present
|
|
||||||
*/
|
|
||||||
inline size_t getPSRAMSize() {
|
|
||||||
#if defined(RP2350_PSRAM_CS)
|
|
||||||
extern size_t __psram_size;
|
|
||||||
return __psram_size;
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Freezes the other core in a flash-write-safe state. Not generally needed by applications
|
|
||||||
|
|
||||||
@details
|
|
||||||
When the external flash chip is erasing or writing, the Pico cannot fetch instructions from it.
|
|
||||||
In this case both the core doing the writing and the other core (if active) need to run from a
|
|
||||||
routine that's contained in RAM. This call forces the other core into a tight, RAM-based loop
|
|
||||||
safe for this operation. When flash erase/write is completed, ``resumeOtherCore`` to return
|
|
||||||
it to operation.
|
|
||||||
|
|
||||||
Be sure to disable any interrupts or task switches before calling to avoid deadlocks.
|
|
||||||
|
|
||||||
If the second core is not started, this is a no-op.
|
|
||||||
*/
|
|
||||||
void idleOtherCore() {
|
void idleOtherCore() {
|
||||||
fifo.idleOtherCore();
|
fifo.idleOtherCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Resumes normal operation of the other core
|
|
||||||
*/
|
|
||||||
void resumeOtherCore() {
|
void resumeOtherCore() {
|
||||||
fifo.resumeOtherCore();
|
fifo.resumeOtherCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Hard resets the 2nd core (CORE1).
|
|
||||||
|
|
||||||
@details
|
|
||||||
Because core1 will restart with the heap and global variables not in the same state as
|
|
||||||
power-on, this call may not work as desired and a full CPU reset may be necessary in
|
|
||||||
certain cases.
|
|
||||||
*/
|
|
||||||
void restartCore1() {
|
void restartCore1() {
|
||||||
multicore_reset_core1();
|
multicore_reset_core1();
|
||||||
fifo.clear();
|
fifo.clear();
|
||||||
multicore_launch_core1(main1);
|
multicore_launch_core1(main1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Multicore comms FIFO
|
||||||
@brief Warm-reboots the chip in normal mode
|
|
||||||
*/
|
|
||||||
void reboot() {
|
|
||||||
watchdog_reboot(0, 0, 10);
|
|
||||||
while (1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Warm-reboots the chip in normal mode
|
|
||||||
*/
|
|
||||||
inline void restart() {
|
|
||||||
reboot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Warm-reboots the chip into the USB bootloader mode
|
|
||||||
*/
|
|
||||||
inline void rebootToBootloader() {
|
|
||||||
reset_usb_boot(0, 0);
|
|
||||||
while (1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PICO_RP2040
|
|
||||||
static void enableDoubleResetBootloader();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Starts the hardware watchdog timer. The CPU will reset if the watchdog is not fed every delay_ms
|
|
||||||
|
|
||||||
@param [in] delay_ms Milliseconds without a wdt_reset before rebooting
|
|
||||||
*/
|
|
||||||
void wdt_begin(uint32_t delay_ms) {
|
|
||||||
watchdog_enable(delay_ms, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Feeds the watchdog timer, resetting it for another delay_ms countdown
|
|
||||||
*/
|
|
||||||
void wdt_reset() {
|
|
||||||
watchdog_update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Best-effort reasons for chip reset
|
|
||||||
*/
|
|
||||||
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Attempts to determine the reason for the last chip reset. May not always be able to determine accurately
|
|
||||||
|
|
||||||
@returns Reason for reset
|
|
||||||
*/
|
|
||||||
resetReason_t getResetReason(void) {
|
|
||||||
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
|
|
||||||
|
|
||||||
if (watchdog_caused_reboot() && watchdog_enable_caused_reboot()) { // watchdog timer
|
|
||||||
return WDT_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*WD_reason_reg & WATCHDOG_REASON_TIMER_BITS) { // soft reset() or reboot()
|
|
||||||
return SOFT_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PICO_RP2350
|
|
||||||
// **** RP2350 is untested ****
|
|
||||||
io_rw_32 *rrp = (io_rw_32 *)(POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET);
|
|
||||||
|
|
||||||
if (*rrp & POWMAN_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset (brownout is separately detected on RP2350)
|
|
||||||
return PWRON_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*rrp & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { // RUN pin
|
|
||||||
return RUN_PIN_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*rrp & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_HZD_SYS_RESET_REQ_BITS)) { // DEBUG port
|
|
||||||
return DEBUG_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*rrp & POWMAN_CHIP_RESET_HAD_GLITCH_DETECT_BITS) { // power supply glitch
|
|
||||||
return GLITCH_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*rrp & POWMAN_CHIP_RESET_HAD_BOR_BITS) { // power supply brownout reset
|
|
||||||
return BROWNOUT_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
io_rw_32 *rrp = (io_rw_32 *)(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET);
|
|
||||||
|
|
||||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset or brown-out detection
|
|
||||||
return PWRON_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { // RUN pin
|
|
||||||
return RUN_PIN_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { // DEBUG port
|
|
||||||
return DEBUG_RESET; // **** untested **** debug reset may just cause a rebootToBootloader()
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return UNKNOWN_RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Get unique ID string for the running board
|
|
||||||
@returns String with the unique board ID as determined by the SDK
|
|
||||||
*/
|
|
||||||
const char *getChipID() {
|
|
||||||
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
|
||||||
if (!id[0]) {
|
|
||||||
pico_get_unique_board_id_string(id, sizeof(id));
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC push_options
|
|
||||||
#pragma GCC optimize ("Os")
|
|
||||||
/**
|
|
||||||
@brief Perform a memcpy using a DMA engine for speed
|
|
||||||
|
|
||||||
@details
|
|
||||||
Uses the DMA to copy to and from RAM. Only works on 4-byte aligned, 4-byte multiple length
|
|
||||||
sources and destination (i.e. word-aligned, word-length). Falls back to normal memcpy otherwise.
|
|
||||||
|
|
||||||
@param [out] dest Memcpy destination, 4-byte aligned
|
|
||||||
@param [in] src Memcpy source, 4-byte aligned
|
|
||||||
@param [in] n Count in bytes to transfer (should be a multiple of 4 bytes)
|
|
||||||
*/
|
|
||||||
void *memcpyDMA(void *dest, const void *src, size_t n) {
|
|
||||||
// Allocate a DMA channel on 1st call, reuse it every call after
|
|
||||||
if (memcpyDMAChannel < 1) {
|
|
||||||
memcpyDMAChannel = dma_claim_unused_channel(true);
|
|
||||||
dma_channel_config c = dma_channel_get_default_config(memcpyDMAChannel);
|
|
||||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
|
|
||||||
channel_config_set_read_increment(&c, true);
|
|
||||||
channel_config_set_write_increment(&c, true);
|
|
||||||
channel_config_set_irq_quiet(&c, true);
|
|
||||||
dma_channel_set_config(memcpyDMAChannel, &c, false);
|
|
||||||
}
|
|
||||||
// If there's any misalignment or too small, use regular memcpy which can handle it
|
|
||||||
if ((n < 64) || (((uint32_t)dest) | ((uint32_t)src) | n) & 3) {
|
|
||||||
return memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
int words = n / 4;
|
|
||||||
dma_channel_set_read_addr(memcpyDMAChannel, src, false);
|
|
||||||
dma_channel_set_write_addr(memcpyDMAChannel, dest, false);
|
|
||||||
dma_channel_set_trans_count(memcpyDMAChannel, words, false);
|
|
||||||
dma_channel_start(memcpyDMAChannel);
|
|
||||||
while (dma_channel_is_busy(memcpyDMAChannel)) {
|
|
||||||
/* busy wait dma */
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
#pragma GCC pop_options
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Multicore communications FIFO
|
|
||||||
*/
|
|
||||||
_MFIFO fifo;
|
_MFIFO fifo;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Return a 32-bit from the hardware random number generator
|
|
||||||
|
|
||||||
@returns Random value using appropriate hardware (RP2350 has true RNG, RP2040 has a less true RNG method)
|
|
||||||
*/
|
|
||||||
uint32_t hwrand32() {
|
|
||||||
return get_rand_32();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Determines if code is running on a Pico or a PicoW
|
|
||||||
|
|
||||||
@details
|
|
||||||
Code compiled for the RP2040 PicoW can run on the RP2040 Pico. This call lets an application
|
|
||||||
identify if the current device is really a Pico or PicoW and handle appropriately. For
|
|
||||||
the RP2350, this runtime detection is not available and the call returns whether it was
|
|
||||||
compiled for the CYW43 WiFi driver
|
|
||||||
|
|
||||||
@returns True if running on a PicoW board with CYW43 WiFi chip.
|
|
||||||
*/
|
|
||||||
bool isPicoW() {
|
|
||||||
#if !defined(PICO_CYW43_SUPPORTED)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
extern bool __isPicoW;
|
|
||||||
return __isPicoW;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __PROFILE
|
|
||||||
void writeProfiling(Stream *f) {
|
|
||||||
extern Stream *__profileFile;
|
|
||||||
extern int __writeProfileCB(const void *data, int len);
|
|
||||||
__profileFile = f;
|
|
||||||
_writeProfile(__writeProfileCB);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getProfileMemoryUsage() {
|
|
||||||
extern int __profileMemSize;
|
|
||||||
return (size_t) __profileMemSize;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void __no_inline_not_in_flash_func(_SystickHandler)() {
|
static void _SystickHandler() {
|
||||||
rp2040._epoch[sio_hw->cpuid] += 1LL << 24;
|
rp2040._epoch += 1LL << 24;
|
||||||
}
|
}
|
||||||
PIO _pio;
|
PIO _pio;
|
||||||
int _sm;
|
int _sm;
|
||||||
PIOProgram *_ccountPgm;
|
PIOProgram *_ccountPgm;
|
||||||
int memcpyDMAChannel = -1;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,14 @@
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
#include "RP2040USB.h"
|
#include "RP2040USB.h"
|
||||||
|
|
||||||
#include <tusb.h>
|
#include "tusb.h"
|
||||||
#include <class/hid/hid_device.h>
|
#include "class/hid/hid_device.h"
|
||||||
#include <class/audio/audio.h>
|
#include "class/audio/audio.h"
|
||||||
#include <pico/time.h>
|
#include "class/midi/midi.h"
|
||||||
#include <hardware/irq.h>
|
#include "pico/time.h"
|
||||||
#include <pico/mutex.h>
|
#include "hardware/irq.h"
|
||||||
#include <pico/unique_id.h>
|
#include "pico/mutex.h"
|
||||||
#include <pico/usb_reset_interface.h>
|
#include "pico/unique_id.h"
|
||||||
#include <hardware/watchdog.h>
|
|
||||||
#include <pico/bootrom.h>
|
|
||||||
#include "sdkoverride/tusb_gamepad16.h"
|
|
||||||
#include <device/usbd_pvt.h>
|
|
||||||
|
|
||||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||||
// have multiple cores updating the TUSB state in parallel
|
// have multiple cores updating the TUSB state in parallel
|
||||||
|
|
@ -44,13 +40,14 @@ mutex_t __usb_mutex;
|
||||||
|
|
||||||
// USB processing will be a periodic timer task
|
// USB processing will be a periodic timer task
|
||||||
#define USB_TASK_INTERVAL 1000
|
#define USB_TASK_INTERVAL 1000
|
||||||
static int __usb_task_irq;
|
#define USB_TASK_IRQ 31
|
||||||
|
|
||||||
#ifndef USBD_VID
|
// USB VID/PID (note that PID can change depending on the add'l interfaces)
|
||||||
#define USBD_VID (0x2E8A) // Raspberry Pi
|
#define USBD_VID (0x2E8A) // Raspberry Pi
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USBD_PID
|
#ifdef SERIALUSB_PID
|
||||||
|
#define USBD_PID (SERIALUSB_PID)
|
||||||
|
#else
|
||||||
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -70,20 +67,12 @@ static int __usb_task_irq;
|
||||||
#define USBD_STR_PRODUCT (0x02)
|
#define USBD_STR_PRODUCT (0x02)
|
||||||
#define USBD_STR_SERIAL (0x03)
|
#define USBD_STR_SERIAL (0x03)
|
||||||
#define USBD_STR_CDC (0x04)
|
#define USBD_STR_CDC (0x04)
|
||||||
#define USBD_STR_RPI_RESET (0x05)
|
|
||||||
|
|
||||||
#define EPNUM_HID 0x83
|
#define EPNUM_HID 0x83
|
||||||
|
|
||||||
#define USBD_MSC_EPOUT 0x03
|
#define EPNUM_MIDI 0x01
|
||||||
#define USBD_MSC_EPIN 0x84
|
|
||||||
#define USBD_MSC_EPSIZE 64
|
|
||||||
|
|
||||||
#define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx) \
|
|
||||||
/* Interface */\
|
|
||||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, _stridx,
|
|
||||||
|
|
||||||
|
|
||||||
int usb_hid_poll_interval __attribute__((weak)) = 10;
|
|
||||||
|
|
||||||
const uint8_t *tud_descriptor_device_cb(void) {
|
const uint8_t *tud_descriptor_device_cb(void) {
|
||||||
static tusb_desc_device_t usbd_desc_device = {
|
static tusb_desc_device_t usbd_desc_device = {
|
||||||
|
|
@ -102,7 +91,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||||
.iSerialNumber = USBD_STR_SERIAL,
|
.iSerialNumber = USBD_STR_SERIAL,
|
||||||
.bNumConfigurations = 1
|
.bNumConfigurations = 1
|
||||||
};
|
};
|
||||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallAbsoluteMouse && !__USBInstallJoystick && !__USBInstallMassStorage) {
|
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallMIDI) {
|
||||||
// Can use as-is, this is the default USB case
|
// Can use as-is, this is the default USB case
|
||||||
return (const uint8_t *)&usbd_desc_device;
|
return (const uint8_t *)&usbd_desc_device;
|
||||||
}
|
}
|
||||||
|
|
@ -110,14 +99,11 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||||
if (__USBInstallKeyboard) {
|
if (__USBInstallKeyboard) {
|
||||||
usbd_desc_device.idProduct |= 0x8000;
|
usbd_desc_device.idProduct |= 0x8000;
|
||||||
}
|
}
|
||||||
if (__USBInstallMouse || __USBInstallAbsoluteMouse) {
|
if (__USBInstallMouse) {
|
||||||
usbd_desc_device.idProduct |= 0x4000;
|
usbd_desc_device.idProduct |= 0x4000;
|
||||||
}
|
}
|
||||||
if (__USBInstallJoystick) {
|
if (__USBInstallMIDI) {
|
||||||
usbd_desc_device.idProduct |= 0x0100;
|
usbd_desc_device.idProduct |= 0x2000;
|
||||||
}
|
|
||||||
if (__USBInstallMassStorage) {
|
|
||||||
usbd_desc_device.idProduct ^= 0x2000;
|
|
||||||
}
|
}
|
||||||
// Set the device class to 0 to indicate multiple device classes
|
// Set the device class to 0 to indicate multiple device classes
|
||||||
usbd_desc_device.bDeviceClass = 0;
|
usbd_desc_device.bDeviceClass = 0;
|
||||||
|
|
@ -131,18 +117,7 @@ int __USBGetKeyboardReportID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int __USBGetMouseReportID() {
|
int __USBGetMouseReportID() {
|
||||||
return __USBInstallKeyboard ? 3 : 1;
|
return __USBInstallKeyboard ? 2 : 1;
|
||||||
}
|
|
||||||
|
|
||||||
int __USBGetJoystickReportID() {
|
|
||||||
int i = 1;
|
|
||||||
if (__USBInstallKeyboard) {
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
if (__USBInstallMouse || __USBInstallAbsoluteMouse) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __hid_report_len = 0;
|
static int __hid_report_len = 0;
|
||||||
|
|
@ -155,83 +130,38 @@ static uint8_t *GetDescHIDReport(int *len) {
|
||||||
return __hid_report;
|
return __hid_report;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __SetupDescHIDReport() {
|
static void __SetupDescHIDReport() {
|
||||||
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
|
if (__USBInstallKeyboard && __USBInstallMouse) {
|
||||||
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
|
uint8_t desc_hid_report[] = {
|
||||||
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
|
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)),
|
||||||
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(1)) };
|
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(2))
|
||||||
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)), TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2)) };
|
};
|
||||||
int size = 0;
|
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||||
|
if (__hid_report) {
|
||||||
//accumulate the size of all used HID report descriptors
|
__hid_report_len = sizeof(desc_hid_report);
|
||||||
if (__USBInstallKeyboard) {
|
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||||
size += sizeof(desc_hid_report_keyboard);
|
}
|
||||||
}
|
} else if (__USBInstallKeyboard && ! __USBInstallMouse) {
|
||||||
if (__USBInstallMouse) {
|
uint8_t desc_hid_report[] = {
|
||||||
size += sizeof(desc_hid_report_mouse);
|
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1))
|
||||||
} else if (__USBInstallAbsoluteMouse) {
|
};
|
||||||
size += sizeof(desc_hid_report_absmouse);
|
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||||
}
|
if (__hid_report) {
|
||||||
if (__USBInstallJoystick) {
|
__hid_report_len = sizeof(desc_hid_report);
|
||||||
size += sizeof(desc_hid_report_joystick);
|
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||||
}
|
}
|
||||||
|
} else if (! __USBInstallKeyboard && __USBInstallMouse) {
|
||||||
//no HID used at all
|
uint8_t desc_hid_report[] = {
|
||||||
if (size == 0) {
|
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1))
|
||||||
|
};
|
||||||
|
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||||
|
if (__hid_report) {
|
||||||
|
__hid_report_len = sizeof(desc_hid_report);
|
||||||
|
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
__hid_report = nullptr;
|
__hid_report = nullptr;
|
||||||
__hid_report_len = 0;
|
__hid_report_len = 0;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//allocate the "real" HID report descriptor
|
|
||||||
__hid_report = (uint8_t *)malloc(size);
|
|
||||||
if (__hid_report) {
|
|
||||||
__hid_report_len = size;
|
|
||||||
|
|
||||||
//now copy the descriptors
|
|
||||||
|
|
||||||
//1.) keyboard descriptor, if requested
|
|
||||||
if (__USBInstallKeyboard) {
|
|
||||||
memcpy(__hid_report, desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard));
|
|
||||||
}
|
|
||||||
|
|
||||||
//2.) mouse descriptor, if necessary. Additional offset & new array is necessary if there is a keyboard.
|
|
||||||
if (__USBInstallMouse) {
|
|
||||||
//determine if we need an offset (USB keyboard is installed)
|
|
||||||
if (__USBInstallKeyboard) {
|
|
||||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(3)) };
|
|
||||||
memcpy(__hid_report + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
|
|
||||||
} else {
|
|
||||||
memcpy(__hid_report, desc_hid_report_mouse, sizeof(desc_hid_report_mouse));
|
|
||||||
}
|
|
||||||
} else if (__USBInstallAbsoluteMouse) {
|
|
||||||
//determine if we need an offset (USB keyboard is installed)
|
|
||||||
if (__USBInstallKeyboard) {
|
|
||||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(3)) };
|
|
||||||
memcpy(__hid_report + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
|
|
||||||
} else {
|
|
||||||
memcpy(__hid_report, desc_hid_report_absmouse, sizeof(desc_hid_report_absmouse));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//3.) joystick descriptor. 2 additional checks are necessary for mouse and/or keyboard
|
|
||||||
if (__USBInstallJoystick) {
|
|
||||||
uint8_t reportid = 1;
|
|
||||||
int offset = 0;
|
|
||||||
if (__USBInstallKeyboard) {
|
|
||||||
reportid += 2;
|
|
||||||
offset += sizeof(desc_hid_report_keyboard);
|
|
||||||
}
|
|
||||||
if (__USBInstallMouse) {
|
|
||||||
reportid++;
|
|
||||||
offset += sizeof(desc_hid_report_mouse);
|
|
||||||
} else if (__USBInstallAbsoluteMouse) {
|
|
||||||
reportid++;
|
|
||||||
offset += sizeof(desc_hid_report_absmouse);
|
|
||||||
}
|
|
||||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(reportid)) };
|
|
||||||
memcpy(__hid_report + offset, desc_local, sizeof(desc_local));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,11 +179,11 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||||
return usbd_desc_cfg;
|
return usbd_desc_cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __SetupUSBDescriptor() {
|
static void __SetupUSBDescriptor() {
|
||||||
if (!usbd_desc_cfg) {
|
if (!usbd_desc_cfg) {
|
||||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallAbsoluteMouse || __USBInstallJoystick;
|
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
|
||||||
|
|
||||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMassStorage ? 1 : 0);
|
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMIDI ? 2 : 0);
|
||||||
|
|
||||||
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||||
|
|
@ -265,23 +195,16 @@ void __SetupUSBDescriptor() {
|
||||||
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
||||||
uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
||||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, (uint8_t)usb_hid_poll_interval)
|
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t msd_itf = interface_count - 1;
|
uint8_t midi_itf = hid_itf + (hasHID ? 1 : 0);
|
||||||
uint8_t msd_desc[TUD_MSC_DESC_LEN] = {
|
uint8_t midi_desc[TUD_MIDI_DESC_LEN] = {
|
||||||
TUD_MSC_DESCRIPTOR(msd_itf, 0, USBD_MSC_EPOUT, USBD_MSC_EPIN, USBD_MSC_EPSIZE)
|
// Interface number, string index, EP Out & EP In address, EP size
|
||||||
|
TUD_MIDI_DESCRIPTOR(midi_itf, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 64)
|
||||||
};
|
};
|
||||||
|
|
||||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMassStorage ? sizeof(msd_desc) : 0);
|
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMIDI ? sizeof(midi_desc) : 0);
|
||||||
|
|
||||||
#ifdef ENABLE_PICOTOOL_USB
|
|
||||||
uint8_t picotool_itf = interface_count++;
|
|
||||||
uint8_t picotool_desc[] = {
|
|
||||||
TUD_RPI_RESET_DESCRIPTOR(picotool_itf, USBD_STR_RPI_RESET)
|
|
||||||
};
|
|
||||||
usbd_desc_len += sizeof(picotool_desc);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
|
|
@ -303,34 +226,26 @@ void __SetupUSBDescriptor() {
|
||||||
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||||
ptr += sizeof(hid_desc);
|
ptr += sizeof(hid_desc);
|
||||||
}
|
}
|
||||||
if (__USBInstallMassStorage) {
|
if (__USBInstallMIDI) {
|
||||||
memcpy(ptr, msd_desc, sizeof(msd_desc));
|
memcpy(ptr, midi_desc, sizeof(midi_desc));
|
||||||
ptr += sizeof(msd_desc);
|
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_PICOTOOL_USB
|
|
||||||
memcpy(ptr, picotool_desc, sizeof(picotool_desc));
|
|
||||||
ptr += sizeof(picotool_desc);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||||
(void) langid;
|
(void) langid;
|
||||||
#define DESC_STR_MAX (32)
|
#define DESC_STR_MAX (20)
|
||||||
static uint16_t desc_str[DESC_STR_MAX];
|
static uint16_t desc_str[DESC_STR_MAX];
|
||||||
|
|
||||||
static char idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
static char idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
||||||
|
|
||||||
static const char *const usbd_desc_str[] = {
|
static const char *const usbd_desc_str[] = {
|
||||||
[USBD_STR_0] = "",
|
[USBD_STR_0] = "",
|
||||||
[USBD_STR_MANUF] = USB_MANUFACTURER,
|
[USBD_STR_MANUF] = "Raspberry Pi",
|
||||||
[USBD_STR_PRODUCT] = USB_PRODUCT,
|
[USBD_STR_PRODUCT] = "PicoArduino",
|
||||||
[USBD_STR_SERIAL] = idString,
|
[USBD_STR_SERIAL] = idString,
|
||||||
[USBD_STR_CDC] = "Board CDC",
|
[USBD_STR_CDC] = "Board CDC",
|
||||||
#ifdef ENABLE_PICOTOOL_USB
|
|
||||||
[USBD_STR_RPI_RESET] = "Reset",
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!idString[0]) {
|
if (!idString[0]) {
|
||||||
|
|
@ -343,7 +258,7 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||||
len = 1;
|
len = 1;
|
||||||
} else {
|
} else {
|
||||||
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
const char *str = usbd_desc_str[index];
|
const char *str = usbd_desc_str[index];
|
||||||
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
||||||
|
|
@ -362,14 +277,14 @@ static void usb_irq() {
|
||||||
// if the mutex is already owned, then we are in user code
|
// if the mutex is already owned, then we are in user code
|
||||||
// in this file which will do a tud_task itself, so we'll just do nothing
|
// in this file which will do a tud_task itself, so we'll just do nothing
|
||||||
// until the next tick; we won't starve
|
// until the next tick; we won't starve
|
||||||
if (mutex_try_enter(&__usb_mutex, nullptr)) {
|
if (mutex_try_enter(&__usb_mutex, NULL)) {
|
||||||
tud_task();
|
tud_task();
|
||||||
mutex_exit(&__usb_mutex);
|
mutex_exit(&__usb_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
||||||
irq_set_pending(__usb_task_irq);
|
irq_set_pending(USB_TASK_IRQ);
|
||||||
return USB_TASK_INTERVAL;
|
return USB_TASK_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,30 +303,16 @@ void __USBStart() {
|
||||||
|
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
__usb_task_irq = user_irq_claim_unused(true);
|
irq_set_exclusive_handler(USB_TASK_IRQ, usb_irq);
|
||||||
irq_set_exclusive_handler(__usb_task_irq, usb_irq);
|
irq_set_enabled(USB_TASK_IRQ, true);
|
||||||
irq_set_enabled(__usb_task_irq, true);
|
|
||||||
|
|
||||||
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, nullptr, true);
|
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, NULL, true);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool __USBHIDReady() {
|
|
||||||
uint32_t start = millis();
|
|
||||||
const uint32_t timeout = 500;
|
|
||||||
|
|
||||||
while (((millis() - start) < timeout) && tud_ready() && !tud_hid_ready()) {
|
|
||||||
tud_task();
|
|
||||||
delayMicroseconds(1);
|
|
||||||
}
|
|
||||||
return tud_hid_ready();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Invoked when received GET_REPORT control request
|
// Invoked when received GET_REPORT control request
|
||||||
// Application must fill buffer report's content and return its length.
|
// Application must fill buffer report's content and return its length.
|
||||||
// Return zero will cause the stack to STALL request
|
// Return zero will cause the stack to STALL request
|
||||||
extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) __attribute__((weak));
|
|
||||||
extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||||
// TODO not implemented
|
// TODO not implemented
|
||||||
(void) instance;
|
(void) instance;
|
||||||
|
|
@ -425,7 +326,6 @@ extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, h
|
||||||
|
|
||||||
// Invoked when received SET_REPORT control request or
|
// Invoked when received SET_REPORT control request or
|
||||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||||
extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) __attribute__((weak));
|
|
||||||
extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
||||||
(void) instance;
|
(void) instance;
|
||||||
|
|
@ -435,186 +335,4 @@ extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_r
|
||||||
(void) bufsize;
|
(void) bufsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) __attribute__((weak));
|
|
||||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
|
||||||
(void) lun;
|
|
||||||
(void) lba;
|
|
||||||
(void) offset;
|
|
||||||
(void) buffer;
|
|
||||||
(void) bufsize;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) __attribute__((weak));
|
|
||||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
|
||||||
(void) lun;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) __attribute__((weak));
|
|
||||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
|
||||||
(void) lun;
|
|
||||||
(void) lba;
|
|
||||||
(void) offset;
|
|
||||||
(void) buffer;
|
|
||||||
(void) bufsize;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) __attribute__((weak));
|
|
||||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
|
||||||
(void) lun;
|
|
||||||
(void) scsi_cmd;
|
|
||||||
(void) buffer;
|
|
||||||
(void) bufsize;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) __attribute__((weak));
|
|
||||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
|
||||||
(void) lun;
|
|
||||||
*block_count = 0;
|
|
||||||
*block_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) __attribute__((weak));
|
|
||||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
|
||||||
(void) lun;
|
|
||||||
vendor_id[0] = 0;
|
|
||||||
product_id[0] = 0;
|
|
||||||
product_rev[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_PICOTOOL_USB
|
|
||||||
|
|
||||||
static uint8_t _picotool_itf_num;
|
|
||||||
|
|
||||||
static void resetd_init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetd_reset(uint8_t rhport) {
|
|
||||||
(void) rhport;
|
|
||||||
_picotool_itf_num = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t resetd_open(uint8_t rhport,
|
|
||||||
tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
|
|
||||||
(void) rhport;
|
|
||||||
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
|
|
||||||
RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
|
|
||||||
RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
|
|
||||||
|
|
||||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t);
|
|
||||||
TU_VERIFY(max_len >= drv_len, 0);
|
|
||||||
|
|
||||||
_picotool_itf_num = itf_desc->bInterfaceNumber;
|
|
||||||
return drv_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support for parameterized reset via vendor interface control request
|
|
||||||
static bool resetd_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
|
||||||
tusb_control_request_t const *request) {
|
|
||||||
(void) rhport;
|
|
||||||
// nothing to do with DATA & ACK stage
|
|
||||||
if (stage != CONTROL_STAGE_SETUP) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->wIndex == _picotool_itf_num) {
|
|
||||||
if (request->bRequest == RESET_REQUEST_BOOTSEL) {
|
|
||||||
reset_usb_boot(0, (request->wValue & 0x7f));
|
|
||||||
// does not return, otherwise we'd return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request->bRequest == RESET_REQUEST_FLASH) {
|
|
||||||
watchdog_reboot(0, 0, 100);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool resetd_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
|
||||||
xfer_result_t result, uint32_t xferred_bytes) {
|
|
||||||
(void) rhport;
|
|
||||||
(void) ep_addr;
|
|
||||||
(void) result;
|
|
||||||
(void) xferred_bytes;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static usbd_class_driver_t const _resetd_driver = {
|
|
||||||
#if CFG_TUSB_DEBUG >= 2
|
|
||||||
.name = "RESET",
|
|
||||||
#endif
|
|
||||||
.init = resetd_init,
|
|
||||||
.reset = resetd_reset,
|
|
||||||
.open = resetd_open,
|
|
||||||
.control_xfer_cb = resetd_control_xfer_cb,
|
|
||||||
.xfer_cb = resetd_xfer_cb,
|
|
||||||
.sof = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implement callback to add our custom driver
|
|
||||||
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
|
|
||||||
*driver_count = 1;
|
|
||||||
return &_resetd_driver;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined NO_USB
|
|
||||||
|
|
||||||
#warning "NO_USB selected. No output to Serial will occur!"
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
void SerialUSB::begin(unsigned long baud) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialUSB::end() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int SerialUSB::peek() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SerialUSB::read() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SerialUSB::available() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SerialUSB::availableForWrite() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialUSB::flush() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SerialUSB::write(uint8_t c) {
|
|
||||||
(void) c;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
|
||||||
(void) buf;
|
|
||||||
(void) length;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialUSB::operator bool() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialUSB Serial;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -19,20 +19,13 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pico/mutex.h>
|
#include "pico/mutex.h"
|
||||||
|
|
||||||
// Weak function definitions for each type of endpoint
|
// Weak function definitions for each type of endpoint
|
||||||
extern void __USBInstallSerial() __attribute__((weak));
|
extern void __USBInstallSerial() __attribute__((weak));
|
||||||
|
|
||||||
extern void __USBInstallKeyboard() __attribute__((weak));
|
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||||
|
|
||||||
extern void __USBInstallJoystick() __attribute__((weak));
|
|
||||||
|
|
||||||
// One or the other allowed, not both
|
|
||||||
extern void __USBInstallMouse() __attribute__((weak));
|
extern void __USBInstallMouse() __attribute__((weak));
|
||||||
extern void __USBInstallAbsoluteMouse() __attribute__((weak));
|
extern void __USBInstallMIDI() __attribute__((weak));
|
||||||
|
|
||||||
extern void __USBInstallMassStorage() __attribute__((weak));
|
|
||||||
|
|
||||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||||
// have multiple cores updating the TUSB state in parallel
|
// have multiple cores updating the TUSB state in parallel
|
||||||
|
|
@ -41,10 +34,6 @@ extern mutex_t __usb_mutex;
|
||||||
// HID report ID inquiry (report ID will vary depending on the number/type of other HID)
|
// HID report ID inquiry (report ID will vary depending on the number/type of other HID)
|
||||||
int __USBGetKeyboardReportID();
|
int __USBGetKeyboardReportID();
|
||||||
int __USBGetMouseReportID();
|
int __USBGetMouseReportID();
|
||||||
int __USBGetJoystickReportID();
|
|
||||||
|
|
||||||
// Called by main() to init the USB HW/SW.
|
// Called by main() to init the USB HW/SW.
|
||||||
void __USBStart();
|
void __USBStart();
|
||||||
|
|
||||||
// Helper class for HID report sending with wait and timeout
|
|
||||||
bool __USBHIDReady();
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define ARDUINO_PICO_MAJOR 4
|
#define ARDUINO_PICO_MAJOR 2
|
||||||
#define ARDUINO_PICO_MINOR 5
|
#define ARDUINO_PICO_MINOR 1
|
||||||
#define ARDUINO_PICO_REVISION 4
|
#define ARDUINO_PICO_REVISION 1
|
||||||
#define ARDUINO_PICO_VERSION_STR "4.5.4"
|
#define ARDUINO_PICO_VERSION_STR "2.1.1"
|
||||||
|
|
|
||||||
|
|
@ -1,297 +0,0 @@
|
||||||
/*
|
|
||||||
SemiFS.h - File system wrapper for Semihosting ARM
|
|
||||||
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Semihosting.h"
|
|
||||||
#include "FS.h"
|
|
||||||
#include "FSImpl.h"
|
|
||||||
|
|
||||||
using namespace fs;
|
|
||||||
|
|
||||||
namespace semifs {
|
|
||||||
|
|
||||||
class SemiFSFileImpl;
|
|
||||||
class SemiFSConfig : public FSConfig {
|
|
||||||
public:
|
|
||||||
static constexpr uint32_t FSId = 0x53454d49;
|
|
||||||
SemiFSConfig() : FSConfig(FSId, false) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
class SemiFSFileImpl : public FileImpl {
|
|
||||||
public:
|
|
||||||
SemiFSFileImpl(int fd, const char *name, bool writable)
|
|
||||||
: _fd(fd), _opened(true), _writable(writable) {
|
|
||||||
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
|
|
||||||
strcpy(_name.get(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
~SemiFSFileImpl() override {
|
|
||||||
flush();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
int availableForWrite() override {
|
|
||||||
return 1; // TODO - not implemented? _opened ? _fd->availableSpaceForWrite() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(const uint8_t *buf, size_t size) override {
|
|
||||||
if (_opened) {
|
|
||||||
uint32_t a[3];
|
|
||||||
a[0] = _fd;
|
|
||||||
a[1] = (uint32_t)buf;
|
|
||||||
a[2] = size;
|
|
||||||
return 0 == Semihost(SEMIHOST_SYS_WRITE, a) ? size : -1;
|
|
||||||
}
|
|
||||||
return -1; // some kind of error
|
|
||||||
}
|
|
||||||
|
|
||||||
int read(uint8_t* buf, size_t size) override {
|
|
||||||
if (_opened) {
|
|
||||||
uint32_t a[3];
|
|
||||||
a[0] = _fd;
|
|
||||||
a[1] = (uint32_t)buf;
|
|
||||||
a[2] = size;
|
|
||||||
int ret = Semihost(SEMIHOST_SYS_READ, a);
|
|
||||||
if (ret == 0) {
|
|
||||||
return size;
|
|
||||||
} else if (ret == (int)size) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush() override {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
bool seek(uint32_t pos, SeekMode mode) override {
|
|
||||||
if (!_opened || (mode != SeekSet)) {
|
|
||||||
// No seek cur/end in semihost
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t a[2];
|
|
||||||
a[0] = _fd;
|
|
||||||
a[1] = pos;
|
|
||||||
return !Semihost(SEMIHOST_SYS_SEEK, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t position() const override {
|
|
||||||
return 0; // Not available semihost
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const override {
|
|
||||||
if (!_opened) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint32_t a;
|
|
||||||
a = _fd;
|
|
||||||
int ret = Semihost(SEMIHOST_SYS_FLEN, &a);
|
|
||||||
if (ret < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool truncate(uint32_t size) override {
|
|
||||||
return false; // Not allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() override {
|
|
||||||
if (_opened) {
|
|
||||||
uint32_t a = _fd;
|
|
||||||
Semihost(SEMIHOST_SYS_CLOSE, &a);
|
|
||||||
_opened = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name() const override {
|
|
||||||
if (!_opened) {
|
|
||||||
DEBUGV("SemiFSFileImpl::name: file not opened\n");
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
const char *p = _name.get();
|
|
||||||
const char *slash = strrchr(p, '/');
|
|
||||||
// For names w/o any path elements, return directly
|
|
||||||
// If there are slashes, return name after the last slash
|
|
||||||
// (note that strrchr will return the address of the slash,
|
|
||||||
// so need to increment to ckip it)
|
|
||||||
return (slash && slash[1]) ? slash + 1 : p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* fullName() const override {
|
|
||||||
return _opened ? _name.get() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFile() const override {
|
|
||||||
return _opened; // Could look at ISTTY but that's not the sense here. Just differentiating between dirs and files
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDirectory() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t getLastWrite() override {
|
|
||||||
return getCreationTime(); // TODO - FatFS doesn't seem to report both filetimes
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t getCreationTime() override {
|
|
||||||
time_t ftime = 0;
|
|
||||||
return ftime;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int _fd;
|
|
||||||
std::shared_ptr<char> _name;
|
|
||||||
bool _opened;
|
|
||||||
bool _writable;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SemiFSImpl : public FSImpl {
|
|
||||||
public:
|
|
||||||
SemiFSImpl() {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override {
|
|
||||||
if (!path || !path[0]) {
|
|
||||||
DEBUGV("SemiFSImpl::open() called with invalid filename\n");
|
|
||||||
return FileImplPtr();
|
|
||||||
}
|
|
||||||
// Mode conversion https://developer.arm.com/documentation/dui0471/m/what-is-semihosting-/sys-open--0x01-?lang=en
|
|
||||||
int mode = 1; // "rb"
|
|
||||||
if (accessMode == AM_READ) {
|
|
||||||
mode = 1; // "rb"
|
|
||||||
} else if (accessMode == AM_WRITE) {
|
|
||||||
if (openMode & OM_APPEND) {
|
|
||||||
mode = 9; // "ab";
|
|
||||||
} else {
|
|
||||||
mode = 5; // "wb";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (openMode & OM_TRUNCATE) {
|
|
||||||
mode = 7; // "w+b";
|
|
||||||
} else if (openMode & OM_APPEND) {
|
|
||||||
mode = 3; // "r+b"
|
|
||||||
} else {
|
|
||||||
mode = 11; // "a+b";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t a[3];
|
|
||||||
a[0] = (uint32_t)path;
|
|
||||||
a[1] = mode;
|
|
||||||
a[2] = strlen(path);
|
|
||||||
int handle = Semihost(SEMIHOST_SYS_OPEN, a);
|
|
||||||
if (handle < 0) {
|
|
||||||
return FileImplPtr();
|
|
||||||
}
|
|
||||||
return std::make_shared<SemiFSFileImpl>(handle, path, (accessMode & AM_WRITE) ? true : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool exists(const char* path) override {
|
|
||||||
File f = open(path, OM_DEFAULT, AM_READ);
|
|
||||||
return f ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirImplPtr openDir(const char* path) override {
|
|
||||||
// No directories
|
|
||||||
return DirImplPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rename(const char* pathFrom, const char* pathTo) override {
|
|
||||||
uint32_t a[4];
|
|
||||||
a[0] = (uint32_t)pathFrom;
|
|
||||||
a[1] = strlen(pathFrom);
|
|
||||||
a[2] = (uint32_t)pathTo;
|
|
||||||
a[3] = strlen(pathTo);
|
|
||||||
return !Semihost(SEMIHOST_SYS_RENAME, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool info(FSInfo& info) override {
|
|
||||||
// Not available
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove(const char* path) override {
|
|
||||||
uint32_t a[2];
|
|
||||||
a[0] = (uint32_t)path;
|
|
||||||
a[1] = strlen(path);
|
|
||||||
return !Semihost(SEMIHOST_SYS_REMOVE, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mkdir(const char* path) override {
|
|
||||||
// No mkdir
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rmdir(const char* path) override {
|
|
||||||
// No rmdir
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool stat(const char *path, FSStat *st) override {
|
|
||||||
if (!path || !path[0]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t a[3];
|
|
||||||
a[0] = (uint32_t)path;
|
|
||||||
a[1] = 0; // READ
|
|
||||||
a[2] = strlen(path);
|
|
||||||
int fn = Semihost(SEMIHOST_SYS_OPEN, a);
|
|
||||||
if (fn < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bzero(st, sizeof(*st));
|
|
||||||
a[0] = fn;
|
|
||||||
st->size = Semihost(SEMIHOST_SYS_FLEN, a);
|
|
||||||
a[0] = fn;
|
|
||||||
Semihost(SEMIHOST_SYS_CLOSE, a);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool setConfig(const FSConfig &cfg) override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool begin() override {
|
|
||||||
/* noop */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void end() override {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
bool format() override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}; // namespace sdfs
|
|
||||||
|
|
||||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SEMIFS)
|
|
||||||
extern FS SemiFS;
|
|
||||||
using semifs::SemiFSConfig;
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#include "Semihosting.h"
|
|
||||||
#include "SerialSemi.h"
|
|
||||||
#include "SemiFS.h"
|
|
||||||
|
|
||||||
SerialSemiClass SerialSemi;
|
|
||||||
FS SemiFS = FS(FSImplPtr(new semifs::SemiFSImpl()));
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
Semihosting.h - Semihosting for Serial and FS access via GDB
|
|
||||||
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Be sure to only use this library with GDB and to enable the ARM semihosting support
|
|
||||||
// (gdb) monitor arm semihosting enable
|
|
||||||
|
|
||||||
// Input/output will be handled by OpenOCD
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Semihosting host API opcodes, from https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations?lang=en
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
SEMIHOST_SYS_CLOSE = 0x02,
|
|
||||||
SEMIHOST_SYS_CLOCK = 0x10,
|
|
||||||
SEMIHOST_SYS_ELAPSED = 0x30,
|
|
||||||
SEMIHOST_SYS_ERRNO = 0x13,
|
|
||||||
SEMIHOST_SYS_FLEN = 0x0C,
|
|
||||||
SEMIHOST_SYS_GET_CMDLINE = 0x15,
|
|
||||||
SEMIHOST_SYS_HEAPINFO = 0x16,
|
|
||||||
SEMIHOST_SYS_ISERROR = 0x08,
|
|
||||||
SEMIHOST_SYS_ISTTY = 0x09,
|
|
||||||
SEMIHOST_SYS_OPEN = 0x01,
|
|
||||||
SEMIHOST_SYS_READ = 0x06,
|
|
||||||
SEMIHOST_SYS_READC = 0x07,
|
|
||||||
SEMIHOST_SYS_REMOVE = 0x0E,
|
|
||||||
SEMIHOST_SYS_RENAME = 0x0F,
|
|
||||||
SEMIHOST_SYS_SEEK = 0x0A,
|
|
||||||
SEMIHOST_SYS_SYSTEM = 0x12,
|
|
||||||
SEMIHOST_SYS_TICKFREQ = 0x31,
|
|
||||||
SEMIHOST_SYS_TIME = 0x11,
|
|
||||||
SEMIHOST_SYS_TMPNAM = 0x0D,
|
|
||||||
SEMIHOST_SYS_WRITE = 0x05,
|
|
||||||
SEMIHOST_SYS_WRITEC = 0x03,
|
|
||||||
SEMIHOST_SYS_WRITE0 = 0x04
|
|
||||||
} SEMIHOST_OPCODES;
|
|
||||||
|
|
||||||
#ifdef __arm__
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Execute a semihosted request, from https://github.com/ErichStyger/mcuoneclipse/blob/master/Examples/MCUXpresso/FRDM-K22F/FRDM-K22F_Semihosting/source/McuSemihost.c
|
|
||||||
|
|
||||||
@param [in] reason Opcode to execute
|
|
||||||
@param [in] arg Any arguments for the opcode
|
|
||||||
@returns Result of operation
|
|
||||||
*/
|
|
||||||
static inline int __attribute__((always_inline)) Semihost(int reason, void *arg) {
|
|
||||||
int value;
|
|
||||||
__asm volatile(
|
|
||||||
"mov r0, %[rsn] \n" /* place semihost operation code into R0 */
|
|
||||||
"mov r1, %[arg] \n" /* R1 points to the argument array */
|
|
||||||
"bkpt 0xAB \n" /* call debugger */
|
|
||||||
"mov %[val], r0 \n" /* debugger has stored result code in R0 */
|
|
||||||
|
|
||||||
: [val] "=r"(value) /* outputs */
|
|
||||||
: [rsn] "r"(reason), [arg] "r"(arg) /* inputs */
|
|
||||||
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" /* clobber */
|
|
||||||
);
|
|
||||||
return value; /* return result code, stored in R0 */
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Execute a semihosted request, from https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/n-5VQ9PHZ4w/m/KbzH5t9MBgAJ
|
|
||||||
|
|
||||||
@param [in] reason Opcode to execute
|
|
||||||
@param [in] argPack Any arguments for the opcode
|
|
||||||
@returns Result of operation
|
|
||||||
*/
|
|
||||||
static inline int __attribute__((always_inline)) Semihost(int reason, void *argPack) {
|
|
||||||
register int value asm("a0") = reason;
|
|
||||||
register void *ptr asm("a1") = argPack;
|
|
||||||
asm volatile(
|
|
||||||
// Force 16-byte alignment to make sure that the 3 instructions fall
|
|
||||||
// within the same virtual page.
|
|
||||||
" .balign 16 \n"
|
|
||||||
" .option push \n"
|
|
||||||
// Force non-compressed RISC-V instructions
|
|
||||||
" .option norvc \n"
|
|
||||||
// semihosting e-break sequence
|
|
||||||
" slli x0, x0, 0x1f \n" // # Entry NOP
|
|
||||||
" ebreak \n" // # Break to debugger
|
|
||||||
" srai x0, x0, 0x7 \n" // # NOP encoding the semihosting call number 7
|
|
||||||
" .option pop \n"
|
|
||||||
/*mark (value) as an output operand*/
|
|
||||||
: "=r"(value) /* Outputs */
|
|
||||||
// The semihosting call number is passed in a0, and the argument in a1.
|
|
||||||
: "0"(value), "r"(ptr) /* Inputs */
|
|
||||||
// The "memory" clobber makes GCC assume that any memory may be arbitrarily read or written by the asm block,
|
|
||||||
// so will prevent the compiler from reordering loads or stores across it, or from caching memory values in registers across it.
|
|
||||||
// The "memory" clobber also prevents the compiler from removing the asm block as dead code.
|
|
||||||
: "memory" /* Clobbers */
|
|
||||||
);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -33,7 +33,6 @@ static std::map<int, PIOProgram*> _rxMap;
|
||||||
// Duplicate a program and replace the first insn with a "set x, repl"
|
// Duplicate a program and replace the first insn with a "set x, repl"
|
||||||
static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
|
static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
|
||||||
pio_program_t *p = new pio_program_t;
|
pio_program_t *p = new pio_program_t;
|
||||||
memcpy(p, pg, sizeof(*p));
|
|
||||||
p->length = pg->length;
|
p->length = pg->length;
|
||||||
p->origin = pg->origin;
|
p->origin = pg->origin;
|
||||||
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
|
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
|
||||||
|
|
@ -68,17 +67,20 @@ static PIOProgram *_getRxProgram(int bits) {
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
static int __not_in_flash_func(_parity)(int data) {
|
// TODO - this works, but there must be a faster/better way...
|
||||||
data ^= data >> 4;
|
static int _parity(int bits, int data) {
|
||||||
data &= 0xf;
|
int p = 0;
|
||||||
return (0x6996 >> data) & 1;
|
for (int b = 0; b < bits; b++) {
|
||||||
|
p ^= (data & (1 << b)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to cache generated SerialPIOs so we can add data to them from
|
// We need to cache generated SerialPIOs so we can add data to them from
|
||||||
// the shared handler
|
// the shared handler
|
||||||
static SerialPIO *_pioSP[3][4];
|
static SerialPIO *_pioSP[2][4];
|
||||||
static void __not_in_flash_func(_fifoIRQ)() {
|
static void __not_in_flash_func(_fifoIRQ)() {
|
||||||
for (int p = 0; p < 3; p++) {
|
for (int p = 0; p < 2; p++) {
|
||||||
for (int sm = 0; sm < 4; sm++) {
|
for (int sm = 0; sm < 4; sm++) {
|
||||||
SerialPIO *s = _pioSP[p][sm];
|
SerialPIO *s = _pioSP[p][sm];
|
||||||
if (s) {
|
if (s) {
|
||||||
|
|
@ -95,16 +97,20 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||||
}
|
}
|
||||||
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
|
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
|
||||||
uint32_t decode = _rxPIO->rxf[_rxSM];
|
uint32_t decode = _rxPIO->rxf[_rxSM];
|
||||||
uint32_t val = decode >> (32 - _rxBits - 1);
|
decode >>= 33 - _rxBits;
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int b = 0; b < _bits + 1; b++) {
|
||||||
|
val |= (decode & (1 << (b * 2))) ? 1 << b : 0;
|
||||||
|
}
|
||||||
if (_parity == UART_PARITY_EVEN) {
|
if (_parity == UART_PARITY_EVEN) {
|
||||||
int p = ::_parity(val);
|
int p = ::_parity(_bits, val);
|
||||||
int r = (val & (1 << _bits)) ? 1 : 0;
|
int r = (val & (1 << _bits)) ? 1 : 0;
|
||||||
if (p != r) {
|
if (p != r) {
|
||||||
// TODO - parity error
|
// TODO - parity error
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (_parity == UART_PARITY_ODD) {
|
} else if (_parity == UART_PARITY_ODD) {
|
||||||
int p = ::_parity(val);
|
int p = ::_parity(_bits, val);
|
||||||
int r = (val & (1 << _bits)) ? 1 : 0;
|
int r = (val & (1 << _bits)) ? 1 : 0;
|
||||||
if (p == r) {
|
if (p == r) {
|
||||||
// TODO - parity error
|
// TODO - parity error
|
||||||
|
|
@ -132,8 +138,6 @@ SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize) {
|
||||||
_fifoSize = fifoSize + 1; // Always one unused entry
|
_fifoSize = fifoSize + 1; // Always one unused entry
|
||||||
_queue = new uint8_t[_fifoSize];
|
_queue = new uint8_t[_fifoSize];
|
||||||
mutex_init(&_mutex);
|
mutex_init(&_mutex);
|
||||||
_invertTX = false;
|
|
||||||
_invertRX = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPIO::~SerialPIO() {
|
SerialPIO::~SerialPIO() {
|
||||||
|
|
@ -141,21 +145,6 @@ SerialPIO::~SerialPIO() {
|
||||||
delete[] _queue;
|
delete[] _queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pio_irq_0(PIO p) {
|
|
||||||
switch (pio_get_index(p)) {
|
|
||||||
case 0:
|
|
||||||
return PIO0_IRQ_0;
|
|
||||||
case 1:
|
|
||||||
return PIO1_IRQ_0;
|
|
||||||
#if defined(PICO_RP2350)
|
|
||||||
case 2:
|
|
||||||
return PIO2_IRQ_0;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
_overflow = false;
|
_overflow = false;
|
||||||
_baud = baud;
|
_baud = baud;
|
||||||
|
|
@ -202,7 +191,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
||||||
_txPgm = _getTxProgram(_txBits);
|
_txPgm = _getTxProgram(_txBits);
|
||||||
int off;
|
int off;
|
||||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off, _tx, 1)) {
|
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
|
||||||
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
||||||
// ERROR, no free slots
|
// ERROR, no free slots
|
||||||
return;
|
return;
|
||||||
|
|
@ -220,17 +209,16 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
pio_sm_exec(_txPIO, _txSM, pio_encode_mov(pio_isr, pio_osr));
|
pio_sm_exec(_txPIO, _txSM, pio_encode_mov(pio_isr, pio_osr));
|
||||||
|
|
||||||
// Start running!
|
// Start running!
|
||||||
gpio_set_outover(_tx, _invertTX);
|
|
||||||
pio_sm_set_enabled(_txPIO, _txSM, true);
|
pio_sm_set_enabled(_txPIO, _txSM, true);
|
||||||
}
|
}
|
||||||
if (_rx != NOPIN) {
|
if (_rx != NOPIN) {
|
||||||
_writer = 0;
|
_writer = 0;
|
||||||
_reader = 0;
|
_reader = 0;
|
||||||
|
|
||||||
_rxBits = _bits + (_parity != UART_PARITY_NONE ? 1 : 0);
|
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
|
||||||
_rxPgm = _getRxProgram(_rxBits);
|
_rxPgm = _getRxProgram(_rxBits);
|
||||||
int off;
|
int off;
|
||||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
|
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
|
||||||
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +230,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
|
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
|
||||||
|
|
||||||
// Put phase divider into OSR w/o using add'l program memory
|
// Put phase divider into OSR w/o using add'l program memory
|
||||||
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 3);
|
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 5 /* insns in PIO halfbit loop */);
|
||||||
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
|
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
|
||||||
|
|
||||||
// Join the TX FIFO to the RX one now that we don't need it
|
// Join the TX FIFO to the RX one now that we don't need it
|
||||||
|
|
@ -255,11 +243,10 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
case 2: pio_set_irq0_source_enabled(_rxPIO, pis_sm2_rx_fifo_not_empty, true); break;
|
case 2: pio_set_irq0_source_enabled(_rxPIO, pis_sm2_rx_fifo_not_empty, true); break;
|
||||||
case 3: pio_set_irq0_source_enabled(_rxPIO, pis_sm3_rx_fifo_not_empty, true); break;
|
case 3: pio_set_irq0_source_enabled(_rxPIO, pis_sm3_rx_fifo_not_empty, true); break;
|
||||||
}
|
}
|
||||||
auto irqno = pio_irq_0(_rxPIO);
|
auto irqno = pio_get_index(_rxPIO) == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||||
irq_set_exclusive_handler(irqno, _fifoIRQ);
|
irq_set_exclusive_handler(irqno, _fifoIRQ);
|
||||||
irq_set_enabled(irqno, true);
|
irq_set_enabled(irqno, true);
|
||||||
|
|
||||||
gpio_set_inover(_rx, _invertRX);
|
|
||||||
pio_sm_set_enabled(_rxPIO, _rxSM, true);
|
pio_sm_set_enabled(_rxPIO, _rxSM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,12 +259,9 @@ void SerialPIO::end() {
|
||||||
}
|
}
|
||||||
if (_tx != NOPIN) {
|
if (_tx != NOPIN) {
|
||||||
pio_sm_set_enabled(_txPIO, _txSM, false);
|
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||||
pio_sm_unclaim(_txPIO, _txSM);
|
|
||||||
gpio_set_outover(_tx, 0);
|
|
||||||
}
|
}
|
||||||
if (_rx != NOPIN) {
|
if (_rx != NOPIN) {
|
||||||
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||||
pio_sm_unclaim(_rxPIO, _rxSM);
|
|
||||||
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
||||||
// If no more active, disable the IRQ
|
// If no more active, disable the IRQ
|
||||||
auto pioNum = pio_get_index(_rxPIO);
|
auto pioNum = pio_get_index(_rxPIO);
|
||||||
|
|
@ -286,10 +270,9 @@ void SerialPIO::end() {
|
||||||
used = used || !!_pioSP[pioNum][i];
|
used = used || !!_pioSP[pioNum][i];
|
||||||
}
|
}
|
||||||
if (!used) {
|
if (!used) {
|
||||||
auto irqno = pio_irq_0(_rxPIO);
|
auto irqno = pioNum == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||||
irq_set_enabled(irqno, false);
|
irq_set_enabled(irqno, false);
|
||||||
}
|
}
|
||||||
gpio_set_inover(_rx, 0);
|
|
||||||
}
|
}
|
||||||
_running = false;
|
_running = false;
|
||||||
}
|
}
|
||||||
|
|
@ -371,10 +354,10 @@ size_t SerialPIO::write(uint8_t c) {
|
||||||
if (_parity == UART_PARITY_NONE) {
|
if (_parity == UART_PARITY_NONE) {
|
||||||
val |= 7 << _bits; // Set 2 stop bits, the HW will only transmit the required number
|
val |= 7 << _bits; // Set 2 stop bits, the HW will only transmit the required number
|
||||||
} else if (_parity == UART_PARITY_EVEN) {
|
} else if (_parity == UART_PARITY_EVEN) {
|
||||||
val |= ::_parity(c) << _bits;
|
val |= ::_parity(_bits, c) << _bits;
|
||||||
val |= 7 << (_bits + 1);
|
val |= 7 << (_bits + 1);
|
||||||
} else {
|
} else {
|
||||||
val |= (1 ^ ::_parity(c)) << _bits;
|
val |= (1 ^ ::_parity(_bits, c)) << _bits;
|
||||||
val |= 7 << (_bits + 1);
|
val |= 7 << (_bits + 1);
|
||||||
}
|
}
|
||||||
val <<= 1; // Start bit = low
|
val <<= 1; // Start bit = low
|
||||||
|
|
@ -387,8 +370,3 @@ size_t SerialPIO::write(uint8_t c) {
|
||||||
SerialPIO::operator bool() {
|
SerialPIO::operator bool() {
|
||||||
return _running;
|
return _running;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
|
||||||
// NINA updates
|
|
||||||
SerialPIO Serial3(SERIAL3_TX, SERIAL3_RX);
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
extern "C" typedef struct uart_inst uart_inst_t;
|
extern "C" typedef struct uart_inst uart_inst_t;
|
||||||
|
|
||||||
class SerialPIO : public arduino::HardwareSerial {
|
class SerialPIO : public HardwareSerial {
|
||||||
public:
|
public:
|
||||||
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
|
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
|
||||||
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
|
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
|
||||||
|
|
@ -41,23 +41,6 @@ public:
|
||||||
void begin(unsigned long baud, uint16_t config) override;
|
void begin(unsigned long baud, uint16_t config) override;
|
||||||
void end() override;
|
void end() override;
|
||||||
|
|
||||||
void setInverted(bool invTx = true, bool invRx = true) {
|
|
||||||
setInvertTX(invTx);
|
|
||||||
setInvertRX(invRx);
|
|
||||||
}
|
|
||||||
bool setInvertTX(bool invert = true) {
|
|
||||||
if (!_running) {
|
|
||||||
_invertTX = invert;
|
|
||||||
}
|
|
||||||
return !_running;
|
|
||||||
}
|
|
||||||
bool setInvertRX(bool invert = true) {
|
|
||||||
if (!_running) {
|
|
||||||
_invertRX = invert;
|
|
||||||
}
|
|
||||||
return !_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int peek() override;
|
virtual int peek() override;
|
||||||
virtual int read() override;
|
virtual int read() override;
|
||||||
virtual int available() override;
|
virtual int available() override;
|
||||||
|
|
@ -68,7 +51,7 @@ public:
|
||||||
using Print::write;
|
using Print::write;
|
||||||
operator bool() override;
|
operator bool() override;
|
||||||
|
|
||||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IRQ callback can access it
|
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||||
void _handleIRQ();
|
void _handleIRQ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -80,8 +63,6 @@ protected:
|
||||||
int _stop;
|
int _stop;
|
||||||
bool _overflow;
|
bool _overflow;
|
||||||
mutex_t _mutex;
|
mutex_t _mutex;
|
||||||
bool _invertTX;
|
|
||||||
bool _invertRX;
|
|
||||||
|
|
||||||
PIOProgram *_txPgm;
|
PIOProgram *_txPgm;
|
||||||
PIO _txPIO;
|
PIO _txPIO;
|
||||||
|
|
@ -99,8 +80,3 @@ protected:
|
||||||
uint32_t _reader;
|
uint32_t _reader;
|
||||||
uint8_t *_queue;
|
uint8_t *_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
|
||||||
// NINA updates
|
|
||||||
extern SerialPIO Serial3;
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
SerialSemi.h - Serial port over Semihosting for ARM
|
|
||||||
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Semihosting.h"
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "api/HardwareSerial.h"
|
|
||||||
|
|
||||||
class SerialSemiClass : public arduino::HardwareSerial {
|
|
||||||
public:
|
|
||||||
SerialSemiClass() {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
~SerialSemiClass() {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
void begin(unsigned long baudIgnored = 115200) override {
|
|
||||||
(void)baudIgnored;
|
|
||||||
}
|
|
||||||
|
|
||||||
void begin(unsigned long baudIgnored, uint16_t configIgnored) override {
|
|
||||||
(void)baudIgnored;
|
|
||||||
(void)configIgnored;
|
|
||||||
}
|
|
||||||
|
|
||||||
void end() override {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int peek() override {
|
|
||||||
// Can't really peek on SH, so fake it best we can
|
|
||||||
if (!_peeked) {
|
|
||||||
_peekedChar = read();
|
|
||||||
_peeked = true;
|
|
||||||
}
|
|
||||||
return _peekedChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int read() override {
|
|
||||||
if (_peeked) {
|
|
||||||
_peeked = false;
|
|
||||||
return _peekedChar;
|
|
||||||
}
|
|
||||||
return Semihost(SEMIHOST_SYS_READC, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int available() override {
|
|
||||||
// Can't really tell with SH, so always true. Buyer beware
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int availableForWrite() override {
|
|
||||||
// Can't really tell with SH, so always true. Buyer beware
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() override {
|
|
||||||
/* noop */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(uint8_t c) override {
|
|
||||||
int32_t param = c;
|
|
||||||
Semihost(SEMIHOST_SYS_WRITEC, ¶m);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
using Print::write;
|
|
||||||
|
|
||||||
operator bool() override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _peeked = false;
|
|
||||||
uint8_t _peekedChar;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern SerialSemiClass SerialSemi;
|
|
||||||
|
|
@ -32,29 +32,14 @@ extern void serialEvent1() __attribute__((weak));
|
||||||
extern void serialEvent2() __attribute__((weak));
|
extern void serialEvent2() __attribute__((weak));
|
||||||
|
|
||||||
bool SerialUART::setRX(pin_size_t pin) {
|
bool SerialUART::setRX(pin_size_t pin) {
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
constexpr uint32_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||||
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29, 31, 33, 35, 45, 47}) /* UART0 */,
|
|
||||||
__bitset({5, 7, 9, 11, 21, 23, 25, 27, 37, 39, 41, 43}) /* UART1 */
|
|
||||||
};
|
|
||||||
#elif defined(PICO_RP2350)
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29}) /* UART0 */,
|
|
||||||
__bitset({5, 7, 9, 11, 21, 23, 25, 27}) /* UART1 */
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
|
||||||
__bitset({5, 9, 21, 25}) /* UART1 */
|
__bitset({5, 9, 21, 25}) /* UART1 */
|
||||||
};
|
};
|
||||||
#endif
|
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||||
|
|
||||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
|
||||||
_rx = pin;
|
_rx = pin;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rx == pin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_running) {
|
if (_running) {
|
||||||
panic("FATAL: Attempting to set Serial%d.RX while running", uart_get_index(_uart) + 1);
|
panic("FATAL: Attempting to set Serial%d.RX while running", uart_get_index(_uart) + 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -64,28 +49,14 @@ bool SerialUART::setRX(pin_size_t pin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::setTX(pin_size_t pin) {
|
bool SerialUART::setTX(pin_size_t pin) {
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
constexpr uint32_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||||
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28, 30, 32, 34, 44, 46}) /* UART0 */,
|
|
||||||
__bitset({4, 6, 8, 10, 20, 22, 24, 26, 36, 38, 40, 42}) /* UART1 */
|
|
||||||
};
|
|
||||||
#elif defined(PICO_RP2350)
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28}) /* UART0 */,
|
|
||||||
__bitset({4, 6, 8, 10, 20, 22, 24, 26}) /* UART1 */
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
|
||||||
__bitset({4, 8, 20, 24}) /* UART1 */
|
__bitset({4, 8, 20, 24}) /* UART1 */
|
||||||
};
|
};
|
||||||
#endif
|
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
|
||||||
_tx = pin;
|
_tx = pin;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tx == pin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_running) {
|
if (_running) {
|
||||||
panic("FATAL: Attempting to set Serial%d.TX while running", uart_get_index(_uart) + 1);
|
panic("FATAL: Attempting to set Serial%d.TX while running", uart_get_index(_uart) + 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -95,24 +66,14 @@ bool SerialUART::setTX(pin_size_t pin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::setRTS(pin_size_t pin) {
|
bool SerialUART::setRTS(pin_size_t pin) {
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
constexpr uint32_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||||
constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */,
|
|
||||||
__bitset({7, 11, 23, 27, 39, 43}) /* UART1 */
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
|
||||||
__bitset({7, 11, 23, 27}) /* UART1 */
|
__bitset({7, 11, 23, 27}) /* UART1 */
|
||||||
};
|
};
|
||||||
#endif
|
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
|
||||||
_rts = pin;
|
_rts = pin;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rts == pin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_running) {
|
if (_running) {
|
||||||
panic("FATAL: Attempting to set Serial%d.RTS while running", uart_get_index(_uart) + 1);
|
panic("FATAL: Attempting to set Serial%d.RTS while running", uart_get_index(_uart) + 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -122,24 +83,14 @@ bool SerialUART::setRTS(pin_size_t pin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::setCTS(pin_size_t pin) {
|
bool SerialUART::setCTS(pin_size_t pin) {
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
constexpr uint32_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||||
constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */,
|
|
||||||
__bitset({6, 10, 22, 26, 38, 42}) /* UART1 */
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
constexpr uint64_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
|
||||||
__bitset({6, 10, 22, 26}) /* UART1 */
|
__bitset({6, 10, 22, 26}) /* UART1 */
|
||||||
};
|
};
|
||||||
#endif
|
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
|
||||||
_cts = pin;
|
_cts = pin;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cts == pin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_running) {
|
if (_running) {
|
||||||
panic("FATAL: Attempting to set Serial%d.CTS while running", uart_get_index(_uart) + 1);
|
panic("FATAL: Attempting to set Serial%d.CTS while running", uart_get_index(_uart) + 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -171,49 +122,11 @@ SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size
|
||||||
_cts = cts;
|
_cts = cts;
|
||||||
mutex_init(&_mutex);
|
mutex_init(&_mutex);
|
||||||
mutex_init(&_fifoMutex);
|
mutex_init(&_fifoMutex);
|
||||||
_invertTX = false;
|
|
||||||
_invertRX = false;
|
|
||||||
_invertControl = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _uart0IRQ();
|
static void _uart0IRQ();
|
||||||
static void _uart1IRQ();
|
static void _uart1IRQ();
|
||||||
|
|
||||||
// Does the selected TX/RX need UART_AUX function (rp2350)
|
|
||||||
static gpio_function_t __gpioFunction(int pin) {
|
|
||||||
switch (pin) {
|
|
||||||
#if defined(PICO_RP2350) && !PICO_RP2350A
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 10:
|
|
||||||
case 11:
|
|
||||||
case 14:
|
|
||||||
case 15:
|
|
||||||
case 18:
|
|
||||||
case 19:
|
|
||||||
case 22:
|
|
||||||
case 23:
|
|
||||||
case 26:
|
|
||||||
case 27:
|
|
||||||
case 30:
|
|
||||||
case 31:
|
|
||||||
case 34:
|
|
||||||
case 35:
|
|
||||||
case 38:
|
|
||||||
case 39:
|
|
||||||
case 42:
|
|
||||||
case 43:
|
|
||||||
case 46:
|
|
||||||
case 47:
|
|
||||||
return GPIO_FUNC_UART_AUX;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return GPIO_FUNC_UART;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialUART::begin(unsigned long baud, uint16_t config) {
|
void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||||
if (_running) {
|
if (_running) {
|
||||||
end();
|
end();
|
||||||
|
|
@ -221,24 +134,6 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||||
_overflow = false;
|
_overflow = false;
|
||||||
_queue = new uint8_t[_fifoSize];
|
_queue = new uint8_t[_fifoSize];
|
||||||
_baud = baud;
|
_baud = baud;
|
||||||
|
|
||||||
_fcnTx = gpio_get_function(_tx);
|
|
||||||
_fcnRx = gpio_get_function(_rx);
|
|
||||||
gpio_set_function(_tx, __gpioFunction(_tx));
|
|
||||||
gpio_set_outover(_tx, _invertTX ? 1 : 0);
|
|
||||||
gpio_set_function(_rx, __gpioFunction(_rx));
|
|
||||||
gpio_set_inover(_rx, _invertRX ? 1 : 0);
|
|
||||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
|
||||||
_fcnRts = gpio_get_function(_rts);
|
|
||||||
gpio_set_function(_rts, GPIO_FUNC_UART);
|
|
||||||
gpio_set_outover(_rts, _invertControl ? 1 : 0);
|
|
||||||
}
|
|
||||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
|
||||||
_fcnCts = gpio_get_function(_cts);
|
|
||||||
gpio_set_function(_cts, GPIO_FUNC_UART);
|
|
||||||
gpio_set_inover(_cts, _invertControl ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uart_init(_uart, baud);
|
uart_init(_uart, baud);
|
||||||
int bits, stop;
|
int bits, stop;
|
||||||
uart_parity_t parity;
|
uart_parity_t parity;
|
||||||
|
|
@ -276,7 +171,15 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uart_set_format(_uart, bits, stop, parity);
|
uart_set_format(_uart, bits, stop, parity);
|
||||||
uart_set_hw_flow(_uart, _cts != UART_PIN_NOT_DEFINED, _rts != UART_PIN_NOT_DEFINED);
|
gpio_set_function(_tx, GPIO_FUNC_UART);
|
||||||
|
gpio_set_function(_rx, GPIO_FUNC_UART);
|
||||||
|
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||||
|
gpio_set_function(_rts, GPIO_FUNC_UART);
|
||||||
|
}
|
||||||
|
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||||
|
gpio_set_function(_cts, GPIO_FUNC_UART);
|
||||||
|
}
|
||||||
|
uart_set_hw_flow(_uart, _rts != UART_PIN_NOT_DEFINED, _cts != UART_PIN_NOT_DEFINED);
|
||||||
_writer = 0;
|
_writer = 0;
|
||||||
_reader = 0;
|
_reader = 0;
|
||||||
|
|
||||||
|
|
@ -293,7 +196,6 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||||
} else {
|
} else {
|
||||||
// Polling mode has no IRQs used
|
// Polling mode has no IRQs used
|
||||||
}
|
}
|
||||||
_break = false;
|
|
||||||
_running = true;
|
_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,7 +211,6 @@ void SerialUART::end() {
|
||||||
irq_set_enabled(UART1_IRQ, false);
|
irq_set_enabled(UART1_IRQ, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paranoia - ensure nobody else is using anything here at the same time
|
// Paranoia - ensure nobody else is using anything here at the same time
|
||||||
mutex_enter_blocking(&_mutex);
|
mutex_enter_blocking(&_mutex);
|
||||||
mutex_enter_blocking(&_fifoMutex);
|
mutex_enter_blocking(&_fifoMutex);
|
||||||
|
|
@ -318,20 +219,6 @@ void SerialUART::end() {
|
||||||
// Reset the mutexes once all is off/cleaned up
|
// Reset the mutexes once all is off/cleaned up
|
||||||
mutex_exit(&_fifoMutex);
|
mutex_exit(&_fifoMutex);
|
||||||
mutex_exit(&_mutex);
|
mutex_exit(&_mutex);
|
||||||
|
|
||||||
// Restore pin functions
|
|
||||||
gpio_set_function(_tx, _fcnTx);
|
|
||||||
gpio_set_outover(_tx, 0);
|
|
||||||
gpio_set_function(_rx, _fcnRx);
|
|
||||||
gpio_set_inover(_rx, 0);
|
|
||||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
|
||||||
gpio_set_function(_rts, _fcnRts);
|
|
||||||
gpio_set_outover(_rts, 0);
|
|
||||||
}
|
|
||||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
|
||||||
gpio_set_function(_cts, _fcnCts);
|
|
||||||
gpio_set_inover(_cts, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUART::_pumpFIFO() {
|
void SerialUART::_pumpFIFO() {
|
||||||
|
|
@ -386,22 +273,13 @@ int SerialUART::read() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::overflow() {
|
bool SerialUART::overflow() {
|
||||||
if (!_running) {
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool hold = _overflow;
|
||||||
if (_polling) {
|
|
||||||
_handleIRQ(false);
|
|
||||||
} else {
|
|
||||||
_pumpFIFO();
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_enter_blocking(&_fifoMutex);
|
|
||||||
bool ovf = _overflow;
|
|
||||||
_overflow = false;
|
_overflow = false;
|
||||||
mutex_exit(&_fifoMutex);
|
return hold;
|
||||||
|
|
||||||
return ovf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::available() {
|
int SerialUART::available() {
|
||||||
|
|
@ -414,7 +292,7 @@ int SerialUART::available() {
|
||||||
} else {
|
} else {
|
||||||
_pumpFIFO();
|
_pumpFIFO();
|
||||||
}
|
}
|
||||||
return (_fifoSize + _writer - _reader) % _fifoSize;
|
return (_writer - _reader) % _fifoSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::availableForWrite() {
|
int SerialUART::availableForWrite() {
|
||||||
|
|
@ -472,25 +350,6 @@ SerialUART::operator bool() {
|
||||||
return _running;
|
return _running;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::getBreakReceived() {
|
|
||||||
if (!_running) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_polling) {
|
|
||||||
_handleIRQ(false);
|
|
||||||
} else {
|
|
||||||
_pumpFIFO();
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_enter_blocking(&_fifoMutex);
|
|
||||||
bool break_received = _break;
|
|
||||||
_break = false;
|
|
||||||
mutex_exit(&_fifoMutex);
|
|
||||||
|
|
||||||
return break_received;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arduino::serialEvent1Run(void) {
|
void arduino::serialEvent1Run(void) {
|
||||||
if (serialEvent1 && Serial1.available()) {
|
if (serialEvent1 && Serial1.available()) {
|
||||||
serialEvent1();
|
serialEvent1();
|
||||||
|
|
@ -516,16 +375,7 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
|
||||||
// ICR is write-to-clear
|
// ICR is write-to-clear
|
||||||
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||||
while (uart_is_readable(_uart)) {
|
while (uart_is_readable(_uart)) {
|
||||||
uint32_t raw = uart_get_hw(_uart)->dr;
|
auto val = uart_getc(_uart);
|
||||||
if (raw & 0x400) {
|
|
||||||
// break!
|
|
||||||
_break = true;
|
|
||||||
continue;
|
|
||||||
} else if (raw & 0x300) {
|
|
||||||
// Framing, Parity Error. Ignore this bad char
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint8_t val = raw & 0xff;
|
|
||||||
auto next_writer = _writer + 1;
|
auto next_writer = _writer + 1;
|
||||||
if (next_writer == _fifoSize) {
|
if (next_writer == _fifoSize) {
|
||||||
next_writer = 0;
|
next_writer = 0;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
extern "C" typedef struct uart_inst uart_inst_t;
|
extern "C" typedef struct uart_inst uart_inst_t;
|
||||||
|
|
||||||
#define UART_PIN_NOT_DEFINED (255u)
|
#define UART_PIN_NOT_DEFINED (255u)
|
||||||
class SerialUART : public arduino::HardwareSerial {
|
class SerialUART : public HardwareSerial {
|
||||||
public:
|
public:
|
||||||
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
|
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
|
||||||
|
|
||||||
|
|
@ -43,26 +43,6 @@ public:
|
||||||
ret &= setTX(tx);
|
ret &= setTX(tx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setInvertTX(bool invert = true) {
|
|
||||||
if (!_running) {
|
|
||||||
_invertTX = invert;
|
|
||||||
}
|
|
||||||
return !_running;
|
|
||||||
}
|
|
||||||
bool setInvertRX(bool invert = true) {
|
|
||||||
if (!_running) {
|
|
||||||
_invertRX = invert;
|
|
||||||
}
|
|
||||||
return !_running;
|
|
||||||
}
|
|
||||||
bool setInvertControl(bool invert = true) {
|
|
||||||
if (!_running) {
|
|
||||||
_invertControl = invert;
|
|
||||||
}
|
|
||||||
return !_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool setFIFOSize(size_t size);
|
bool setFIFOSize(size_t size);
|
||||||
bool setPollingMode(bool mode = true);
|
bool setPollingMode(bool mode = true);
|
||||||
|
|
||||||
|
|
@ -83,30 +63,18 @@ public:
|
||||||
bool overflow();
|
bool overflow();
|
||||||
operator bool() override;
|
operator bool() override;
|
||||||
|
|
||||||
// ESP8266 compat
|
|
||||||
void setDebugOutput(bool unused) {
|
|
||||||
(void) unused;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||||
void _handleIRQ(bool inIRQ = true);
|
void _handleIRQ(bool inIRQ = true);
|
||||||
|
|
||||||
// Allows the user to sleep until a break is received (self-clears the flag
|
|
||||||
// on read)
|
|
||||||
bool getBreakReceived();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
uart_inst_t *_uart;
|
uart_inst_t *_uart;
|
||||||
pin_size_t _tx, _rx;
|
pin_size_t _tx, _rx;
|
||||||
pin_size_t _rts, _cts;
|
pin_size_t _rts, _cts;
|
||||||
gpio_function_t _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
|
||||||
int _baud;
|
int _baud;
|
||||||
mutex_t _mutex;
|
mutex_t _mutex;
|
||||||
bool _polling = false;
|
bool _polling = false;
|
||||||
bool _overflow;
|
bool _overflow;
|
||||||
bool _break;
|
|
||||||
bool _invertTX, _invertRX, _invertControl;
|
|
||||||
|
|
||||||
// Lockless, IRQ-handled circular queue
|
// Lockless, IRQ-handled circular queue
|
||||||
uint32_t _writer;
|
uint32_t _writer;
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,14 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
|
|
||||||
#include <tusb.h>
|
#include "tusb.h"
|
||||||
#include <pico/time.h>
|
#include "pico/time.h"
|
||||||
#include <pico/binary_info.h>
|
#include "pico/binary_info.h"
|
||||||
#include <pico/bootrom.h>
|
#include "pico/bootrom.h"
|
||||||
#include <hardware/irq.h>
|
#include "hardware/irq.h"
|
||||||
#include <pico/mutex.h>
|
#include "pico/mutex.h"
|
||||||
#include <hardware/watchdog.h>
|
#include "hardware/watchdog.h"
|
||||||
#include <pico/unique_id.h>
|
#include "pico/unique_id.h"
|
||||||
#include <hardware/resets.h>
|
|
||||||
|
|
||||||
#ifndef DISABLE_USB_SERIAL
|
#ifndef DISABLE_USB_SERIAL
|
||||||
// Ensure we are installed in the USB chain
|
// Ensure we are installed in the USB chain
|
||||||
|
|
@ -65,57 +64,52 @@ void SerialUSB::end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::peek() {
|
int SerialUSB::peek() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
tud_task();
|
|
||||||
return tud_cdc_peek(&c) ? (int) c : -1;
|
return tud_cdc_peek(&c) ? (int) c : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::read() {
|
int SerialUSB::read() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_task();
|
if (tud_cdc_connected() && tud_cdc_available()) {
|
||||||
if (tud_cdc_available()) {
|
|
||||||
return tud_cdc_read_char();
|
return tud_cdc_read_char();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::available() {
|
int SerialUSB::available() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_task();
|
|
||||||
return tud_cdc_available();
|
return tud_cdc_available();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::availableForWrite() {
|
int SerialUSB::availableForWrite() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_task();
|
|
||||||
return tud_cdc_write_available();
|
return tud_cdc_write_available();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUSB::flush() {
|
void SerialUSB::flush() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
tud_task();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialUSB::write(uint8_t c) {
|
size_t SerialUSB::write(uint8_t c) {
|
||||||
|
|
@ -123,14 +117,14 @@ size_t SerialUSB::write(uint8_t c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t last_avail_time;
|
static uint64_t last_avail_time;
|
||||||
int written = 0;
|
int i = 0;
|
||||||
if (tud_cdc_connected() || _ignoreFlowControl) {
|
if (tud_cdc_connected()) {
|
||||||
for (size_t i = 0; i < length;) {
|
for (size_t i = 0; i < length;) {
|
||||||
int n = length - i;
|
int n = length - i;
|
||||||
int avail = tud_cdc_write_available();
|
int avail = tud_cdc_write_available();
|
||||||
|
|
@ -142,13 +136,12 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
tud_task();
|
tud_task();
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
i += n2;
|
i += n2;
|
||||||
written += n2;
|
|
||||||
last_avail_time = time_us_64();
|
last_avail_time = time_us_64();
|
||||||
} else {
|
} else {
|
||||||
tud_task();
|
tud_task();
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
if (!tud_cdc_connected() ||
|
if (!tud_cdc_connected() ||
|
||||||
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1'000'000 /* 1 second */)) {
|
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1000000 /* 1 second */)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,12 +150,11 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
// reset our timeout
|
// reset our timeout
|
||||||
last_avail_time = 0;
|
last_avail_time = 0;
|
||||||
}
|
}
|
||||||
tud_task();
|
return i;
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialUSB::operator bool() {
|
SerialUSB::operator bool() {
|
||||||
CoreMutex m(&__usb_mutex, false);
|
CoreMutex m(&__usb_mutex);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -171,40 +163,17 @@ SerialUSB::operator bool() {
|
||||||
return tud_cdc_connected();
|
return tud_cdc_connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUSB::ignoreFlowControl(bool ignore) {
|
|
||||||
_ignoreFlowControl = ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _dtr = false;
|
static bool _dtr = false;
|
||||||
static bool _rts = false;
|
static bool _rts = false;
|
||||||
static int _bps = 115200;
|
static int _bps = 115200;
|
||||||
static bool _rebooting = false;
|
|
||||||
static void CheckSerialReset() {
|
static void CheckSerialReset() {
|
||||||
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
|
if ((_bps == 1200) && (!_dtr)) {
|
||||||
if (__isFreeRTOS) {
|
|
||||||
__freertos_idle_other_core();
|
|
||||||
}
|
|
||||||
_rebooting = true;
|
|
||||||
// Disable NVIC IRQ, so that we don't get bothered anymore
|
|
||||||
irq_set_enabled(USBCTRL_IRQ, false);
|
|
||||||
// Reset the whole USB hardware block
|
|
||||||
reset_block(RESETS_RESET_USBCTRL_BITS);
|
|
||||||
unreset_block(RESETS_RESET_USBCTRL_BITS);
|
|
||||||
// Delay a bit, so the PC can figure out that we have disconnected.
|
|
||||||
busy_wait_ms(3);
|
|
||||||
reset_usb_boot(0, 0);
|
reset_usb_boot(0, 0);
|
||||||
while (1); // WDT will fire here
|
while (1); // WDT will fire here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUSB::dtr() {
|
|
||||||
return _dtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SerialUSB::rts() {
|
|
||||||
return _rts;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||||
(void) itf;
|
(void) itf;
|
||||||
_dtr = dtr ? true : false;
|
_dtr = dtr ? true : false;
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef __SERIALUSB_H__
|
||||||
|
#define __SERIALUSB_H__
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "api/HardwareSerial.h"
|
#include "api/HardwareSerial.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
class SerialUSB : public arduino::HardwareSerial {
|
class SerialUSB : public HardwareSerial {
|
||||||
public:
|
public:
|
||||||
SerialUSB() { }
|
SerialUSB() { }
|
||||||
void begin(unsigned long baud = 115200) override;
|
void begin(unsigned long baud = 115200) override;
|
||||||
|
|
@ -43,19 +44,9 @@ public:
|
||||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||||
using Print::write;
|
using Print::write;
|
||||||
operator bool() override;
|
operator bool() override;
|
||||||
bool dtr();
|
|
||||||
bool rts();
|
|
||||||
|
|
||||||
void ignoreFlowControl(bool ignore = true);
|
|
||||||
|
|
||||||
// ESP8266 compat
|
|
||||||
void setDebugOutput(bool unused) {
|
|
||||||
(void) unused;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
bool _ignoreFlowControl = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SerialUSB Serial;
|
extern SerialUSB Serial;
|
||||||
|
|
@ -63,3 +54,5 @@ extern SerialUSB Serial;
|
||||||
namespace arduino {
|
namespace arduino {
|
||||||
extern void serialEventRun(void) __attribute__((weak));
|
extern void serialEventRun(void) __attribute__((weak));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,56 +22,34 @@
|
||||||
|
|
||||||
#include "SerialPIO.h"
|
#include "SerialPIO.h"
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Implements a UART port using PIO for input and output
|
|
||||||
*/
|
|
||||||
class SoftwareSerial : public SerialPIO {
|
class SoftwareSerial : public SerialPIO {
|
||||||
public:
|
public:
|
||||||
/**
|
// Note the rx/tx pins are swapped in PIO vs SWSerial
|
||||||
@brief Constructs a PIO-based UART
|
|
||||||
|
|
||||||
@param [in] rx GPIO for RX pin or -1 for transmit-only
|
|
||||||
@param [in] tx GPIO for TX pin or -1 for receive-only
|
|
||||||
@param [in] invert True to invert the receive and transmit lines
|
|
||||||
*/
|
|
||||||
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
|
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
|
||||||
_invert = invert;
|
_invert = invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
~SoftwareSerial() {
|
~SoftwareSerial() {
|
||||||
|
if (_invert) {
|
||||||
|
gpio_set_outover(_tx, 0);
|
||||||
|
gpio_set_outover(_rx, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Starts the PIO UART
|
|
||||||
|
|
||||||
@param [in] baud Serial bit rate
|
|
||||||
*/
|
|
||||||
virtual void begin(unsigned long baud = 115200) override {
|
virtual void begin(unsigned long baud = 115200) override {
|
||||||
begin(baud, SERIAL_8N1);
|
begin(baud, SERIAL_8N1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Starts the PIO UART
|
|
||||||
|
|
||||||
@param [in] baud Serial bit rate
|
|
||||||
@param [in] config Start/Stop/Len configuration (i.e. SERIAL_8N1 or SERIAL_7E2)
|
|
||||||
*/
|
|
||||||
void begin(unsigned long baud, uint16_t config) override {
|
void begin(unsigned long baud, uint16_t config) override {
|
||||||
setInvertTX(_invert);
|
|
||||||
setInvertRX(_invert);
|
|
||||||
SerialPIO::begin(baud, config);
|
SerialPIO::begin(baud, config);
|
||||||
|
if (_invert) {
|
||||||
|
gpio_set_outover(_tx, GPIO_OVERRIDE_INVERT);
|
||||||
|
gpio_set_inover(_rx, GPIO_OVERRIDE_INVERT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@brief No-op on this core
|
|
||||||
*/
|
|
||||||
void listen() { /* noop */ }
|
void listen() { /* noop */ }
|
||||||
|
|
||||||
/**
|
|
||||||
@brief No-op on this core
|
|
||||||
|
|
||||||
@returns True always
|
|
||||||
*/
|
|
||||||
bool isListening() {
|
bool isListening() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
StackThunk - Implements a simple 2nd stack for BSSL and others
|
|
||||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "StackThunk.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
uint32_t *stack_thunk_ptr = nullptr;
|
|
||||||
uint32_t *stack_thunk_top = nullptr;
|
|
||||||
uint32_t *stack_thunk_save = nullptr; /* Saved A1 while in BearSSL */
|
|
||||||
uint32_t stack_thunk_refcnt = 0;
|
|
||||||
|
|
||||||
/* Largest stack usage seen in the wild at 6120 */
|
|
||||||
#define _stackSize (6400/4)
|
|
||||||
#define _stackPaint 0xdeadbeef
|
|
||||||
|
|
||||||
/* Add a reference, and allocate the stack if necessary */
|
|
||||||
void stack_thunk_add_ref() {
|
|
||||||
stack_thunk_refcnt++;
|
|
||||||
if (stack_thunk_refcnt == 1) {
|
|
||||||
// The stack must be in DRAM, or an Soft WDT will follow. Not sure why,
|
|
||||||
// maybe too much time is consumed with the non32-bit exception handler.
|
|
||||||
// Also, interrupt handling on an IRAM stack would be very slow.
|
|
||||||
// Strings on the stack would be very slow to access as well.
|
|
||||||
stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
|
|
||||||
if (!stack_thunk_ptr) {
|
|
||||||
// This is a fatal error, stop the sketch
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
|
|
||||||
stack_thunk_save = nullptr;
|
|
||||||
stack_thunk_repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drop a reference, and free stack if no more in use */
|
|
||||||
void stack_thunk_del_ref() {
|
|
||||||
if (stack_thunk_refcnt == 0) {
|
|
||||||
/* Error! */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stack_thunk_refcnt--;
|
|
||||||
if (!stack_thunk_refcnt) {
|
|
||||||
free(stack_thunk_ptr);
|
|
||||||
stack_thunk_ptr = nullptr;
|
|
||||||
stack_thunk_top = nullptr;
|
|
||||||
stack_thunk_save = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stack_thunk_repaint() {
|
|
||||||
for (int i = 0; i < _stackSize; i++) {
|
|
||||||
stack_thunk_ptr[i] = _stackPaint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simple accessor functions used by postmortem */
|
|
||||||
uint32_t stack_thunk_get_refcnt() {
|
|
||||||
return stack_thunk_refcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t stack_thunk_get_stack_top() {
|
|
||||||
return (uint32_t)stack_thunk_top;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t stack_thunk_get_stack_bot() {
|
|
||||||
return (uint32_t)stack_thunk_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t stack_thunk_get_cont_sp() {
|
|
||||||
return (uint32_t)stack_thunk_save;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the number of bytes ever used since the stack was created */
|
|
||||||
uint32_t stack_thunk_get_max_usage() {
|
|
||||||
uint32_t cnt = 0;
|
|
||||||
|
|
||||||
/* No stack == no usage by definition! */
|
|
||||||
if (!stack_thunk_ptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cnt = 0; (cnt < _stackSize) && (stack_thunk_ptr[cnt] == _stackPaint); cnt++) {
|
|
||||||
/* Noop, all work done in for() */
|
|
||||||
}
|
|
||||||
return 4 * (_stackSize - cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
StackThunk - Implements a simple 2nd stack for BSSL and others
|
|
||||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void stack_thunk_add_ref();
|
|
||||||
extern void stack_thunk_del_ref();
|
|
||||||
extern void stack_thunk_repaint();
|
|
||||||
|
|
||||||
extern uint32_t stack_thunk_get_refcnt();
|
|
||||||
extern uint32_t stack_thunk_get_stack_top();
|
|
||||||
extern uint32_t stack_thunk_get_stack_bot();
|
|
||||||
extern uint32_t stack_thunk_get_cont_sp();
|
|
||||||
extern uint32_t stack_thunk_get_max_usage();
|
|
||||||
extern void stack_thunk_dump_stack();
|
|
||||||
extern void stack_thunk_fatal_overflow();
|
|
||||||
|
|
||||||
// Globals required for thunking operation
|
|
||||||
extern uint32_t *stack_thunk_ptr;
|
|
||||||
extern uint32_t *stack_thunk_top;
|
|
||||||
extern uint32_t *stack_thunk_save;
|
|
||||||
extern uint32_t stack_thunk_refcnt;
|
|
||||||
|
|
||||||
#define make_stack_thunk_void(fcnToThunk, proto, params) \
|
|
||||||
extern "C" void thunk_##fcnToThunk proto { \
|
|
||||||
register uint32_t* sp asm("sp"); \
|
|
||||||
stack_thunk_save = sp; \
|
|
||||||
sp = stack_thunk_top; \
|
|
||||||
fcnToThunk params; \
|
|
||||||
sp = stack_thunk_save; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define make_stack_thunk_unsigned_char_ptr(fcnToThunk, proto, params) \
|
|
||||||
extern "C" unsigned char * thunk_##fcnToThunk proto { \
|
|
||||||
register uint32_t* sp asm("sp"); \
|
|
||||||
stack_thunk_save = sp; \
|
|
||||||
sp = stack_thunk_top; \
|
|
||||||
auto x = fcnToThunk params; \
|
|
||||||
sp = stack_thunk_save; \
|
|
||||||
return x; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define make_stack_thunk_bool(fcnToThunk, proto, params) \
|
|
||||||
extern "C" bool thunk_##fcnToThunk proto { \
|
|
||||||
register uint32_t* sp asm("sp"); \
|
|
||||||
stack_thunk_save = sp; \
|
|
||||||
sp = stack_thunk_top; \
|
|
||||||
auto x = fcnToThunk params; \
|
|
||||||
sp = stack_thunk_save; \
|
|
||||||
return x; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,247 +0,0 @@
|
||||||
/**
|
|
||||||
StreamString.h
|
|
||||||
|
|
||||||
Copyright (c) 2020 D. Gauchard. All rights reserved.
|
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __STREAMSTRING_H
|
|
||||||
#define __STREAMSTRING_H
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <algorithm>
|
|
||||||
#include "Stream.h"
|
|
||||||
#include "api/String.h"
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// S2Stream points to a String and makes it a Stream
|
|
||||||
// (it is also the helper for StreamString)
|
|
||||||
|
|
||||||
class S2Stream: public Stream {
|
|
||||||
public:
|
|
||||||
S2Stream(String& string, int peekPointer = -1) : string(&string), peekPointer(peekPointer) { }
|
|
||||||
|
|
||||||
S2Stream(String* string, int peekPointer = -1) : string(string), peekPointer(peekPointer) { }
|
|
||||||
|
|
||||||
virtual int available() override {
|
|
||||||
return string->length();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int availableForWrite() override {
|
|
||||||
return std::numeric_limits<int16_t>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int read() override {
|
|
||||||
if (peekPointer < 0) {
|
|
||||||
// consume chars
|
|
||||||
if (string->length()) {
|
|
||||||
char c = string->charAt(0);
|
|
||||||
string->remove(0, 1);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
} else if (peekPointer < (int)string->length()) {
|
|
||||||
// return pointed and move pointer
|
|
||||||
return string->charAt(peekPointer++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// everything is read
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t write(uint8_t data) override {
|
|
||||||
return string->concat((char)data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// virtual int read(uint8_t* buffer, size_t len) override
|
|
||||||
// {
|
|
||||||
// if (peekPointer < 0)
|
|
||||||
// {
|
|
||||||
// // string will be consumed
|
|
||||||
// size_t l = std::min(len, (size_t)string->length());
|
|
||||||
// memcpy(buffer, string->c_str(), l);
|
|
||||||
// string->remove(0, l);
|
|
||||||
// return l;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (peekPointer >= (int)string->length())
|
|
||||||
// {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // only the pointer is moved
|
|
||||||
// size_t l = std::min(len, (size_t)(string->length() - peekPointer));
|
|
||||||
// memcpy(buffer, string->c_str() + peekPointer, l);
|
|
||||||
// peekPointer += l;
|
|
||||||
// return l;
|
|
||||||
// }
|
|
||||||
|
|
||||||
virtual size_t write(const uint8_t* buffer, size_t len) override {
|
|
||||||
return string->concat((const char*)buffer, len) ? len : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int peek() override {
|
|
||||||
if (peekPointer < 0) {
|
|
||||||
if (string->length()) {
|
|
||||||
return string->charAt(0);
|
|
||||||
}
|
|
||||||
} else if (peekPointer < (int)string->length()) {
|
|
||||||
return string->charAt(peekPointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() override {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
virtual bool inputCanTimeout() override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool outputCanTimeout() override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// Stream's peekBufferAPI
|
|
||||||
|
|
||||||
virtual bool hasPeekBufferAPI() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t peekAvailable() {
|
|
||||||
if (peekPointer < 0) {
|
|
||||||
return string->length();
|
|
||||||
}
|
|
||||||
return string->length() - peekPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const char* peekBuffer() override {
|
|
||||||
if (peekPointer < 0) {
|
|
||||||
return string->c_str();
|
|
||||||
}
|
|
||||||
if (peekPointer < (int)string->length()) {
|
|
||||||
return string->c_str() + peekPointer;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void peekConsume(size_t consume) override {
|
|
||||||
if (peekPointer < 0) {
|
|
||||||
// string is really consumed
|
|
||||||
string->remove(0, consume);
|
|
||||||
} else {
|
|
||||||
// only the pointer is moved
|
|
||||||
peekPointer = std::min((size_t)string->length(), peekPointer + consume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ssize_t streamRemaining() override {
|
|
||||||
return peekPointer < 0 ? string->length() : string->length() - peekPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calling setConsume() will consume bytes as the stream is read
|
|
||||||
// (enabled by default)
|
|
||||||
void setConsume() {
|
|
||||||
peekPointer = -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Reading this stream will mark the string as read without consuming
|
|
||||||
// (not enabled by default)
|
|
||||||
// Calling resetPointer() resets the read state and allows rereading.
|
|
||||||
void resetPointer(int pointer = 0) {
|
|
||||||
peekPointer = pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
String* string;
|
|
||||||
int peekPointer; // -1:String is consumed / >=0:resettable pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
// StreamString is a S2Stream holding the String
|
|
||||||
|
|
||||||
class StreamString: public String, public S2Stream {
|
|
||||||
protected:
|
|
||||||
void resetpp() {
|
|
||||||
if (peekPointer > 0) {
|
|
||||||
peekPointer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
StreamString(StreamString&& bro) : String(bro), S2Stream(this) { }
|
|
||||||
StreamString(const StreamString& bro) : String(bro), S2Stream(this) { }
|
|
||||||
|
|
||||||
// duplicate String constructors and operator=:
|
|
||||||
|
|
||||||
StreamString(const char* text = nullptr) : String(text), S2Stream(this) { }
|
|
||||||
StreamString(const String& string) : String(string), S2Stream(this) { }
|
|
||||||
StreamString(const __FlashStringHelper* str) : String(str), S2Stream(this) { }
|
|
||||||
StreamString(String&& string) : String(string), S2Stream(this) { }
|
|
||||||
|
|
||||||
explicit StreamString(char c) : String(c), S2Stream(this) { }
|
|
||||||
explicit StreamString(unsigned char c, unsigned char base = 10) :
|
|
||||||
String(c, base), S2Stream(this) {
|
|
||||||
}
|
|
||||||
explicit StreamString(int i, unsigned char base = 10) : String(i, base), S2Stream(this) { }
|
|
||||||
explicit StreamString(unsigned int i, unsigned char base = 10) : String(i, base), S2Stream(this) {
|
|
||||||
}
|
|
||||||
explicit StreamString(long l, unsigned char base = 10) : String(l, base), S2Stream(this) { }
|
|
||||||
explicit StreamString(unsigned long l, unsigned char base = 10) :
|
|
||||||
String(l, base), S2Stream(this) {
|
|
||||||
}
|
|
||||||
explicit StreamString(float f, unsigned char decimalPlaces = 2) :
|
|
||||||
String(f, decimalPlaces), S2Stream(this) {
|
|
||||||
}
|
|
||||||
explicit StreamString(double d, unsigned char decimalPlaces = 2) :
|
|
||||||
String(d, decimalPlaces), S2Stream(this) {
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamString& operator=(const StreamString& rhs) {
|
|
||||||
String::operator=(rhs);
|
|
||||||
resetpp();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamString& operator=(const String& rhs) {
|
|
||||||
String::operator=(rhs);
|
|
||||||
resetpp();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamString& operator=(const char* cstr) {
|
|
||||||
String::operator=(cstr);
|
|
||||||
resetpp();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamString& operator=(const __FlashStringHelper* str) {
|
|
||||||
String::operator=(str);
|
|
||||||
resetpp();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamString& operator=(String&& rval) {
|
|
||||||
String::operator=(rval);
|
|
||||||
resetpp();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __STREAMSTRING_H
|
|
||||||
|
|
@ -1,474 +0,0 @@
|
||||||
|
|
||||||
// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
|
||||||
// by script <rp2040 arduino core>/tools/tzupdate.sh
|
|
||||||
// Sat 20 Jan 2024 08:54:45 PM UTC
|
|
||||||
//
|
|
||||||
// This database is autogenerated from IANA timezone database
|
|
||||||
// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
|
||||||
// (using https://www.iana.org/time-zones)
|
|
||||||
// and can be updated on demand in this repository
|
|
||||||
// or by yourself using the above script
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define TZ_Africa_Abidjan ("GMT0")
|
|
||||||
#define TZ_Africa_Accra ("GMT0")
|
|
||||||
#define TZ_Africa_Addis_Ababa ("EAT-3")
|
|
||||||
#define TZ_Africa_Algiers ("CET-1")
|
|
||||||
#define TZ_Africa_Asmara ("EAT-3")
|
|
||||||
#define TZ_Africa_Bamako ("GMT0")
|
|
||||||
#define TZ_Africa_Bangui ("WAT-1")
|
|
||||||
#define TZ_Africa_Banjul ("GMT0")
|
|
||||||
#define TZ_Africa_Bissau ("GMT0")
|
|
||||||
#define TZ_Africa_Blantyre ("CAT-2")
|
|
||||||
#define TZ_Africa_Brazzaville ("WAT-1")
|
|
||||||
#define TZ_Africa_Bujumbura ("CAT-2")
|
|
||||||
#define TZ_Africa_Cairo ("EET-2EEST,M4.5.5/0,M10.5.4/24")
|
|
||||||
#define TZ_Africa_Casablanca ("<+01>-1")
|
|
||||||
#define TZ_Africa_Ceuta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Africa_Conakry ("GMT0")
|
|
||||||
#define TZ_Africa_Dakar ("GMT0")
|
|
||||||
#define TZ_Africa_Dar_es_Salaam ("EAT-3")
|
|
||||||
#define TZ_Africa_Djibouti ("EAT-3")
|
|
||||||
#define TZ_Africa_Douala ("WAT-1")
|
|
||||||
#define TZ_Africa_El_Aaiun ("<+01>-1")
|
|
||||||
#define TZ_Africa_Freetown ("GMT0")
|
|
||||||
#define TZ_Africa_Gaborone ("CAT-2")
|
|
||||||
#define TZ_Africa_Harare ("CAT-2")
|
|
||||||
#define TZ_Africa_Johannesburg ("SAST-2")
|
|
||||||
#define TZ_Africa_Juba ("CAT-2")
|
|
||||||
#define TZ_Africa_Kampala ("EAT-3")
|
|
||||||
#define TZ_Africa_Khartoum ("CAT-2")
|
|
||||||
#define TZ_Africa_Kigali ("CAT-2")
|
|
||||||
#define TZ_Africa_Kinshasa ("WAT-1")
|
|
||||||
#define TZ_Africa_Lagos ("WAT-1")
|
|
||||||
#define TZ_Africa_Libreville ("WAT-1")
|
|
||||||
#define TZ_Africa_Lome ("GMT0")
|
|
||||||
#define TZ_Africa_Luanda ("WAT-1")
|
|
||||||
#define TZ_Africa_Lubumbashi ("CAT-2")
|
|
||||||
#define TZ_Africa_Lusaka ("CAT-2")
|
|
||||||
#define TZ_Africa_Malabo ("WAT-1")
|
|
||||||
#define TZ_Africa_Maputo ("CAT-2")
|
|
||||||
#define TZ_Africa_Maseru ("SAST-2")
|
|
||||||
#define TZ_Africa_Mbabane ("SAST-2")
|
|
||||||
#define TZ_Africa_Mogadishu ("EAT-3")
|
|
||||||
#define TZ_Africa_Monrovia ("GMT0")
|
|
||||||
#define TZ_Africa_Nairobi ("EAT-3")
|
|
||||||
#define TZ_Africa_Ndjamena ("WAT-1")
|
|
||||||
#define TZ_Africa_Niamey ("WAT-1")
|
|
||||||
#define TZ_Africa_Nouakchott ("GMT0")
|
|
||||||
#define TZ_Africa_Ouagadougou ("GMT0")
|
|
||||||
#define TZ_Africa_PortomNovo ("WAT-1")
|
|
||||||
#define TZ_Africa_Sao_Tome ("GMT0")
|
|
||||||
#define TZ_Africa_Tripoli ("EET-2")
|
|
||||||
#define TZ_Africa_Tunis ("CET-1")
|
|
||||||
#define TZ_Africa_Windhoek ("CAT-2")
|
|
||||||
#define TZ_America_Adak ("HST10HDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Anchorage ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Anguilla ("AST4")
|
|
||||||
#define TZ_America_Antigua ("AST4")
|
|
||||||
#define TZ_America_Araguaina ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Buenos_Aires ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Catamarca ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Cordoba ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Jujuy ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_La_Rioja ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Mendoza ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Rio_Gallegos ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Salta ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_San_Juan ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_San_Luis ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Tucuman ("<-03>3")
|
|
||||||
#define TZ_America_Argentina_Ushuaia ("<-03>3")
|
|
||||||
#define TZ_America_Aruba ("AST4")
|
|
||||||
#define TZ_America_Asuncion ("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
|
|
||||||
#define TZ_America_Atikokan ("EST5")
|
|
||||||
#define TZ_America_Bahia ("<-03>3")
|
|
||||||
#define TZ_America_Bahia_Banderas ("CST6")
|
|
||||||
#define TZ_America_Barbados ("AST4")
|
|
||||||
#define TZ_America_Belem ("<-03>3")
|
|
||||||
#define TZ_America_Belize ("CST6")
|
|
||||||
#define TZ_America_BlancmSablon ("AST4")
|
|
||||||
#define TZ_America_Boa_Vista ("<-04>4")
|
|
||||||
#define TZ_America_Bogota ("<-05>5")
|
|
||||||
#define TZ_America_Boise ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Cambridge_Bay ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Campo_Grande ("<-04>4")
|
|
||||||
#define TZ_America_Cancun ("EST5")
|
|
||||||
#define TZ_America_Caracas ("<-04>4")
|
|
||||||
#define TZ_America_Cayenne ("<-03>3")
|
|
||||||
#define TZ_America_Cayman ("EST5")
|
|
||||||
#define TZ_America_Chicago ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Chihuahua ("CST6")
|
|
||||||
#define TZ_America_Costa_Rica ("CST6")
|
|
||||||
#define TZ_America_Creston ("MST7")
|
|
||||||
#define TZ_America_Cuiaba ("<-04>4")
|
|
||||||
#define TZ_America_Curacao ("AST4")
|
|
||||||
#define TZ_America_Danmarkshavn ("GMT0")
|
|
||||||
#define TZ_America_Dawson ("MST7")
|
|
||||||
#define TZ_America_Dawson_Creek ("MST7")
|
|
||||||
#define TZ_America_Denver ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Detroit ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Dominica ("AST4")
|
|
||||||
#define TZ_America_Edmonton ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Eirunepe ("<-05>5")
|
|
||||||
#define TZ_America_El_Salvador ("CST6")
|
|
||||||
#define TZ_America_Fortaleza ("<-03>3")
|
|
||||||
#define TZ_America_Fort_Nelson ("MST7")
|
|
||||||
#define TZ_America_Glace_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Godthab ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
|
||||||
#define TZ_America_Goose_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Grand_Turk ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Grenada ("AST4")
|
|
||||||
#define TZ_America_Guadeloupe ("AST4")
|
|
||||||
#define TZ_America_Guatemala ("CST6")
|
|
||||||
#define TZ_America_Guayaquil ("<-05>5")
|
|
||||||
#define TZ_America_Guyana ("<-04>4")
|
|
||||||
#define TZ_America_Halifax ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Havana ("CST5CDT,M3.2.0/0,M11.1.0/1")
|
|
||||||
#define TZ_America_Hermosillo ("MST7")
|
|
||||||
#define TZ_America_Indiana_Indianapolis ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Knox ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Marengo ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Petersburg ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Tell_City ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Vevay ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Vincennes ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Indiana_Winamac ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Inuvik ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Iqaluit ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Jamaica ("EST5")
|
|
||||||
#define TZ_America_Juneau ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Kentucky_Louisville ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Kentucky_Monticello ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Kralendijk ("AST4")
|
|
||||||
#define TZ_America_La_Paz ("<-04>4")
|
|
||||||
#define TZ_America_Lima ("<-05>5")
|
|
||||||
#define TZ_America_Los_Angeles ("PST8PDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Lower_Princes ("AST4")
|
|
||||||
#define TZ_America_Maceio ("<-03>3")
|
|
||||||
#define TZ_America_Managua ("CST6")
|
|
||||||
#define TZ_America_Manaus ("<-04>4")
|
|
||||||
#define TZ_America_Marigot ("AST4")
|
|
||||||
#define TZ_America_Martinique ("AST4")
|
|
||||||
#define TZ_America_Matamoros ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Mazatlan ("MST7")
|
|
||||||
#define TZ_America_Menominee ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Merida ("CST6")
|
|
||||||
#define TZ_America_Metlakatla ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Mexico_City ("CST6")
|
|
||||||
#define TZ_America_Miquelon ("<-03>3<-02>,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Moncton ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Monterrey ("CST6")
|
|
||||||
#define TZ_America_Montevideo ("<-03>3")
|
|
||||||
#define TZ_America_Montreal ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Montserrat ("AST4")
|
|
||||||
#define TZ_America_Nassau ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_New_York ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Nipigon ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Nome ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Noronha ("<-02>2")
|
|
||||||
#define TZ_America_North_Dakota_Beulah ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_North_Dakota_Center ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_North_Dakota_New_Salem ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Nuuk ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
|
||||||
#define TZ_America_Ojinaga ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Panama ("EST5")
|
|
||||||
#define TZ_America_Pangnirtung ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Paramaribo ("<-03>3")
|
|
||||||
#define TZ_America_Phoenix ("MST7")
|
|
||||||
#define TZ_America_PortmaumPrince ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Port_of_Spain ("AST4")
|
|
||||||
#define TZ_America_Porto_Velho ("<-04>4")
|
|
||||||
#define TZ_America_Puerto_Rico ("AST4")
|
|
||||||
#define TZ_America_Punta_Arenas ("<-03>3")
|
|
||||||
#define TZ_America_Rainy_River ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Rankin_Inlet ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Recife ("<-03>3")
|
|
||||||
#define TZ_America_Regina ("CST6")
|
|
||||||
#define TZ_America_Resolute ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Rio_Branco ("<-05>5")
|
|
||||||
#define TZ_America_Santarem ("<-03>3")
|
|
||||||
#define TZ_America_Santiago ("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
|
|
||||||
#define TZ_America_Santo_Domingo ("AST4")
|
|
||||||
#define TZ_America_Sao_Paulo ("<-03>3")
|
|
||||||
#define TZ_America_Scoresbysund ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
|
||||||
#define TZ_America_Sitka ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_St_Barthelemy ("AST4")
|
|
||||||
#define TZ_America_St_Johns ("NST3:30NDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_St_Kitts ("AST4")
|
|
||||||
#define TZ_America_St_Lucia ("AST4")
|
|
||||||
#define TZ_America_St_Thomas ("AST4")
|
|
||||||
#define TZ_America_St_Vincent ("AST4")
|
|
||||||
#define TZ_America_Swift_Current ("CST6")
|
|
||||||
#define TZ_America_Tegucigalpa ("CST6")
|
|
||||||
#define TZ_America_Thule ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Thunder_Bay ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Tijuana ("PST8PDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Toronto ("EST5EDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Tortola ("AST4")
|
|
||||||
#define TZ_America_Vancouver ("PST8PDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Whitehorse ("MST7")
|
|
||||||
#define TZ_America_Winnipeg ("CST6CDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Yakutat ("AKST9AKDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_America_Yellowknife ("MST7MDT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_Antarctica_Casey ("<+11>-11")
|
|
||||||
#define TZ_Antarctica_Davis ("<+07>-7")
|
|
||||||
#define TZ_Antarctica_DumontDUrville ("<+10>-10")
|
|
||||||
#define TZ_Antarctica_Macquarie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Antarctica_Mawson ("<+05>-5")
|
|
||||||
#define TZ_Antarctica_McMurdo ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
|
||||||
#define TZ_Antarctica_Palmer ("<-03>3")
|
|
||||||
#define TZ_Antarctica_Rothera ("<-03>3")
|
|
||||||
#define TZ_Antarctica_Syowa ("<+03>-3")
|
|
||||||
#define TZ_Antarctica_Troll ("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
|
|
||||||
#define TZ_Antarctica_Vostok ("<+06>-6")
|
|
||||||
#define TZ_Arctic_Longyearbyen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Asia_Aden ("<+03>-3")
|
|
||||||
#define TZ_Asia_Almaty ("<+06>-6")
|
|
||||||
#define TZ_Asia_Amman ("<+03>-3")
|
|
||||||
#define TZ_Asia_Anadyr ("<+12>-12")
|
|
||||||
#define TZ_Asia_Aqtau ("<+05>-5")
|
|
||||||
#define TZ_Asia_Aqtobe ("<+05>-5")
|
|
||||||
#define TZ_Asia_Ashgabat ("<+05>-5")
|
|
||||||
#define TZ_Asia_Atyrau ("<+05>-5")
|
|
||||||
#define TZ_Asia_Baghdad ("<+03>-3")
|
|
||||||
#define TZ_Asia_Bahrain ("<+03>-3")
|
|
||||||
#define TZ_Asia_Baku ("<+04>-4")
|
|
||||||
#define TZ_Asia_Bangkok ("<+07>-7")
|
|
||||||
#define TZ_Asia_Barnaul ("<+07>-7")
|
|
||||||
#define TZ_Asia_Beirut ("EET-2EEST,M3.5.0/0,M10.5.0/0")
|
|
||||||
#define TZ_Asia_Bishkek ("<+06>-6")
|
|
||||||
#define TZ_Asia_Brunei ("<+08>-8")
|
|
||||||
#define TZ_Asia_Chita ("<+09>-9")
|
|
||||||
#define TZ_Asia_Choibalsan ("<+08>-8")
|
|
||||||
#define TZ_Asia_Colombo ("<+0530>-5:30")
|
|
||||||
#define TZ_Asia_Damascus ("<+03>-3")
|
|
||||||
#define TZ_Asia_Dhaka ("<+06>-6")
|
|
||||||
#define TZ_Asia_Dili ("<+09>-9")
|
|
||||||
#define TZ_Asia_Dubai ("<+04>-4")
|
|
||||||
#define TZ_Asia_Dushanbe ("<+05>-5")
|
|
||||||
#define TZ_Asia_Famagusta ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Asia_Gaza ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
|
||||||
#define TZ_Asia_Hebron ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
|
||||||
#define TZ_Asia_Ho_Chi_Minh ("<+07>-7")
|
|
||||||
#define TZ_Asia_Hong_Kong ("HKT-8")
|
|
||||||
#define TZ_Asia_Hovd ("<+07>-7")
|
|
||||||
#define TZ_Asia_Irkutsk ("<+08>-8")
|
|
||||||
#define TZ_Asia_Jakarta ("WIB-7")
|
|
||||||
#define TZ_Asia_Jayapura ("WIT-9")
|
|
||||||
#define TZ_Asia_Jerusalem ("IST-2IDT,M3.4.4/26,M10.5.0")
|
|
||||||
#define TZ_Asia_Kabul ("<+0430>-4:30")
|
|
||||||
#define TZ_Asia_Kamchatka ("<+12>-12")
|
|
||||||
#define TZ_Asia_Karachi ("PKT-5")
|
|
||||||
#define TZ_Asia_Kathmandu ("<+0545>-5:45")
|
|
||||||
#define TZ_Asia_Khandyga ("<+09>-9")
|
|
||||||
#define TZ_Asia_Kolkata ("IST-5:30")
|
|
||||||
#define TZ_Asia_Krasnoyarsk ("<+07>-7")
|
|
||||||
#define TZ_Asia_Kuala_Lumpur ("<+08>-8")
|
|
||||||
#define TZ_Asia_Kuching ("<+08>-8")
|
|
||||||
#define TZ_Asia_Kuwait ("<+03>-3")
|
|
||||||
#define TZ_Asia_Macau ("CST-8")
|
|
||||||
#define TZ_Asia_Magadan ("<+11>-11")
|
|
||||||
#define TZ_Asia_Makassar ("WITA-8")
|
|
||||||
#define TZ_Asia_Manila ("PST-8")
|
|
||||||
#define TZ_Asia_Muscat ("<+04>-4")
|
|
||||||
#define TZ_Asia_Nicosia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Asia_Novokuznetsk ("<+07>-7")
|
|
||||||
#define TZ_Asia_Novosibirsk ("<+07>-7")
|
|
||||||
#define TZ_Asia_Omsk ("<+06>-6")
|
|
||||||
#define TZ_Asia_Oral ("<+05>-5")
|
|
||||||
#define TZ_Asia_Phnom_Penh ("<+07>-7")
|
|
||||||
#define TZ_Asia_Pontianak ("WIB-7")
|
|
||||||
#define TZ_Asia_Pyongyang ("KST-9")
|
|
||||||
#define TZ_Asia_Qatar ("<+03>-3")
|
|
||||||
#define TZ_Asia_Qyzylorda ("<+05>-5")
|
|
||||||
#define TZ_Asia_Riyadh ("<+03>-3")
|
|
||||||
#define TZ_Asia_Sakhalin ("<+11>-11")
|
|
||||||
#define TZ_Asia_Samarkand ("<+05>-5")
|
|
||||||
#define TZ_Asia_Seoul ("KST-9")
|
|
||||||
#define TZ_Asia_Shanghai ("CST-8")
|
|
||||||
#define TZ_Asia_Singapore ("<+08>-8")
|
|
||||||
#define TZ_Asia_Srednekolymsk ("<+11>-11")
|
|
||||||
#define TZ_Asia_Taipei ("CST-8")
|
|
||||||
#define TZ_Asia_Tashkent ("<+05>-5")
|
|
||||||
#define TZ_Asia_Tbilisi ("<+04>-4")
|
|
||||||
#define TZ_Asia_Tehran ("<+0330>-3:30")
|
|
||||||
#define TZ_Asia_Thimphu ("<+06>-6")
|
|
||||||
#define TZ_Asia_Tokyo ("JST-9")
|
|
||||||
#define TZ_Asia_Tomsk ("<+07>-7")
|
|
||||||
#define TZ_Asia_Ulaanbaatar ("<+08>-8")
|
|
||||||
#define TZ_Asia_Urumqi ("<+06>-6")
|
|
||||||
#define TZ_Asia_UstmNera ("<+10>-10")
|
|
||||||
#define TZ_Asia_Vientiane ("<+07>-7")
|
|
||||||
#define TZ_Asia_Vladivostok ("<+10>-10")
|
|
||||||
#define TZ_Asia_Yakutsk ("<+09>-9")
|
|
||||||
#define TZ_Asia_Yangon ("<+0630>-6:30")
|
|
||||||
#define TZ_Asia_Yekaterinburg ("<+05>-5")
|
|
||||||
#define TZ_Asia_Yerevan ("<+04>-4")
|
|
||||||
#define TZ_Atlantic_Azores ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
|
||||||
#define TZ_Atlantic_Bermuda ("AST4ADT,M3.2.0,M11.1.0")
|
|
||||||
#define TZ_Atlantic_Canary ("WET0WEST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Atlantic_Cape_Verde ("<-01>1")
|
|
||||||
#define TZ_Atlantic_Faroe ("WET0WEST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Atlantic_Madeira ("WET0WEST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Atlantic_Reykjavik ("GMT0")
|
|
||||||
#define TZ_Atlantic_South_Georgia ("<-02>2")
|
|
||||||
#define TZ_Atlantic_Stanley ("<-03>3")
|
|
||||||
#define TZ_Atlantic_St_Helena ("GMT0")
|
|
||||||
#define TZ_Australia_Adelaide ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Australia_Brisbane ("AEST-10")
|
|
||||||
#define TZ_Australia_Broken_Hill ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Australia_Currie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Australia_Darwin ("ACST-9:30")
|
|
||||||
#define TZ_Australia_Eucla ("<+0845>-8:45")
|
|
||||||
#define TZ_Australia_Hobart ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Australia_Lindeman ("AEST-10")
|
|
||||||
#define TZ_Australia_Lord_Howe ("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
|
|
||||||
#define TZ_Australia_Melbourne ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Australia_Perth ("AWST-8")
|
|
||||||
#define TZ_Australia_Sydney ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Europe_Amsterdam ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Andorra ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Astrakhan ("<+04>-4")
|
|
||||||
#define TZ_Europe_Athens ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Belgrade ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Berlin ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Bratislava ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Brussels ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Bucharest ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Budapest ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Busingen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Chisinau ("EET-2EEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Copenhagen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Dublin ("IST-1GMT0,M10.5.0,M3.5.0/1")
|
|
||||||
#define TZ_Europe_Gibraltar ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Guernsey ("GMT0BST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Europe_Helsinki ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Isle_of_Man ("GMT0BST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Europe_Istanbul ("<+03>-3")
|
|
||||||
#define TZ_Europe_Jersey ("GMT0BST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Europe_Kaliningrad ("EET-2")
|
|
||||||
#define TZ_Europe_Kiev ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Kirov ("MSK-3")
|
|
||||||
#define TZ_Europe_Lisbon ("WET0WEST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Europe_Ljubljana ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_London ("GMT0BST,M3.5.0/1,M10.5.0")
|
|
||||||
#define TZ_Europe_Luxembourg ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Madrid ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Malta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Mariehamn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Minsk ("<+03>-3")
|
|
||||||
#define TZ_Europe_Monaco ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Moscow ("MSK-3")
|
|
||||||
#define TZ_Europe_Oslo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Paris ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Podgorica ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Prague ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Riga ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Rome ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Samara ("<+04>-4")
|
|
||||||
#define TZ_Europe_San_Marino ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Sarajevo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Saratov ("<+04>-4")
|
|
||||||
#define TZ_Europe_Simferopol ("MSK-3")
|
|
||||||
#define TZ_Europe_Skopje ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Sofia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Stockholm ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Tallinn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Tirane ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Ulyanovsk ("<+04>-4")
|
|
||||||
#define TZ_Europe_Uzhgorod ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Vaduz ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Vatican ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Vienna ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Vilnius ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Volgograd ("MSK-3")
|
|
||||||
#define TZ_Europe_Warsaw ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Zagreb ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Europe_Zaporozhye ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
|
||||||
#define TZ_Europe_Zurich ("CET-1CEST,M3.5.0,M10.5.0/3")
|
|
||||||
#define TZ_Indian_Antananarivo ("EAT-3")
|
|
||||||
#define TZ_Indian_Chagos ("<+06>-6")
|
|
||||||
#define TZ_Indian_Christmas ("<+07>-7")
|
|
||||||
#define TZ_Indian_Cocos ("<+0630>-6:30")
|
|
||||||
#define TZ_Indian_Comoro ("EAT-3")
|
|
||||||
#define TZ_Indian_Kerguelen ("<+05>-5")
|
|
||||||
#define TZ_Indian_Mahe ("<+04>-4")
|
|
||||||
#define TZ_Indian_Maldives ("<+05>-5")
|
|
||||||
#define TZ_Indian_Mauritius ("<+04>-4")
|
|
||||||
#define TZ_Indian_Mayotte ("EAT-3")
|
|
||||||
#define TZ_Indian_Reunion ("<+04>-4")
|
|
||||||
#define TZ_Pacific_Apia ("<+13>-13")
|
|
||||||
#define TZ_Pacific_Auckland ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
|
||||||
#define TZ_Pacific_Bougainville ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Chatham ("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
|
|
||||||
#define TZ_Pacific_Chuuk ("<+10>-10")
|
|
||||||
#define TZ_Pacific_Easter ("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
|
|
||||||
#define TZ_Pacific_Efate ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Enderbury ("<+13>-13")
|
|
||||||
#define TZ_Pacific_Fakaofo ("<+13>-13")
|
|
||||||
#define TZ_Pacific_Fiji ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Funafuti ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Galapagos ("<-06>6")
|
|
||||||
#define TZ_Pacific_Gambier ("<-09>9")
|
|
||||||
#define TZ_Pacific_Guadalcanal ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Guam ("ChST-10")
|
|
||||||
#define TZ_Pacific_Honolulu ("HST10")
|
|
||||||
#define TZ_Pacific_Kiritimati ("<+14>-14")
|
|
||||||
#define TZ_Pacific_Kosrae ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Kwajalein ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Majuro ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Marquesas ("<-0930>9:30")
|
|
||||||
#define TZ_Pacific_Midway ("SST11")
|
|
||||||
#define TZ_Pacific_Nauru ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Niue ("<-11>11")
|
|
||||||
#define TZ_Pacific_Norfolk ("<+11>-11<+12>,M10.1.0,M4.1.0/3")
|
|
||||||
#define TZ_Pacific_Noumea ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Pago_Pago ("SST11")
|
|
||||||
#define TZ_Pacific_Palau ("<+09>-9")
|
|
||||||
#define TZ_Pacific_Pitcairn ("<-08>8")
|
|
||||||
#define TZ_Pacific_Pohnpei ("<+11>-11")
|
|
||||||
#define TZ_Pacific_Port_Moresby ("<+10>-10")
|
|
||||||
#define TZ_Pacific_Rarotonga ("<-10>10")
|
|
||||||
#define TZ_Pacific_Saipan ("ChST-10")
|
|
||||||
#define TZ_Pacific_Tahiti ("<-10>10")
|
|
||||||
#define TZ_Pacific_Tarawa ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Tongatapu ("<+13>-13")
|
|
||||||
#define TZ_Pacific_Wake ("<+12>-12")
|
|
||||||
#define TZ_Pacific_Wallis ("<+12>-12")
|
|
||||||
#define TZ_Etc_GMT ("GMT0")
|
|
||||||
#define TZ_Etc_GMTm0 ("GMT0")
|
|
||||||
#define TZ_Etc_GMTm1 ("<+01>-1")
|
|
||||||
#define TZ_Etc_GMTm2 ("<+02>-2")
|
|
||||||
#define TZ_Etc_GMTm3 ("<+03>-3")
|
|
||||||
#define TZ_Etc_GMTm4 ("<+04>-4")
|
|
||||||
#define TZ_Etc_GMTm5 ("<+05>-5")
|
|
||||||
#define TZ_Etc_GMTm6 ("<+06>-6")
|
|
||||||
#define TZ_Etc_GMTm7 ("<+07>-7")
|
|
||||||
#define TZ_Etc_GMTm8 ("<+08>-8")
|
|
||||||
#define TZ_Etc_GMTm9 ("<+09>-9")
|
|
||||||
#define TZ_Etc_GMTm10 ("<+10>-10")
|
|
||||||
#define TZ_Etc_GMTm11 ("<+11>-11")
|
|
||||||
#define TZ_Etc_GMTm12 ("<+12>-12")
|
|
||||||
#define TZ_Etc_GMTm13 ("<+13>-13")
|
|
||||||
#define TZ_Etc_GMTm14 ("<+14>-14")
|
|
||||||
#define TZ_Etc_GMT0 ("GMT0")
|
|
||||||
#define TZ_Etc_GMTp0 ("GMT0")
|
|
||||||
#define TZ_Etc_GMTp1 ("<-01>1")
|
|
||||||
#define TZ_Etc_GMTp2 ("<-02>2")
|
|
||||||
#define TZ_Etc_GMTp3 ("<-03>3")
|
|
||||||
#define TZ_Etc_GMTp4 ("<-04>4")
|
|
||||||
#define TZ_Etc_GMTp5 ("<-05>5")
|
|
||||||
#define TZ_Etc_GMTp6 ("<-06>6")
|
|
||||||
#define TZ_Etc_GMTp7 ("<-07>7")
|
|
||||||
#define TZ_Etc_GMTp8 ("<-08>8")
|
|
||||||
#define TZ_Etc_GMTp9 ("<-09>9")
|
|
||||||
#define TZ_Etc_GMTp10 ("<-10>10")
|
|
||||||
#define TZ_Etc_GMTp11 ("<-11>11")
|
|
||||||
#define TZ_Etc_GMTp12 ("<-12>12")
|
|
||||||
#define TZ_Etc_UCT ("UTC0")
|
|
||||||
#define TZ_Etc_UTC ("UTC0")
|
|
||||||
#define TZ_Etc_Greenwich ("GMT0")
|
|
||||||
#define TZ_Etc_Universal ("UTC0")
|
|
||||||
#define TZ_Etc_Zulu ("UTC0")
|
|
||||||
|
|
@ -28,7 +28,6 @@ typedef struct {
|
||||||
pin_size_t pin;
|
pin_size_t pin;
|
||||||
PIO pio;
|
PIO pio;
|
||||||
int sm;
|
int sm;
|
||||||
int off;
|
|
||||||
alarm_id_t alarm;
|
alarm_id_t alarm;
|
||||||
} Tone;
|
} Tone;
|
||||||
|
|
||||||
|
|
@ -39,24 +38,16 @@ auto_init_mutex(_toneMutex);
|
||||||
static PIOProgram _tone2Pgm(&tone2_program);
|
static PIOProgram _tone2Pgm(&tone2_program);
|
||||||
static std::map<pin_size_t, Tone *> _toneMap;
|
static std::map<pin_size_t, Tone *> _toneMap;
|
||||||
|
|
||||||
static inline bool pio_sm_get_enabled(PIO pio, uint sm) {
|
|
||||||
check_pio_param(pio);
|
|
||||||
check_sm_param(sm);
|
|
||||||
return (pio->ctrl & ~(1u << sm)) & (1 << sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
||||||
(void) id;
|
(void) id;
|
||||||
Tone *tone = (Tone *)user_data;
|
Tone *tone = (Tone *)user_data;
|
||||||
tone->alarm = 0;
|
tone->alarm = 0;
|
||||||
digitalWrite(tone->pin, LOW);
|
|
||||||
pinMode(tone->pin, OUTPUT);
|
|
||||||
pio_sm_set_enabled(tone->pio, tone->sm, false);
|
pio_sm_set_enabled(tone->pio, tone->sm, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
if (pin >= __GPIOCNT) {
|
if (pin > 29) {
|
||||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -71,19 +62,24 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
return; // Weird deadlock case
|
return; // Weird deadlock case
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int delay = (RP2040::f_cpu() + frequency) / (frequency * 2) - 3; // rounded
|
int us = 1000000 / frequency / 2;
|
||||||
|
if (us < 5) {
|
||||||
|
us = 5;
|
||||||
|
}
|
||||||
auto entry = _toneMap.find(pin);
|
auto entry = _toneMap.find(pin);
|
||||||
Tone *newTone;
|
Tone *newTone;
|
||||||
if (entry == _toneMap.end()) {
|
if (entry == _toneMap.end()) {
|
||||||
newTone = new Tone();
|
newTone = new Tone();
|
||||||
newTone->pin = pin;
|
newTone->pin = pin;
|
||||||
pinMode(pin, OUTPUT);
|
pinMode(pin, OUTPUT);
|
||||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off, pin, 1)) {
|
int off;
|
||||||
|
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &off)) {
|
||||||
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
||||||
// ERROR, no free slots
|
// ERROR, no free slots
|
||||||
delete newTone;
|
delete newTone;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
tone2_program_init(newTone->pio, newTone->sm, off, pin);
|
||||||
newTone->alarm = 0;
|
newTone->alarm = 0;
|
||||||
} else {
|
} else {
|
||||||
newTone = entry->second;
|
newTone = entry->second;
|
||||||
|
|
@ -92,13 +88,8 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
newTone->alarm = 0;
|
newTone->alarm = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pio_sm_get_enabled(newTone->pio, newTone->sm)) {
|
|
||||||
tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin);
|
|
||||||
}
|
|
||||||
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
|
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
|
||||||
pio_sm_put_blocking(newTone->pio, newTone->sm, delay);
|
pio_sm_put_blocking(newTone->pio, newTone->sm, RP2040::usToPIOCycles(us));
|
||||||
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_pull(false, false));
|
|
||||||
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_mov(pio_x, pio_osr));
|
|
||||||
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
||||||
|
|
||||||
_toneMap.insert({pin, newTone});
|
_toneMap.insert({pin, newTone});
|
||||||
|
|
@ -108,7 +99,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
newTone->alarm = ret;
|
newTone->alarm = ret;
|
||||||
} else {
|
} else {
|
||||||
DEBUGCORE("ERROR: Unable to allocate timer for tone(%d, %d, %lu)\n",
|
DEBUGCORE("ERROR: Unable to allocate timer for tone(%d, %d, %d)\n",
|
||||||
pin, frequency, duration);
|
pin, frequency, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +108,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
void noTone(uint8_t pin) {
|
void noTone(uint8_t pin) {
|
||||||
CoreMutex m(&_toneMutex);
|
CoreMutex m(&_toneMutex);
|
||||||
|
|
||||||
if ((pin > __GPIOCNT) || !m) {
|
if ((pin > 29) || !m) {
|
||||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include "stdlib.h"
|
||||||
#include <stdint.h>
|
#include "stdint.h"
|
||||||
|
|
||||||
void randomSeed(uint32_t dwSeed) {
|
void randomSeed(uint32_t dwSeed) {
|
||||||
if (dwSeed != 0) {
|
if (dwSeed != 0) {
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include "api/String.h"
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
_freertos.cpp - Internal core definitions for FreeRTOS
|
|
||||||
|
|
||||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "_freertos.h"
|
|
||||||
#include <pico/mutex.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
mutex_t *src;
|
|
||||||
SemaphoreHandle_t dst;
|
|
||||||
} FMMap;
|
|
||||||
|
|
||||||
static FMMap *_map = nullptr;
|
|
||||||
SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
|
||||||
if (!_map) {
|
|
||||||
_map = (FMMap *)calloc(16, sizeof(FMMap));
|
|
||||||
}
|
|
||||||
// Pre-existing map
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (m == _map[i].src) {
|
|
||||||
return _map[i].dst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
if (_map[i].src == nullptr) {
|
|
||||||
// Make a new mutex
|
|
||||||
SemaphoreHandle_t fm;
|
|
||||||
if (recursive) {
|
|
||||||
fm = _freertos_recursive_mutex_create();
|
|
||||||
} else {
|
|
||||||
fm = __freertos_mutex_create();
|
|
||||||
}
|
|
||||||
if (fm == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
_map[i].src = m;
|
|
||||||
_map[i].dst = fm;
|
|
||||||
return fm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr; // Need to make space for more mutex maps!
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
_freertos.h - Internal core definitions for FreeRTOS
|
|
||||||
|
|
||||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <pico/mutex.h>
|
|
||||||
|
|
||||||
// Cannot include refs to FreeRTOS's actual semaphore calls because they
|
|
||||||
// are implemented as macros, so we have a wrapper in our variant hook
|
|
||||||
// to handle it.
|
|
||||||
|
|
||||||
extern bool __isFreeRTOS;
|
|
||||||
|
|
||||||
// FreeRTOS has been set up
|
|
||||||
extern volatile bool __freeRTOSinitted;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif // __cplusplus
|
|
||||||
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
|
||||||
typedef struct QueueDefinition * QueueHandle_t;
|
|
||||||
typedef QueueHandle_t SemaphoreHandle_t;
|
|
||||||
typedef int32_t BaseType_t;
|
|
||||||
|
|
||||||
extern bool __freertos_check_if_in_isr() __attribute__((weak));
|
|
||||||
|
|
||||||
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
|
|
||||||
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
|
|
||||||
|
|
||||||
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
|
|
||||||
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
|
||||||
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
|
||||||
|
|
||||||
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
|
||||||
|
|
||||||
extern void __freertos_idle_other_core() __attribute__((weak));
|
|
||||||
extern void __freertos_resume_other_core() __attribute__((weak));
|
|
||||||
|
|
||||||
extern void __freertos_task_exit_critical() __attribute__((weak));
|
|
||||||
extern void __freertos_task_enter_critical() __attribute__((weak));
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
// Simple helper header to ensure pico libs support ?BT
|
|
||||||
|
|
||||||
#ifndef ENABLE_CLASSIC
|
|
||||||
#define ENABLE_CLASSIC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static_assert(ENABLE_CLASSIC, "This library needs Bluetooth enabled. Use the 'Tools->IP/Bluetooth Stack' menu in the IDE to enable it.");
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,2 +1,57 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/ArduinoAPI.h"
|
Arduino API main include
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARDUINO_API_H
|
||||||
|
#define ARDUINO_API_H
|
||||||
|
|
||||||
|
// version 1.2.0
|
||||||
|
#define ARDUINO_API_VERSION 10200
|
||||||
|
|
||||||
|
#include "Binary.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "Interrupts.h"
|
||||||
|
#include "IPAddress.h"
|
||||||
|
#include "Print.h"
|
||||||
|
#include "Printable.h"
|
||||||
|
#include "PluggableUSB.h"
|
||||||
|
#include "Server.h"
|
||||||
|
#include "String.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "Udp.h"
|
||||||
|
#include "USBAPI.h"
|
||||||
|
#include "WCharacter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Standard C library includes */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
// Misc Arduino core functions
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
// Compatibility layer for older code
|
||||||
|
#include "Compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,552 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/Binary.h"
|
binary.h - Definitions for binary constants
|
||||||
|
Deprecated -- use 0b binary literals instead
|
||||||
|
Copyright (c) 2006 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Binary_h
|
||||||
|
#define Binary_h
|
||||||
|
|
||||||
|
/* If supported, 0b binary literals are preferable to these constants.
|
||||||
|
* In that case, warn the user about these being deprecated (if possible). */
|
||||||
|
#if __cplusplus >= 201402L
|
||||||
|
/* C++14 introduces binary literals; C++11 introduces [[deprecated()]] */
|
||||||
|
#define DEPRECATED(x) [[deprecated("use " #x " instead")]]
|
||||||
|
#elif __GNUC__ >= 6
|
||||||
|
/* GCC 4.3 supports binary literals; GCC 6 supports __deprecated__ on enums*/
|
||||||
|
#define DEPRECATED(x) __attribute__ ((__deprecated__ ("use " #x " instead")))
|
||||||
|
#else
|
||||||
|
/* binary literals not supported, or "deprecated" warning not displayable */
|
||||||
|
#define DEPRECATED(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
B0 DEPRECATED(0b0 ) = 0,
|
||||||
|
B00 DEPRECATED(0b00 ) = 0,
|
||||||
|
B000 DEPRECATED(0b000 ) = 0,
|
||||||
|
B0000 DEPRECATED(0b0000 ) = 0,
|
||||||
|
B00000 DEPRECATED(0b00000 ) = 0,
|
||||||
|
B000000 DEPRECATED(0b000000 ) = 0,
|
||||||
|
B0000000 DEPRECATED(0b0000000 ) = 0,
|
||||||
|
B00000000 DEPRECATED(0b00000000) = 0,
|
||||||
|
B1 DEPRECATED(0b1 ) = 1,
|
||||||
|
B01 DEPRECATED(0b01 ) = 1,
|
||||||
|
B001 DEPRECATED(0b001 ) = 1,
|
||||||
|
B0001 DEPRECATED(0b0001 ) = 1,
|
||||||
|
B00001 DEPRECATED(0b00001 ) = 1,
|
||||||
|
B000001 DEPRECATED(0b000001 ) = 1,
|
||||||
|
B0000001 DEPRECATED(0b0000001 ) = 1,
|
||||||
|
B00000001 DEPRECATED(0b00000001) = 1,
|
||||||
|
B10 DEPRECATED(0b10 ) = 2,
|
||||||
|
B010 DEPRECATED(0b010 ) = 2,
|
||||||
|
B0010 DEPRECATED(0b0010 ) = 2,
|
||||||
|
B00010 DEPRECATED(0b00010 ) = 2,
|
||||||
|
B000010 DEPRECATED(0b000010 ) = 2,
|
||||||
|
B0000010 DEPRECATED(0b0000010 ) = 2,
|
||||||
|
B00000010 DEPRECATED(0b00000010) = 2,
|
||||||
|
B11 DEPRECATED(0b11 ) = 3,
|
||||||
|
B011 DEPRECATED(0b011 ) = 3,
|
||||||
|
B0011 DEPRECATED(0b0011 ) = 3,
|
||||||
|
B00011 DEPRECATED(0b00011 ) = 3,
|
||||||
|
B000011 DEPRECATED(0b000011 ) = 3,
|
||||||
|
B0000011 DEPRECATED(0b0000011 ) = 3,
|
||||||
|
B00000011 DEPRECATED(0b00000011) = 3,
|
||||||
|
B100 DEPRECATED(0b100 ) = 4,
|
||||||
|
B0100 DEPRECATED(0b0100 ) = 4,
|
||||||
|
B00100 DEPRECATED(0b00100 ) = 4,
|
||||||
|
B000100 DEPRECATED(0b000100 ) = 4,
|
||||||
|
B0000100 DEPRECATED(0b0000100 ) = 4,
|
||||||
|
B00000100 DEPRECATED(0b00000100) = 4,
|
||||||
|
B101 DEPRECATED(0b101 ) = 5,
|
||||||
|
B0101 DEPRECATED(0b0101 ) = 5,
|
||||||
|
B00101 DEPRECATED(0b00101 ) = 5,
|
||||||
|
B000101 DEPRECATED(0b000101 ) = 5,
|
||||||
|
B0000101 DEPRECATED(0b0000101 ) = 5,
|
||||||
|
B00000101 DEPRECATED(0b00000101) = 5,
|
||||||
|
B110 DEPRECATED(0b110 ) = 6,
|
||||||
|
B0110 DEPRECATED(0b0110 ) = 6,
|
||||||
|
B00110 DEPRECATED(0b00110 ) = 6,
|
||||||
|
B000110 DEPRECATED(0b000110 ) = 6,
|
||||||
|
B0000110 DEPRECATED(0b0000110 ) = 6,
|
||||||
|
B00000110 DEPRECATED(0b00000110) = 6,
|
||||||
|
B111 DEPRECATED(0b111 ) = 7,
|
||||||
|
B0111 DEPRECATED(0b0111 ) = 7,
|
||||||
|
B00111 DEPRECATED(0b00111 ) = 7,
|
||||||
|
B000111 DEPRECATED(0b000111 ) = 7,
|
||||||
|
B0000111 DEPRECATED(0b0000111 ) = 7,
|
||||||
|
B00000111 DEPRECATED(0b00000111) = 7,
|
||||||
|
B1000 DEPRECATED(0b1000 ) = 8,
|
||||||
|
B01000 DEPRECATED(0b01000 ) = 8,
|
||||||
|
B001000 DEPRECATED(0b001000 ) = 8,
|
||||||
|
B0001000 DEPRECATED(0b0001000 ) = 8,
|
||||||
|
B00001000 DEPRECATED(0b00001000) = 8,
|
||||||
|
B1001 DEPRECATED(0b1001 ) = 9,
|
||||||
|
B01001 DEPRECATED(0b01001 ) = 9,
|
||||||
|
B001001 DEPRECATED(0b001001 ) = 9,
|
||||||
|
B0001001 DEPRECATED(0b0001001 ) = 9,
|
||||||
|
B00001001 DEPRECATED(0b00001001) = 9,
|
||||||
|
B1010 DEPRECATED(0b1010 ) = 10,
|
||||||
|
B01010 DEPRECATED(0b01010 ) = 10,
|
||||||
|
B001010 DEPRECATED(0b001010 ) = 10,
|
||||||
|
B0001010 DEPRECATED(0b0001010 ) = 10,
|
||||||
|
B00001010 DEPRECATED(0b00001010) = 10,
|
||||||
|
B1011 DEPRECATED(0b1011 ) = 11,
|
||||||
|
B01011 DEPRECATED(0b01011 ) = 11,
|
||||||
|
B001011 DEPRECATED(0b001011 ) = 11,
|
||||||
|
B0001011 DEPRECATED(0b0001011 ) = 11,
|
||||||
|
B00001011 DEPRECATED(0b00001011) = 11,
|
||||||
|
B1100 DEPRECATED(0b1100 ) = 12,
|
||||||
|
B01100 DEPRECATED(0b01100 ) = 12,
|
||||||
|
B001100 DEPRECATED(0b001100 ) = 12,
|
||||||
|
B0001100 DEPRECATED(0b0001100 ) = 12,
|
||||||
|
B00001100 DEPRECATED(0b00001100) = 12,
|
||||||
|
B1101 DEPRECATED(0b1101 ) = 13,
|
||||||
|
B01101 DEPRECATED(0b01101 ) = 13,
|
||||||
|
B001101 DEPRECATED(0b001101 ) = 13,
|
||||||
|
B0001101 DEPRECATED(0b0001101 ) = 13,
|
||||||
|
B00001101 DEPRECATED(0b00001101) = 13,
|
||||||
|
B1110 DEPRECATED(0b1110 ) = 14,
|
||||||
|
B01110 DEPRECATED(0b01110 ) = 14,
|
||||||
|
B001110 DEPRECATED(0b001110 ) = 14,
|
||||||
|
B0001110 DEPRECATED(0b0001110 ) = 14,
|
||||||
|
B00001110 DEPRECATED(0b00001110) = 14,
|
||||||
|
B1111 DEPRECATED(0b1111 ) = 15,
|
||||||
|
B01111 DEPRECATED(0b01111 ) = 15,
|
||||||
|
B001111 DEPRECATED(0b001111 ) = 15,
|
||||||
|
B0001111 DEPRECATED(0b0001111 ) = 15,
|
||||||
|
B00001111 DEPRECATED(0b00001111) = 15,
|
||||||
|
B10000 DEPRECATED(0b10000 ) = 16,
|
||||||
|
B010000 DEPRECATED(0b010000 ) = 16,
|
||||||
|
B0010000 DEPRECATED(0b0010000 ) = 16,
|
||||||
|
B00010000 DEPRECATED(0b00010000) = 16,
|
||||||
|
B10001 DEPRECATED(0b10001 ) = 17,
|
||||||
|
B010001 DEPRECATED(0b010001 ) = 17,
|
||||||
|
B0010001 DEPRECATED(0b0010001 ) = 17,
|
||||||
|
B00010001 DEPRECATED(0b00010001) = 17,
|
||||||
|
B10010 DEPRECATED(0b10010 ) = 18,
|
||||||
|
B010010 DEPRECATED(0b010010 ) = 18,
|
||||||
|
B0010010 DEPRECATED(0b0010010 ) = 18,
|
||||||
|
B00010010 DEPRECATED(0b00010010) = 18,
|
||||||
|
B10011 DEPRECATED(0b10011 ) = 19,
|
||||||
|
B010011 DEPRECATED(0b010011 ) = 19,
|
||||||
|
B0010011 DEPRECATED(0b0010011 ) = 19,
|
||||||
|
B00010011 DEPRECATED(0b00010011) = 19,
|
||||||
|
B10100 DEPRECATED(0b10100 ) = 20,
|
||||||
|
B010100 DEPRECATED(0b010100 ) = 20,
|
||||||
|
B0010100 DEPRECATED(0b0010100 ) = 20,
|
||||||
|
B00010100 DEPRECATED(0b00010100) = 20,
|
||||||
|
B10101 DEPRECATED(0b10101 ) = 21,
|
||||||
|
B010101 DEPRECATED(0b010101 ) = 21,
|
||||||
|
B0010101 DEPRECATED(0b0010101 ) = 21,
|
||||||
|
B00010101 DEPRECATED(0b00010101) = 21,
|
||||||
|
B10110 DEPRECATED(0b10110 ) = 22,
|
||||||
|
B010110 DEPRECATED(0b010110 ) = 22,
|
||||||
|
B0010110 DEPRECATED(0b0010110 ) = 22,
|
||||||
|
B00010110 DEPRECATED(0b00010110) = 22,
|
||||||
|
B10111 DEPRECATED(0b10111 ) = 23,
|
||||||
|
B010111 DEPRECATED(0b010111 ) = 23,
|
||||||
|
B0010111 DEPRECATED(0b0010111 ) = 23,
|
||||||
|
B00010111 DEPRECATED(0b00010111) = 23,
|
||||||
|
B11000 DEPRECATED(0b11000 ) = 24,
|
||||||
|
B011000 DEPRECATED(0b011000 ) = 24,
|
||||||
|
B0011000 DEPRECATED(0b0011000 ) = 24,
|
||||||
|
B00011000 DEPRECATED(0b00011000) = 24,
|
||||||
|
B11001 DEPRECATED(0b11001 ) = 25,
|
||||||
|
B011001 DEPRECATED(0b011001 ) = 25,
|
||||||
|
B0011001 DEPRECATED(0b0011001 ) = 25,
|
||||||
|
B00011001 DEPRECATED(0b00011001) = 25,
|
||||||
|
B11010 DEPRECATED(0b11010 ) = 26,
|
||||||
|
B011010 DEPRECATED(0b011010 ) = 26,
|
||||||
|
B0011010 DEPRECATED(0b0011010 ) = 26,
|
||||||
|
B00011010 DEPRECATED(0b00011010) = 26,
|
||||||
|
B11011 DEPRECATED(0b11011 ) = 27,
|
||||||
|
B011011 DEPRECATED(0b011011 ) = 27,
|
||||||
|
B0011011 DEPRECATED(0b0011011 ) = 27,
|
||||||
|
B00011011 DEPRECATED(0b00011011) = 27,
|
||||||
|
B11100 DEPRECATED(0b11100 ) = 28,
|
||||||
|
B011100 DEPRECATED(0b011100 ) = 28,
|
||||||
|
B0011100 DEPRECATED(0b0011100 ) = 28,
|
||||||
|
B00011100 DEPRECATED(0b00011100) = 28,
|
||||||
|
B11101 DEPRECATED(0b11101 ) = 29,
|
||||||
|
B011101 DEPRECATED(0b011101 ) = 29,
|
||||||
|
B0011101 DEPRECATED(0b0011101 ) = 29,
|
||||||
|
B00011101 DEPRECATED(0b00011101) = 29,
|
||||||
|
B11110 DEPRECATED(0b11110 ) = 30,
|
||||||
|
B011110 DEPRECATED(0b011110 ) = 30,
|
||||||
|
B0011110 DEPRECATED(0b0011110 ) = 30,
|
||||||
|
B00011110 DEPRECATED(0b00011110) = 30,
|
||||||
|
B11111 DEPRECATED(0b11111 ) = 31,
|
||||||
|
B011111 DEPRECATED(0b011111 ) = 31,
|
||||||
|
B0011111 DEPRECATED(0b0011111 ) = 31,
|
||||||
|
B00011111 DEPRECATED(0b00011111) = 31,
|
||||||
|
B100000 DEPRECATED(0b100000 ) = 32,
|
||||||
|
B0100000 DEPRECATED(0b0100000 ) = 32,
|
||||||
|
B00100000 DEPRECATED(0b00100000) = 32,
|
||||||
|
B100001 DEPRECATED(0b100001 ) = 33,
|
||||||
|
B0100001 DEPRECATED(0b0100001 ) = 33,
|
||||||
|
B00100001 DEPRECATED(0b00100001) = 33,
|
||||||
|
B100010 DEPRECATED(0b100010 ) = 34,
|
||||||
|
B0100010 DEPRECATED(0b0100010 ) = 34,
|
||||||
|
B00100010 DEPRECATED(0b00100010) = 34,
|
||||||
|
B100011 DEPRECATED(0b100011 ) = 35,
|
||||||
|
B0100011 DEPRECATED(0b0100011 ) = 35,
|
||||||
|
B00100011 DEPRECATED(0b00100011) = 35,
|
||||||
|
B100100 DEPRECATED(0b100100 ) = 36,
|
||||||
|
B0100100 DEPRECATED(0b0100100 ) = 36,
|
||||||
|
B00100100 DEPRECATED(0b00100100) = 36,
|
||||||
|
B100101 DEPRECATED(0b100101 ) = 37,
|
||||||
|
B0100101 DEPRECATED(0b0100101 ) = 37,
|
||||||
|
B00100101 DEPRECATED(0b00100101) = 37,
|
||||||
|
B100110 DEPRECATED(0b100110 ) = 38,
|
||||||
|
B0100110 DEPRECATED(0b0100110 ) = 38,
|
||||||
|
B00100110 DEPRECATED(0b00100110) = 38,
|
||||||
|
B100111 DEPRECATED(0b100111 ) = 39,
|
||||||
|
B0100111 DEPRECATED(0b0100111 ) = 39,
|
||||||
|
B00100111 DEPRECATED(0b00100111) = 39,
|
||||||
|
B101000 DEPRECATED(0b101000 ) = 40,
|
||||||
|
B0101000 DEPRECATED(0b0101000 ) = 40,
|
||||||
|
B00101000 DEPRECATED(0b00101000) = 40,
|
||||||
|
B101001 DEPRECATED(0b101001 ) = 41,
|
||||||
|
B0101001 DEPRECATED(0b0101001 ) = 41,
|
||||||
|
B00101001 DEPRECATED(0b00101001) = 41,
|
||||||
|
B101010 DEPRECATED(0b101010 ) = 42,
|
||||||
|
B0101010 DEPRECATED(0b0101010 ) = 42,
|
||||||
|
B00101010 DEPRECATED(0b00101010) = 42,
|
||||||
|
B101011 DEPRECATED(0b101011 ) = 43,
|
||||||
|
B0101011 DEPRECATED(0b0101011 ) = 43,
|
||||||
|
B00101011 DEPRECATED(0b00101011) = 43,
|
||||||
|
B101100 DEPRECATED(0b101100 ) = 44,
|
||||||
|
B0101100 DEPRECATED(0b0101100 ) = 44,
|
||||||
|
B00101100 DEPRECATED(0b00101100) = 44,
|
||||||
|
B101101 DEPRECATED(0b101101 ) = 45,
|
||||||
|
B0101101 DEPRECATED(0b0101101 ) = 45,
|
||||||
|
B00101101 DEPRECATED(0b00101101) = 45,
|
||||||
|
B101110 DEPRECATED(0b101110 ) = 46,
|
||||||
|
B0101110 DEPRECATED(0b0101110 ) = 46,
|
||||||
|
B00101110 DEPRECATED(0b00101110) = 46,
|
||||||
|
B101111 DEPRECATED(0b101111 ) = 47,
|
||||||
|
B0101111 DEPRECATED(0b0101111 ) = 47,
|
||||||
|
B00101111 DEPRECATED(0b00101111) = 47,
|
||||||
|
B110000 DEPRECATED(0b110000 ) = 48,
|
||||||
|
B0110000 DEPRECATED(0b0110000 ) = 48,
|
||||||
|
B00110000 DEPRECATED(0b00110000) = 48,
|
||||||
|
B110001 DEPRECATED(0b110001 ) = 49,
|
||||||
|
B0110001 DEPRECATED(0b0110001 ) = 49,
|
||||||
|
B00110001 DEPRECATED(0b00110001) = 49,
|
||||||
|
B110010 DEPRECATED(0b110010 ) = 50,
|
||||||
|
B0110010 DEPRECATED(0b0110010 ) = 50,
|
||||||
|
B00110010 DEPRECATED(0b00110010) = 50,
|
||||||
|
B110011 DEPRECATED(0b110011 ) = 51,
|
||||||
|
B0110011 DEPRECATED(0b0110011 ) = 51,
|
||||||
|
B00110011 DEPRECATED(0b00110011) = 51,
|
||||||
|
B110100 DEPRECATED(0b110100 ) = 52,
|
||||||
|
B0110100 DEPRECATED(0b0110100 ) = 52,
|
||||||
|
B00110100 DEPRECATED(0b00110100) = 52,
|
||||||
|
B110101 DEPRECATED(0b110101 ) = 53,
|
||||||
|
B0110101 DEPRECATED(0b0110101 ) = 53,
|
||||||
|
B00110101 DEPRECATED(0b00110101) = 53,
|
||||||
|
B110110 DEPRECATED(0b110110 ) = 54,
|
||||||
|
B0110110 DEPRECATED(0b0110110 ) = 54,
|
||||||
|
B00110110 DEPRECATED(0b00110110) = 54,
|
||||||
|
B110111 DEPRECATED(0b110111 ) = 55,
|
||||||
|
B0110111 DEPRECATED(0b0110111 ) = 55,
|
||||||
|
B00110111 DEPRECATED(0b00110111) = 55,
|
||||||
|
B111000 DEPRECATED(0b111000 ) = 56,
|
||||||
|
B0111000 DEPRECATED(0b0111000 ) = 56,
|
||||||
|
B00111000 DEPRECATED(0b00111000) = 56,
|
||||||
|
B111001 DEPRECATED(0b111001 ) = 57,
|
||||||
|
B0111001 DEPRECATED(0b0111001 ) = 57,
|
||||||
|
B00111001 DEPRECATED(0b00111001) = 57,
|
||||||
|
B111010 DEPRECATED(0b111010 ) = 58,
|
||||||
|
B0111010 DEPRECATED(0b0111010 ) = 58,
|
||||||
|
B00111010 DEPRECATED(0b00111010) = 58,
|
||||||
|
B111011 DEPRECATED(0b111011 ) = 59,
|
||||||
|
B0111011 DEPRECATED(0b0111011 ) = 59,
|
||||||
|
B00111011 DEPRECATED(0b00111011) = 59,
|
||||||
|
B111100 DEPRECATED(0b111100 ) = 60,
|
||||||
|
B0111100 DEPRECATED(0b0111100 ) = 60,
|
||||||
|
B00111100 DEPRECATED(0b00111100) = 60,
|
||||||
|
B111101 DEPRECATED(0b111101 ) = 61,
|
||||||
|
B0111101 DEPRECATED(0b0111101 ) = 61,
|
||||||
|
B00111101 DEPRECATED(0b00111101) = 61,
|
||||||
|
B111110 DEPRECATED(0b111110 ) = 62,
|
||||||
|
B0111110 DEPRECATED(0b0111110 ) = 62,
|
||||||
|
B00111110 DEPRECATED(0b00111110) = 62,
|
||||||
|
B111111 DEPRECATED(0b111111 ) = 63,
|
||||||
|
B0111111 DEPRECATED(0b0111111 ) = 63,
|
||||||
|
B00111111 DEPRECATED(0b00111111) = 63,
|
||||||
|
B1000000 DEPRECATED(0b1000000 ) = 64,
|
||||||
|
B01000000 DEPRECATED(0b01000000) = 64,
|
||||||
|
B1000001 DEPRECATED(0b1000001 ) = 65,
|
||||||
|
B01000001 DEPRECATED(0b01000001) = 65,
|
||||||
|
B1000010 DEPRECATED(0b1000010 ) = 66,
|
||||||
|
B01000010 DEPRECATED(0b01000010) = 66,
|
||||||
|
B1000011 DEPRECATED(0b1000011 ) = 67,
|
||||||
|
B01000011 DEPRECATED(0b01000011) = 67,
|
||||||
|
B1000100 DEPRECATED(0b1000100 ) = 68,
|
||||||
|
B01000100 DEPRECATED(0b01000100) = 68,
|
||||||
|
B1000101 DEPRECATED(0b1000101 ) = 69,
|
||||||
|
B01000101 DEPRECATED(0b01000101) = 69,
|
||||||
|
B1000110 DEPRECATED(0b1000110 ) = 70,
|
||||||
|
B01000110 DEPRECATED(0b01000110) = 70,
|
||||||
|
B1000111 DEPRECATED(0b1000111 ) = 71,
|
||||||
|
B01000111 DEPRECATED(0b01000111) = 71,
|
||||||
|
B1001000 DEPRECATED(0b1001000 ) = 72,
|
||||||
|
B01001000 DEPRECATED(0b01001000) = 72,
|
||||||
|
B1001001 DEPRECATED(0b1001001 ) = 73,
|
||||||
|
B01001001 DEPRECATED(0b01001001) = 73,
|
||||||
|
B1001010 DEPRECATED(0b1001010 ) = 74,
|
||||||
|
B01001010 DEPRECATED(0b01001010) = 74,
|
||||||
|
B1001011 DEPRECATED(0b1001011 ) = 75,
|
||||||
|
B01001011 DEPRECATED(0b01001011) = 75,
|
||||||
|
B1001100 DEPRECATED(0b1001100 ) = 76,
|
||||||
|
B01001100 DEPRECATED(0b01001100) = 76,
|
||||||
|
B1001101 DEPRECATED(0b1001101 ) = 77,
|
||||||
|
B01001101 DEPRECATED(0b01001101) = 77,
|
||||||
|
B1001110 DEPRECATED(0b1001110 ) = 78,
|
||||||
|
B01001110 DEPRECATED(0b01001110) = 78,
|
||||||
|
B1001111 DEPRECATED(0b1001111 ) = 79,
|
||||||
|
B01001111 DEPRECATED(0b01001111) = 79,
|
||||||
|
B1010000 DEPRECATED(0b1010000 ) = 80,
|
||||||
|
B01010000 DEPRECATED(0b01010000) = 80,
|
||||||
|
B1010001 DEPRECATED(0b1010001 ) = 81,
|
||||||
|
B01010001 DEPRECATED(0b01010001) = 81,
|
||||||
|
B1010010 DEPRECATED(0b1010010 ) = 82,
|
||||||
|
B01010010 DEPRECATED(0b01010010) = 82,
|
||||||
|
B1010011 DEPRECATED(0b1010011 ) = 83,
|
||||||
|
B01010011 DEPRECATED(0b01010011) = 83,
|
||||||
|
B1010100 DEPRECATED(0b1010100 ) = 84,
|
||||||
|
B01010100 DEPRECATED(0b01010100) = 84,
|
||||||
|
B1010101 DEPRECATED(0b1010101 ) = 85,
|
||||||
|
B01010101 DEPRECATED(0b01010101) = 85,
|
||||||
|
B1010110 DEPRECATED(0b1010110 ) = 86,
|
||||||
|
B01010110 DEPRECATED(0b01010110) = 86,
|
||||||
|
B1010111 DEPRECATED(0b1010111 ) = 87,
|
||||||
|
B01010111 DEPRECATED(0b01010111) = 87,
|
||||||
|
B1011000 DEPRECATED(0b1011000 ) = 88,
|
||||||
|
B01011000 DEPRECATED(0b01011000) = 88,
|
||||||
|
B1011001 DEPRECATED(0b1011001 ) = 89,
|
||||||
|
B01011001 DEPRECATED(0b01011001) = 89,
|
||||||
|
B1011010 DEPRECATED(0b1011010 ) = 90,
|
||||||
|
B01011010 DEPRECATED(0b01011010) = 90,
|
||||||
|
B1011011 DEPRECATED(0b1011011 ) = 91,
|
||||||
|
B01011011 DEPRECATED(0b01011011) = 91,
|
||||||
|
B1011100 DEPRECATED(0b1011100 ) = 92,
|
||||||
|
B01011100 DEPRECATED(0b01011100) = 92,
|
||||||
|
B1011101 DEPRECATED(0b1011101 ) = 93,
|
||||||
|
B01011101 DEPRECATED(0b01011101) = 93,
|
||||||
|
B1011110 DEPRECATED(0b1011110 ) = 94,
|
||||||
|
B01011110 DEPRECATED(0b01011110) = 94,
|
||||||
|
B1011111 DEPRECATED(0b1011111 ) = 95,
|
||||||
|
B01011111 DEPRECATED(0b01011111) = 95,
|
||||||
|
B1100000 DEPRECATED(0b1100000 ) = 96,
|
||||||
|
B01100000 DEPRECATED(0b01100000) = 96,
|
||||||
|
B1100001 DEPRECATED(0b1100001 ) = 97,
|
||||||
|
B01100001 DEPRECATED(0b01100001) = 97,
|
||||||
|
B1100010 DEPRECATED(0b1100010 ) = 98,
|
||||||
|
B01100010 DEPRECATED(0b01100010) = 98,
|
||||||
|
B1100011 DEPRECATED(0b1100011 ) = 99,
|
||||||
|
B01100011 DEPRECATED(0b01100011) = 99,
|
||||||
|
B1100100 DEPRECATED(0b1100100 ) = 100,
|
||||||
|
B01100100 DEPRECATED(0b01100100) = 100,
|
||||||
|
B1100101 DEPRECATED(0b1100101 ) = 101,
|
||||||
|
B01100101 DEPRECATED(0b01100101) = 101,
|
||||||
|
B1100110 DEPRECATED(0b1100110 ) = 102,
|
||||||
|
B01100110 DEPRECATED(0b01100110) = 102,
|
||||||
|
B1100111 DEPRECATED(0b1100111 ) = 103,
|
||||||
|
B01100111 DEPRECATED(0b01100111) = 103,
|
||||||
|
B1101000 DEPRECATED(0b1101000 ) = 104,
|
||||||
|
B01101000 DEPRECATED(0b01101000) = 104,
|
||||||
|
B1101001 DEPRECATED(0b1101001 ) = 105,
|
||||||
|
B01101001 DEPRECATED(0b01101001) = 105,
|
||||||
|
B1101010 DEPRECATED(0b1101010 ) = 106,
|
||||||
|
B01101010 DEPRECATED(0b01101010) = 106,
|
||||||
|
B1101011 DEPRECATED(0b1101011 ) = 107,
|
||||||
|
B01101011 DEPRECATED(0b01101011) = 107,
|
||||||
|
B1101100 DEPRECATED(0b1101100 ) = 108,
|
||||||
|
B01101100 DEPRECATED(0b01101100) = 108,
|
||||||
|
B1101101 DEPRECATED(0b1101101 ) = 109,
|
||||||
|
B01101101 DEPRECATED(0b01101101) = 109,
|
||||||
|
B1101110 DEPRECATED(0b1101110 ) = 110,
|
||||||
|
B01101110 DEPRECATED(0b01101110) = 110,
|
||||||
|
B1101111 DEPRECATED(0b1101111 ) = 111,
|
||||||
|
B01101111 DEPRECATED(0b01101111) = 111,
|
||||||
|
B1110000 DEPRECATED(0b1110000 ) = 112,
|
||||||
|
B01110000 DEPRECATED(0b01110000) = 112,
|
||||||
|
B1110001 DEPRECATED(0b1110001 ) = 113,
|
||||||
|
B01110001 DEPRECATED(0b01110001) = 113,
|
||||||
|
B1110010 DEPRECATED(0b1110010 ) = 114,
|
||||||
|
B01110010 DEPRECATED(0b01110010) = 114,
|
||||||
|
B1110011 DEPRECATED(0b1110011 ) = 115,
|
||||||
|
B01110011 DEPRECATED(0b01110011) = 115,
|
||||||
|
B1110100 DEPRECATED(0b1110100 ) = 116,
|
||||||
|
B01110100 DEPRECATED(0b01110100) = 116,
|
||||||
|
B1110101 DEPRECATED(0b1110101 ) = 117,
|
||||||
|
B01110101 DEPRECATED(0b01110101) = 117,
|
||||||
|
B1110110 DEPRECATED(0b1110110 ) = 118,
|
||||||
|
B01110110 DEPRECATED(0b01110110) = 118,
|
||||||
|
B1110111 DEPRECATED(0b1110111 ) = 119,
|
||||||
|
B01110111 DEPRECATED(0b01110111) = 119,
|
||||||
|
B1111000 DEPRECATED(0b1111000 ) = 120,
|
||||||
|
B01111000 DEPRECATED(0b01111000) = 120,
|
||||||
|
B1111001 DEPRECATED(0b1111001 ) = 121,
|
||||||
|
B01111001 DEPRECATED(0b01111001) = 121,
|
||||||
|
B1111010 DEPRECATED(0b1111010 ) = 122,
|
||||||
|
B01111010 DEPRECATED(0b01111010) = 122,
|
||||||
|
B1111011 DEPRECATED(0b1111011 ) = 123,
|
||||||
|
B01111011 DEPRECATED(0b01111011) = 123,
|
||||||
|
B1111100 DEPRECATED(0b1111100 ) = 124,
|
||||||
|
B01111100 DEPRECATED(0b01111100) = 124,
|
||||||
|
B1111101 DEPRECATED(0b1111101 ) = 125,
|
||||||
|
B01111101 DEPRECATED(0b01111101) = 125,
|
||||||
|
B1111110 DEPRECATED(0b1111110 ) = 126,
|
||||||
|
B01111110 DEPRECATED(0b01111110) = 126,
|
||||||
|
B1111111 DEPRECATED(0b1111111 ) = 127,
|
||||||
|
B01111111 DEPRECATED(0b01111111) = 127,
|
||||||
|
B10000000 DEPRECATED(0b10000000) = 128,
|
||||||
|
B10000001 DEPRECATED(0b10000001) = 129,
|
||||||
|
B10000010 DEPRECATED(0b10000010) = 130,
|
||||||
|
B10000011 DEPRECATED(0b10000011) = 131,
|
||||||
|
B10000100 DEPRECATED(0b10000100) = 132,
|
||||||
|
B10000101 DEPRECATED(0b10000101) = 133,
|
||||||
|
B10000110 DEPRECATED(0b10000110) = 134,
|
||||||
|
B10000111 DEPRECATED(0b10000111) = 135,
|
||||||
|
B10001000 DEPRECATED(0b10001000) = 136,
|
||||||
|
B10001001 DEPRECATED(0b10001001) = 137,
|
||||||
|
B10001010 DEPRECATED(0b10001010) = 138,
|
||||||
|
B10001011 DEPRECATED(0b10001011) = 139,
|
||||||
|
B10001100 DEPRECATED(0b10001100) = 140,
|
||||||
|
B10001101 DEPRECATED(0b10001101) = 141,
|
||||||
|
B10001110 DEPRECATED(0b10001110) = 142,
|
||||||
|
B10001111 DEPRECATED(0b10001111) = 143,
|
||||||
|
B10010000 DEPRECATED(0b10010000) = 144,
|
||||||
|
B10010001 DEPRECATED(0b10010001) = 145,
|
||||||
|
B10010010 DEPRECATED(0b10010010) = 146,
|
||||||
|
B10010011 DEPRECATED(0b10010011) = 147,
|
||||||
|
B10010100 DEPRECATED(0b10010100) = 148,
|
||||||
|
B10010101 DEPRECATED(0b10010101) = 149,
|
||||||
|
B10010110 DEPRECATED(0b10010110) = 150,
|
||||||
|
B10010111 DEPRECATED(0b10010111) = 151,
|
||||||
|
B10011000 DEPRECATED(0b10011000) = 152,
|
||||||
|
B10011001 DEPRECATED(0b10011001) = 153,
|
||||||
|
B10011010 DEPRECATED(0b10011010) = 154,
|
||||||
|
B10011011 DEPRECATED(0b10011011) = 155,
|
||||||
|
B10011100 DEPRECATED(0b10011100) = 156,
|
||||||
|
B10011101 DEPRECATED(0b10011101) = 157,
|
||||||
|
B10011110 DEPRECATED(0b10011110) = 158,
|
||||||
|
B10011111 DEPRECATED(0b10011111) = 159,
|
||||||
|
B10100000 DEPRECATED(0b10100000) = 160,
|
||||||
|
B10100001 DEPRECATED(0b10100001) = 161,
|
||||||
|
B10100010 DEPRECATED(0b10100010) = 162,
|
||||||
|
B10100011 DEPRECATED(0b10100011) = 163,
|
||||||
|
B10100100 DEPRECATED(0b10100100) = 164,
|
||||||
|
B10100101 DEPRECATED(0b10100101) = 165,
|
||||||
|
B10100110 DEPRECATED(0b10100110) = 166,
|
||||||
|
B10100111 DEPRECATED(0b10100111) = 167,
|
||||||
|
B10101000 DEPRECATED(0b10101000) = 168,
|
||||||
|
B10101001 DEPRECATED(0b10101001) = 169,
|
||||||
|
B10101010 DEPRECATED(0b10101010) = 170,
|
||||||
|
B10101011 DEPRECATED(0b10101011) = 171,
|
||||||
|
B10101100 DEPRECATED(0b10101100) = 172,
|
||||||
|
B10101101 DEPRECATED(0b10101101) = 173,
|
||||||
|
B10101110 DEPRECATED(0b10101110) = 174,
|
||||||
|
B10101111 DEPRECATED(0b10101111) = 175,
|
||||||
|
B10110000 DEPRECATED(0b10110000) = 176,
|
||||||
|
B10110001 DEPRECATED(0b10110001) = 177,
|
||||||
|
B10110010 DEPRECATED(0b10110010) = 178,
|
||||||
|
B10110011 DEPRECATED(0b10110011) = 179,
|
||||||
|
B10110100 DEPRECATED(0b10110100) = 180,
|
||||||
|
B10110101 DEPRECATED(0b10110101) = 181,
|
||||||
|
B10110110 DEPRECATED(0b10110110) = 182,
|
||||||
|
B10110111 DEPRECATED(0b10110111) = 183,
|
||||||
|
B10111000 DEPRECATED(0b10111000) = 184,
|
||||||
|
B10111001 DEPRECATED(0b10111001) = 185,
|
||||||
|
B10111010 DEPRECATED(0b10111010) = 186,
|
||||||
|
B10111011 DEPRECATED(0b10111011) = 187,
|
||||||
|
B10111100 DEPRECATED(0b10111100) = 188,
|
||||||
|
B10111101 DEPRECATED(0b10111101) = 189,
|
||||||
|
B10111110 DEPRECATED(0b10111110) = 190,
|
||||||
|
B10111111 DEPRECATED(0b10111111) = 191,
|
||||||
|
B11000000 DEPRECATED(0b11000000) = 192,
|
||||||
|
B11000001 DEPRECATED(0b11000001) = 193,
|
||||||
|
B11000010 DEPRECATED(0b11000010) = 194,
|
||||||
|
B11000011 DEPRECATED(0b11000011) = 195,
|
||||||
|
B11000100 DEPRECATED(0b11000100) = 196,
|
||||||
|
B11000101 DEPRECATED(0b11000101) = 197,
|
||||||
|
B11000110 DEPRECATED(0b11000110) = 198,
|
||||||
|
B11000111 DEPRECATED(0b11000111) = 199,
|
||||||
|
B11001000 DEPRECATED(0b11001000) = 200,
|
||||||
|
B11001001 DEPRECATED(0b11001001) = 201,
|
||||||
|
B11001010 DEPRECATED(0b11001010) = 202,
|
||||||
|
B11001011 DEPRECATED(0b11001011) = 203,
|
||||||
|
B11001100 DEPRECATED(0b11001100) = 204,
|
||||||
|
B11001101 DEPRECATED(0b11001101) = 205,
|
||||||
|
B11001110 DEPRECATED(0b11001110) = 206,
|
||||||
|
B11001111 DEPRECATED(0b11001111) = 207,
|
||||||
|
B11010000 DEPRECATED(0b11010000) = 208,
|
||||||
|
B11010001 DEPRECATED(0b11010001) = 209,
|
||||||
|
B11010010 DEPRECATED(0b11010010) = 210,
|
||||||
|
B11010011 DEPRECATED(0b11010011) = 211,
|
||||||
|
B11010100 DEPRECATED(0b11010100) = 212,
|
||||||
|
B11010101 DEPRECATED(0b11010101) = 213,
|
||||||
|
B11010110 DEPRECATED(0b11010110) = 214,
|
||||||
|
B11010111 DEPRECATED(0b11010111) = 215,
|
||||||
|
B11011000 DEPRECATED(0b11011000) = 216,
|
||||||
|
B11011001 DEPRECATED(0b11011001) = 217,
|
||||||
|
B11011010 DEPRECATED(0b11011010) = 218,
|
||||||
|
B11011011 DEPRECATED(0b11011011) = 219,
|
||||||
|
B11011100 DEPRECATED(0b11011100) = 220,
|
||||||
|
B11011101 DEPRECATED(0b11011101) = 221,
|
||||||
|
B11011110 DEPRECATED(0b11011110) = 222,
|
||||||
|
B11011111 DEPRECATED(0b11011111) = 223,
|
||||||
|
B11100000 DEPRECATED(0b11100000) = 224,
|
||||||
|
B11100001 DEPRECATED(0b11100001) = 225,
|
||||||
|
B11100010 DEPRECATED(0b11100010) = 226,
|
||||||
|
B11100011 DEPRECATED(0b11100011) = 227,
|
||||||
|
B11100100 DEPRECATED(0b11100100) = 228,
|
||||||
|
B11100101 DEPRECATED(0b11100101) = 229,
|
||||||
|
B11100110 DEPRECATED(0b11100110) = 230,
|
||||||
|
B11100111 DEPRECATED(0b11100111) = 231,
|
||||||
|
B11101000 DEPRECATED(0b11101000) = 232,
|
||||||
|
B11101001 DEPRECATED(0b11101001) = 233,
|
||||||
|
B11101010 DEPRECATED(0b11101010) = 234,
|
||||||
|
B11101011 DEPRECATED(0b11101011) = 235,
|
||||||
|
B11101100 DEPRECATED(0b11101100) = 236,
|
||||||
|
B11101101 DEPRECATED(0b11101101) = 237,
|
||||||
|
B11101110 DEPRECATED(0b11101110) = 238,
|
||||||
|
B11101111 DEPRECATED(0b11101111) = 239,
|
||||||
|
B11110000 DEPRECATED(0b11110000) = 240,
|
||||||
|
B11110001 DEPRECATED(0b11110001) = 241,
|
||||||
|
B11110010 DEPRECATED(0b11110010) = 242,
|
||||||
|
B11110011 DEPRECATED(0b11110011) = 243,
|
||||||
|
B11110100 DEPRECATED(0b11110100) = 244,
|
||||||
|
B11110101 DEPRECATED(0b11110101) = 245,
|
||||||
|
B11110110 DEPRECATED(0b11110110) = 246,
|
||||||
|
B11110111 DEPRECATED(0b11110111) = 247,
|
||||||
|
B11111000 DEPRECATED(0b11111000) = 248,
|
||||||
|
B11111001 DEPRECATED(0b11111001) = 249,
|
||||||
|
B11111010 DEPRECATED(0b11111010) = 250,
|
||||||
|
B11111011 DEPRECATED(0b11111011) = 251,
|
||||||
|
B11111100 DEPRECATED(0b11111100) = 252,
|
||||||
|
B11111101 DEPRECATED(0b11111101) = 253,
|
||||||
|
B11111110 DEPRECATED(0b11111110) = 254,
|
||||||
|
B11111111 DEPRECATED(0b11111111) = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef DEPRECATED
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,46 @@
|
||||||
|
/*
|
||||||
|
Client.h - Base class that provides Client
|
||||||
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Client.h"
|
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "IPAddress.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class Client : public Stream {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int connect(IPAddress ip, uint16_t port) =0;
|
||||||
|
virtual int connect(const char *host, uint16_t port) =0;
|
||||||
|
virtual size_t write(uint8_t) =0;
|
||||||
|
virtual size_t write(const uint8_t *buf, size_t size) =0;
|
||||||
|
virtual int available() = 0;
|
||||||
|
virtual int read() = 0;
|
||||||
|
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||||
|
virtual int peek() = 0;
|
||||||
|
virtual void flush() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
virtual uint8_t connected() = 0;
|
||||||
|
virtual operator bool() = 0;
|
||||||
|
protected:
|
||||||
|
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1,10 @@
|
||||||
#include "../../../ArduinoCore-API/api/Common.cpp"
|
#include "Common.h"
|
||||||
|
|
||||||
|
/* C++ prototypes */
|
||||||
|
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||||
|
{
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t makeWord(uint16_t w) { return w; }
|
||||||
|
uint16_t makeWord(uint8_t h, uint8_t l) { return (h << 8) | l; }
|
||||||
|
|
@ -1,2 +1,173 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Common.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void yield(void);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOW = 0,
|
||||||
|
HIGH = 1,
|
||||||
|
CHANGE = 2,
|
||||||
|
FALLING = 3,
|
||||||
|
RISING = 4,
|
||||||
|
} PinStatus;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
INPUT = 0x0,
|
||||||
|
OUTPUT = 0x1,
|
||||||
|
INPUT_PULLUP = 0x2,
|
||||||
|
INPUT_PULLDOWN = 0x3,
|
||||||
|
OUTPUT_2MA = 0x4,
|
||||||
|
OUTPUT_4MA = 0x5,
|
||||||
|
OUTPUT_8MA = 0x6,
|
||||||
|
OUTPUT_12MA = 0x7,
|
||||||
|
} PinMode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LSBFIRST = 0,
|
||||||
|
MSBFIRST = 1,
|
||||||
|
} BitOrder;
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#define HALF_PI 1.5707963267948966192313216916398
|
||||||
|
#define TWO_PI 6.283185307179586476925286766559
|
||||||
|
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||||
|
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||||
|
#define EULER 2.718281828459045235360287471352
|
||||||
|
|
||||||
|
#define SERIAL 0x0
|
||||||
|
#define DISPLAY 0x1
|
||||||
|
|
||||||
|
#ifndef constrain
|
||||||
|
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef radians
|
||||||
|
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef degrees
|
||||||
|
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef sq
|
||||||
|
#define sq(x) ((x)*(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*voidFuncPtr)(void);
|
||||||
|
typedef void (*voidFuncPtrParam)(void*);
|
||||||
|
|
||||||
|
// interrupts() / noInterrupts() must be defined by the core
|
||||||
|
|
||||||
|
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||||
|
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||||
|
|
||||||
|
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||||
|
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||||
|
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||||
|
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
|
||||||
|
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||||
|
|
||||||
|
#ifndef bit
|
||||||
|
#define bit(b) (1UL << (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO: request for removal */
|
||||||
|
typedef bool boolean;
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint16_t word;
|
||||||
|
|
||||||
|
void init(void);
|
||||||
|
void initVariant(void);
|
||||||
|
|
||||||
|
#ifndef HOST
|
||||||
|
int atexit(void (*func)()) __attribute__((weak));
|
||||||
|
#endif
|
||||||
|
int main() __attribute__((weak));
|
||||||
|
|
||||||
|
#ifdef EXTENDED_PIN_MODE
|
||||||
|
// Platforms who wnat to declare more than 256 pins need to define EXTENDED_PIN_MODE globally
|
||||||
|
typedef uint32_t pin_size_t;
|
||||||
|
#else
|
||||||
|
typedef uint8_t pin_size_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void pinMode(pin_size_t pinNumber, PinMode pinMode);
|
||||||
|
void digitalWrite(pin_size_t pinNumber, PinStatus status);
|
||||||
|
PinStatus digitalRead(pin_size_t pinNumber);
|
||||||
|
int analogRead(pin_size_t pinNumber);
|
||||||
|
void analogReference(uint8_t mode);
|
||||||
|
void analogWrite(pin_size_t pinNumber, int value);
|
||||||
|
|
||||||
|
unsigned long millis(void);
|
||||||
|
unsigned long micros(void);
|
||||||
|
void delay(unsigned long);
|
||||||
|
void delayMicroseconds(unsigned int us);
|
||||||
|
unsigned long pulseIn(pin_size_t pin, uint8_t state, unsigned long timeout);
|
||||||
|
unsigned long pulseInLong(pin_size_t pin, uint8_t state, unsigned long timeout);
|
||||||
|
|
||||||
|
void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val);
|
||||||
|
uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder);
|
||||||
|
|
||||||
|
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode);
|
||||||
|
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void* param);
|
||||||
|
void detachInterrupt(pin_size_t interruptNumber);
|
||||||
|
|
||||||
|
void setup(void);
|
||||||
|
void loop(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
template<class T, class L>
|
||||||
|
auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||||
|
{
|
||||||
|
return (b < a) ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class L>
|
||||||
|
auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)
|
||||||
|
{
|
||||||
|
return (a < b) ? b : a;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifndef min
|
||||||
|
#define min(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; })
|
||||||
|
#endif
|
||||||
|
#ifndef max
|
||||||
|
#define max(a,b) \
|
||||||
|
({ __typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; })
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
/* C++ prototypes */
|
||||||
|
uint16_t makeWord(uint16_t w);
|
||||||
|
uint16_t makeWord(byte h, byte l);
|
||||||
|
|
||||||
|
#define word(...) makeWord(__VA_ARGS__)
|
||||||
|
|
||||||
|
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||||
|
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
|
||||||
|
|
||||||
|
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
|
||||||
|
void noTone(uint8_t _pin);
|
||||||
|
|
||||||
|
// WMath prototypes
|
||||||
|
long random(long);
|
||||||
|
long random(long, long);
|
||||||
|
void randomSeed(unsigned long);
|
||||||
|
long map(long, long, long, long, long);
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,16 @@
|
||||||
#pragma once
|
#ifndef __COMPAT_H__
|
||||||
#include "../../../ArduinoCore-API/api/Compat.h"
|
#define __COMPAT_H__
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
inline void pinMode(pin_size_t pinNumber, int mode) {
|
||||||
|
pinMode(pinNumber, (PinMode)mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void digitalWrite(pin_size_t pinNumber, int status) {
|
||||||
|
digitalWrite(pinNumber, (PinStatus)status);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,2 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/HardwareI2C.h"
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class HardwareI2C : public Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void begin() = 0;
|
||||||
|
virtual void begin(uint8_t address) = 0;
|
||||||
|
virtual void end() = 0;
|
||||||
|
|
||||||
|
virtual void setClock(uint32_t freq) = 0;
|
||||||
|
|
||||||
|
virtual void beginTransmission(uint8_t address) = 0;
|
||||||
|
virtual uint8_t endTransmission(bool stopBit) = 0;
|
||||||
|
virtual uint8_t endTransmission(void) = 0;
|
||||||
|
|
||||||
|
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
|
||||||
|
virtual size_t requestFrom(uint8_t address, size_t len) = 0;
|
||||||
|
|
||||||
|
virtual void onReceive(void(*)(int)) = 0;
|
||||||
|
virtual void onRequest(void(*)(void)) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,130 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2018 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/HardwareSPI.h"
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
|
#define SPI_HAS_TRANSACTION
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SPI_MODE0 = 0,
|
||||||
|
SPI_MODE1 = 1,
|
||||||
|
SPI_MODE2 = 2,
|
||||||
|
SPI_MODE3 = 3,
|
||||||
|
} SPIMode;
|
||||||
|
|
||||||
|
|
||||||
|
class SPISettings {
|
||||||
|
public:
|
||||||
|
SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) {
|
||||||
|
if (__builtin_constant_p(clock)) {
|
||||||
|
init_AlwaysInline(clock, bitOrder, dataMode);
|
||||||
|
} else {
|
||||||
|
init_MightInline(clock, bitOrder, dataMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPISettings(uint32_t clock, BitOrder bitOrder, int dataMode) {
|
||||||
|
if (__builtin_constant_p(clock)) {
|
||||||
|
init_AlwaysInline(clock, bitOrder, (SPIMode)dataMode);
|
||||||
|
} else {
|
||||||
|
init_MightInline(clock, bitOrder, (SPIMode)dataMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
|
||||||
|
SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }
|
||||||
|
|
||||||
|
bool operator==(const SPISettings& rhs) const
|
||||||
|
{
|
||||||
|
if ((this->clockFreq == rhs.clockFreq) &&
|
||||||
|
(this->bitOrder == rhs.bitOrder) &&
|
||||||
|
(this->dataMode == rhs.dataMode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const SPISettings& rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getClockFreq() const {
|
||||||
|
return clockFreq;
|
||||||
|
}
|
||||||
|
SPIMode getDataMode() const {
|
||||||
|
return dataMode;
|
||||||
|
}
|
||||||
|
BitOrder getBitOrder() const {
|
||||||
|
return (bitOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init_MightInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) {
|
||||||
|
init_AlwaysInline(clock, bitOrder, dataMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core developer MUST use an helper function in beginTransaction() to use this data
|
||||||
|
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) __attribute__((__always_inline__)) {
|
||||||
|
this->clockFreq = clock;
|
||||||
|
this->dataMode = dataMode;
|
||||||
|
this->bitOrder = bitOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t clockFreq;
|
||||||
|
SPIMode dataMode;
|
||||||
|
BitOrder bitOrder;
|
||||||
|
|
||||||
|
friend class HardwareSPI;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
|
||||||
|
|
||||||
|
class HardwareSPI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~HardwareSPI() { }
|
||||||
|
|
||||||
|
virtual uint8_t transfer(uint8_t data) = 0;
|
||||||
|
virtual uint16_t transfer16(uint16_t data) = 0;
|
||||||
|
virtual void transfer(void *buf, size_t count) = 0;
|
||||||
|
|
||||||
|
// Transaction Functions
|
||||||
|
virtual void usingInterrupt(int interruptNumber) = 0;
|
||||||
|
virtual void notUsingInterrupt(int interruptNumber) = 0;
|
||||||
|
virtual void beginTransaction(SPISettings settings) = 0;
|
||||||
|
virtual void endTransaction(void) = 0;
|
||||||
|
|
||||||
|
// SPI Configuration methods
|
||||||
|
virtual void attachInterrupt() = 0;
|
||||||
|
virtual void detachInterrupt() = 0;
|
||||||
|
|
||||||
|
virtual void begin() = 0;
|
||||||
|
virtual void end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Alias SPIClass to HardwareSPI since it's already the defacto standard for SPI classe name
|
||||||
|
typedef HardwareSPI SPIClass;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,105 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/HardwareSerial.h"
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// XXX: Those constants should be defined as const int / enums?
|
||||||
|
// XXX: shall we use namespaces too?
|
||||||
|
#define SERIAL_PARITY_EVEN (0x1ul)
|
||||||
|
#define SERIAL_PARITY_ODD (0x2ul)
|
||||||
|
#define SERIAL_PARITY_NONE (0x3ul)
|
||||||
|
#define SERIAL_PARITY_MARK (0x4ul)
|
||||||
|
#define SERIAL_PARITY_SPACE (0x5ul)
|
||||||
|
#define SERIAL_PARITY_MASK (0xFul)
|
||||||
|
|
||||||
|
#define SERIAL_STOP_BIT_1 (0x10ul)
|
||||||
|
#define SERIAL_STOP_BIT_1_5 (0x20ul)
|
||||||
|
#define SERIAL_STOP_BIT_2 (0x30ul)
|
||||||
|
#define SERIAL_STOP_BIT_MASK (0xF0ul)
|
||||||
|
|
||||||
|
#define SERIAL_DATA_5 (0x100ul)
|
||||||
|
#define SERIAL_DATA_6 (0x200ul)
|
||||||
|
#define SERIAL_DATA_7 (0x300ul)
|
||||||
|
#define SERIAL_DATA_8 (0x400ul)
|
||||||
|
#define SERIAL_DATA_MASK (0xF00ul)
|
||||||
|
|
||||||
|
#define SERIAL_5N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
|
||||||
|
#define SERIAL_5S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
|
||||||
|
#define SERIAL_6S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
|
||||||
|
#define SERIAL_7S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
|
||||||
|
#define SERIAL_8S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
|
||||||
|
|
||||||
|
class HardwareSerial : public Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void begin(unsigned long) = 0;
|
||||||
|
virtual void begin(unsigned long baudrate, uint16_t config) = 0;
|
||||||
|
virtual void end() = 0;
|
||||||
|
virtual int available(void) = 0;
|
||||||
|
virtual int peek(void) = 0;
|
||||||
|
virtual int read(void) = 0;
|
||||||
|
virtual void flush(void) = 0;
|
||||||
|
virtual size_t write(uint8_t) = 0;
|
||||||
|
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||||
|
virtual operator bool() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// XXX: Are we keeping the serialEvent API?
|
||||||
|
extern void serialEventRun(void) __attribute__((weak));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1,127 @@
|
||||||
#include "../../../ArduinoCore-API/api/IPAddress.cpp"
|
/*
|
||||||
|
IPAddress.cpp - Base class that provides IPAddress
|
||||||
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IPAddress.h"
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
using namespace arduino;
|
||||||
|
|
||||||
|
IPAddress::IPAddress()
|
||||||
|
{
|
||||||
|
_address.dword = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
|
||||||
|
{
|
||||||
|
_address.bytes[0] = first_octet;
|
||||||
|
_address.bytes[1] = second_octet;
|
||||||
|
_address.bytes[2] = third_octet;
|
||||||
|
_address.bytes[3] = fourth_octet;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(uint32_t address)
|
||||||
|
{
|
||||||
|
_address.dword = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress::IPAddress(const uint8_t *address)
|
||||||
|
{
|
||||||
|
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPAddress::fromString(const char *address)
|
||||||
|
{
|
||||||
|
// TODO: add support for "a", "a.b", "a.b.c" formats
|
||||||
|
|
||||||
|
int16_t acc = -1; // Accumulator
|
||||||
|
uint8_t dots = 0;
|
||||||
|
|
||||||
|
while (*address)
|
||||||
|
{
|
||||||
|
char c = *address++;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
acc = (acc < 0) ? (c - '0') : acc * 10 + (c - '0');
|
||||||
|
if (acc > 255) {
|
||||||
|
// Value out of [0..255] range
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '.')
|
||||||
|
{
|
||||||
|
if (dots == 3) {
|
||||||
|
// Too much dots (there must be 3 dots)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (acc < 0) {
|
||||||
|
/* No value between dots, e.g. '1..' */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_address.bytes[dots++] = acc;
|
||||||
|
acc = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid char
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dots != 3) {
|
||||||
|
// Too few dots (there must be 3 dots)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (acc < 0) {
|
||||||
|
/* No value between dots, e.g. '1..' */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_address.bytes[3] = acc;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||||
|
{
|
||||||
|
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress& IPAddress::operator=(uint32_t address)
|
||||||
|
{
|
||||||
|
_address.dword = address;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IPAddress::operator==(const uint8_t* addr) const
|
||||||
|
{
|
||||||
|
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t IPAddress::printTo(Print& p) const
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
for (int i =0; i < 3; i++)
|
||||||
|
{
|
||||||
|
n += p.print(_address.bytes[i], DEC);
|
||||||
|
n += p.print('.');
|
||||||
|
}
|
||||||
|
n += p.print(_address.bytes[3], DEC);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPAddress arduino::INADDR_NONE(0,0,0,0);
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,85 @@
|
||||||
|
/*
|
||||||
|
IPAddress.h - Base class that provides IPAddress
|
||||||
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/IPAddress.h"
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Printable.h"
|
||||||
|
#include "String.h"
|
||||||
|
|
||||||
|
// forward declartions of global name space friend classes
|
||||||
|
class EthernetClass;
|
||||||
|
class DhcpClass;
|
||||||
|
class DNSClient;
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// A class to make it easier to handle and pass around IP addresses
|
||||||
|
|
||||||
|
class IPAddress : public Printable {
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
uint8_t bytes[4]; // IPv4 address
|
||||||
|
uint32_t dword;
|
||||||
|
} _address;
|
||||||
|
|
||||||
|
// Access the raw byte array containing the address. Because this returns a pointer
|
||||||
|
// to the internal structure rather than a copy of the address this function should only
|
||||||
|
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||||
|
// stored.
|
||||||
|
uint8_t* raw_address() { return _address.bytes; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
IPAddress();
|
||||||
|
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||||
|
IPAddress(uint32_t address);
|
||||||
|
IPAddress(const uint8_t *address);
|
||||||
|
|
||||||
|
bool fromString(const char *address);
|
||||||
|
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||||
|
|
||||||
|
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
|
||||||
|
// to a four-byte uint8_t array is expected
|
||||||
|
operator uint32_t() const { return _address.dword; };
|
||||||
|
bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
|
||||||
|
bool operator!=(const IPAddress& addr) const { return _address.dword != addr._address.dword; };
|
||||||
|
bool operator==(const uint8_t* addr) const;
|
||||||
|
|
||||||
|
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||||
|
uint8_t operator[](int index) const { return _address.bytes[index]; };
|
||||||
|
uint8_t& operator[](int index) { return _address.bytes[index]; };
|
||||||
|
|
||||||
|
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||||
|
IPAddress& operator=(const uint8_t *address);
|
||||||
|
IPAddress& operator=(uint32_t address);
|
||||||
|
|
||||||
|
virtual size_t printTo(Print& p) const;
|
||||||
|
|
||||||
|
friend class UDP;
|
||||||
|
friend class Client;
|
||||||
|
friend class Server;
|
||||||
|
|
||||||
|
friend ::EthernetClass;
|
||||||
|
friend ::DhcpClass;
|
||||||
|
friend ::DNSClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const IPAddress INADDR_NONE;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,44 @@
|
||||||
#pragma once
|
#ifndef W_INTERRUPTS_CPP
|
||||||
#include "../../../ArduinoCore-API/api/Interrupts.h"
|
#define W_INTERRUPTS_CPP
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using voidTemplateFuncPtrParam = void (*)(T param);
|
||||||
|
|
||||||
|
template<typename T> struct __container__ {
|
||||||
|
void* param;
|
||||||
|
voidTemplateFuncPtrParam<T> function;
|
||||||
|
};
|
||||||
|
|
||||||
|
// C++ only overloaded version of attachInterrupt function
|
||||||
|
template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T> userFunc, PinStatus mode, T& param) {
|
||||||
|
|
||||||
|
struct __container__<T> *cont = new __container__<T>();
|
||||||
|
cont->param = ¶m;
|
||||||
|
cont->function = userFunc;
|
||||||
|
|
||||||
|
// TODO: check lambda scope
|
||||||
|
// TODO: add structure to delete(__container__) when detachInterrupt() is called
|
||||||
|
auto f = [](void* a) -> void
|
||||||
|
{
|
||||||
|
T param = *(T*)((struct __container__<T>*)a)->param;
|
||||||
|
(((struct __container__<T>*)a)->function)(param);
|
||||||
|
};
|
||||||
|
|
||||||
|
attachInterruptParam(interruptNum, f, mode, cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void attachInterrupt(pin_size_t interruptNum, voidTemplateFuncPtrParam<T*> userFunc, PinStatus mode, T* param) {
|
||||||
|
attachInterruptParam(interruptNum, (voidFuncPtrParam)userFunc, mode, (void*)param);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1 +1,101 @@
|
||||||
#include "../../../ArduinoCore-API/api/PluggableUSB.cpp"
|
/*
|
||||||
|
PluggableUSB.cpp
|
||||||
|
Copyright (c) 2015 Arduino LLC
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "USBAPI.h"
|
||||||
|
#include "PluggableUSB.h"
|
||||||
|
|
||||||
|
using namespace arduino;
|
||||||
|
|
||||||
|
int PluggableUSB_::getInterface(uint8_t* interfaceCount)
|
||||||
|
{
|
||||||
|
int sent = 0;
|
||||||
|
PluggableUSBModule* node;
|
||||||
|
for (node = rootNode; node; node = node->next) {
|
||||||
|
int res = node->getInterface(interfaceCount);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
sent += res;
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PluggableUSB_::getDescriptor(USBSetup& setup)
|
||||||
|
{
|
||||||
|
PluggableUSBModule* node;
|
||||||
|
for (node = rootNode; node; node = node->next) {
|
||||||
|
int ret = node->getDescriptor(setup);
|
||||||
|
// ret!=0 -> request has been processed
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluggableUSB_::getShortName(char *iSerialNum)
|
||||||
|
{
|
||||||
|
PluggableUSBModule* node;
|
||||||
|
for (node = rootNode; node; node = node->next) {
|
||||||
|
iSerialNum += node->getShortName(iSerialNum);
|
||||||
|
}
|
||||||
|
*iSerialNum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PluggableUSB_::setup(USBSetup& setup)
|
||||||
|
{
|
||||||
|
PluggableUSBModule* node;
|
||||||
|
for (node = rootNode; node; node = node->next) {
|
||||||
|
if (node->setup(setup)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PluggableUSB_::plug(PluggableUSBModule *node)
|
||||||
|
{
|
||||||
|
if ((lastEp + node->numEndpoints) > totalEP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rootNode) {
|
||||||
|
rootNode = node;
|
||||||
|
} else {
|
||||||
|
PluggableUSBModule *current = rootNode;
|
||||||
|
while (current->next) {
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
current->next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->pluggedInterface = lastIf;
|
||||||
|
node->pluggedEndpoint = lastEp;
|
||||||
|
lastIf += node->numInterfaces;
|
||||||
|
for (uint8_t i = 0; i < node->numEndpoints; i++) {
|
||||||
|
*(unsigned int*)(epBuffer(lastEp)) = node->endpointType[i];
|
||||||
|
lastEp++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
// restart USB layer???
|
||||||
|
}
|
||||||
|
|
||||||
|
PluggableUSB_& PluggableUSB()
|
||||||
|
{
|
||||||
|
static PluggableUSB_ obj;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,78 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/PluggableUSB.h"
|
PluggableUSB.h
|
||||||
|
Copyright (c) 2015 Arduino LLC
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PUSB_h
|
||||||
|
#define PUSB_h
|
||||||
|
|
||||||
|
#include "USBAPI.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class PluggableUSBModule {
|
||||||
|
public:
|
||||||
|
PluggableUSBModule(uint8_t numEps, uint8_t numIfs, unsigned int *epType) :
|
||||||
|
numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool setup(USBSetup& setup) = 0;
|
||||||
|
virtual int getInterface(uint8_t* interfaceCount) = 0;
|
||||||
|
virtual int getDescriptor(USBSetup& setup) = 0;
|
||||||
|
virtual uint8_t getShortName(char *name) { name[0] = 'A'+pluggedInterface; return 1; }
|
||||||
|
|
||||||
|
uint8_t pluggedInterface;
|
||||||
|
uint8_t pluggedEndpoint;
|
||||||
|
|
||||||
|
const uint8_t numEndpoints;
|
||||||
|
const uint8_t numInterfaces;
|
||||||
|
const unsigned int *endpointType;
|
||||||
|
|
||||||
|
PluggableUSBModule *next = NULL;
|
||||||
|
|
||||||
|
friend class PluggableUSB_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PluggableUSB_ {
|
||||||
|
public:
|
||||||
|
PluggableUSB_();
|
||||||
|
bool plug(PluggableUSBModule *node);
|
||||||
|
int getInterface(uint8_t* interfaceCount);
|
||||||
|
int getDescriptor(USBSetup& setup);
|
||||||
|
bool setup(USBSetup& setup);
|
||||||
|
void getShortName(char *iSerialNum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t lastIf;
|
||||||
|
uint8_t lastEp;
|
||||||
|
PluggableUSBModule* rootNode;
|
||||||
|
uint8_t totalEP;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// core need to define
|
||||||
|
void* epBuffer(unsigned int n); // -> returns a pointer to the Nth element of the EP buffer structure
|
||||||
|
|
||||||
|
// Replacement for global singleton.
|
||||||
|
// This function prevents static-initialization-order-fiasco
|
||||||
|
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
|
||||||
|
arduino::PluggableUSB_& PluggableUSB();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1 +1,429 @@
|
||||||
#include "../../../ArduinoCore-API/api/Print.cpp"
|
/*
|
||||||
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
using namespace arduino;
|
||||||
|
|
||||||
|
// Public Methods //////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* default implementation: may be overridden */
|
||||||
|
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||||
|
{
|
||||||
|
size_t n = 0;
|
||||||
|
while (size--) {
|
||||||
|
if (write(*buffer++)) n++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||||
|
{
|
||||||
|
#if defined(__AVR__)
|
||||||
|
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||||
|
size_t n = 0;
|
||||||
|
while (1) {
|
||||||
|
unsigned char c = pgm_read_byte(p++);
|
||||||
|
if (c == 0) break;
|
||||||
|
if (write(c)) n++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
#else
|
||||||
|
return print(reinterpret_cast<const char *>(ifsh));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(const String &s)
|
||||||
|
{
|
||||||
|
return write(s.c_str(), s.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(const char str[])
|
||||||
|
{
|
||||||
|
return write(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(char c)
|
||||||
|
{
|
||||||
|
return write(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(unsigned char b, int base)
|
||||||
|
{
|
||||||
|
return print((unsigned long) b, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(int n, int base)
|
||||||
|
{
|
||||||
|
return print((long) n, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(unsigned int n, int base)
|
||||||
|
{
|
||||||
|
return print((unsigned long) n, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(long n, int base)
|
||||||
|
{
|
||||||
|
if (base == 0) {
|
||||||
|
return write(n);
|
||||||
|
} else if (base == 10) {
|
||||||
|
if (n < 0) {
|
||||||
|
int t = print('-');
|
||||||
|
n = -n;
|
||||||
|
return printNumber(n, 10) + t;
|
||||||
|
}
|
||||||
|
return printNumber(n, 10);
|
||||||
|
} else {
|
||||||
|
return printNumber(n, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(unsigned long n, int base)
|
||||||
|
{
|
||||||
|
if (base == 0) return write(n);
|
||||||
|
else return printNumber(n, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(long long n, int base)
|
||||||
|
{
|
||||||
|
if (base == 0) {
|
||||||
|
return write(n);
|
||||||
|
} else if (base == 10) {
|
||||||
|
if (n < 0) {
|
||||||
|
int t = print('-');
|
||||||
|
n = -n;
|
||||||
|
return printULLNumber(n, 10) + t;
|
||||||
|
}
|
||||||
|
return printULLNumber(n, 10);
|
||||||
|
} else {
|
||||||
|
return printULLNumber(n, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(unsigned long long n, int base)
|
||||||
|
{
|
||||||
|
if (base == 0) return write(n);
|
||||||
|
else return printULLNumber(n, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(double n, int digits)
|
||||||
|
{
|
||||||
|
return printFloat(n, digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(const __FlashStringHelper *ifsh)
|
||||||
|
{
|
||||||
|
size_t n = print(ifsh);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::print(const Printable& x)
|
||||||
|
{
|
||||||
|
return x.printTo(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(void)
|
||||||
|
{
|
||||||
|
return write("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(const String &s)
|
||||||
|
{
|
||||||
|
size_t n = print(s);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(const char c[])
|
||||||
|
{
|
||||||
|
size_t n = print(c);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(char c)
|
||||||
|
{
|
||||||
|
size_t n = print(c);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(unsigned char b, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(b, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(int num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(unsigned int num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(long num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(unsigned long num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(long long num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(unsigned long long num, int base)
|
||||||
|
{
|
||||||
|
size_t n = print(num, base);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(double num, int digits)
|
||||||
|
{
|
||||||
|
size_t n = print(num, digits);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::println(const Printable& x)
|
||||||
|
{
|
||||||
|
size_t n = print(x);
|
||||||
|
n += println();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::printf(const char *format, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, format);
|
||||||
|
char temp[64];
|
||||||
|
char* buffer = temp;
|
||||||
|
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
if (len > sizeof(temp) - 1) {
|
||||||
|
buffer = new char[len + 1];
|
||||||
|
if (!buffer) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
va_start(arg, format);
|
||||||
|
vsnprintf(buffer, len + 1, format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
len = write((const uint8_t*) buffer, len);
|
||||||
|
if (buffer != temp) {
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - must be better way than cut-n-paste!
|
||||||
|
size_t Print::printf_P(const char *format, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, format);
|
||||||
|
char temp[64];
|
||||||
|
char* buffer = temp;
|
||||||
|
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
if (len > sizeof(temp) - 1) {
|
||||||
|
buffer = new char[len + 1];
|
||||||
|
if (!buffer) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
va_start(arg, format);
|
||||||
|
vsnprintf(buffer, len + 1, format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
len = write((const uint8_t*) buffer, len);
|
||||||
|
if (buffer != temp) {
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private Methods /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||||
|
{
|
||||||
|
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||||
|
char *str = &buf[sizeof(buf) - 1];
|
||||||
|
|
||||||
|
*str = '\0';
|
||||||
|
|
||||||
|
// prevent crash if called with base == 1
|
||||||
|
if (base < 2) base = 10;
|
||||||
|
|
||||||
|
do {
|
||||||
|
char c = n % base;
|
||||||
|
n /= base;
|
||||||
|
|
||||||
|
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
} while(n);
|
||||||
|
|
||||||
|
return write(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// REFERENCE IMPLEMENTATION FOR ULL
|
||||||
|
// size_t Print::printULLNumber(unsigned long long n, uint8_t base)
|
||||||
|
// {
|
||||||
|
// // if limited to base 10 and 16 the bufsize can be smaller
|
||||||
|
// char buf[65];
|
||||||
|
// char *str = &buf[64];
|
||||||
|
|
||||||
|
// *str = '\0';
|
||||||
|
|
||||||
|
// // prevent crash if called with base == 1
|
||||||
|
// if (base < 2) base = 10;
|
||||||
|
|
||||||
|
// do {
|
||||||
|
// unsigned long long t = n / base;
|
||||||
|
// char c = n - t * base; // faster than c = n%base;
|
||||||
|
// n = t;
|
||||||
|
// *--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
// } while(n);
|
||||||
|
|
||||||
|
// return write(str);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FAST IMPLEMENTATION FOR ULL
|
||||||
|
size_t Print::printULLNumber(unsigned long long n64, uint8_t base)
|
||||||
|
{
|
||||||
|
// if limited to base 10 and 16 the bufsize can be 20
|
||||||
|
char buf[64];
|
||||||
|
uint8_t i = 0;
|
||||||
|
uint8_t innerLoops = 0;
|
||||||
|
|
||||||
|
// prevent crash if called with base == 1
|
||||||
|
if (base < 2) base = 10;
|
||||||
|
|
||||||
|
// process chunks that fit in "16 bit math".
|
||||||
|
uint16_t top = 0xFFFF / base;
|
||||||
|
uint16_t th16 = 1;
|
||||||
|
while (th16 < top)
|
||||||
|
{
|
||||||
|
th16 *= base;
|
||||||
|
innerLoops++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (n64 > th16)
|
||||||
|
{
|
||||||
|
// 64 bit math part
|
||||||
|
uint64_t q = n64 / th16;
|
||||||
|
uint16_t r = n64 - q*th16;
|
||||||
|
n64 = q;
|
||||||
|
|
||||||
|
// 16 bit math loop to do remainder. (note buffer is filled reverse)
|
||||||
|
for (uint8_t j=0; j < innerLoops; j++)
|
||||||
|
{
|
||||||
|
uint16_t qq = r/base;
|
||||||
|
buf[i++] = r - qq*base;
|
||||||
|
r = qq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t n16 = n64;
|
||||||
|
while (n16 > 0)
|
||||||
|
{
|
||||||
|
uint16_t qq = n16/base;
|
||||||
|
buf[i++] = n16 - qq*base;
|
||||||
|
n16 = qq;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes = i;
|
||||||
|
for (; i > 0; i--)
|
||||||
|
write((char) (buf[i - 1] < 10 ?
|
||||||
|
'0' + buf[i - 1] :
|
||||||
|
'A' + buf[i - 1] - 10));
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Print::printFloat(double number, int digits)
|
||||||
|
{
|
||||||
|
if (digits < 0)
|
||||||
|
digits = 2;
|
||||||
|
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
if (isnan(number)) return print("nan");
|
||||||
|
if (isinf(number)) return print("inf");
|
||||||
|
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
|
||||||
|
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
|
||||||
|
|
||||||
|
// Handle negative numbers
|
||||||
|
if (number < 0.0)
|
||||||
|
{
|
||||||
|
n += print('-');
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||||
|
double rounding = 0.5;
|
||||||
|
for (uint8_t i=0; i<digits; ++i)
|
||||||
|
rounding /= 10.0;
|
||||||
|
|
||||||
|
number += rounding;
|
||||||
|
|
||||||
|
// Extract the integer part of the number and print it
|
||||||
|
unsigned long int_part = (unsigned long)number;
|
||||||
|
double remainder = number - (double)int_part;
|
||||||
|
n += print(int_part);
|
||||||
|
|
||||||
|
// Print the decimal point, but only if there are digits beyond
|
||||||
|
if (digits > 0) {
|
||||||
|
n += print(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract digits from the remainder one at a time
|
||||||
|
while (digits-- > 0)
|
||||||
|
{
|
||||||
|
remainder *= 10.0;
|
||||||
|
unsigned int toPrint = (unsigned int)remainder;
|
||||||
|
n += print(toPrint);
|
||||||
|
remainder -= toPrint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,100 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Print.h"
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h> // for size_t
|
||||||
|
|
||||||
|
#include "String.h"
|
||||||
|
#include "Printable.h"
|
||||||
|
|
||||||
|
#define DEC 10
|
||||||
|
#define HEX 16
|
||||||
|
#define OCT 8
|
||||||
|
#define BIN 2
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class Print
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int write_error;
|
||||||
|
size_t printNumber(unsigned long, uint8_t);
|
||||||
|
size_t printULLNumber(unsigned long long, uint8_t);
|
||||||
|
size_t printFloat(double, int);
|
||||||
|
protected:
|
||||||
|
void setWriteError(int err = 1) { write_error = err; }
|
||||||
|
public:
|
||||||
|
Print() : write_error(0) {}
|
||||||
|
|
||||||
|
int getWriteError() { return write_error; }
|
||||||
|
void clearWriteError() { setWriteError(0); }
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t) = 0;
|
||||||
|
size_t write(const char *str) {
|
||||||
|
if (str == NULL) return 0;
|
||||||
|
return write((const uint8_t *)str, strlen(str));
|
||||||
|
}
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||||
|
size_t write(const char *buffer, size_t size) {
|
||||||
|
return write((const uint8_t *)buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to zero, meaning "a single write may block"
|
||||||
|
// should be overriden by subclasses with buffering
|
||||||
|
virtual int availableForWrite() { return 0; }
|
||||||
|
|
||||||
|
size_t print(const __FlashStringHelper *);
|
||||||
|
size_t print(const String &);
|
||||||
|
size_t print(const char[]);
|
||||||
|
size_t print(char);
|
||||||
|
size_t print(unsigned char, int = DEC);
|
||||||
|
size_t print(int, int = DEC);
|
||||||
|
size_t print(unsigned int, int = DEC);
|
||||||
|
size_t print(long, int = DEC);
|
||||||
|
size_t print(unsigned long, int = DEC);
|
||||||
|
size_t print(long long, int = DEC);
|
||||||
|
size_t print(unsigned long long, int = DEC);
|
||||||
|
size_t print(double, int = 2);
|
||||||
|
size_t print(const Printable&);
|
||||||
|
|
||||||
|
size_t println(const __FlashStringHelper *);
|
||||||
|
size_t println(const String &s);
|
||||||
|
size_t println(const char[]);
|
||||||
|
size_t println(char);
|
||||||
|
size_t println(unsigned char, int = DEC);
|
||||||
|
size_t println(int, int = DEC);
|
||||||
|
size_t println(unsigned int, int = DEC);
|
||||||
|
size_t println(long, int = DEC);
|
||||||
|
size_t println(unsigned long, int = DEC);
|
||||||
|
size_t println(long long, int = DEC);
|
||||||
|
size_t println(unsigned long long, int = DEC);
|
||||||
|
size_t println(double, int = 2);
|
||||||
|
size_t println(const Printable&);
|
||||||
|
size_t println(void);
|
||||||
|
|
||||||
|
// EFP3 - Add printf() to make life so much easier...
|
||||||
|
size_t printf(const char *format, ...);
|
||||||
|
size_t printf_P(const char *format, ...);
|
||||||
|
|
||||||
|
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
using namespace arduino;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,39 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Printable.h"
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class Print;
|
||||||
|
|
||||||
|
/** The Printable class provides a way for new classes to allow themselves to be printed.
|
||||||
|
By deriving from Printable and implementing the printTo method, it will then be possible
|
||||||
|
for users to print out instances of this class by passing them into the usual
|
||||||
|
Print::print and Print::println methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Printable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual size_t printTo(Print& p) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1,141 @@
|
||||||
#include "../../../ArduinoCore-API/api/RingBuffer.h"
|
/*
|
||||||
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#ifndef _RING_BUFFER_
|
||||||
|
#define _RING_BUFFER_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// Define constants and variables for buffering incoming serial data. We're
|
||||||
|
// using a ring buffer (I think), in which head is the index of the location
|
||||||
|
// to which to write the next incoming character and tail is the index of the
|
||||||
|
// location from which to read.
|
||||||
|
#define SERIAL_BUFFER_SIZE 64
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class RingBufferN
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8_t _aucBuffer[N] ;
|
||||||
|
volatile int _iHead ;
|
||||||
|
volatile int _iTail ;
|
||||||
|
volatile int _numElems;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RingBufferN( void ) ;
|
||||||
|
void store_char( uint8_t c ) ;
|
||||||
|
void clear();
|
||||||
|
int read_char();
|
||||||
|
int available();
|
||||||
|
int availableForStore();
|
||||||
|
int peek();
|
||||||
|
bool isFull();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int nextIndex(int index);
|
||||||
|
inline bool isEmpty() const { return (_numElems == 0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef RingBufferN<SERIAL_BUFFER_SIZE> RingBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
RingBufferN<N>::RingBufferN( void )
|
||||||
|
{
|
||||||
|
memset( _aucBuffer, 0, N ) ;
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
void RingBufferN<N>::store_char( uint8_t c )
|
||||||
|
{
|
||||||
|
// if we should be storing the received character into the location
|
||||||
|
// just before the tail (meaning that the head would advance to the
|
||||||
|
// current location of the tail), we're about to overflow the buffer
|
||||||
|
// and so we don't write the character or advance the head.
|
||||||
|
if (!isFull())
|
||||||
|
{
|
||||||
|
_aucBuffer[_iHead] = c ;
|
||||||
|
_iHead = nextIndex(_iHead);
|
||||||
|
_numElems++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
void RingBufferN<N>::clear()
|
||||||
|
{
|
||||||
|
_iHead = 0;
|
||||||
|
_iTail = 0;
|
||||||
|
_numElems = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int RingBufferN<N>::read_char()
|
||||||
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint8_t value = _aucBuffer[_iTail];
|
||||||
|
_iTail = nextIndex(_iTail);
|
||||||
|
_numElems--;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int RingBufferN<N>::available()
|
||||||
|
{
|
||||||
|
return _numElems;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int RingBufferN<N>::availableForStore()
|
||||||
|
{
|
||||||
|
return (N - _numElems);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int RingBufferN<N>::peek()
|
||||||
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return _aucBuffer[_iTail];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
int RingBufferN<N>::nextIndex(int index)
|
||||||
|
{
|
||||||
|
return (uint32_t)(index + 1) % N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
bool RingBufferN<N>::isFull()
|
||||||
|
{
|
||||||
|
return (_numElems == N);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _RING_BUFFER_ */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
@ -1,2 +1,31 @@
|
||||||
|
/*
|
||||||
|
Server.h - Base class that provides Server
|
||||||
|
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Server.h"
|
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class Server : public Print {
|
||||||
|
public:
|
||||||
|
virtual void begin() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1,321 @@
|
||||||
#include "../../../ArduinoCore-API/api/Stream.cpp"
|
/*
|
||||||
|
Stream.cpp - adds parsing methods to Stream class
|
||||||
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Created July 2011
|
||||||
|
parsing functions based on TextFinder library by Michael Margolis
|
||||||
|
|
||||||
|
findMulti/findUntil routines written by Jim Leonard/Xuth
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
|
||||||
|
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
||||||
|
|
||||||
|
using namespace arduino;
|
||||||
|
|
||||||
|
// private method to read stream with timeout
|
||||||
|
int Stream::timedRead()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
_startMillis = millis();
|
||||||
|
do {
|
||||||
|
c = read();
|
||||||
|
if (c >= 0) return c;
|
||||||
|
} while(millis() - _startMillis < _timeout);
|
||||||
|
return -1; // -1 indicates timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// private method to peek stream with timeout
|
||||||
|
int Stream::timedPeek()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
_startMillis = millis();
|
||||||
|
do {
|
||||||
|
c = peek();
|
||||||
|
if (c >= 0) return c;
|
||||||
|
} while(millis() - _startMillis < _timeout);
|
||||||
|
return -1; // -1 indicates timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns peek of the next digit in the stream or -1 if timeout
|
||||||
|
// discards non-numeric characters
|
||||||
|
int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
while (1) {
|
||||||
|
c = timedPeek();
|
||||||
|
|
||||||
|
if( c < 0 ||
|
||||||
|
c == '-' ||
|
||||||
|
(c >= '0' && c <= '9') ||
|
||||||
|
(detectDecimal && c == '.')) return c;
|
||||||
|
|
||||||
|
switch( lookahead ){
|
||||||
|
case SKIP_NONE: return -1; // Fail code.
|
||||||
|
case SKIP_WHITESPACE:
|
||||||
|
switch( c ){
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n': break;
|
||||||
|
default: return -1; // Fail code.
|
||||||
|
}
|
||||||
|
case SKIP_ALL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read(); // discard non-numeric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public Methods
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
||||||
|
{
|
||||||
|
_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find returns true if the target string is found
|
||||||
|
bool Stream::find(const char *target)
|
||||||
|
{
|
||||||
|
return findUntil(target, strlen(target), NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads data from the stream until the target string of given length is found
|
||||||
|
// returns true if target string is found, false if timed out
|
||||||
|
bool Stream::find(const char *target, size_t length)
|
||||||
|
{
|
||||||
|
return findUntil(target, length, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// as find but search ends if the terminator string is found
|
||||||
|
bool Stream::findUntil(const char *target, const char *terminator)
|
||||||
|
{
|
||||||
|
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads data from the stream until the target string of the given length is found
|
||||||
|
// search terminated if the terminator string is found
|
||||||
|
// returns true if target string is found, false if terminated or timed out
|
||||||
|
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
|
||||||
|
{
|
||||||
|
if (terminator == NULL) {
|
||||||
|
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||||
|
return findMulti(t, 1) == 0;
|
||||||
|
} else {
|
||||||
|
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||||
|
return findMulti(t, 2) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the first valid (long) integer value from the current position.
|
||||||
|
// lookahead determines how parseInt looks ahead in the stream.
|
||||||
|
// See LookaheadMode enumeration at the top of the file.
|
||||||
|
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||||
|
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||||
|
long Stream::parseInt(LookaheadMode lookahead, char ignore)
|
||||||
|
{
|
||||||
|
bool isNegative = false;
|
||||||
|
long value = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = peekNextDigit(lookahead, false);
|
||||||
|
// ignore non numeric leading characters
|
||||||
|
if(c < 0)
|
||||||
|
return 0; // zero returned if timeout
|
||||||
|
|
||||||
|
do{
|
||||||
|
if((char)c == ignore)
|
||||||
|
; // ignore this character
|
||||||
|
else if(c == '-')
|
||||||
|
isNegative = true;
|
||||||
|
else if(c >= '0' && c <= '9') // is c a digit?
|
||||||
|
value = value * 10 + c - '0';
|
||||||
|
read(); // consume the character we got with peek
|
||||||
|
c = timedPeek();
|
||||||
|
}
|
||||||
|
while( (c >= '0' && c <= '9') || (char)c == ignore );
|
||||||
|
|
||||||
|
if(isNegative)
|
||||||
|
value = -value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// as parseInt but returns a floating point value
|
||||||
|
float Stream::parseFloat(LookaheadMode lookahead, char ignore)
|
||||||
|
{
|
||||||
|
bool isNegative = false;
|
||||||
|
bool isFraction = false;
|
||||||
|
double value = 0.0;
|
||||||
|
int c;
|
||||||
|
double fraction = 1.0;
|
||||||
|
|
||||||
|
c = peekNextDigit(lookahead, true);
|
||||||
|
// ignore non numeric leading characters
|
||||||
|
if(c < 0)
|
||||||
|
return 0; // zero returned if timeout
|
||||||
|
|
||||||
|
do{
|
||||||
|
if((char)c == ignore)
|
||||||
|
; // ignore
|
||||||
|
else if(c == '-')
|
||||||
|
isNegative = true;
|
||||||
|
else if (c == '.')
|
||||||
|
isFraction = true;
|
||||||
|
else if(c >= '0' && c <= '9') { // is c a digit?
|
||||||
|
if(isFraction) {
|
||||||
|
fraction *= 0.1;
|
||||||
|
value = value + fraction * (c - '0');
|
||||||
|
} else {
|
||||||
|
value = value * 10 + c - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read(); // consume the character we got with peek
|
||||||
|
c = timedPeek();
|
||||||
|
}
|
||||||
|
while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || (char)c == ignore );
|
||||||
|
|
||||||
|
if(isNegative)
|
||||||
|
value = -value;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read characters from stream into buffer
|
||||||
|
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||||
|
// returns the number of characters placed in the buffer
|
||||||
|
// the buffer is NOT null terminated.
|
||||||
|
//
|
||||||
|
size_t Stream::readBytes(char *buffer, size_t length)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
while (count < length) {
|
||||||
|
int c = timedRead();
|
||||||
|
if (c < 0) break;
|
||||||
|
*buffer++ = (char)c;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// as readBytes with terminator character
|
||||||
|
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||||
|
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||||
|
|
||||||
|
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||||
|
{
|
||||||
|
size_t index = 0;
|
||||||
|
while (index < length) {
|
||||||
|
int c = timedRead();
|
||||||
|
if (c < 0 || (char)c == terminator) break;
|
||||||
|
*buffer++ = (char)c;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return index; // return number of characters, not including null terminator
|
||||||
|
}
|
||||||
|
|
||||||
|
String Stream::readString()
|
||||||
|
{
|
||||||
|
String ret;
|
||||||
|
int c = timedRead();
|
||||||
|
while (c >= 0)
|
||||||
|
{
|
||||||
|
ret += (char)c;
|
||||||
|
c = timedRead();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Stream::readStringUntil(char terminator)
|
||||||
|
{
|
||||||
|
String ret;
|
||||||
|
int c = timedRead();
|
||||||
|
while (c >= 0 && (char)c != terminator)
|
||||||
|
{
|
||||||
|
ret += (char)c;
|
||||||
|
c = timedRead();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
|
||||||
|
// any zero length target string automatically matches and would make
|
||||||
|
// a mess of the rest of the algorithm.
|
||||||
|
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||||
|
if (t->len <= 0)
|
||||||
|
return t - targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int c = timedRead();
|
||||||
|
if (c < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||||
|
// the simple case is if we match, deal with that first.
|
||||||
|
if ((char)c == t->str[t->index]) {
|
||||||
|
if (++t->index == t->len)
|
||||||
|
return t - targets;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not we need to walk back and see if we could have matched further
|
||||||
|
// down the stream (ie '1112' doesn't match the first position in '11112'
|
||||||
|
// but it will match the second position so we can't just reset the current
|
||||||
|
// index to 0 when we find a mismatch.
|
||||||
|
if (t->index == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int origIndex = t->index;
|
||||||
|
do {
|
||||||
|
--t->index;
|
||||||
|
// first check if current char works against the new current index
|
||||||
|
if ((char)c != t->str[t->index])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// if it's the only char then we're good, nothing more to check
|
||||||
|
if (t->index == 0) {
|
||||||
|
t->index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we need to check the rest of the found string
|
||||||
|
int diff = origIndex - t->index;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < t->index; ++i) {
|
||||||
|
if (t->str[i] != t->str[i + diff])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we successfully got through the previous loop then our current
|
||||||
|
// index is good.
|
||||||
|
if (i == t->index) {
|
||||||
|
t->index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we just try the next index
|
||||||
|
} while (t->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unreachable
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,131 @@
|
||||||
|
/*
|
||||||
|
Stream.h - base class for character-based streams.
|
||||||
|
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
parsing functions based on TextFinder library by Michael Margolis
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Stream.h"
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
// compatability macros for testing
|
||||||
|
/*
|
||||||
|
#define getInt() parseInt()
|
||||||
|
#define getInt(ignore) parseInt(ignore)
|
||||||
|
#define getFloat() parseFloat()
|
||||||
|
#define getFloat(ignore) parseFloat(ignore)
|
||||||
|
#define getString( pre_string, post_string, buffer, length)
|
||||||
|
readBytesBetween( pre_string, terminator, buffer, length)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// This enumeration provides the lookahead options for parseInt(), parseFloat()
|
||||||
|
// The rules set out here are used until either the first valid character is found
|
||||||
|
// or a time out occurs due to lack of input.
|
||||||
|
enum LookaheadMode{
|
||||||
|
SKIP_ALL, // All invalid characters are ignored.
|
||||||
|
SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid.
|
||||||
|
SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped.
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field
|
||||||
|
|
||||||
|
class Stream : public Print
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||||
|
unsigned long _startMillis; // used for timeout measurement
|
||||||
|
int timedRead(); // private method to read stream with timeout
|
||||||
|
int timedPeek(); // private method to peek stream with timeout
|
||||||
|
int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int available() = 0;
|
||||||
|
virtual int read() = 0;
|
||||||
|
virtual int peek() = 0;
|
||||||
|
|
||||||
|
Stream() {_timeout=1000;}
|
||||||
|
|
||||||
|
// parsing methods
|
||||||
|
|
||||||
|
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||||
|
unsigned long getTimeout(void) { return _timeout; }
|
||||||
|
|
||||||
|
bool find(const char *target); // reads data from the stream until the target string is found
|
||||||
|
bool find(const uint8_t *target) { return find ((const char *)target); }
|
||||||
|
// returns true if target string is found, false if timed out (see setTimeout)
|
||||||
|
|
||||||
|
bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||||
|
bool find(const uint8_t *target, size_t length) { return find ((const char *)target, length); }
|
||||||
|
// returns true if target string is found, false if timed out
|
||||||
|
|
||||||
|
bool find(char target) { return find (&target, 1); }
|
||||||
|
|
||||||
|
bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found
|
||||||
|
bool findUntil(const uint8_t *target, const char *terminator) { return findUntil((const char *)target, terminator); }
|
||||||
|
|
||||||
|
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||||
|
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {return findUntil((const char *)target, targetLen, terminate, termLen); }
|
||||||
|
|
||||||
|
long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||||
|
// returns the first valid (long) integer value from the current position.
|
||||||
|
// lookahead determines how parseInt looks ahead in the stream.
|
||||||
|
// See LookaheadMode enumeration at the top of the file.
|
||||||
|
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||||
|
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||||
|
|
||||||
|
float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||||
|
// float version of parseInt
|
||||||
|
|
||||||
|
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
|
||||||
|
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
|
||||||
|
// terminates if length characters have been read or timeout (see setTimeout)
|
||||||
|
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||||
|
|
||||||
|
size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
|
||||||
|
size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); }
|
||||||
|
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||||
|
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||||
|
|
||||||
|
// Arduino String functions to be added here
|
||||||
|
String readString();
|
||||||
|
String readStringUntil(char terminator);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); }
|
||||||
|
float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); }
|
||||||
|
// These overload exists for compatibility with any class that has derived
|
||||||
|
// Stream and used parseFloat/Int with a custom ignore character. To keep
|
||||||
|
// the public API simple, these overload remains protected.
|
||||||
|
|
||||||
|
struct MultiTarget {
|
||||||
|
const char *str; // string you're searching for
|
||||||
|
size_t len; // length of string you're searching for
|
||||||
|
size_t index; // index used by the search routine.
|
||||||
|
};
|
||||||
|
|
||||||
|
// This allows you to search for an arbitrary number of strings.
|
||||||
|
// Returns index of the target that is found first or -1 if timeout occurs.
|
||||||
|
int findMulti(struct MultiTarget *targets, int tCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef NO_IGNORE_CHAR
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1,768 @@
|
||||||
#include "../../../ArduinoCore-API/api/String.cpp"
|
/*
|
||||||
|
String library for Wiring & Arduino
|
||||||
|
...mostly rewritten by Paul Stoffregen...
|
||||||
|
Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
|
||||||
|
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "String.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "itoa.h"
|
||||||
|
#include "deprecated-avr-comp/avr/dtostrf.h"
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Static Member Initialisation */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
size_t const String::FLT_MAX_DECIMAL_PLACES;
|
||||||
|
size_t const String::DBL_MAX_DECIMAL_PLACES;
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Constructors */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
String::String(const char *cstr)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
if (cstr) copy(cstr, strlen(cstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(const char *cstr, unsigned int length)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
if (cstr) copy(cstr, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(const String &value)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
*this = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(const __FlashStringHelper *pstr)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
*this = pstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
String::String(String &&rval)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
move(rval);
|
||||||
|
}
|
||||||
|
String::String(StringSumHelper &&rval)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
move(rval);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String::String(char c)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[2];
|
||||||
|
buf[0] = c;
|
||||||
|
buf[1] = 0;
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(unsigned char value, unsigned char base)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[1 + 8 * sizeof(unsigned char)];
|
||||||
|
utoa(value, buf, base);
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(int value, unsigned char base)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[2 + 8 * sizeof(int)];
|
||||||
|
itoa(value, buf, base);
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(unsigned int value, unsigned char base)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[1 + 8 * sizeof(unsigned int)];
|
||||||
|
utoa(value, buf, base);
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(long value, unsigned char base)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[2 + 8 * sizeof(long)];
|
||||||
|
ltoa(value, buf, base);
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(unsigned long value, unsigned char base)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
char buf[1 + 8 * sizeof(unsigned long)];
|
||||||
|
ultoa(value, buf, base);
|
||||||
|
*this = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(float value, unsigned char decimalPlaces)
|
||||||
|
{
|
||||||
|
static size_t const FLOAT_BUF_SIZE = FLT_MAX_10_EXP + FLT_MAX_DECIMAL_PLACES + 1 /* '-' */ + 1 /* '.' */ + 1 /* '\0' */;
|
||||||
|
init();
|
||||||
|
char buf[FLOAT_BUF_SIZE];
|
||||||
|
decimalPlaces = min(decimalPlaces, FLT_MAX_DECIMAL_PLACES);
|
||||||
|
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(double value, unsigned char decimalPlaces)
|
||||||
|
{
|
||||||
|
static size_t const DOUBLE_BUF_SIZE = DBL_MAX_10_EXP + DBL_MAX_DECIMAL_PLACES + 1 /* '-' */ + 1 /* '.' */ + 1 /* '\0' */;
|
||||||
|
init();
|
||||||
|
char buf[DOUBLE_BUF_SIZE];
|
||||||
|
decimalPlaces = min(decimalPlaces, DBL_MAX_DECIMAL_PLACES);
|
||||||
|
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::~String()
|
||||||
|
{
|
||||||
|
if (buffer) free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Memory Management */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
inline void String::init(void)
|
||||||
|
{
|
||||||
|
buffer = NULL;
|
||||||
|
capacity = 0;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::invalidate(void)
|
||||||
|
{
|
||||||
|
if (buffer) free(buffer);
|
||||||
|
buffer = NULL;
|
||||||
|
capacity = len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::reserve(unsigned int size)
|
||||||
|
{
|
||||||
|
if (buffer && capacity >= size) return 1;
|
||||||
|
if (changeBuffer(size)) {
|
||||||
|
if (len == 0) buffer[0] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::changeBuffer(unsigned int maxStrLen)
|
||||||
|
{
|
||||||
|
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
|
||||||
|
if (newbuffer) {
|
||||||
|
buffer = newbuffer;
|
||||||
|
capacity = maxStrLen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Copy and Move */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
String & String::copy(const char *cstr, unsigned int length)
|
||||||
|
{
|
||||||
|
if (!reserve(length)) {
|
||||||
|
invalidate();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
len = length;
|
||||||
|
memcpy(buffer, cstr, length);
|
||||||
|
buffer[len] = '\0';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
|
||||||
|
{
|
||||||
|
if (!reserve(length)) {
|
||||||
|
invalidate();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
len = length;
|
||||||
|
strcpy_P(buffer, (PGM_P)pstr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
void String::move(String &rhs)
|
||||||
|
{
|
||||||
|
if (buffer) {
|
||||||
|
if (rhs && capacity >= rhs.len) {
|
||||||
|
memcpy(buffer, rhs.buffer, rhs.len);
|
||||||
|
len = rhs.len;
|
||||||
|
buffer[len] = '\0';
|
||||||
|
rhs.len = 0;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = rhs.buffer;
|
||||||
|
capacity = rhs.capacity;
|
||||||
|
len = rhs.len;
|
||||||
|
rhs.buffer = NULL;
|
||||||
|
rhs.capacity = 0;
|
||||||
|
rhs.len = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String & String::operator = (const String &rhs)
|
||||||
|
{
|
||||||
|
if (this == &rhs) return *this;
|
||||||
|
|
||||||
|
if (rhs.buffer) copy(rhs.buffer, rhs.len);
|
||||||
|
else invalidate();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
String & String::operator = (String &&rval)
|
||||||
|
{
|
||||||
|
if (this != &rval) move(rval);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String & String::operator = (StringSumHelper &&rval)
|
||||||
|
{
|
||||||
|
if (this != &rval) move(rval);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String & String::operator = (const char *cstr)
|
||||||
|
{
|
||||||
|
if (cstr) copy(cstr, strlen(cstr));
|
||||||
|
else invalidate();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String & String::operator = (const __FlashStringHelper *pstr)
|
||||||
|
{
|
||||||
|
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
|
||||||
|
else invalidate();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* concat */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
unsigned char String::concat(const String &s)
|
||||||
|
{
|
||||||
|
return concat(s.buffer, s.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(const char *cstr, unsigned int length)
|
||||||
|
{
|
||||||
|
unsigned int newlen = len + length;
|
||||||
|
if (!cstr) return 0;
|
||||||
|
if (length == 0) return 1;
|
||||||
|
if (!reserve(newlen)) return 0;
|
||||||
|
memcpy(buffer + len, cstr, length);
|
||||||
|
len = newlen;
|
||||||
|
buffer[len] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(const char *cstr)
|
||||||
|
{
|
||||||
|
if (!cstr) return 0;
|
||||||
|
return concat(cstr, strlen(cstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(char c)
|
||||||
|
{
|
||||||
|
return concat(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(unsigned char num)
|
||||||
|
{
|
||||||
|
char buf[1 + 3 * sizeof(unsigned char)];
|
||||||
|
itoa(num, buf, 10);
|
||||||
|
return concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(int num)
|
||||||
|
{
|
||||||
|
char buf[2 + 3 * sizeof(int)];
|
||||||
|
itoa(num, buf, 10);
|
||||||
|
return concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(unsigned int num)
|
||||||
|
{
|
||||||
|
char buf[1 + 3 * sizeof(unsigned int)];
|
||||||
|
utoa(num, buf, 10);
|
||||||
|
return concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(long num)
|
||||||
|
{
|
||||||
|
char buf[2 + 3 * sizeof(long)];
|
||||||
|
ltoa(num, buf, 10);
|
||||||
|
return concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(unsigned long num)
|
||||||
|
{
|
||||||
|
char buf[1 + 3 * sizeof(unsigned long)];
|
||||||
|
ultoa(num, buf, 10);
|
||||||
|
return concat(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(float num)
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
char* string = dtostrf(num, 4, 2, buf);
|
||||||
|
return concat(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(double num)
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
char* string = dtostrf(num, 4, 2, buf);
|
||||||
|
return concat(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::concat(const __FlashStringHelper * str)
|
||||||
|
{
|
||||||
|
if (!str) return 0;
|
||||||
|
int length = strlen_P((const char *) str);
|
||||||
|
if (length == 0) return 1;
|
||||||
|
unsigned int newlen = len + length;
|
||||||
|
if (!reserve(newlen)) return 0;
|
||||||
|
strcpy_P(buffer + len, (const char *) str);
|
||||||
|
len = newlen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Concatenate */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!cstr || !a.concat(cstr)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, char c)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(c)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, int num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, long num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, float num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, double num)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(num)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
|
||||||
|
{
|
||||||
|
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||||
|
if (!a.concat(rhs)) a.invalidate();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Comparison */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
int String::compareTo(const String &s) const
|
||||||
|
{
|
||||||
|
if (!buffer || !s.buffer) {
|
||||||
|
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
|
||||||
|
if (buffer && len > 0) return *(unsigned char *)buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return strcmp(buffer, s.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::compareTo(const char *cstr) const
|
||||||
|
{
|
||||||
|
if (!buffer || !cstr) {
|
||||||
|
if (cstr && *cstr) return 0 - *(unsigned char *)cstr;
|
||||||
|
if (buffer && len > 0) return *(unsigned char *)buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return strcmp(buffer, cstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::equals(const String &s2) const
|
||||||
|
{
|
||||||
|
return (len == s2.len && compareTo(s2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::equals(const char *cstr) const
|
||||||
|
{
|
||||||
|
if (len == 0) return (cstr == NULL || *cstr == 0);
|
||||||
|
if (cstr == NULL) return buffer[0] == 0;
|
||||||
|
return strcmp(buffer, cstr) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::equalsIgnoreCase( const String &s2 ) const
|
||||||
|
{
|
||||||
|
if (this == &s2) return 1;
|
||||||
|
if (len != s2.len) return 0;
|
||||||
|
if (len == 0) return 1;
|
||||||
|
const char *p1 = buffer;
|
||||||
|
const char *p2 = s2.buffer;
|
||||||
|
while (*p1) {
|
||||||
|
if (tolower(*p1++) != tolower(*p2++)) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::startsWith( const String &s2 ) const
|
||||||
|
{
|
||||||
|
if (len < s2.len) return 0;
|
||||||
|
return startsWith(s2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::startsWith( const String &s2, unsigned int offset ) const
|
||||||
|
{
|
||||||
|
if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
|
||||||
|
return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char String::endsWith( const String &s2 ) const
|
||||||
|
{
|
||||||
|
if ( len < s2.len || !buffer || !s2.buffer) return 0;
|
||||||
|
return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Character Access */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
char String::charAt(unsigned int loc) const
|
||||||
|
{
|
||||||
|
return operator[](loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::setCharAt(unsigned int loc, char c)
|
||||||
|
{
|
||||||
|
if (loc < len) buffer[loc] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
char & String::operator[](unsigned int index)
|
||||||
|
{
|
||||||
|
static char dummy_writable_char;
|
||||||
|
if (index >= len || !buffer) {
|
||||||
|
dummy_writable_char = 0;
|
||||||
|
return dummy_writable_char;
|
||||||
|
}
|
||||||
|
return buffer[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
char String::operator[]( unsigned int index ) const
|
||||||
|
{
|
||||||
|
if (index >= len || !buffer) return 0;
|
||||||
|
return buffer[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
|
||||||
|
{
|
||||||
|
if (!bufsize || !buf) return;
|
||||||
|
if (index >= len) {
|
||||||
|
buf[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned int n = bufsize - 1;
|
||||||
|
if (n > len - index) n = len - index;
|
||||||
|
strncpy((char *)buf, buffer + index, n);
|
||||||
|
buf[n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Search */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
int String::indexOf(char c) const
|
||||||
|
{
|
||||||
|
return indexOf(c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::indexOf( char ch, unsigned int fromIndex ) const
|
||||||
|
{
|
||||||
|
if (fromIndex >= len) return -1;
|
||||||
|
const char* temp = strchr(buffer + fromIndex, ch);
|
||||||
|
if (temp == NULL) return -1;
|
||||||
|
return temp - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::indexOf(const String &s2) const
|
||||||
|
{
|
||||||
|
return indexOf(s2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::indexOf(const String &s2, unsigned int fromIndex) const
|
||||||
|
{
|
||||||
|
if (fromIndex >= len) return -1;
|
||||||
|
const char *found = strstr(buffer + fromIndex, s2.buffer);
|
||||||
|
if (found == NULL) return -1;
|
||||||
|
return found - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::lastIndexOf( char theChar ) const
|
||||||
|
{
|
||||||
|
return lastIndexOf(theChar, len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::lastIndexOf(char ch, unsigned int fromIndex) const
|
||||||
|
{
|
||||||
|
if (fromIndex >= len) return -1;
|
||||||
|
char tempchar = buffer[fromIndex + 1];
|
||||||
|
buffer[fromIndex + 1] = '\0';
|
||||||
|
char* temp = strrchr( buffer, ch );
|
||||||
|
buffer[fromIndex + 1] = tempchar;
|
||||||
|
if (temp == NULL) return -1;
|
||||||
|
return temp - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::lastIndexOf(const String &s2) const
|
||||||
|
{
|
||||||
|
return lastIndexOf(s2, len - s2.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
|
||||||
|
{
|
||||||
|
if (s2.len == 0 || len == 0 || s2.len > len) return -1;
|
||||||
|
if (fromIndex >= len) fromIndex = len - 1;
|
||||||
|
int found = -1;
|
||||||
|
for (char *p = buffer; p <= buffer + fromIndex; p++) {
|
||||||
|
p = strstr(p, s2.buffer);
|
||||||
|
if (!p) break;
|
||||||
|
if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::substring(unsigned int left, unsigned int right) const
|
||||||
|
{
|
||||||
|
if (left > right) {
|
||||||
|
unsigned int temp = right;
|
||||||
|
right = left;
|
||||||
|
left = temp;
|
||||||
|
}
|
||||||
|
String out;
|
||||||
|
if (left >= len) return out;
|
||||||
|
if (right > len) right = len;
|
||||||
|
out.copy(buffer + left, right - left);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Modification */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
void String::replace(char find, char replace)
|
||||||
|
{
|
||||||
|
if (!buffer) return;
|
||||||
|
for (char *p = buffer; *p; p++) {
|
||||||
|
if (*p == find) *p = replace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::replace(const String& find, const String& replace)
|
||||||
|
{
|
||||||
|
if (len == 0 || find.len == 0) return;
|
||||||
|
int diff = replace.len - find.len;
|
||||||
|
char *readFrom = buffer;
|
||||||
|
char *foundAt;
|
||||||
|
if (diff == 0) {
|
||||||
|
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||||
|
memcpy(foundAt, replace.buffer, replace.len);
|
||||||
|
readFrom = foundAt + replace.len;
|
||||||
|
}
|
||||||
|
} else if (diff < 0) {
|
||||||
|
unsigned int size = len; // compute size needed for result
|
||||||
|
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||||
|
readFrom = foundAt + find.len;
|
||||||
|
diff = 0 - diff;
|
||||||
|
size -= diff;
|
||||||
|
}
|
||||||
|
if (size == len) return;
|
||||||
|
int index = len - 1;
|
||||||
|
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
||||||
|
readFrom = buffer + index + find.len;
|
||||||
|
memmove(readFrom - diff, readFrom, len - (readFrom - buffer));
|
||||||
|
len -= diff;
|
||||||
|
buffer[len] = 0;
|
||||||
|
memcpy(buffer + index, replace.buffer, replace.len);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned int size = len; // compute size needed for result
|
||||||
|
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||||
|
readFrom = foundAt + find.len;
|
||||||
|
size += diff;
|
||||||
|
}
|
||||||
|
if (size == len) return;
|
||||||
|
if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
|
||||||
|
int index = len - 1;
|
||||||
|
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
||||||
|
readFrom = buffer + index + find.len;
|
||||||
|
memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
|
||||||
|
len += diff;
|
||||||
|
buffer[len] = 0;
|
||||||
|
memcpy(buffer + index, replace.buffer, replace.len);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::remove(unsigned int index){
|
||||||
|
// Pass the biggest integer as the count. The remove method
|
||||||
|
// below will take care of truncating it at the end of the
|
||||||
|
// string.
|
||||||
|
remove(index, (unsigned int)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::remove(unsigned int index, unsigned int count){
|
||||||
|
if (index >= len) { return; }
|
||||||
|
if (count <= 0) { return; }
|
||||||
|
if (count > len - index) { count = len - index; }
|
||||||
|
char *writeTo = buffer + index;
|
||||||
|
len = len - count;
|
||||||
|
memmove(writeTo, buffer + index + count,len - index);
|
||||||
|
buffer[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::toLowerCase(void)
|
||||||
|
{
|
||||||
|
if (!buffer) return;
|
||||||
|
for (char *p = buffer; *p; p++) {
|
||||||
|
*p = tolower(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::toUpperCase(void)
|
||||||
|
{
|
||||||
|
if (!buffer) return;
|
||||||
|
for (char *p = buffer; *p; p++) {
|
||||||
|
*p = toupper(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::trim(void)
|
||||||
|
{
|
||||||
|
if (!buffer || len == 0) return;
|
||||||
|
char *begin = buffer;
|
||||||
|
while (isspace(*begin)) begin++;
|
||||||
|
char *end = buffer + len - 1;
|
||||||
|
while (isspace(*end) && end >= begin) end--;
|
||||||
|
len = end + 1 - begin;
|
||||||
|
if (begin > buffer) memmove(buffer, begin, len);
|
||||||
|
buffer[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************/
|
||||||
|
/* Parsing / Conversion */
|
||||||
|
/*********************************************/
|
||||||
|
|
||||||
|
long String::toInt(void) const
|
||||||
|
{
|
||||||
|
if (buffer) return atol(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float String::toFloat(void) const
|
||||||
|
{
|
||||||
|
return float(toDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
double String::toDouble(void) const
|
||||||
|
{
|
||||||
|
if (buffer) return atof(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arduino
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,259 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/String.h"
|
String library for Wiring & Arduino
|
||||||
|
...mostly rewritten by Paul Stoffregen...
|
||||||
|
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
|
||||||
|
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#ifndef __ARDUINO_STRINGS__
|
||||||
|
#define __ARDUINO_STRINGS__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#if defined(__AVR__)
|
||||||
|
#include "avr/pgmspace.h"
|
||||||
|
#else
|
||||||
|
#include "deprecated-avr-comp/avr/pgmspace.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// When compiling programs with this class, the following gcc parameters
|
||||||
|
// dramatically increase performance and memory (RAM) efficiency, typically
|
||||||
|
// with little or no increase in code size.
|
||||||
|
// -felide-constructors
|
||||||
|
// -std=c++0x
|
||||||
|
|
||||||
|
class __FlashStringHelper;
|
||||||
|
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
||||||
|
|
||||||
|
// An inherited class for holding the result of a concatenation. These
|
||||||
|
// result objects are assumed to be writable by subsequent concatenations.
|
||||||
|
class StringSumHelper;
|
||||||
|
|
||||||
|
// The string class
|
||||||
|
class String
|
||||||
|
{
|
||||||
|
friend class StringSumHelper;
|
||||||
|
// use a function pointer to allow for "if (s)" without the
|
||||||
|
// complications of an operator bool(). for more information, see:
|
||||||
|
// http://www.artima.com/cppsource/safebool.html
|
||||||
|
typedef void (String::*StringIfHelperType)() const;
|
||||||
|
void StringIfHelper() const {}
|
||||||
|
|
||||||
|
static size_t const FLT_MAX_DECIMAL_PLACES = 10;
|
||||||
|
static size_t const DBL_MAX_DECIMAL_PLACES = FLT_MAX_DECIMAL_PLACES;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
// creates a copy of the initial value.
|
||||||
|
// if the initial value is null or invalid, or if memory allocation
|
||||||
|
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||||
|
// be false).
|
||||||
|
String(const char *cstr = "");
|
||||||
|
String(const char *cstr, unsigned int length);
|
||||||
|
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
|
||||||
|
String(const String &str);
|
||||||
|
String(const __FlashStringHelper *str);
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
String(String &&rval);
|
||||||
|
String(StringSumHelper &&rval);
|
||||||
|
#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(unsigned long, unsigned char base=10);
|
||||||
|
explicit String(float, unsigned char decimalPlaces=2);
|
||||||
|
explicit String(double, unsigned char decimalPlaces=2);
|
||||||
|
~String(void);
|
||||||
|
|
||||||
|
// memory management
|
||||||
|
// return true on success, false on failure (in which case, the string
|
||||||
|
// is left unchanged). reserve(0), if successful, will validate an
|
||||||
|
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||||
|
unsigned char reserve(unsigned int size);
|
||||||
|
inline unsigned int length(void) const {return len;}
|
||||||
|
|
||||||
|
// creates a copy of the assigned value. if the value is null or
|
||||||
|
// invalid, or if the memory allocation fails, the string will be
|
||||||
|
// marked as invalid ("if (s)" will be false).
|
||||||
|
String & operator = (const String &rhs);
|
||||||
|
String & operator = (const char *cstr);
|
||||||
|
String & operator = (const __FlashStringHelper *str);
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
String & operator = (String &&rval);
|
||||||
|
String & operator = (StringSumHelper &&rval);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// concatenate (works w/ built-in types)
|
||||||
|
|
||||||
|
// returns true on success, false on failure (in which case, the string
|
||||||
|
// is left unchanged). if the argument is null or invalid, the
|
||||||
|
// concatenation is considered unsucessful.
|
||||||
|
unsigned char concat(const String &str);
|
||||||
|
unsigned char concat(const char *cstr);
|
||||||
|
unsigned char concat(const char *cstr, unsigned int length);
|
||||||
|
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
|
||||||
|
unsigned char concat(char c);
|
||||||
|
unsigned char concat(unsigned char num);
|
||||||
|
unsigned char concat(int num);
|
||||||
|
unsigned char concat(unsigned int num);
|
||||||
|
unsigned char concat(long num);
|
||||||
|
unsigned char concat(unsigned long num);
|
||||||
|
unsigned char concat(float num);
|
||||||
|
unsigned char concat(double num);
|
||||||
|
unsigned char concat(const __FlashStringHelper * str);
|
||||||
|
|
||||||
|
// if there's not enough memory for the concatenated value, the string
|
||||||
|
// will be left unchanged (but this isn't signalled in any way)
|
||||||
|
String & operator += (const String &rhs) {concat(rhs); return (*this);}
|
||||||
|
String & operator += (const char *cstr) {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 += (unsigned long num) {concat(num); return (*this);}
|
||||||
|
String & operator += (float num) {concat(num); return (*this);}
|
||||||
|
String & operator += (double num) {concat(num); return (*this);}
|
||||||
|
String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}
|
||||||
|
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
|
||||||
|
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||||
|
|
||||||
|
// comparison (only works w/ Strings and "strings")
|
||||||
|
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
|
||||||
|
int compareTo(const String &s) const;
|
||||||
|
int compareTo(const char *cstr) const;
|
||||||
|
unsigned char equals(const String &s) const;
|
||||||
|
unsigned char equals(const char *cstr) const;
|
||||||
|
|
||||||
|
friend unsigned char operator == (const String &a, const String &b) { return a.equals(b); }
|
||||||
|
friend unsigned char operator == (const String &a, const char *b) { return a.equals(b); }
|
||||||
|
friend unsigned char operator == (const char *a, const String &b) { return b == a; }
|
||||||
|
friend unsigned char operator < (const String &a, const String &b) { return a.compareTo(b) < 0; }
|
||||||
|
friend unsigned char operator < (const String &a, const char *b) { return a.compareTo(b) < 0; }
|
||||||
|
friend unsigned char operator < (const char *a, const String &b) { return b.compareTo(a) > 0; }
|
||||||
|
|
||||||
|
friend unsigned char operator != (const String &a, const String &b) { return !(a == b); }
|
||||||
|
friend unsigned char operator != (const String &a, const char *b) { return !(a == b); }
|
||||||
|
friend unsigned char operator != (const char *a, const String &b) { return !(a == b); }
|
||||||
|
friend unsigned char operator > (const String &a, const String &b) { return b < a; }
|
||||||
|
friend unsigned char operator > (const String &a, const char *b) { return b < a; }
|
||||||
|
friend unsigned char operator > (const char *a, const String &b) { return b < a; }
|
||||||
|
friend unsigned char operator <= (const String &a, const String &b) { return !(b < a); }
|
||||||
|
friend unsigned char operator <= (const String &a, const char *b) { return !(b < a); }
|
||||||
|
friend unsigned char operator <= (const char *a, const String &b) { return !(b < a); }
|
||||||
|
friend unsigned char operator >= (const String &a, const String &b) { return !(a < b); }
|
||||||
|
friend unsigned char operator >= (const String &a, const char *b) { return !(a < b); }
|
||||||
|
friend unsigned char operator >= (const char *a, const String &b) { return !(a < b); }
|
||||||
|
|
||||||
|
unsigned char equalsIgnoreCase(const String &s) const;
|
||||||
|
unsigned char startsWith( const String &prefix) const;
|
||||||
|
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||||
|
unsigned char endsWith(const String &suffix) const;
|
||||||
|
|
||||||
|
// character acccess
|
||||||
|
char charAt(unsigned int index) const;
|
||||||
|
void setCharAt(unsigned int index, char c);
|
||||||
|
char operator [] (unsigned int index) const;
|
||||||
|
char& operator [] (unsigned int index);
|
||||||
|
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
|
||||||
|
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
|
||||||
|
{ getBytes((unsigned char *)buf, bufsize, index); }
|
||||||
|
const char* c_str() const { return buffer; }
|
||||||
|
char* begin() { return buffer; }
|
||||||
|
char* end() { return buffer + length(); }
|
||||||
|
const char* begin() const { return c_str(); }
|
||||||
|
const char* end() const { return c_str() + length(); }
|
||||||
|
|
||||||
|
// search
|
||||||
|
int indexOf( char ch ) const;
|
||||||
|
int indexOf( char ch, unsigned int fromIndex ) const;
|
||||||
|
int indexOf( const String &str ) const;
|
||||||
|
int indexOf( const String &str, unsigned int fromIndex ) const;
|
||||||
|
int lastIndexOf( char ch ) const;
|
||||||
|
int lastIndexOf( char ch, unsigned int fromIndex ) const;
|
||||||
|
int lastIndexOf( const String &str ) const;
|
||||||
|
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
|
||||||
|
String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };
|
||||||
|
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
|
||||||
|
|
||||||
|
// modification
|
||||||
|
void replace(char find, char replace);
|
||||||
|
void replace(const String& find, const String& replace);
|
||||||
|
void remove(unsigned int index);
|
||||||
|
void remove(unsigned int index, unsigned int count);
|
||||||
|
void toLowerCase(void);
|
||||||
|
void toUpperCase(void);
|
||||||
|
void trim(void);
|
||||||
|
|
||||||
|
// parsing/conversion
|
||||||
|
long toInt(void) const;
|
||||||
|
float toFloat(void) const;
|
||||||
|
double toDouble(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char *buffer; // the actual char array
|
||||||
|
unsigned int capacity; // the array length minus one (for the '\0')
|
||||||
|
unsigned int len; // the String length (not counting the '\0')
|
||||||
|
protected:
|
||||||
|
void init(void);
|
||||||
|
void invalidate(void);
|
||||||
|
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||||
|
|
||||||
|
// copy and move
|
||||||
|
String & copy(const char *cstr, unsigned int length);
|
||||||
|
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||||
|
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||||
|
void move(String &rhs);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class StringSumHelper : public String
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringSumHelper(const String &s) : String(s) {}
|
||||||
|
StringSumHelper(const char *p) : String(p) {}
|
||||||
|
StringSumHelper(char c) : String(c) {}
|
||||||
|
StringSumHelper(unsigned char num) : String(num) {}
|
||||||
|
StringSumHelper(int num) : String(num) {}
|
||||||
|
StringSumHelper(unsigned int num) : String(num) {}
|
||||||
|
StringSumHelper(long num) : String(num) {}
|
||||||
|
StringSumHelper(unsigned long num) : String(num) {}
|
||||||
|
StringSumHelper(float num) : String(num) {}
|
||||||
|
StringSumHelper(double num) : String(num) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace arduino
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
#endif // __ARDUINO_STRINGS__
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,64 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/USBAPI.h"
|
USBAPI.h
|
||||||
|
Copyright (c) 2005-2014 Arduino. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USBAPI__
|
||||||
|
#define __USBAPI__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
//================================================================================
|
||||||
|
//================================================================================
|
||||||
|
// Low level API
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint8_t bmRequestType;
|
||||||
|
struct {
|
||||||
|
uint8_t direction : 5;
|
||||||
|
uint8_t type : 2;
|
||||||
|
uint8_t transferDirection : 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
uint8_t bRequest;
|
||||||
|
uint8_t wValueL;
|
||||||
|
uint8_t wValueH;
|
||||||
|
uint16_t wIndex;
|
||||||
|
uint16_t wLength;
|
||||||
|
} USBSetup;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// USB APIs (C scope)
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
int USB_SendControl(uint8_t flags, const void* d, int len);
|
||||||
|
int USB_RecvControl(void* d, int len);
|
||||||
|
int USB_RecvControlLong(void* d, int len);
|
||||||
|
|
||||||
|
uint8_t USB_Available(uint8_t ep);
|
||||||
|
uint8_t USB_SendSpace(uint8_t ep);
|
||||||
|
int USB_Send(uint8_t ep, const void* data, int len); // blocking
|
||||||
|
int USB_Recv(uint8_t ep, void* data, int len); // non-blocking
|
||||||
|
int USB_Recv(uint8_t ep); // non-blocking
|
||||||
|
void USB_Flush(uint8_t ep);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,2 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Udp.cpp: Library to send/receive UDP packets.
|
||||||
|
*
|
||||||
|
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||||
|
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||||
|
* might not happen often in practice, but in larger network topologies, a UDP
|
||||||
|
* packet can be received out of sequence.
|
||||||
|
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||||
|
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||||
|
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||||
|
*
|
||||||
|
* MIT License:
|
||||||
|
* Copyright (c) 2008 Bjoern Hartmann
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* bjoern@cs.stanford.edu 12/30/2008
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/Udp.h"
|
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "IPAddress.h"
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
class UDP : public Stream {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||||
|
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
|
||||||
|
virtual void stop() =0; // Finish with the UDP socket
|
||||||
|
|
||||||
|
// Sending UDP packets
|
||||||
|
|
||||||
|
// Start building up a packet to send to the remote host specific in ip and port
|
||||||
|
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||||
|
virtual int beginPacket(IPAddress ip, uint16_t port) =0;
|
||||||
|
// Start building up a packet to send to the remote host specific in host and port
|
||||||
|
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||||
|
virtual int beginPacket(const char *host, uint16_t port) =0;
|
||||||
|
// Finish off this packet and send it
|
||||||
|
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||||
|
virtual int endPacket() =0;
|
||||||
|
// Write a single byte into the packet
|
||||||
|
virtual size_t write(uint8_t) =0;
|
||||||
|
// Write size bytes from buffer into the packet
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size) =0;
|
||||||
|
|
||||||
|
// Start processing the next available incoming packet
|
||||||
|
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||||
|
virtual int parsePacket() =0;
|
||||||
|
// Number of bytes remaining in the current packet
|
||||||
|
virtual int available() =0;
|
||||||
|
// Read a single byte from the current packet
|
||||||
|
virtual int read() =0;
|
||||||
|
// Read up to len bytes from the current packet and place them into buffer
|
||||||
|
// Returns the number of bytes read, or 0 if none are available
|
||||||
|
virtual int read(unsigned char* buffer, size_t len) =0;
|
||||||
|
// Read up to len characters from the current packet and place them into buffer
|
||||||
|
// Returns the number of characters read, or 0 if none are available
|
||||||
|
virtual int read(char* buffer, size_t len) =0;
|
||||||
|
// Return the next byte from the current packet without moving on to the next byte
|
||||||
|
virtual int peek() =0;
|
||||||
|
virtual void flush() =0; // Finish reading the current packet
|
||||||
|
|
||||||
|
// Return the IP address of the host who sent the current incoming packet
|
||||||
|
virtual IPAddress remoteIP() =0;
|
||||||
|
// Return the port of the host who sent the current incoming packet
|
||||||
|
virtual uint16_t remotePort() =0;
|
||||||
|
protected:
|
||||||
|
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace arduino;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,171 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../ArduinoCore-API/api/WCharacter.h"
|
WCharacter.h - Character utility functions for Wiring & Arduino
|
||||||
|
Copyright (c) 2010 Hernando Barragan. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Character_h
|
||||||
|
#define Character_h
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
namespace arduino {
|
||||||
|
|
||||||
|
// WCharacter.h prototypes
|
||||||
|
inline bool isAlphaNumeric(int c) __attribute__((always_inline));
|
||||||
|
inline bool isAlpha(int c) __attribute__((always_inline));
|
||||||
|
inline bool isAscii(int c) __attribute__((always_inline));
|
||||||
|
inline bool isWhitespace(int c) __attribute__((always_inline));
|
||||||
|
inline bool isControl(int c) __attribute__((always_inline));
|
||||||
|
inline bool isDigit(int c) __attribute__((always_inline));
|
||||||
|
inline bool isGraph(int c) __attribute__((always_inline));
|
||||||
|
inline bool isLowerCase(int c) __attribute__((always_inline));
|
||||||
|
inline bool isPrintable(int c) __attribute__((always_inline));
|
||||||
|
inline bool isPunct(int c) __attribute__((always_inline));
|
||||||
|
inline bool isSpace(int c) __attribute__((always_inline));
|
||||||
|
inline bool isUpperCase(int c) __attribute__((always_inline));
|
||||||
|
inline bool isHexadecimalDigit(int c) __attribute__((always_inline));
|
||||||
|
inline int toAscii(int c) __attribute__((always_inline));
|
||||||
|
inline int toLowerCase(int c) __attribute__((always_inline));
|
||||||
|
inline int toUpperCase(int c)__attribute__((always_inline));
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for an alphanumeric character.
|
||||||
|
// It is equivalent to (isalpha(c) || isdigit(c)).
|
||||||
|
inline bool isAlphaNumeric(int c)
|
||||||
|
{
|
||||||
|
return ( isalnum(c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for an alphabetic character.
|
||||||
|
// It is equivalent to (isupper(c) || islower(c)).
|
||||||
|
inline bool isAlpha(int c)
|
||||||
|
{
|
||||||
|
return ( isalpha(c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks whether c is a 7-bit unsigned char value
|
||||||
|
// that fits into the ASCII character set.
|
||||||
|
inline bool isAscii(int c)
|
||||||
|
{
|
||||||
|
return ( isascii (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for a blank character, that is, a space or a tab.
|
||||||
|
inline bool isWhitespace(int c)
|
||||||
|
{
|
||||||
|
return ( isblank (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for a control character.
|
||||||
|
inline bool isControl(int c)
|
||||||
|
{
|
||||||
|
return ( iscntrl (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for a digit (0 through 9).
|
||||||
|
inline bool isDigit(int c)
|
||||||
|
{
|
||||||
|
return ( isdigit (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for any printable character except space.
|
||||||
|
inline bool isGraph(int c)
|
||||||
|
{
|
||||||
|
return ( isgraph (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for a lower-case character.
|
||||||
|
inline bool isLowerCase(int c)
|
||||||
|
{
|
||||||
|
return (islower (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for any printable character including space.
|
||||||
|
inline bool isPrintable(int c)
|
||||||
|
{
|
||||||
|
return ( isprint (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for any printable character which is not a space
|
||||||
|
// or an alphanumeric character.
|
||||||
|
inline bool isPunct(int c)
|
||||||
|
{
|
||||||
|
return ( ispunct (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for white-space characters. For the avr-libc library,
|
||||||
|
// these are: space, formfeed ('\f'), newline ('\n'), carriage
|
||||||
|
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
|
||||||
|
inline bool isSpace(int c)
|
||||||
|
{
|
||||||
|
return ( isspace (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for an uppercase letter.
|
||||||
|
inline bool isUpperCase(int c)
|
||||||
|
{
|
||||||
|
return ( isupper (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
|
||||||
|
// 8 9 a b c d e f A B C D E F.
|
||||||
|
inline bool isHexadecimalDigit(int c)
|
||||||
|
{
|
||||||
|
return ( isxdigit (c) == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Converts c to a 7-bit unsigned char value that fits into the
|
||||||
|
// ASCII character set, by clearing the high-order bits.
|
||||||
|
inline int toAscii(int c)
|
||||||
|
{
|
||||||
|
return toascii (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Warning:
|
||||||
|
// Many people will be unhappy if you use this function.
|
||||||
|
// This function will convert accented letters into random
|
||||||
|
// characters.
|
||||||
|
|
||||||
|
// Converts the letter c to lower case, if possible.
|
||||||
|
inline int toLowerCase(int c)
|
||||||
|
{
|
||||||
|
return tolower (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Converts the letter c to upper case, if possible.
|
||||||
|
inline int toUpperCase(int c)
|
||||||
|
{
|
||||||
|
return toupper (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1 +1,37 @@
|
||||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl"
|
/*
|
||||||
|
dtostrf - Emulation for dtostrf function from avr-libc
|
||||||
|
Copyright (c) 2016 Arduino LLC. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is a default implementation for dtostrf function.
|
||||||
|
// This file should be used if the standard lib doesn't provide an
|
||||||
|
// implementation of dtostrf.
|
||||||
|
|
||||||
|
// Create a file called "dtostrf.c" with the following include:
|
||||||
|
// #include "api/deprecated-avr-comp/avr/dtostrf.c.impl"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
|
||||||
|
asm(".global _printf_float");
|
||||||
|
|
||||||
|
char fmt[20];
|
||||||
|
sprintf(fmt, "%%%d.%df", width, prec);
|
||||||
|
sprintf(sout, fmt, val);
|
||||||
|
return sout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,34 @@
|
||||||
|
/*
|
||||||
|
dtostrf - Emulation for dtostrf function from avr-libc
|
||||||
|
Copyright (c) 2015 Arduino LLC. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.h"
|
|
||||||
|
#if !defined(ARDUINO_ARCH_AVR)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *dtostrf(double val, signed char width, unsigned char prec, char *sout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,23 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h"
|
Copyright (c) 2015 Arduino LCC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Empty file.
|
||||||
|
This file is here to allow compatibility with sketches (made for AVR)
|
||||||
|
that includes <AVR/interrupt.h>
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,158 @@
|
||||||
#pragma once
|
/*
|
||||||
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h"
|
pgmspace.h - Definitions for compatibility with AVR pgmspace macros
|
||||||
|
|
||||||
|
Copyright (c) 2015 Arduino LLC
|
||||||
|
|
||||||
|
Based on work of Paul Stoffregen on Teensy 3 (http://pjrc.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PGMSPACE_H_
|
||||||
|
#define __PGMSPACE_H_ 1
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define PROGMEM
|
||||||
|
#define PGM_P const char *
|
||||||
|
#define PSTR(str) (str)
|
||||||
|
|
||||||
|
#define _SFR_BYTE(n) (n)
|
||||||
|
|
||||||
|
typedef void prog_void;
|
||||||
|
typedef char prog_char;
|
||||||
|
typedef unsigned char prog_uchar;
|
||||||
|
typedef int8_t prog_int8_t;
|
||||||
|
typedef uint8_t prog_uint8_t;
|
||||||
|
typedef int16_t prog_int16_t;
|
||||||
|
typedef uint16_t prog_uint16_t;
|
||||||
|
typedef int32_t prog_int32_t;
|
||||||
|
typedef uint32_t prog_uint32_t;
|
||||||
|
typedef int64_t prog_int64_t;
|
||||||
|
typedef uint64_t prog_uint64_t;
|
||||||
|
|
||||||
|
typedef const void* int_farptr_t;
|
||||||
|
typedef const void* uint_farptr_t;
|
||||||
|
|
||||||
|
#define memchr_P(s, c, n) memchr((s), (c), (n))
|
||||||
|
#define memcmp_P(s1, s2, n) memcmp((s1), (s2), (n))
|
||||||
|
#define memccpy_P(dest, src, c, n) memccpy((dest), (src), (c), (n))
|
||||||
|
#define memcpy_P(dest, src, n) memcpy((dest), (src), (n))
|
||||||
|
#define memmem_P(haystack, haystacklen, needle, needlelen) memmem((haystack), (haystacklen), (needle), (needlelen))
|
||||||
|
#define memrchr_P(s, c, n) memrchr((s), (c), (n))
|
||||||
|
#define strcat_P(dest, src) strcat((dest), (src))
|
||||||
|
#define strchr_P(s, c) strchr((s), (c))
|
||||||
|
#define strchrnul_P(s, c) strchrnul((s), (c))
|
||||||
|
#define strcmp_P(a, b) strcmp((a), (b))
|
||||||
|
#define strcpy_P(dest, src) strcpy((dest), (src))
|
||||||
|
#define strcasecmp_P(s1, s2) strcasecmp((s1), (s2))
|
||||||
|
#define strcasestr_P(haystack, needle) strcasestr((haystack), (needle))
|
||||||
|
#define strcspn_P(s, accept) strcspn((s), (accept))
|
||||||
|
#define strlcat_P(s1, s2, n) strlcat((s1), (s2), (n))
|
||||||
|
#define strlcpy_P(s1, s2, n) strlcpy((s1), (s2), (n))
|
||||||
|
#define strlen_P(a) strlen((a))
|
||||||
|
#define strnlen_P(s, n) strnlen((s), (n))
|
||||||
|
#define strncmp_P(s1, s2, n) strncmp((s1), (s2), (n))
|
||||||
|
#define strncasecmp_P(s1, s2, n) strncasecmp((s1), (s2), (n))
|
||||||
|
#define strncat_P(s1, s2, n) strncat((s1), (s2), (n))
|
||||||
|
#define strncpy_P(s1, s2, n) strncpy((s1), (s2), (n))
|
||||||
|
#define strpbrk_P(s, accept) strpbrk((s), (accept))
|
||||||
|
#define strrchr_P(s, c) strrchr((s), (c))
|
||||||
|
#define strsep_P(sp, delim) strsep((sp), (delim))
|
||||||
|
#define strspn_P(s, accept) strspn((s), (accept))
|
||||||
|
#define strstr_P(a, b) strstr((a), (b))
|
||||||
|
#define strtok_P(s, delim) strtok((s), (delim))
|
||||||
|
#define strtok_rP(s, delim, last) strtok((s), (delim), (last))
|
||||||
|
|
||||||
|
#define strlen_PF(a) strlen((a))
|
||||||
|
#define strnlen_PF(src, len) strnlen((src), (len))
|
||||||
|
#define memcpy_PF(dest, src, len) memcpy((dest), (src), (len))
|
||||||
|
#define strcpy_PF(dest, src) strcpy((dest), (src))
|
||||||
|
#define strncpy_PF(dest, src, len) strncpy((dest), (src), (len))
|
||||||
|
#define strcat_PF(dest, src) strcat((dest), (src))
|
||||||
|
#define strlcat_PF(dest, src, len) strlcat((dest), (src), (len))
|
||||||
|
#define strncat_PF(dest, src, len) strncat((dest), (src), (len))
|
||||||
|
#define strcmp_PF(s1, s2) strcmp((s1), (s2))
|
||||||
|
#define strncmp_PF(s1, s2, n) strncmp((s1), (s2), (n))
|
||||||
|
#define strcasecmp_PF(s1, s2) strcasecmp((s1), (s2))
|
||||||
|
#define strncasecmp_PF(s1, s2, n) strncasecmp((s1), (s2), (n))
|
||||||
|
#define strstr_PF(s1, s2) strstr((s1), (s2))
|
||||||
|
#define strlcpy_PF(dest, src, n) strlcpy((dest), (src), (n))
|
||||||
|
#define memcmp_PF(s1, s2, n) memcmp((s1), (s2), (n))
|
||||||
|
|
||||||
|
#define sprintf_P(s, f, ...) sprintf((s), (f), __VA_ARGS__)
|
||||||
|
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
|
||||||
|
#define vsprintf_P(s, f, ...) vsprintf((s), (f), __VA_ARGS__)
|
||||||
|
#define vsnprintf_P(s, f, ...) vsnprintf((s), (f), __VA_ARGS__)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Requires natural aligned addresses
|
||||||
|
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||||
|
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
|
||||||
|
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
|
||||||
|
#define pgm_read_float(addr) (*(const float *)(addr))
|
||||||
|
#define pgm_read_ptr(addr) (*(void *const *)(addr))
|
||||||
|
#else
|
||||||
|
// Supports misaligned addresses
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
static inline unsigned char pgm_read_byte(const void *addr) {
|
||||||
|
return *(const unsigned char *)(addr);
|
||||||
|
}
|
||||||
|
static inline unsigned short pgm_read_word(const void *addr) {
|
||||||
|
const unsigned char *a = (const unsigned char *)addr;
|
||||||
|
return pgm_read_byte(a) | ( pgm_read_byte(a + 1) << 8 );
|
||||||
|
}
|
||||||
|
static inline unsigned long pgm_read_dword(const void *addr) {
|
||||||
|
const unsigned char *a = (const unsigned char *)addr;
|
||||||
|
return pgm_read_byte(a) | ( pgm_read_byte(a + 1) << 8 ) | ( pgm_read_byte(a + 2) << 16 ) | ( pgm_read_byte(a + 3) << 24 );
|
||||||
|
}
|
||||||
|
static inline void *pgm_read_ptr(const void *addr) {
|
||||||
|
return (void*) pgm_read_dword(addr);
|
||||||
|
}
|
||||||
|
static inline float pgm_read_float(const void *addr) {
|
||||||
|
union {
|
||||||
|
void *p;
|
||||||
|
float f;
|
||||||
|
} x;
|
||||||
|
x.p = pgm_read_ptr(addr);
|
||||||
|
return x.f;
|
||||||
|
}
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
|
||||||
|
#define pgm_read_word_near(addr) pgm_read_word(addr)
|
||||||
|
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
|
||||||
|
#define pgm_read_float_near(addr) pgm_read_float(addr)
|
||||||
|
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr)
|
||||||
|
|
||||||
|
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
|
||||||
|
#define pgm_read_word_far(addr) pgm_read_word(addr)
|
||||||
|
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
|
||||||
|
#define pgm_read_float_far(addr) pgm_read_float(addr)
|
||||||
|
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr)
|
||||||
|
|
||||||
|
#define pgm_get_far_address(addr) (&(addr))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2016 Arduino LLC. All right reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../../ArduinoCore-API/api/itoa.h"
|
|
||||||
|
// Standard C functions required in Arduino API
|
||||||
|
// If these functions are not provided by the standard library, the
|
||||||
|
// core should supply an implementation of them.
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern char* itoa(int value, char *string, int radix);
|
||||||
|
extern char* ltoa(long value, char *string, int radix);
|
||||||
|
extern char* utoa(unsigned value, char *string, int radix);
|
||||||
|
extern char* ultoa(unsigned long value, char *string, int radix);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#define ccount_wrap_target 0
|
#define ccount_wrap_target 0
|
||||||
#define ccount_wrap 1
|
#define ccount_wrap 1
|
||||||
#define ccount_pio_version 0
|
|
||||||
|
|
||||||
static const uint16_t ccount_program_instructions[] = {
|
static const uint16_t ccount_program_instructions[] = {
|
||||||
// .wrap_target
|
// .wrap_target
|
||||||
|
|
@ -28,10 +27,6 @@ static const struct pio_program ccount_program = {
|
||||||
.instructions = ccount_program_instructions,
|
.instructions = ccount_program_instructions,
|
||||||
.length = 2,
|
.length = 2,
|
||||||
.origin = -1,
|
.origin = -1,
|
||||||
.pio_version = ccount_pio_version,
|
|
||||||
#if PICO_PIO_VERSION > 0
|
|
||||||
.used_gpio_ranges = 0x0
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
|
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
// Use to create a callback thunk from C to C++
|
|
||||||
// #define CCALLBACKNAME to a unique per-file name and #include this file
|
|
||||||
// To make a CB use a define of the form:
|
|
||||||
/*
|
|
||||||
#define PACKETHANDLERCB(class, cbFcn) \
|
|
||||||
(CCALLBACKNAME<void(uint8_t, uint16_t, uint8_t*, uint16_t), __COUNTER__>::func = std::bind(&class::cbFcn, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), \
|
|
||||||
static_cast<btstack_packet_handler_t>(<CCALLBACKNAMEvoid(uint8_t, uint16_t, uint8_t*, uint16_t), __COUNTER__ - 1>::callback))
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
// Thank you to https://stackoverflow.com/questions/66474621/multiple-non-static-callbacks-of-c-member-functions for the following beautiful hack
|
|
||||||
|
|
||||||
#ifndef CCALLBACKNAME
|
|
||||||
#define CCALLBACKNAME _CCallback
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T, int tag>
|
|
||||||
struct CCALLBACKNAME;
|
|
||||||
|
|
||||||
template <typename Ret, typename... Params, int tag>
|
|
||||||
struct CCALLBACKNAME<Ret(Params...), tag> {
|
|
||||||
template <typename... Args>
|
|
||||||
static Ret callback(Args... args) {
|
|
||||||
return func(args...);
|
|
||||||
}
|
|
||||||
int _tag = tag;
|
|
||||||
static std::function<Ret(Params...)> func;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Ret, typename... Params, int tag>
|
|
||||||
std::function<Ret(Params...)> CCALLBACKNAME<Ret(Params...), tag>::func;
|
|
||||||
|
|
@ -1,206 +0,0 @@
|
||||||
/*
|
|
||||||
CYW43 TCP/Ethernet wrappers
|
|
||||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(PICO_CYW43_SUPPORTED)
|
|
||||||
|
|
||||||
#include <lwip/netif.h>
|
|
||||||
extern "C" {
|
|
||||||
#include <cyw43.h>
|
|
||||||
#include <cyw43_stats.h>
|
|
||||||
}
|
|
||||||
#include <pico/cyw43_arch.h>
|
|
||||||
#include <pico/cyw43_driver.h>
|
|
||||||
#include <pico/lwip_nosys.h>
|
|
||||||
#include <hardware/resets.h>
|
|
||||||
#include <hardware/gpio.h>
|
|
||||||
#include <hardware/adc.h>
|
|
||||||
#include <hardware/clocks.h>
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
// From cyw43_ctrl.c
|
|
||||||
#define WIFI_JOIN_STATE_KIND_MASK (0x000f)
|
|
||||||
#define WIFI_JOIN_STATE_ACTIVE (0x0001)
|
|
||||||
#define WIFI_JOIN_STATE_FAIL (0x0002)
|
|
||||||
#define WIFI_JOIN_STATE_NONET (0x0003)
|
|
||||||
#define WIFI_JOIN_STATE_BADAUTH (0x0004)
|
|
||||||
#define WIFI_JOIN_STATE_AUTH (0x0200)
|
|
||||||
#define WIFI_JOIN_STATE_LINK (0x0400)
|
|
||||||
#define WIFI_JOIN_STATE_KEYED (0x0800)
|
|
||||||
#define WIFI_JOIN_STATE_ALL (0x0e01)
|
|
||||||
|
|
||||||
// The core can't directly call a library, so put in a dummy weak one to be overridden by one in lwip_cyw43 library
|
|
||||||
extern struct netif *__getCYW43Netif() __attribute__((weak));
|
|
||||||
struct netif *__getCYW43Netif() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CB from the cyw43 driver
|
|
||||||
extern "C" void __wrap_cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
|
|
||||||
(void) cb_data;
|
|
||||||
(void) itf;
|
|
||||||
struct netif *netif = __getCYW43Netif();
|
|
||||||
if (netif && (netif->flags & NETIF_FLAG_LINK_UP)) {
|
|
||||||
struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
||||||
if (p != nullptr) {
|
|
||||||
pbuf_take(p, buf, len);
|
|
||||||
if ((netif->input(p, netif) != ERR_OK)) {
|
|
||||||
pbuf_free(p);
|
|
||||||
}
|
|
||||||
CYW43_STAT_INC(PACKET_IN_COUNT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __wrap_cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
|
|
||||||
(void) self;
|
|
||||||
(void) itf;
|
|
||||||
struct netif *netif = __getCYW43Netif();
|
|
||||||
if (netif) {
|
|
||||||
netif_set_link_up(netif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __wrap_cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
|
||||||
(void) self;
|
|
||||||
(void) itf;
|
|
||||||
struct netif *netif = __getCYW43Netif();
|
|
||||||
if (netif) {
|
|
||||||
netif_set_link_down(netif);
|
|
||||||
}
|
|
||||||
self->wifi_join_state &= ~WIFI_JOIN_STATE_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int __wrap_cyw43_tcpip_link_status(cyw43_t *self, int itf) {
|
|
||||||
struct netif *netif = __getCYW43Netif();
|
|
||||||
//if ((CYW43::_netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP))
|
|
||||||
// Fake this since it's only used in the SDK
|
|
||||||
if (netif && ((netif->flags & (NETIF_FLAG_LINK_UP)) == (NETIF_FLAG_LINK_UP))) {
|
|
||||||
return CYW43_LINK_UP;
|
|
||||||
} else {
|
|
||||||
return cyw43_wifi_link_status(self, itf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CBs from the SDK, not needed here as we do TCP later in the game
|
|
||||||
extern "C" void __wrap_cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
|
|
||||||
(void) self;
|
|
||||||
(void) itf;
|
|
||||||
}
|
|
||||||
extern "C" void __wrap_cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
|
|
||||||
(void) self;
|
|
||||||
(void) itf;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIFICC
|
|
||||||
#define WIFICC CYW43_COUNTRY_WORLDWIDE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Taken from https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
|
|
||||||
// also discussion in https://github.com/earlephilhower/arduino-pico/issues/849
|
|
||||||
static bool CheckPicoW() {
|
|
||||||
#ifdef PICO_RP2040
|
|
||||||
adc_init();
|
|
||||||
auto dir = gpio_get_dir(29);
|
|
||||||
auto fnc = gpio_get_function(29);
|
|
||||||
adc_gpio_init(29);
|
|
||||||
adc_select_input(3);
|
|
||||||
auto adc29 = adc_read();
|
|
||||||
gpio_set_function(29, fnc);
|
|
||||||
gpio_set_dir(29, dir);
|
|
||||||
|
|
||||||
dir = gpio_get_dir(25);
|
|
||||||
fnc = gpio_get_function(25);
|
|
||||||
gpio_init(25);
|
|
||||||
gpio_set_dir(25, GPIO_IN);
|
|
||||||
auto gp25 = gpio_get(25);
|
|
||||||
gpio_set_function(25, fnc);
|
|
||||||
gpio_set_dir(25, dir);
|
|
||||||
|
|
||||||
if (gp25) {
|
|
||||||
return true; // Can't tell, so assume yes
|
|
||||||
} else if (adc29 < 200) {
|
|
||||||
return true; // PicoW
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool __isPicoW = true;
|
|
||||||
|
|
||||||
extern "C" void init_cyw43_wifi() {
|
|
||||||
__isPicoW = CheckPicoW();
|
|
||||||
if (__isPicoW) {
|
|
||||||
// Fix for overclocked CPU: SPI communication breaks down with default "div by 2" speed
|
|
||||||
// So, divide clock by 4 for anything including and above 250MHz CPU frequency.
|
|
||||||
if (clock_get_hz(clk_sys) >= 250000000) {
|
|
||||||
cyw43_set_pio_clock_divisor(4, 0); // div by 4.0
|
|
||||||
}
|
|
||||||
cyw43_arch_init_with_country(WIFICC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __lockBluetooth() {
|
|
||||||
async_context_acquire_lock_blocking(cyw43_arch_async_context());
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __unlockBluetooth() {
|
|
||||||
async_context_release_lock(cyw43_arch_async_context());
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __pinMode(pin_size_t pin, PinMode mode);
|
|
||||||
extern "C" void __digitalWrite(pin_size_t pin, PinStatus val);
|
|
||||||
extern "C" PinStatus __digitalRead(pin_size_t pin);
|
|
||||||
|
|
||||||
extern "C" void cyw43_pinMode(pin_size_t pin, PinMode mode) {
|
|
||||||
if (!__isPicoW && (pin == PIN_LED)) {
|
|
||||||
pin = 25; // Silently swap in the Pico's LED
|
|
||||||
}
|
|
||||||
if (pin < 64) {
|
|
||||||
__pinMode(pin, mode);
|
|
||||||
} else {
|
|
||||||
// TBD - There is no GPIO direction control in the driver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void cyw43_digitalWrite(pin_size_t pin, PinStatus val) {
|
|
||||||
if (!__isPicoW && (pin == PIN_LED)) {
|
|
||||||
pin = 25; // Silently swap in the Pico's LED
|
|
||||||
}
|
|
||||||
if (pin < 64) {
|
|
||||||
__digitalWrite(pin, val);
|
|
||||||
} else {
|
|
||||||
cyw43_arch_gpio_put(pin - 64, val == HIGH ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" PinStatus cyw43_digitalRead(pin_size_t pin) {
|
|
||||||
if (!__isPicoW && (pin == PIN_LED)) {
|
|
||||||
pin = 25; // Silently swap in the Pico's LED
|
|
||||||
}
|
|
||||||
if (pin < 64) {
|
|
||||||
return __digitalRead(pin);
|
|
||||||
} else {
|
|
||||||
return cyw43_arch_gpio_get(pin - 64) ? HIGH : LOW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
CYW43 TCP/Ethernet wrappers
|
|
||||||
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <pico/cyw43_driver.h>
|
|
||||||
|
|
||||||
extern bool __isPicoW;
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void init_cyw43_wifi();
|
|
||||||
void __lockBluetooth();
|
|
||||||
void __unlockBluetooth();
|
|
||||||
void cyw43_pinMode(pin_size_t pin, PinMode mode);
|
|
||||||
void cyw43_digitalWrite(pin_size_t pin, PinStatus val);
|
|
||||||
PinStatus cyw43_digitalRead(pin_size_t pin);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue