Compare commits
@@ -6,35 +6,23 @@ name: Arduino-Pico CI
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
# Me no spell so good
|
||||
code-spell:
|
||||
name: Check spelling
|
||||
# Consistent style, spelling
|
||||
astyle:
|
||||
name: Spelling, Style, Boards, Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
submodules: false
|
||||
- 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,./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
|
||||
ignore_words_list: ser,dout
|
||||
|
||||
# Consistent style
|
||||
astyle:
|
||||
name: Style, Boards, Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: false
|
||||
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
|
||||
ignore_words_list: ser,dout,shiftIn,acount
|
||||
- name: Get submodules for following tests
|
||||
run: git submodule update --init
|
||||
- name: Check package references
|
||||
run: |
|
||||
./tests/ci/pkgrefs_test.sh
|
||||
@@ -59,15 +47,15 @@ jobs:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -82,20 +70,51 @@ jobs:
|
||||
cd ..
|
||||
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 TinyUSB examples, requires custom build command line
|
||||
build-tinyusb:
|
||||
name: Build TinyUSB Examples
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -113,15 +132,15 @@ jobs:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Windows toolchain
|
||||
id: cache-windows
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -144,17 +163,20 @@ jobs:
|
||||
# Single build under macOS to ensure the Mac toolchain is good.
|
||||
build-mac:
|
||||
name: Mac
|
||||
runs-on: macOS-12
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-12, macOS-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Mac toolchain
|
||||
id: cache-mac
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -165,17 +187,23 @@ jobs:
|
||||
mod: 500
|
||||
rem: 1
|
||||
run: |
|
||||
brew update
|
||||
brew install bash
|
||||
/usr/bin/env bash --version
|
||||
uname -a
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
/usr/bin/env 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@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Initialize needed submodules
|
||||
@@ -186,19 +214,19 @@ jobs:
|
||||
git submodule update --init
|
||||
cd ../..
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
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@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
@@ -207,8 +235,9 @@ jobs:
|
||||
pip install --upgrade platformio
|
||||
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 --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
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 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
|
||||
@@ -219,3 +248,55 @@ jobs:
|
||||
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
|
||||
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
|
||||
|
||||
@@ -9,31 +9,30 @@ jobs:
|
||||
name: Update master JSON file
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
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@v3
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
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
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
BUILD_TYPE: package
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
@@ -43,5 +42,5 @@ jobs:
|
||||
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
|
||||
# Upload to Platform.IO
|
||||
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
pio package publish rp2040-$TAG.zip --non-interactive
|
||||
# curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
# pio package publish rp2040-$TAG.zip --non-interactive
|
||||
|
||||
@@ -15,16 +15,15 @@ jobs:
|
||||
name: Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build package JSON
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
BUILD_TYPE: package
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
|
||||
+12
@@ -37,3 +37,15 @@
|
||||
[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
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# 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
Submodule ArduinoCore-API updated: e37df85425...ece6e68f29
@@ -2,9 +2,9 @@
|
||||
[](https://github.com/earlephilhower/arduino-pico/releases)
|
||||
[](https://gitter.im/arduino-pico/community)
|
||||
|
||||
Raspberry Pi Pico Arduino core, for all RP2040 boards
|
||||
Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
|
||||
|
||||
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.
|
||||
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 12.3/Newlib 4.0 toolchain.
|
||||
|
||||
# Documentation
|
||||
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
||||
@@ -15,42 +15,78 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
# Supported Boards
|
||||
* Raspberry Pi Pico
|
||||
* Raspberry Pi Pico W
|
||||
* Raspberry Pi Pico 2
|
||||
* 0xCB Helios
|
||||
* Adafruit Feather RP2040
|
||||
* Adafruit Feather RP2040 SCORPIO
|
||||
* Adafruit ItsyBitsy RP2040
|
||||
* Adafruit KB2040
|
||||
* Adafruit Macropad RP2040
|
||||
* Adafruit Metro RP2040
|
||||
* Adafruit QTPy RP2040
|
||||
* Adafruit STEMMA Friend RP2040
|
||||
* Adafruit Trinkey RP2040 QT
|
||||
* Amken Bunny
|
||||
* Amken Revelop
|
||||
* Amken Revelop Plus
|
||||
* Amken Revelop eS
|
||||
* 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 Nano RP2040
|
||||
* DatanoiseTV PicoADK+
|
||||
* Cytron Maker Uno RP2040
|
||||
* Cytron Motion 2350 Pro
|
||||
* Datanoise PicoADK v1
|
||||
* Datanoise PicoADK v2 (RP2350)
|
||||
* Degz Suibo RP2040
|
||||
* DeRuiLab FlyBoard2040 Core
|
||||
* DFRobot Beetle RP2040
|
||||
* ElectronicCats Hunter Cat NFC
|
||||
* EVN Alpha
|
||||
* ExtremeElectronics RC2040
|
||||
* GroundStudio Marble Pico
|
||||
* Invector Labs Challenger RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||
* Invector Labs Challenger RP2040 WiFi6/BLE
|
||||
* Invector Labs Challenger NB RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 LTE
|
||||
* 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
|
||||
* Melopero Cookie RP2040
|
||||
* Melopero Shake RP2040
|
||||
* METE HOCA Akana R1
|
||||
* Neko Systems BL2040 Mini
|
||||
* Olimex RP2040-Pico30
|
||||
* Newsan Archi
|
||||
* nullbits Bit-C PRO
|
||||
* Pimoroni PGA2040
|
||||
* Pimoroni Pico Plus 2
|
||||
* Pimoroni Plasma2040
|
||||
* Pimoroni Tiny2040
|
||||
* Pimoroni Tiny2350
|
||||
* Pintronix PinMax
|
||||
* RAKwireless RAK11300
|
||||
* Redscorp RP2040-Eins
|
||||
* Redscorp RP2040-ProMini
|
||||
* Sea-Picro
|
||||
* Seeed Indicator RP2040
|
||||
* Seeed XIAO RP2040
|
||||
* Silicognition RP2040-Shim
|
||||
* Solder Party RP2040 Stamp
|
||||
* Solder Party RP2350 Stamp
|
||||
* Solder Party RP2350 Stamp XL
|
||||
* SparkFun MicroMod RP2040
|
||||
* SparkFun ProMicro RP2040
|
||||
* SparkFun ProMicro RP2350
|
||||
* SparkFun Thing Plus RP2040
|
||||
* uPesy RP2040 DevKit
|
||||
* VCC-GND YD-RP2040
|
||||
@@ -60,10 +96,44 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
* Waveshare RP2040 Plus
|
||||
* Waveshare RP2040 LCD 0.96
|
||||
* Waveshare RP2040 LCD 1.28
|
||||
* Waveshare RP2040 Matrix
|
||||
* Waveshare RP2040 PiZero
|
||||
* WIZnet W5100S-EVB-Pico
|
||||
* WIZnet W5500-EVB-Pico
|
||||
* WIZnet WizFi360-EVB-Pico
|
||||
* Generic (configurable flash, I/O pins)
|
||||
* Generic RP2040 (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)
|
||||
|
||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||
* Servos
|
||||
* Tones
|
||||
* I2S Input
|
||||
* I2S Output
|
||||
* Software UARTs (Serial ports)
|
||||
|
||||
|
||||
# Installing via Arduino Boards Manager
|
||||
## Windows-specific Notes
|
||||
@@ -128,11 +198,6 @@ cd ../tools
|
||||
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
|
||||
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.
|
||||
@@ -153,83 +218,30 @@ To install, follow the directions in
|
||||
* 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
|
||||
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
||||
* https://arduino-pico.readthedocs.io/en/latest/fs.html
|
||||
|
||||
# Uploading Sketches with Picoprobe
|
||||
# Uploading Sketches with Picoprobe/Debugprobe
|
||||
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.
|
||||
|
||||
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
||||
````
|
||||
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}=="0004", MODE="660", GROUP-"plugdev"' | 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 trigger -w -s usb
|
||||
````
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
# Uploading Sketches with pico-debug
|
||||
[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)
|
||||
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
|
||||
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
|
||||
* WiFi (Pico W)
|
||||
* 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
|
||||
* USB drive mode for data loggers (SingleFileDrive)
|
||||
* 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
|
||||
* Home Assistant Pico W integration starter project using Arduino - https://github.com/daniloc/PicoW_HomeAssistant_Starter
|
||||
* Tutorials for the Raspberry Pi Pico / uPesy RP2040 DevKit board
|
||||
- English version: https://www.upesy.com/blogs/tutorials/best-tutorials-for-rpi-pi-pico-with-arduino-code
|
||||
- French version: https://www.upesy.fr/blogs/tutorials/best-tutorials-for-rpi-pi-pico-with-arduino-code
|
||||
|
||||
# Contributing
|
||||
If you want to contribute or have bugfixes, drop me a note at <earlephilhower@yahoo.com> or open an issue/PR here.
|
||||
# Debugging with Picoprobe, 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. 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.
|
||||
|
||||
# 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.
|
||||
@@ -240,14 +252,17 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
|
||||
* [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.
|
||||
* 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
|
||||
|
||||
* 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
|
||||
earlephilhower@yahoo.com
|
||||
|
||||
+16293
-1789
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
// 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
|
||||
@@ -0,0 +1,25 @@
|
||||
// Padded and checksummed version of: boot2_generic_03h.2.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
.byte 0x00, 0xb5, 0x05, 0x4b, 0x05, 0x48, 0xd8, 0x60, 0x4f, 0xf0, 0x03, 0x00, 0x58, 0x61, 0x4f, 0xf4
|
||||
.byte 0x80, 0x50, 0x18, 0x61, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x40, 0x02, 0x01, 0x00, 0x40
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
@@ -0,0 +1,25 @@
|
||||
// Padded and checksummed version of: boot2_generic_03h.4.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
.byte 0x00, 0xb5, 0x05, 0x4b, 0x05, 0x48, 0xd8, 0x60, 0x4f, 0xf0, 0x03, 0x00, 0x58, 0x61, 0x4f, 0xf4
|
||||
.byte 0x80, 0x50, 0x18, 0x61, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x40, 0x04, 0x01, 0x00, 0x40
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
@@ -0,0 +1,25 @@
|
||||
// Padded and checksummed version of: boot2_w25q080.2.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
.byte 0x00, 0xb5, 0x24, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x13, 0xf5, 0x40, 0x53, 0x02, 0x20, 0x98, 0x60
|
||||
.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x13, 0xf5, 0x0d, 0x23, 0x1f, 0x49, 0x19, 0x60, 0x18, 0x68
|
||||
.byte 0x10, 0xf0, 0x02, 0x0f, 0xfb, 0xd1, 0x35, 0x20, 0x00, 0xf0, 0x2c, 0xf8, 0x02, 0x28, 0x14, 0xd0
|
||||
.byte 0x06, 0x20, 0x58, 0x60, 0x00, 0xf0, 0x22, 0xf8, 0x98, 0x68, 0x01, 0x20, 0x58, 0x60, 0x00, 0x20
|
||||
.byte 0x58, 0x60, 0x02, 0x20, 0x58, 0x60, 0x00, 0xf0, 0x19, 0xf8, 0x98, 0x68, 0x98, 0x68, 0x98, 0x68
|
||||
.byte 0x05, 0x20, 0x00, 0xf0, 0x17, 0xf8, 0x40, 0x08, 0xfa, 0xd2, 0x31, 0xf0, 0x01, 0x01, 0x19, 0x60
|
||||
.byte 0x0e, 0x48, 0xd8, 0x60, 0x4a, 0xf2, 0xeb, 0x00, 0x58, 0x61, 0x0d, 0x48, 0x18, 0x61, 0x4f, 0xf0
|
||||
.byte 0xa0, 0x51, 0x09, 0x78, 0x20, 0xf4, 0x80, 0x50, 0x18, 0x61, 0x00, 0xbd, 0x18, 0x68, 0x80, 0x08
|
||||
.byte 0xfc, 0xd2, 0x70, 0x47, 0x00, 0xb5, 0x58, 0x60, 0x58, 0x60, 0xff, 0xf7, 0xf7, 0xff, 0x98, 0x68
|
||||
.byte 0x98, 0x68, 0x00, 0xbd, 0x00, 0x00, 0x04, 0x40, 0x41, 0x00, 0x80, 0x07, 0x02, 0x02, 0x00, 0x40
|
||||
.byte 0xa8, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
@@ -0,0 +1,25 @@
|
||||
// Padded and checksummed version of: boot2_w25q080.4.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
.byte 0x00, 0xb5, 0x24, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x13, 0xf5, 0x40, 0x53, 0x02, 0x20, 0x98, 0x60
|
||||
.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x13, 0xf5, 0x0d, 0x23, 0x1f, 0x49, 0x19, 0x60, 0x18, 0x68
|
||||
.byte 0x10, 0xf0, 0x02, 0x0f, 0xfb, 0xd1, 0x35, 0x20, 0x00, 0xf0, 0x2c, 0xf8, 0x02, 0x28, 0x14, 0xd0
|
||||
.byte 0x06, 0x20, 0x58, 0x60, 0x00, 0xf0, 0x22, 0xf8, 0x98, 0x68, 0x01, 0x20, 0x58, 0x60, 0x00, 0x20
|
||||
.byte 0x58, 0x60, 0x02, 0x20, 0x58, 0x60, 0x00, 0xf0, 0x19, 0xf8, 0x98, 0x68, 0x98, 0x68, 0x98, 0x68
|
||||
.byte 0x05, 0x20, 0x00, 0xf0, 0x17, 0xf8, 0x40, 0x08, 0xfa, 0xd2, 0x31, 0xf0, 0x01, 0x01, 0x19, 0x60
|
||||
.byte 0x0e, 0x48, 0xd8, 0x60, 0x4a, 0xf2, 0xeb, 0x00, 0x58, 0x61, 0x0d, 0x48, 0x18, 0x61, 0x4f, 0xf0
|
||||
.byte 0xa0, 0x51, 0x09, 0x78, 0x20, 0xf4, 0x80, 0x50, 0x18, 0x61, 0x00, 0xbd, 0x18, 0x68, 0x80, 0x08
|
||||
.byte 0xfc, 0xd2, 0x70, 0x47, 0x00, 0xb5, 0x58, 0x60, 0x58, 0x60, 0xff, 0xf7, 0xf7, 0xff, 0x98, 0x68
|
||||
.byte 0x98, 0x68, 0x00, 0xbd, 0x00, 0x00, 0x04, 0x40, 0x41, 0x00, 0x80, 0x07, 0x04, 0x02, 0x00, 0x40
|
||||
.byte 0xa8, 0x92, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
+36
-7
@@ -28,9 +28,8 @@
|
||||
#include "api/ArduinoAPI.h"
|
||||
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
||||
#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 <RP2040.h> // CMSIS
|
||||
|
||||
// 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()
|
||||
@@ -59,15 +58,24 @@ extern "C" {
|
||||
void interrupts();
|
||||
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
|
||||
#define digitalPinToPort(pin) (0)
|
||||
#define digitalPinToBitMask(pin) (1UL << (pin))
|
||||
#define digitalPinToTimer(pin) (0)
|
||||
#define digitalPinToInterrupt(pin) (pin)
|
||||
#define NOT_AN_INTERRUPT (-1)
|
||||
#define portOutputRegister(port) ((volatile uint32_t*) sio_hw->gpio_out)
|
||||
#define portInputRegister(port) ((volatile uint32_t*) sio_hw->gpio_in)
|
||||
#define portModeRegister(port) ((volatile uint32_t*) sio_hw->gpio_oe)
|
||||
#define portOutputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_out))
|
||||
#define portInputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_in))
|
||||
#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()
|
||||
@@ -125,7 +133,28 @@ extern const String emptyString;
|
||||
// Template which will evaluate at *compile time* to a single 32b number
|
||||
// with the specified bits set.
|
||||
template <size_t N>
|
||||
constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
|
||||
constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||
return i < N ? (1LL << a[i]) | __bitset(a, i + 1) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Warn users trying to use Pico SDK's STDIO implementation
|
||||
#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
|
||||
#ifdef PICO_RP2350B
|
||||
#define __GPIOCNT 48
|
||||
#define __FIRSTANALOGGPIO 40
|
||||
#else
|
||||
#define __GPIOCNT 30
|
||||
#define __FIRSTANALOGGPIO 26
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <hardware/structs/ioqspi.h>
|
||||
#include <hardware/structs/sio.h>
|
||||
|
||||
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
||||
//
|
||||
@@ -26,7 +26,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
|
||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||
// are about to temporarily disable flash access!
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
|
||||
// Set chip select to Hi-Z
|
||||
@@ -39,7 +41,12 @@ 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.
|
||||
// Note the button pulls the pin *low* when pressed.
|
||||
bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
||||
#if PICO_RP2040
|
||||
#define CS_BIT (1u << 1)
|
||||
#else
|
||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||
#endif
|
||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||
|
||||
// Need to restore the state of chip select, else we are going to have a
|
||||
// bad time when we return to code in flash!
|
||||
@@ -48,7 +55,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
|
||||
return button_state;
|
||||
}
|
||||
|
||||
@@ -28,14 +28,18 @@ 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 (_option & FromISR) {
|
||||
__freertos_mutex_take_from_isr(m);
|
||||
} else {
|
||||
if (!__freertos_mutex_try_take(m)) {
|
||||
|
||||
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;
|
||||
@@ -56,8 +60,8 @@ CoreMutex::~CoreMutex() {
|
||||
if (_acquired) {
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_give_from_isr(m);
|
||||
if (__freertos_check_if_in_isr()) {
|
||||
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
|
||||
} else {
|
||||
__freertos_mutex_give(m);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include "_freertos.h"
|
||||
|
||||
enum {
|
||||
DebugEnable = 1,
|
||||
FromISR = 1 << 1,
|
||||
DebugEnable = 1
|
||||
};
|
||||
|
||||
class CoreMutex {
|
||||
@@ -44,4 +43,5 @@ private:
|
||||
mutex_t *_mutex;
|
||||
bool _acquired;
|
||||
uint8_t _option;
|
||||
BaseType_t _pxHigherPriorityTaskWoken;
|
||||
};
|
||||
|
||||
+26
-7
@@ -225,6 +225,21 @@ void File::setTimeCallback(time_t (*cb)(void)) {
|
||||
_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) {
|
||||
if (!_impl) {
|
||||
return File();
|
||||
@@ -366,13 +381,6 @@ bool FS::info(FSInfo& 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) {
|
||||
return open(path.c_str(), mode);
|
||||
}
|
||||
@@ -462,6 +470,17 @@ bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||
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() {
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
|
||||
+14
-13
@@ -48,6 +48,14 @@ enum SeekMode {
|
||||
SeekEnd = 2
|
||||
};
|
||||
|
||||
struct FSStat {
|
||||
size_t size;
|
||||
size_t blocksize;
|
||||
time_t ctime;
|
||||
time_t atime;
|
||||
bool isDir;
|
||||
};
|
||||
|
||||
class File : public Stream {
|
||||
public:
|
||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
|
||||
@@ -119,6 +127,8 @@ public:
|
||||
time_t getCreationTime();
|
||||
void setTimeCallback(time_t (*cb)(void));
|
||||
|
||||
bool stat(FSStat *st);
|
||||
|
||||
protected:
|
||||
FileImplPtr _p;
|
||||
time_t (*_timeCallback)(void) = nullptr;
|
||||
@@ -152,18 +162,8 @@ protected:
|
||||
time_t (*_timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
// Backwards compatible, <4GB filesystem usage
|
||||
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 {
|
||||
struct FSInfo {
|
||||
uint64_t totalBytes;
|
||||
uint64_t usedBytes;
|
||||
size_t blockSize;
|
||||
@@ -172,7 +172,6 @@ struct FSInfo64 {
|
||||
size_t maxPathLength;
|
||||
};
|
||||
|
||||
|
||||
class FSConfig {
|
||||
public:
|
||||
static constexpr uint32_t FSId = 0x00000000;
|
||||
@@ -201,7 +200,6 @@ public:
|
||||
|
||||
bool format();
|
||||
bool info(FSInfo& info);
|
||||
bool info64(FSInfo64& info);
|
||||
|
||||
File open(const char* path, const char* mode);
|
||||
File open(const String& path, const char* mode);
|
||||
@@ -224,6 +222,9 @@ public:
|
||||
bool rmdir(const char* 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
|
||||
bool gc();
|
||||
bool check();
|
||||
|
||||
@@ -119,7 +119,6 @@ public:
|
||||
virtual void end() = 0;
|
||||
virtual bool format() = 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 bool exists(const char* path) = 0;
|
||||
virtual DirImplPtr openDir(const char* path) = 0;
|
||||
@@ -127,6 +126,7 @@ public:
|
||||
virtual bool remove(const char* path) = 0;
|
||||
virtual bool mkdir(const char* path) = 0;
|
||||
virtual bool rmdir(const char* path) = 0;
|
||||
virtual bool stat(const char *path, FSStat *st) = 0;
|
||||
virtual bool gc() {
|
||||
return true; // May not be implemented in all file systems.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
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];
|
||||
static bool __pioHighGPIO[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 };
|
||||
|
||||
#if 0
|
||||
uint usm;
|
||||
uint uoff;
|
||||
auto ret = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, pio, &usm, &uoff, start, cnt, true);
|
||||
*sm = usm;
|
||||
*offset = uoff;
|
||||
DEBUGV("clain %d\n", ret);
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
bool needsHigh = (start + cnt) >= 32;
|
||||
DEBUGV("PIOProgram %p: Searching for high=%d, pins %d-%d\n", _pgm, needsHigh ? 1 : 0, 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()) && (__pioHighGPIO[o] == needsHigh)) {
|
||||
int idx = pio_claim_unused_sm(pi[o], false);
|
||||
if (idx >= 0) {
|
||||
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, 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] && (__pioHighGPIO[o] == needsHigh)) {
|
||||
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(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, 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;
|
||||
__pioHighGPIO[o] = needsHigh;
|
||||
DEBUGV("PIOProgram %p: Allocating new PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, 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;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
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;
|
||||
};
|
||||
+107
-66
@@ -27,9 +27,12 @@
|
||||
#include <hardware/structs/rosc.h>
|
||||
#include <hardware/structs/systick.h>
|
||||
#include <pico/multicore.h>
|
||||
#include <hardware/dma.h>
|
||||
#include <pico/rand.h>
|
||||
#include <pico/util/queue.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include "CoreMutex.h"
|
||||
#include "PIOProgram.h"
|
||||
#include "ccount.pio.h"
|
||||
#include <malloc.h>
|
||||
|
||||
@@ -57,8 +60,13 @@ public:
|
||||
void registerCore() {
|
||||
if (!__isFreeRTOS) {
|
||||
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_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
||||
#endif
|
||||
}
|
||||
// FreeRTOS port.c will handle the IRQ hooking
|
||||
}
|
||||
@@ -91,15 +99,14 @@ public:
|
||||
if (!_multicore) {
|
||||
return;
|
||||
}
|
||||
__holdUpPendSV = 1;
|
||||
if (__isFreeRTOS) {
|
||||
vTaskPreemptionDisable(nullptr);
|
||||
vTaskSuspendAll();
|
||||
__freertos_idle_other_core();
|
||||
} else {
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
|
||||
void resumeOtherCore() {
|
||||
@@ -109,10 +116,8 @@ public:
|
||||
mutex_exit(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
if (__isFreeRTOS) {
|
||||
xTaskResumeAll();
|
||||
vTaskPreemptionEnable(nullptr);
|
||||
__freertos_resume_other_core();
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
|
||||
// Other core will exit busy-loop and return to operation
|
||||
// once __otherCoreIdled == false.
|
||||
@@ -156,64 +161,12 @@ private:
|
||||
class RP2040;
|
||||
extern RP2040 rp2040;
|
||||
extern "C" void main1();
|
||||
class PIOProgram;
|
||||
|
||||
extern "C" char __StackLimit;
|
||||
extern "C" char __bss_end__;
|
||||
|
||||
// Wrapper class for PIO programs, abstracting common operations out
|
||||
// TODO - Add unload/destructor
|
||||
class PIOProgram {
|
||||
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;
|
||||
};
|
||||
extern "C" void setup1() __attribute__((weak));
|
||||
extern "C" void loop1() __attribute__((weak));
|
||||
extern "C" bool core1_separate_stack;
|
||||
extern "C" uint32_t* core1_separate_stack_address;
|
||||
|
||||
class RP2040 {
|
||||
public:
|
||||
@@ -295,6 +248,56 @@ public:
|
||||
return &__StackLimit - &__bss_end__;
|
||||
}
|
||||
|
||||
inline int getFreePSRAMHeap() {
|
||||
return getTotalPSRAMHeap() - getUsedPSRAMHeap();
|
||||
}
|
||||
|
||||
inline int getUsedPSRAMHeap() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_total_used();
|
||||
return __psram_total_used();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getTotalPSRAMHeap() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_total_space();
|
||||
return __psram_total_space();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32_t getStackPointer() {
|
||||
uint32_t *sp;
|
||||
asm volatile("mov %0, sp" : "=r"(sp));
|
||||
return (uint32_t)sp;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
inline size_t getPSRAMSize() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_size;
|
||||
return __psram_size;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void idleOtherCore() {
|
||||
fifo.idleOtherCore();
|
||||
}
|
||||
@@ -320,6 +323,13 @@ public:
|
||||
reboot();
|
||||
}
|
||||
|
||||
inline void rebootToBootloader() {
|
||||
reset_usb_boot(0, 0);
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
static void enableDoubleResetBootloader();
|
||||
|
||||
void wdt_begin(uint32_t delay_ms) {
|
||||
@@ -338,6 +348,36 @@ public:
|
||||
return id;
|
||||
}
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
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
|
||||
|
||||
// Multicore comms FIFO
|
||||
_MFIFO fifo;
|
||||
|
||||
@@ -363,4 +403,5 @@ private:
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
PIOProgram *_ccountPgm;
|
||||
int memcpyDMAChannel = -1;
|
||||
};
|
||||
|
||||
+79
-15
@@ -25,18 +25,17 @@
|
||||
#include "CoreMutex.h"
|
||||
#include "RP2040USB.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "class/midi/midi.h"
|
||||
#include "pico/time.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "pico/usb_reset_interface.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "sdkoverride/tusb_absmouse.h"
|
||||
#include <tusb.h>
|
||||
#include <class/hid/hid_device.h>
|
||||
#include <class/audio/audio.h>
|
||||
#include <pico/time.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <pico/usb_reset_interface.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
|
||||
@@ -84,6 +83,8 @@ static int __usb_task_irq;
|
||||
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) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
@@ -158,7 +159,7 @@ void __SetupDescHIDReport() {
|
||||
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
|
||||
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(1)) };
|
||||
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;
|
||||
|
||||
@@ -228,7 +229,7 @@ void __SetupDescHIDReport() {
|
||||
reportid++;
|
||||
offset += sizeof(desc_hid_report_absmouse);
|
||||
}
|
||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(reportid)) };
|
||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(reportid)) };
|
||||
memcpy(__hid_report + offset, desc_local, sizeof(desc_local));
|
||||
}
|
||||
}
|
||||
@@ -264,7 +265,7 @@ void __SetupUSBDescriptor() {
|
||||
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
||||
uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
||||
// 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, 10)
|
||||
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)
|
||||
};
|
||||
|
||||
uint8_t msd_itf = interface_count - 1;
|
||||
@@ -395,6 +396,18 @@ void __USBStart() {
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
@@ -550,6 +563,57 @@ 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
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
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
|
||||
extern void __USBInstallSerial() __attribute__((weak));
|
||||
@@ -45,3 +45,6 @@ int __USBGetJoystickReportID();
|
||||
|
||||
// Called by main() to init the USB HW/SW.
|
||||
void __USBStart();
|
||||
|
||||
// Helper class for HID report sending with wait and timeout
|
||||
bool __USBHIDReady();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 3
|
||||
#define ARDUINO_PICO_MINOR 2
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "3.2.0"
|
||||
#define ARDUINO_PICO_MAJOR 4
|
||||
#define ARDUINO_PICO_MINOR 0
|
||||
#define ARDUINO_PICO_REVISION 3
|
||||
#define ARDUINO_PICO_VERSION_STR "4.0.3"
|
||||
|
||||
@@ -33,6 +33,7 @@ static std::map<int, PIOProgram*> _rxMap;
|
||||
// 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) {
|
||||
pio_program_t *p = new pio_program_t;
|
||||
memcpy(p, pg, sizeof(*p));
|
||||
p->length = pg->length;
|
||||
p->origin = pg->origin;
|
||||
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
|
||||
@@ -78,9 +79,9 @@ static int _parity(int bits, int data) {
|
||||
|
||||
// We need to cache generated SerialPIOs so we can add data to them from
|
||||
// the shared handler
|
||||
static SerialPIO *_pioSP[2][4];
|
||||
static SerialPIO *_pioSP[3][4];
|
||||
static void __not_in_flash_func(_fifoIRQ)() {
|
||||
for (int p = 0; p < 2; p++) {
|
||||
for (int p = 0; p < 3; p++) {
|
||||
for (int sm = 0; sm < 4; sm++) {
|
||||
SerialPIO *s = _pioSP[p][sm];
|
||||
if (s) {
|
||||
@@ -138,6 +139,8 @@ SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize) {
|
||||
_fifoSize = fifoSize + 1; // Always one unused entry
|
||||
_queue = new uint8_t[_fifoSize];
|
||||
mutex_init(&_mutex);
|
||||
_invertTX = false;
|
||||
_invertRX = false;
|
||||
}
|
||||
|
||||
SerialPIO::~SerialPIO() {
|
||||
@@ -145,6 +148,21 @@ SerialPIO::~SerialPIO() {
|
||||
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) {
|
||||
_overflow = false;
|
||||
_baud = baud;
|
||||
@@ -191,7 +209,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
||||
_txPgm = _getTxProgram(_txBits);
|
||||
int off;
|
||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
|
||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off, _tx, 1)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
||||
// ERROR, no free slots
|
||||
return;
|
||||
@@ -209,6 +227,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
pio_sm_exec(_txPIO, _txSM, pio_encode_mov(pio_isr, pio_osr));
|
||||
|
||||
// Start running!
|
||||
gpio_set_outover(_tx, _invertTX);
|
||||
pio_sm_set_enabled(_txPIO, _txSM, true);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
@@ -218,7 +237,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
|
||||
_rxPgm = _getRxProgram(_rxBits);
|
||||
int off;
|
||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
|
||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
||||
return;
|
||||
}
|
||||
@@ -243,10 +262,11 @@ 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 3: pio_set_irq0_source_enabled(_rxPIO, pis_sm3_rx_fifo_not_empty, true); break;
|
||||
}
|
||||
auto irqno = pio_get_index(_rxPIO) == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||
auto irqno = pio_irq_0(_rxPIO);
|
||||
irq_set_exclusive_handler(irqno, _fifoIRQ);
|
||||
irq_set_enabled(irqno, true);
|
||||
|
||||
gpio_set_inover(_rx, _invertRX);
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, true);
|
||||
}
|
||||
|
||||
@@ -260,6 +280,7 @@ void SerialPIO::end() {
|
||||
if (_tx != NOPIN) {
|
||||
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||
pio_sm_unclaim(_txPIO, _txSM);
|
||||
gpio_set_outover(_tx, 0);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||
@@ -272,9 +293,10 @@ void SerialPIO::end() {
|
||||
used = used || !!_pioSP[pioNum][i];
|
||||
}
|
||||
if (!used) {
|
||||
auto irqno = pioNum == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||
auto irqno = pio_irq_0(_rxPIO);
|
||||
irq_set_enabled(irqno, false);
|
||||
}
|
||||
gpio_set_inover(_rx, 0);
|
||||
}
|
||||
_running = false;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,23 @@ public:
|
||||
void begin(unsigned long baud, uint16_t config) 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 read() override;
|
||||
virtual int available() override;
|
||||
@@ -51,7 +68,7 @@ public:
|
||||
using Print::write;
|
||||
operator bool() override;
|
||||
|
||||
// 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 IRQ callback can access it
|
||||
void _handleIRQ();
|
||||
|
||||
protected:
|
||||
@@ -63,6 +80,8 @@ protected:
|
||||
int _stop;
|
||||
bool _overflow;
|
||||
mutex_t _mutex;
|
||||
bool _invertTX;
|
||||
bool _invertRX;
|
||||
|
||||
PIOProgram *_txPgm;
|
||||
PIO _txPIO;
|
||||
|
||||
@@ -32,14 +32,24 @@ extern void serialEvent1() __attribute__((weak));
|
||||
extern void serialEvent2() __attribute__((weak));
|
||||
|
||||
bool SerialUART::setRX(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29, 33, 45}) /* UART0 */,
|
||||
__bitset({5, 9, 21, 25, 37, 41}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||
__bitset({5, 9, 21, 25}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
#endif
|
||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||
_rx = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rx == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.RX while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -49,14 +59,24 @@ bool SerialUART::setRX(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setTX(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28, 32, 44}) /* UART0 */,
|
||||
__bitset({4, 8, 20, 24, 36, 40}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||
__bitset({4, 8, 20, 24}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
#endif
|
||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||
_tx = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_tx == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.TX while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -66,14 +86,24 @@ bool SerialUART::setTX(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setRTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
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 */
|
||||
};
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
#endif
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_rts = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rts == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.RTS while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -83,14 +113,24 @@ bool SerialUART::setRTS(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setCTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
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 */
|
||||
};
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
#endif
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_cts = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_cts == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.CTS while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -122,6 +162,9 @@ SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size
|
||||
_cts = cts;
|
||||
mutex_init(&_mutex);
|
||||
mutex_init(&_fifoMutex);
|
||||
_invertTX = false;
|
||||
_invertRX = false;
|
||||
_invertControl = false;
|
||||
}
|
||||
|
||||
static void _uart0IRQ();
|
||||
@@ -138,14 +181,18 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
_fcnTx = gpio_get_function(_tx);
|
||||
_fcnRx = gpio_get_function(_rx);
|
||||
gpio_set_function(_tx, GPIO_FUNC_UART);
|
||||
gpio_set_outover(_tx, _invertTX ? 1 : 0);
|
||||
gpio_set_function(_rx, GPIO_FUNC_UART);
|
||||
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);
|
||||
@@ -185,7 +232,7 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
break;
|
||||
}
|
||||
uart_set_format(_uart, bits, stop, parity);
|
||||
uart_set_hw_flow(_uart, _rts != UART_PIN_NOT_DEFINED, _cts != UART_PIN_NOT_DEFINED);
|
||||
uart_set_hw_flow(_uart, _cts != UART_PIN_NOT_DEFINED, _rts != UART_PIN_NOT_DEFINED);
|
||||
_writer = 0;
|
||||
_reader = 0;
|
||||
|
||||
@@ -230,12 +277,16 @@ void SerialUART::end() {
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,26 @@ public:
|
||||
ret &= setTX(tx);
|
||||
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 setPollingMode(bool mode = true);
|
||||
|
||||
@@ -80,12 +100,13 @@ private:
|
||||
uart_inst_t *_uart;
|
||||
pin_size_t _tx, _rx;
|
||||
pin_size_t _rts, _cts;
|
||||
enum gpio_function _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||
gpio_function_t _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||
int _baud;
|
||||
mutex_t _mutex;
|
||||
bool _polling = false;
|
||||
bool _overflow;
|
||||
bool _break;
|
||||
bool _invertTX, _invertRX, _invertControl;
|
||||
|
||||
// Lockless, IRQ-handled circular queue
|
||||
uint32_t _writer;
|
||||
|
||||
+25
-13
@@ -25,15 +25,15 @@
|
||||
#include <Arduino.h>
|
||||
#include "CoreMutex.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "hardware/resets.h"
|
||||
#include <tusb.h>
|
||||
#include <pico/time.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <hardware/resets.h>
|
||||
|
||||
#ifndef DISABLE_USB_SERIAL
|
||||
// Ensure we are installed in the USB chain
|
||||
@@ -130,7 +130,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
|
||||
static uint64_t last_avail_time;
|
||||
int written = 0;
|
||||
if (tud_cdc_connected()) {
|
||||
if (tud_cdc_connected() || _ignoreFlowControl) {
|
||||
for (size_t i = 0; i < length;) {
|
||||
int n = length - i;
|
||||
int avail = tud_cdc_write_available();
|
||||
@@ -171,14 +171,19 @@ SerialUSB::operator bool() {
|
||||
return tud_cdc_connected();
|
||||
}
|
||||
|
||||
void SerialUSB::ignoreFlowControl(bool ignore) {
|
||||
_ignoreFlowControl = ignore;
|
||||
}
|
||||
|
||||
static bool _dtr = false;
|
||||
static bool _rts = false;
|
||||
static int _bps = 115200;
|
||||
static bool _rebooting = false;
|
||||
static void CheckSerialReset() {
|
||||
__holdUpPendSV = 1; // Ensure we don't get swapped out by FreeRTOS
|
||||
if (!_rebooting && (_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);
|
||||
@@ -186,11 +191,18 @@ static void CheckSerialReset() {
|
||||
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.
|
||||
sleep_ms(3);
|
||||
busy_wait_ms(3);
|
||||
reset_usb_boot(0, 0);
|
||||
while (1); // WDT will fire here
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -43,6 +43,10 @@ public:
|
||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||
using Print::write;
|
||||
operator bool() override;
|
||||
bool dtr();
|
||||
bool rts();
|
||||
|
||||
void ignoreFlowControl(bool ignore = true);
|
||||
|
||||
// ESP8266 compat
|
||||
void setDebugOutput(bool unused) {
|
||||
@@ -51,6 +55,7 @@ public:
|
||||
|
||||
private:
|
||||
bool _running = false;
|
||||
bool _ignoreFlowControl = false;
|
||||
};
|
||||
|
||||
extern SerialUSB Serial;
|
||||
|
||||
@@ -30,10 +30,6 @@ public:
|
||||
}
|
||||
|
||||
~SoftwareSerial() {
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, 0);
|
||||
gpio_set_outover(_rx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void begin(unsigned long baud = 115200) override {
|
||||
@@ -41,11 +37,9 @@ public:
|
||||
};
|
||||
|
||||
void begin(unsigned long baud, uint16_t config) override {
|
||||
setInvertTX(_invert);
|
||||
setInvertRX(_invert);
|
||||
SerialPIO::begin(baud, config);
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, GPIO_OVERRIDE_INVERT);
|
||||
gpio_set_inover(_rx, GPIO_OVERRIDE_INVERT);
|
||||
}
|
||||
}
|
||||
|
||||
void listen() { /* noop */ }
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
|
||||
// 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")
|
||||
@@ -56,7 +56,7 @@ int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
||||
}
|
||||
|
||||
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
if (pin > 29) {
|
||||
if (pin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
newTone = new Tone();
|
||||
newTone->pin = pin;
|
||||
pinMode(pin, OUTPUT);
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off)) {
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off, pin, 1)) {
|
||||
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
||||
// ERROR, no free slots
|
||||
delete newTone;
|
||||
@@ -118,7 +118,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
void noTone(uint8_t pin) {
|
||||
CoreMutex m(&_toneMutex);
|
||||
|
||||
if ((pin > 29) || !m) {
|
||||
if ((pin > __GPIOCNT) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdint.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void randomSeed(uint32_t dwSeed) {
|
||||
if (dwSeed != 0) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "_freertos.h"
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include <stdlib.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
@@ -60,45 +60,3 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
||||
}
|
||||
return nullptr; // Need to make space for more mutex maps!
|
||||
}
|
||||
|
||||
|
||||
// The HW Random code needs a precise sleep_until() in order to assure it
|
||||
// grabs the ROSC bit when it wants. Unfortunately, under FreeRTOS the
|
||||
// sleep_until() becomes imprecise and the "did I get the bit when I wanted"
|
||||
// check in the pico_rand code always fails and you get an infinite loop.
|
||||
|
||||
// This block wraps the 2 get_rand calls to set a flag to convert
|
||||
// sleep_until() (which can do a task swap and cause bad timing) into a
|
||||
// busy wait.
|
||||
|
||||
extern "C" {
|
||||
static bool __inRand = false;
|
||||
|
||||
extern uint64_t __real_get_rand_64();
|
||||
uint64_t __wrap_get_rand_64() {
|
||||
if (__isFreeRTOS) {
|
||||
rp2040.idleOtherCore();
|
||||
__inRand = true;
|
||||
auto r = __real_get_rand_64();
|
||||
__inRand = false;
|
||||
rp2040.resumeOtherCore();
|
||||
return r;
|
||||
} else {
|
||||
return __real_get_rand_64();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t __wrap_get_rand_32() {
|
||||
return (uint32_t) __wrap_get_rand_64();
|
||||
}
|
||||
|
||||
extern void __real_sleep_until(absolute_time_t t);
|
||||
void __wrap_sleep_until(absolute_time_t t) {
|
||||
if (__inRand) {
|
||||
busy_wait_until(t);
|
||||
} else {
|
||||
__real_sleep_until(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-16
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "pico/mutex.h"
|
||||
#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
|
||||
@@ -31,36 +31,31 @@ extern bool __isFreeRTOS;
|
||||
extern volatile bool __freeRTOSinitted;
|
||||
|
||||
extern "C" {
|
||||
#ifndef INC_FREERTOS_H
|
||||
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
||||
typedef struct QueueDefinition * QueueHandle_t;
|
||||
typedef QueueHandle_t SemaphoreHandle_t;
|
||||
#endif
|
||||
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 void __freertos_mutex_take_from_isr(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) __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));
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
extern void vTaskSuspendAll() __attribute__((weak));
|
||||
extern int32_t xTaskResumeAll() __attribute__((weak));
|
||||
|
||||
typedef struct tskTaskControlBlock * TaskHandle_t;
|
||||
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
|
||||
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
|
||||
#endif
|
||||
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));
|
||||
}
|
||||
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
|
||||
|
||||
// Halt the FreeRTOS PendSV task switching magic
|
||||
extern "C" int __holdUpPendSV;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
|
||||
#define ccount_wrap_target 0
|
||||
#define ccount_wrap 1
|
||||
#define ccount_pio_version 0
|
||||
|
||||
static const uint16_t ccount_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -27,6 +28,10 @@ static const struct pio_program ccount_program = {
|
||||
.instructions = ccount_program_instructions,
|
||||
.length = 2,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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;
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include <lwip/netif.h>
|
||||
extern "C" {
|
||||
#include "cyw43.h"
|
||||
#include "cyw43_stats.h"
|
||||
#include <cyw43.h>
|
||||
#include <cyw43_stats.h>
|
||||
}
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// From cyw43_ctrl.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
LWIP wrappers to protect against timer-based re-entrancy
|
||||
|
||||
Copyright (c) 202s Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
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
|
||||
@@ -18,6 +18,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <lwip/pbuf.h>
|
||||
#include <lwip/udp.h>
|
||||
@@ -25,21 +26,76 @@
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/raw.h>
|
||||
#include <lwip/timeouts.h>
|
||||
#ifdef PICO_RP2040
|
||||
#include <pico/cyw43_arch.h>
|
||||
#endif
|
||||
#include <pico/mutex.h>
|
||||
#include <sys/lock.h>
|
||||
#include "_xoshiro.h"
|
||||
|
||||
extern void ethernet_arch_lwip_begin() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_end() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_gpio_mask() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_gpio_unmask() __attribute__((weak));
|
||||
|
||||
auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?)
|
||||
|
||||
class LWIPMutex {
|
||||
public:
|
||||
LWIPMutex() {
|
||||
cyw43_arch_lwip_begin();
|
||||
if (ethernet_arch_lwip_gpio_mask) {
|
||||
ethernet_arch_lwip_gpio_mask();
|
||||
}
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
if (rp2040.isPicoW()) {
|
||||
cyw43_arch_lwip_begin();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (ethernet_arch_lwip_begin) {
|
||||
ethernet_arch_lwip_begin();
|
||||
} else {
|
||||
recursive_mutex_enter_blocking(&__lwipMutex);
|
||||
}
|
||||
}
|
||||
|
||||
~LWIPMutex() {
|
||||
cyw43_arch_lwip_end();
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
if (rp2040.isPicoW()) {
|
||||
cyw43_arch_lwip_end();
|
||||
} else {
|
||||
#endif
|
||||
if (ethernet_arch_lwip_end) {
|
||||
ethernet_arch_lwip_end();
|
||||
} else {
|
||||
recursive_mutex_exit(&__lwipMutex);
|
||||
}
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
}
|
||||
#endif
|
||||
if (ethernet_arch_lwip_gpio_unmask) {
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
static XoshiroCpp::Xoshiro256PlusPlus *_lwip_rng = nullptr;
|
||||
// Random number generator for LWIP
|
||||
unsigned long __lwip_rand() {
|
||||
return (unsigned long)(*_lwip_rng)();
|
||||
}
|
||||
|
||||
// Avoid calling lwip_init multiple times
|
||||
extern void __real_lwip_init();
|
||||
void __wrap_lwip_init() {
|
||||
if (!_lwip_rng) {
|
||||
_lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros() * rp2040.getCycleCount());
|
||||
__real_lwip_init();
|
||||
}
|
||||
}
|
||||
|
||||
extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size);
|
||||
u8_t __wrap_pbuf_header(struct pbuf *p, s16_t header_size) {
|
||||
LWIPMutex m;
|
||||
@@ -193,19 +249,19 @@ extern "C" {
|
||||
extern void __real_tcp_setprio(struct tcp_pcb *pcb, u8_t prio);
|
||||
void __wrap_tcp_setprio(struct tcp_pcb *pcb, u8_t prio) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_setprio(pcb, prio);
|
||||
__real_tcp_setprio(pcb, prio);
|
||||
}
|
||||
|
||||
extern void __real_tcp_backlog_delayed(struct tcp_pcb* pcb);
|
||||
void __wrap_tcp_backlog_delayed(struct tcp_pcb* pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_backlog_delayed(pcb);
|
||||
__real_tcp_backlog_delayed(pcb);
|
||||
}
|
||||
|
||||
extern void __real_tcp_backlog_accepted(struct tcp_pcb* pcb);
|
||||
void __wrap_tcp_backlog_accepted(struct tcp_pcb* pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_backlog_accepted(pcb);
|
||||
__real_tcp_backlog_accepted(pcb);
|
||||
}
|
||||
extern struct udp_pcb *__real_udp_new(void);
|
||||
struct udp_pcb *__wrap_udp_new(void) {
|
||||
@@ -304,4 +360,16 @@ extern "C" {
|
||||
__real_raw_remove(pcb);
|
||||
}
|
||||
|
||||
extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
|
||||
struct netif *__wrap_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) {
|
||||
LWIPMutex m;
|
||||
return __real_netif_add(netif, ipaddr, netmask, gw, state, init, input);
|
||||
}
|
||||
|
||||
extern void __real_netif_remove(struct netif *netif);
|
||||
void __wrap_netif_remove(struct netif *netif) {
|
||||
LWIPMutex m;
|
||||
__real_netif_remove(netif);
|
||||
}
|
||||
|
||||
}; // extern "C"
|
||||
|
||||
+14
-7
@@ -27,11 +27,9 @@
|
||||
RP2040 rp2040;
|
||||
extern "C" {
|
||||
volatile bool __otherCoreIdled = false;
|
||||
int __holdUpPendSV = 0;
|
||||
uint32_t* core1_separate_stack_address = nullptr;
|
||||
};
|
||||
|
||||
mutex_t _pioMutex;
|
||||
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
@@ -41,12 +39,14 @@ extern void startFreeRTOS() __attribute__((weak));
|
||||
bool __isFreeRTOS;
|
||||
volatile bool __freeRTOSinitted;
|
||||
|
||||
extern void __EnableBluetoothDebug(Print &);
|
||||
|
||||
// Weak empty variant initialization. May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant() { }
|
||||
|
||||
// Optional 2nd core setup and loop
|
||||
bool core1_separate_stack __attribute__((weak)) = false;
|
||||
extern void setup1() __attribute__((weak));
|
||||
extern void loop1() __attribute__((weak));
|
||||
extern "C" void main1() {
|
||||
@@ -79,7 +79,7 @@ extern void __loop() {
|
||||
static struct _reent *_impure_ptr1 = nullptr;
|
||||
|
||||
extern "C" int main() {
|
||||
#if F_CPU != 125000000
|
||||
#if (defined(PICO_RP2040) && (F_CPU != 125000000)) || (defined(PICO_RP2350) && (F_CPU != 150000000))
|
||||
set_sys_clock_khz(F_CPU / 1000, true);
|
||||
#endif
|
||||
|
||||
@@ -92,8 +92,6 @@ extern "C" int main() {
|
||||
_REENT_INIT_PTR(_impure_ptr1);
|
||||
}
|
||||
|
||||
mutex_init(&_pioMutex);
|
||||
|
||||
rp2040.begin();
|
||||
|
||||
initVariant();
|
||||
@@ -122,6 +120,9 @@ extern "C" int main() {
|
||||
#if defined DEBUG_RP2040_PORT
|
||||
if (!__isFreeRTOS) {
|
||||
DEBUG_RP2040_PORT.begin(115200);
|
||||
#if (defined(ENABLE_BLUETOOTH) || defined(ENABLE_BLE)) && defined(DEBUG_RP2040_BLUETOOTH)
|
||||
__EnableBluetoothDebug(DEBUG_RP2040_PORT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -137,7 +138,12 @@ extern "C" int main() {
|
||||
if (!__isFreeRTOS) {
|
||||
if (setup1 || loop1) {
|
||||
delay(1); // Needed to make Picoprobe upload start 2nd core
|
||||
multicore_launch_core1(main1);
|
||||
if (core1_separate_stack) {
|
||||
core1_separate_stack_address = (uint32_t*)malloc(0x2000);
|
||||
multicore_launch_core1_with_stack(main1, core1_separate_stack_address, 0x2000);
|
||||
} else {
|
||||
multicore_launch_core1(main1);
|
||||
}
|
||||
}
|
||||
setup();
|
||||
while (true) {
|
||||
@@ -163,6 +169,7 @@ extern "C" void __register_impure_ptr(struct _reent *p) {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" struct _reent *__wrap___getreent() __attribute__((weak));
|
||||
extern "C" struct _reent *__wrap___getreent() {
|
||||
if (get_core_num() == 0) {
|
||||
return _impure_ptr;
|
||||
|
||||
@@ -19,11 +19,25 @@
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <malloc.h>
|
||||
#include <reent.h>
|
||||
#include "psram.h"
|
||||
|
||||
extern "C" void *__real_malloc(size_t size);
|
||||
extern "C" void *__real_calloc(size_t count, size_t size);
|
||||
extern "C" void *__real_realloc(void *mem, size_t size);
|
||||
extern "C" void __real_free(void *mem);
|
||||
extern "C" struct mallinfo __real_mallinfo();
|
||||
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
extern "C" {
|
||||
extern uint8_t __psram_start__;
|
||||
extern uint8_t __psram_heap_start__;
|
||||
void __malloc_lock(struct _reent *ptr);
|
||||
void __malloc_unlock(struct _reent *ptr);
|
||||
static void *__ram_start = (void *)0x20000000; // TODO - Is there a SDK exposed variable/macro?
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void *__wrap_malloc(size_t size) {
|
||||
noInterrupts();
|
||||
@@ -39,15 +53,72 @@ extern "C" void *__wrap_calloc(size_t count, size_t size) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *__wrap_realloc(void *mem, size_t size) {
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
// Utilize the existing malloc lock infrastructure and interrupt blocking
|
||||
// to work with multicore and FreeRTOS
|
||||
extern "C" void *pmalloc(size_t size) {
|
||||
noInterrupts();
|
||||
void *rc = __real_realloc(mem, size);
|
||||
__malloc_lock(__getreent());
|
||||
auto rc = __psram_malloc(size);
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *pcalloc(size_t count, size_t size) {
|
||||
noInterrupts();
|
||||
__malloc_lock(__getreent());
|
||||
auto rc = __psram_calloc(count, size);
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
// No PSRAM, always fail
|
||||
extern "C" void *pmalloc(size_t size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void *pcalloc(size_t count, size_t size) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void *__wrap_realloc(void *mem, size_t size) {
|
||||
void *rc;
|
||||
noInterrupts();
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
if (mem && (mem < __ram_start)) {
|
||||
rc = __psram_realloc(mem, size);
|
||||
} else {
|
||||
rc = __real_realloc(mem, size);
|
||||
}
|
||||
#else
|
||||
rc = __real_realloc(mem, size);
|
||||
#endif
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void __wrap_free(void *mem) {
|
||||
noInterrupts();
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
if (mem && (mem < __ram_start)) {
|
||||
__psram_free(mem);
|
||||
} else {
|
||||
__real_free(mem);
|
||||
}
|
||||
#else
|
||||
__real_free(mem);
|
||||
#endif
|
||||
interrupts();
|
||||
}
|
||||
|
||||
extern "C" struct mallinfo __wrap_mallinfo() {
|
||||
noInterrupts();
|
||||
__malloc_lock(__getreent());
|
||||
auto ret = __real_mallinfo();
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
; We shift out the start and stop bit as part of the FIFO
|
||||
set x, 9
|
||||
|
||||
pull side 1 ; Force stop bit
|
||||
pull side 1 ; Force stop bit high
|
||||
|
||||
; Send the bits
|
||||
bitloop:
|
||||
@@ -39,15 +39,13 @@ wait_bit:
|
||||
jmp y-- wait_bit
|
||||
jmp x-- bitloop
|
||||
|
||||
|
||||
|
||||
% c-sdk {
|
||||
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
// onto that pin with the IO muxes.
|
||||
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
|
||||
pio_gpio_init(pio, pin_tx);
|
||||
|
||||
pio_sm_config c = pio_tx_program_get_default_config(offset);
|
||||
@@ -68,7 +66,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
|
||||
|
||||
.program pio_rx
|
||||
|
||||
@@ -90,7 +88,6 @@ wait_half:
|
||||
|
||||
push ; Stuff it and wait for next start
|
||||
|
||||
|
||||
% c-sdk {
|
||||
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
@@ -12,6 +14,7 @@
|
||||
|
||||
#define pio_tx_wrap_target 0
|
||||
#define pio_tx_wrap 5
|
||||
#define pio_tx_pio_version 0
|
||||
|
||||
static const uint16_t pio_tx_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -29,6 +32,10 @@ static const struct pio_program pio_tx_program = {
|
||||
.instructions = pio_tx_program_instructions,
|
||||
.length = 6,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
|
||||
@@ -41,8 +48,8 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
// onto that pin with the IO muxes.
|
||||
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
|
||||
pio_gpio_init(pio, pin_tx);
|
||||
pio_sm_config c = pio_tx_program_get_default_config(offset);
|
||||
// OUT shifts to right, no autopull
|
||||
@@ -65,6 +72,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
|
||||
|
||||
#define pio_rx_wrap_target 0
|
||||
#define pio_rx_wrap 6
|
||||
#define pio_rx_pio_version 0
|
||||
|
||||
static const uint16_t pio_rx_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -83,6 +91,10 @@ static const struct pio_program pio_rx_program = {
|
||||
.instructions = pio_rx_program_instructions,
|
||||
.length = 7,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_rx_program_get_default_config(uint offset) {
|
||||
|
||||
+39
-13
@@ -33,7 +33,9 @@
|
||||
|
||||
extern "C" int errno;
|
||||
|
||||
extern "C" ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
#if defined DEBUG_RP2040_PORT
|
||||
(void) fd;
|
||||
return DEBUG_RP2040_PORT.write((const char *)buf, count);
|
||||
@@ -45,7 +47,9 @@ extern "C" ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
(void) path;
|
||||
(void) owner;
|
||||
(void) group;
|
||||
@@ -53,7 +57,9 @@ extern "C" int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _close(int fd) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _close(int fd) {
|
||||
(void) fd;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
@@ -72,7 +78,9 @@ extern "C" int _fork(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _fstat(int fd, struct stat *st) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _fstat(int fd, struct stat *st) {
|
||||
(void) fd;
|
||||
(void) st;
|
||||
errno = ENOSYS;
|
||||
@@ -115,7 +123,9 @@ extern "C" void __setSystemTime(unsigned long long sec, unsigned long usec) {
|
||||
__timedelta_us = newnow_us - now_us;
|
||||
}
|
||||
|
||||
extern "C" int _isatty(int file) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _isatty(int file) {
|
||||
(void) file;
|
||||
errno = ENOSYS;
|
||||
return 0;
|
||||
@@ -128,14 +138,18 @@ extern "C" int _kill(int pid, int sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _link(char *existing, char *newlink) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _link(char *existing, char *newlink) {
|
||||
(void) existing;
|
||||
(void) newlink;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _lseek(int file, int ptr, int dir) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _lseek(int file, int ptr, int dir) {
|
||||
(void) file;
|
||||
(void) ptr;
|
||||
(void) dir;
|
||||
@@ -143,7 +157,9 @@ extern "C" int _lseek(int file, int ptr, int dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _open(char *file, int flags, int mode) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _open(char *file, int flags, int mode) {
|
||||
(void) file;
|
||||
(void) flags;
|
||||
(void) mode;
|
||||
@@ -151,7 +167,9 @@ extern "C" int _open(char *file, int flags, int mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _read(int file, char *ptr, int len) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _read(int file, char *ptr, int len) {
|
||||
(void) file;
|
||||
(void) ptr;
|
||||
(void) len;
|
||||
@@ -159,7 +177,9 @@ extern "C" int _read(int file, char *ptr, int len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
(void) path;
|
||||
(void) buf;
|
||||
(void) bufsize;
|
||||
@@ -167,14 +187,18 @@ extern "C" int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _stat(const char *file, struct stat *st) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _stat(const char *file, struct stat *st) {
|
||||
(void) file;
|
||||
(void) st;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _symlink(const char *path1, const char *path2) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _symlink(const char *path1, const char *path2) {
|
||||
(void) path1;
|
||||
(void) path2;
|
||||
errno = ENOSYS;
|
||||
@@ -187,7 +211,9 @@ extern "C" clock_t _times(struct tms *buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _unlink(char *name) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _unlink(char *name) {
|
||||
(void) name;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
// Originally from https://github.com/sparkfun/sparkfun-pico
|
||||
/**
|
||||
@file sfe_psram.c
|
||||
|
||||
@brief This file contains a function that is used to detect and initialize PSRAM on
|
||||
SparkFun rp2350 boards.
|
||||
*/
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 SparkFun Electronics
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// Hacked by Earle Philhower to work with the Arduino-Pico core
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
|
||||
#include <hardware/address_mapped.h>
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/regs/addressmap.h>
|
||||
#include <hardware/spi.h>
|
||||
#include <hardware/structs/qmi.h>
|
||||
#include <hardware/structs/xip_ctrl.h>
|
||||
#include <pico/runtime_init.h>
|
||||
|
||||
// Include TLSF in this compilation unit
|
||||
#include "../../lib/tlsf/tlsf.c"
|
||||
static tlsf_t _mem_heap = nullptr;
|
||||
static pool_t _mem_psram_pool = nullptr;
|
||||
|
||||
// PSRAM heap minus PSRAM global/static variables from the linker
|
||||
extern "C" {
|
||||
extern uint8_t __psram_start__;
|
||||
extern uint8_t __psram_heap_start__;
|
||||
}
|
||||
|
||||
static bool _bInitalized = false;
|
||||
size_t __psram_size = 0;
|
||||
size_t __psram_heap_size = 0;
|
||||
|
||||
#define PICO_RUNTIME_INIT_PSRAM "11001" // Towards the end, after alarms
|
||||
|
||||
#ifndef RP2350_PSRAM_MAX_SELECT_FS64
|
||||
#define RP2350_PSRAM_MAX_SELECT_FS64 (125'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_MIN_DESELECT_FS
|
||||
#define RP2350_PSRAM_MIN_DESELECT_FS (50'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_MAX_SCK_HZ
|
||||
#define RP2350_PSRAM_MAX_SCK_HZ (109'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_ID
|
||||
#define RP2350_PSRAM_ID (0x5D)
|
||||
#endif
|
||||
|
||||
// DETAILS/
|
||||
//
|
||||
// SparkFun RP2350 boards use the following PSRAM IC:
|
||||
//
|
||||
// apmemory APS6404L-3SQR-ZR
|
||||
// https://www.mouser.com/ProductDetail/AP-Memory/APS6404L-3SQR-ZR?qs=IS%252B4QmGtzzpDOdsCIglviw%3D%3D
|
||||
//
|
||||
// The origin of this logic is from the Circuit Python code that was downloaded from:
|
||||
// https://github.com/raspberrypi/pico-sdk-rp2350/issues/12#issuecomment-2055274428
|
||||
//
|
||||
|
||||
// Details on the PSRAM IC that are used during setup/configuration of PSRAM on SparkFun RP2350 boards.
|
||||
|
||||
// For PSRAM timing calculations - to use int math, we work in femto seconds (fs) (1e-15),
|
||||
// NOTE: This idea is from micro python work on psram..
|
||||
|
||||
#define SFE_SEC_TO_FS 1000000000000000ll
|
||||
|
||||
// max select pulse width = 8us => 8e6 ns => 8000 ns => 8000 * 1e6 fs => 8000e6 fs
|
||||
// Additionally, the MAX select is in units of 64 clock cycles - will use a constant that
|
||||
// takes this into account - so 8000e6 fs / 64 = 125e6 fs
|
||||
|
||||
const uint32_t SFE_PSRAM_MAX_SELECT_FS64 = RP2350_PSRAM_MAX_SELECT_FS64;
|
||||
|
||||
// min deselect pulse width = 50ns => 50 * 1e6 fs => 50e7 fs
|
||||
const uint32_t SFE_PSRAM_MIN_DESELECT_FS = RP2350_PSRAM_MIN_DESELECT_FS;
|
||||
|
||||
// from psram datasheet - max Freq with VDDat 3.3v - SparkFun RP2350 boards run at 3.3v.
|
||||
// If VDD = 3.0 Max Freq is 133 Mhz
|
||||
const uint32_t SFE_PSRAM_MAX_SCK_HZ = RP2350_PSRAM_MAX_SCK_HZ;
|
||||
|
||||
// PSRAM SPI command codes
|
||||
const uint8_t PSRAM_CMD_QUAD_END = 0xF5;
|
||||
const uint8_t PSRAM_CMD_QUAD_ENABLE = 0x35;
|
||||
const uint8_t PSRAM_CMD_READ_ID = 0x9F;
|
||||
const uint8_t PSRAM_CMD_RSTEN = 0x66;
|
||||
const uint8_t PSRAM_CMD_RST = 0x99;
|
||||
const uint8_t PSRAM_CMD_QUAD_READ = 0xEB;
|
||||
const uint8_t PSRAM_CMD_QUAD_WRITE = 0x38;
|
||||
const uint8_t PSRAM_CMD_NOOP = 0xFF;
|
||||
|
||||
const uint8_t PSRAM_ID = RP2350_PSRAM_ID;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Communicate directly with the PSRAM IC - validate it is present and return the size
|
||||
///
|
||||
/// @return size_t The size of the PSRAM
|
||||
///
|
||||
/// @note This function expects the CS pin set
|
||||
static size_t __no_inline_not_in_flash_func(get_psram_size)(void) {
|
||||
size_t psram_size = 0;
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
|
||||
// Try and read the PSRAM ID via direct_csr.
|
||||
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS;
|
||||
|
||||
// Need to poll for the cooldown on the last XIP transfer to expire
|
||||
// (via direct-mode BUSY flag) before it is safe to perform the first
|
||||
// direct-mode operation
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
// Exit out of QMI in case we've inited already
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
|
||||
// Transmit the command to exit QPI quad mode - read ID as standard SPI
|
||||
qmi_hw->direct_tx =
|
||||
QMI_DIRECT_TX_OE_BITS | QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB | PSRAM_CMD_QUAD_END;
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
(void)qmi_hw->direct_rx;
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
|
||||
|
||||
// Read the id
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
uint8_t kgd = 0;
|
||||
uint8_t eid = 0;
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
qmi_hw->direct_tx = (i == 0 ? PSRAM_CMD_READ_ID : PSRAM_CMD_NOOP);
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) {
|
||||
}
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
if (i == 5) {
|
||||
kgd = qmi_hw->direct_rx;
|
||||
} else if (i == 6) {
|
||||
eid = qmi_hw->direct_rx;
|
||||
} else {
|
||||
(void)qmi_hw->direct_rx; // just read and discard
|
||||
}
|
||||
}
|
||||
|
||||
// Disable direct csr.
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
|
||||
|
||||
// is this the PSRAM we're looking for obi-wan?
|
||||
if (kgd == PSRAM_ID) {
|
||||
// PSRAM size
|
||||
psram_size = 1024 * 1024; // 1 MiB
|
||||
uint8_t size_id = eid >> 5;
|
||||
if (eid == 0x26 || size_id == 2) {
|
||||
psram_size *= 8;
|
||||
} else if (size_id == 0) {
|
||||
psram_size *= 2;
|
||||
} else if (size_id == 1) {
|
||||
psram_size *= 4;
|
||||
}
|
||||
}
|
||||
restore_interrupts(intr_stash);
|
||||
return psram_size;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Update the PSRAM timing configuration based on system clock
|
||||
///
|
||||
/// @note This function expects interrupts to be enabled on entry
|
||||
|
||||
static void __no_inline_not_in_flash_func(set_psram_timing)(void) {
|
||||
// Get secs / cycle for the system clock - get before disabling interrupts.
|
||||
uint32_t sysHz = (uint32_t)clock_get_hz(clk_sys);
|
||||
|
||||
// Calculate the clock divider - goal to get clock used for PSRAM <= what
|
||||
// the PSRAM IC can handle - which is defined in SFE_PSRAM_MAX_SCK_HZ
|
||||
volatile uint8_t clockDivider = (sysHz + SFE_PSRAM_MAX_SCK_HZ - 1) / SFE_PSRAM_MAX_SCK_HZ;
|
||||
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
|
||||
// Get the clock femto seconds per cycle.
|
||||
|
||||
uint32_t fsPerCycle = SFE_SEC_TO_FS / sysHz;
|
||||
|
||||
// the maxSelect value is defined in units of 64 clock cycles
|
||||
// So maxFS / (64 * fsPerCycle) = maxSelect = SFE_PSRAM_MAX_SELECT_FS64/fsPerCycle
|
||||
volatile uint8_t maxSelect = SFE_PSRAM_MAX_SELECT_FS64 / fsPerCycle;
|
||||
|
||||
// minDeselect time - in system clock cycle
|
||||
// Must be higher than 50ns (min deselect time for PSRAM) so add a fsPerCycle - 1 to round up
|
||||
// So minFS/fsPerCycle = minDeselect = SFE_PSRAM_MIN_DESELECT_FS/fsPerCycle
|
||||
|
||||
volatile uint8_t minDeselect = (SFE_PSRAM_MIN_DESELECT_FS + fsPerCycle - 1) / fsPerCycle;
|
||||
|
||||
// printf("Max Select: %d, Min Deselect: %d, clock divider: %d\n", maxSelect, minDeselect, clockDivider);
|
||||
|
||||
qmi_hw->m[1].timing = QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | // Break between pages.
|
||||
3 << QMI_M1_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles.
|
||||
1 << QMI_M1_TIMING_COOLDOWN_LSB | 1 << QMI_M1_TIMING_RXDELAY_LSB |
|
||||
maxSelect << QMI_M1_TIMING_MAX_SELECT_LSB | minDeselect << QMI_M1_TIMING_MIN_DESELECT_LSB |
|
||||
clockDivider << QMI_M1_TIMING_CLKDIV_LSB;
|
||||
|
||||
restore_interrupts(intr_stash);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief The setup_psram function - note that this is not in flash
|
||||
///
|
||||
///
|
||||
static void __no_inline_not_in_flash_func(runtime_init_setup_psram)(/*uint32_t psram_cs_pin*/) {
|
||||
// Set the PSRAM CS pin in the SDK
|
||||
gpio_set_function(RP2350_PSRAM_CS, GPIO_FUNC_XIP_CS1);
|
||||
|
||||
// start with zero size
|
||||
size_t psram_size = get_psram_size();
|
||||
|
||||
// No PSRAM - no dice
|
||||
if (psram_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
// Enable quad mode.
|
||||
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS;
|
||||
|
||||
// Need to poll for the cooldown on the last XIP transfer to expire
|
||||
// (via direct-mode BUSY flag) before it is safe to perform the first
|
||||
// direct-mode operation
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
// RESETEN, RESET and quad enable
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
if (i == 0) {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_RSTEN;
|
||||
} else if (i == 1) {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_RST;
|
||||
} else {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_QUAD_ENABLE;
|
||||
}
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
|
||||
for (size_t j = 0; j < 20; j++) {
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
(void)qmi_hw->direct_rx;
|
||||
}
|
||||
|
||||
// Disable direct csr.
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
|
||||
|
||||
// check our interrupts and setup the timing
|
||||
restore_interrupts(intr_stash);
|
||||
set_psram_timing();
|
||||
|
||||
// and now stash interrupts again
|
||||
intr_stash = save_and_disable_interrupts();
|
||||
|
||||
qmi_hw->m[1].rfmt = (QMI_M1_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M1_RFMT_PREFIX_WIDTH_LSB |
|
||||
QMI_M1_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M1_RFMT_ADDR_WIDTH_LSB |
|
||||
QMI_M1_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M1_RFMT_SUFFIX_WIDTH_LSB |
|
||||
QMI_M1_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M1_RFMT_DUMMY_WIDTH_LSB |
|
||||
QMI_M1_RFMT_DUMMY_LEN_VALUE_24 << QMI_M1_RFMT_DUMMY_LEN_LSB |
|
||||
QMI_M1_RFMT_DATA_WIDTH_VALUE_Q << QMI_M1_RFMT_DATA_WIDTH_LSB |
|
||||
QMI_M1_RFMT_PREFIX_LEN_VALUE_8 << QMI_M1_RFMT_PREFIX_LEN_LSB |
|
||||
QMI_M1_RFMT_SUFFIX_LEN_VALUE_NONE << QMI_M1_RFMT_SUFFIX_LEN_LSB);
|
||||
|
||||
qmi_hw->m[1].rcmd = PSRAM_CMD_QUAD_READ << QMI_M1_RCMD_PREFIX_LSB | 0 << QMI_M1_RCMD_SUFFIX_LSB;
|
||||
|
||||
qmi_hw->m[1].wfmt = (QMI_M1_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M1_WFMT_PREFIX_WIDTH_LSB |
|
||||
QMI_M1_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M1_WFMT_ADDR_WIDTH_LSB |
|
||||
QMI_M1_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M1_WFMT_SUFFIX_WIDTH_LSB |
|
||||
QMI_M1_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M1_WFMT_DUMMY_WIDTH_LSB |
|
||||
QMI_M1_WFMT_DUMMY_LEN_VALUE_NONE << QMI_M1_WFMT_DUMMY_LEN_LSB |
|
||||
QMI_M1_WFMT_DATA_WIDTH_VALUE_Q << QMI_M1_WFMT_DATA_WIDTH_LSB |
|
||||
QMI_M1_WFMT_PREFIX_LEN_VALUE_8 << QMI_M1_WFMT_PREFIX_LEN_LSB |
|
||||
QMI_M1_WFMT_SUFFIX_LEN_VALUE_NONE << QMI_M1_WFMT_SUFFIX_LEN_LSB);
|
||||
|
||||
qmi_hw->m[1].wcmd = PSRAM_CMD_QUAD_WRITE << QMI_M1_WCMD_PREFIX_LSB | 0 << QMI_M1_WCMD_SUFFIX_LSB;
|
||||
|
||||
// Mark that we can write to PSRAM.
|
||||
xip_ctrl_hw->ctrl |= XIP_CTRL_WRITABLE_M1_BITS;
|
||||
|
||||
restore_interrupts(intr_stash);
|
||||
|
||||
__psram_size = psram_size;
|
||||
|
||||
uint32_t used_psram_size = &__psram_heap_start__ - &__psram_start__;
|
||||
__psram_heap_size = __psram_size - used_psram_size;
|
||||
}
|
||||
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_psram, PICO_RUNTIME_INIT_PSRAM);
|
||||
|
||||
// update timing -- used if the system clock/timing was changed.
|
||||
void psram_reinit_timing() {
|
||||
set_psram_timing();
|
||||
}
|
||||
|
||||
static bool __psram_heap_init() {
|
||||
if (_bInitalized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!__psram_heap_size) {
|
||||
return false;
|
||||
}
|
||||
_mem_heap = NULL;
|
||||
_mem_psram_pool = NULL;
|
||||
_mem_heap = tlsf_create_with_pool((void *)&__psram_heap_start__, __psram_heap_size, 16 * 1024 * 1024);
|
||||
if (!_mem_heap) {
|
||||
return false;
|
||||
}
|
||||
_mem_psram_pool = tlsf_get_pool(_mem_heap);
|
||||
if (!_mem_psram_pool) {
|
||||
return false;
|
||||
}
|
||||
_bInitalized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void *__psram_malloc(size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
return tlsf_malloc(_mem_heap, size);
|
||||
}
|
||||
|
||||
void __psram_free(void *ptr) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return;
|
||||
}
|
||||
tlsf_free(_mem_heap, ptr);
|
||||
}
|
||||
|
||||
void *__psram_realloc(void *ptr, size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
return tlsf_realloc(_mem_heap, ptr, size);
|
||||
}
|
||||
|
||||
void *__psram_calloc(size_t num, size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
void *ptr = tlsf_malloc(_mem_heap, num * size);
|
||||
if (ptr) {
|
||||
bzero(ptr, num * size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static bool max_free_walker(void *ptr, size_t size, int used, void *user) {
|
||||
size_t *max_size = (size_t *)user;
|
||||
if (!used && *max_size < size) {
|
||||
*max_size = size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_largest_free_block() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t max_free = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, max_free_walker, &max_free);
|
||||
}
|
||||
return max_free;
|
||||
}
|
||||
|
||||
static bool memory_size_walker(void *ptr, size_t size, int used, void *user) {
|
||||
*((size_t *)user) += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_total_space() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_size = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, memory_size_walker, &total_size);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static bool memory_used_walker(void *ptr, size_t size, int used, void *user) {
|
||||
if (used) {
|
||||
*((size_t *)user) += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_total_used() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_size = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, memory_used_walker, &total_size);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
#endif // RP2350_PSRAM_CS
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
@file sfe_psram.c
|
||||
|
||||
@brief This file contains a function that is used to detect and initialize PSRAM on
|
||||
SparkFun rp2350 boards.
|
||||
*/
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions: The
|
||||
above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void psram_reinit_timing();
|
||||
void *__psram_malloc(size_t size);
|
||||
void __psram_free(void *ptr);
|
||||
void *__psram_realloc(void *ptr, size_t size);
|
||||
void *__psram_calloc(size_t num, size_t size);
|
||||
size_t __psram_largest_free_block();
|
||||
size_t __psram_total_space();
|
||||
size_t __psram_total_used();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
Copyright (C) 2014 BlueKitchen GmbH
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
4. Any redistribution, use, or modification is done solely for
|
||||
personal benefit and not for any commercial purpose or for
|
||||
monetary gain.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
|
||||
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Please inquire about commercial licensing options at
|
||||
contact@bluekitchen-gmbh.com
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@title ATT Database Engine
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ATT_DB_H
|
||||
#define ATT_DB_H
|
||||
|
||||
#if defined ENABLE_CLASSIC
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sdkoverride/bluetooth.h>
|
||||
#include "btstack_linked_list.h"
|
||||
#include "btstack_defines.h"
|
||||
#include "btstack_bool.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// MARK: Attribute PDU Opcodes
|
||||
#define ATT_ERROR_RESPONSE 0x01u
|
||||
|
||||
#define ATT_EXCHANGE_MTU_REQUEST 0x02u
|
||||
#define ATT_EXCHANGE_MTU_RESPONSE 0x03u
|
||||
|
||||
#define ATT_FIND_INFORMATION_REQUEST 0x04u
|
||||
#define ATT_FIND_INFORMATION_REPLY 0x05u
|
||||
#define ATT_FIND_BY_TYPE_VALUE_REQUEST 0x06u
|
||||
#define ATT_FIND_BY_TYPE_VALUE_RESPONSE 0x07u
|
||||
|
||||
#define ATT_READ_BY_TYPE_REQUEST 0x08u
|
||||
#define ATT_READ_BY_TYPE_RESPONSE 0x09u
|
||||
#define ATT_READ_REQUEST 0x0au
|
||||
#define ATT_READ_RESPONSE 0x0bu
|
||||
#define ATT_READ_BLOB_REQUEST 0x0cu
|
||||
#define ATT_READ_BLOB_RESPONSE 0x0du
|
||||
#define ATT_READ_MULTIPLE_REQUEST 0x0eu
|
||||
#define ATT_READ_MULTIPLE_RESPONSE 0x0fu
|
||||
#define ATT_READ_BY_GROUP_TYPE_REQUEST 0x10u
|
||||
#define ATT_READ_BY_GROUP_TYPE_RESPONSE 0x11u
|
||||
|
||||
#define ATT_WRITE_REQUEST 0x12u
|
||||
#define ATT_WRITE_RESPONSE 0x13u
|
||||
|
||||
#define ATT_PREPARE_WRITE_REQUEST 0x16u
|
||||
#define ATT_PREPARE_WRITE_RESPONSE 0x17u
|
||||
#define ATT_EXECUTE_WRITE_REQUEST 0x18u
|
||||
#define ATT_EXECUTE_WRITE_RESPONSE 0x19u
|
||||
|
||||
#define ATT_HANDLE_VALUE_NOTIFICATION 0x1bu
|
||||
#define ATT_HANDLE_VALUE_INDICATION 0x1du
|
||||
#define ATT_HANDLE_VALUE_CONFIRMATION 0x1eu
|
||||
|
||||
#define ATT_READ_MULTIPLE_VARIABLE_REQ 0x20u
|
||||
#define ATT_READ_MULTIPLE_VARIABLE_RSP 0x21u
|
||||
#define ATT_MULTIPLE_HANDLE_VALUE_NTF 0x23u
|
||||
|
||||
#define ATT_WRITE_COMMAND 0x52u
|
||||
#define ATT_SIGNED_WRITE_COMMAND 0xD2u
|
||||
|
||||
|
||||
// internal additions
|
||||
// 128 bit UUID used
|
||||
#define ATT_PROPERTY_UUID128 0x200u
|
||||
// Read/Write Permission bits
|
||||
#define ATT_PROPERTY_READ_PERMISSION_BIT_0 0x0400u
|
||||
#define ATT_PROPERTY_READ_PERMISSION_BIT_1 0x0800u
|
||||
#define ATT_PROPERTY_WRITE_PERMISSION_BIT_0 0x0001u
|
||||
#define ATT_PROPERTY_WRITE_PERMISSION_BIT_1 0x0010u
|
||||
#define ATT_PROPERTY_READ_PERMISSION_SC 0x0020u
|
||||
#define ATT_PROPERTY_WRITE_PERMISSION_SC 0x0080u
|
||||
|
||||
|
||||
typedef struct att_connection {
|
||||
hci_con_handle_t con_handle;
|
||||
uint16_t mtu; // initialized to ATT_DEFAULT_MTU (23), negotiated during MTU exchange
|
||||
uint16_t max_mtu; // local maximal L2CAP_MTU, set to l2cap_max_le_mtu()
|
||||
bool mtu_exchanged;
|
||||
uint8_t encryption_key_size;
|
||||
uint8_t authenticated;
|
||||
uint8_t authorized;
|
||||
uint8_t secure_connection;
|
||||
} att_connection_t;
|
||||
|
||||
/* API_START */
|
||||
|
||||
// map ATT ERROR CODES on to att_read_callback length
|
||||
#define ATT_READ_ERROR_CODE_OFFSET 0xfe00u
|
||||
|
||||
// custom BTstack ATT Response Pending for att_read_callback
|
||||
#define ATT_READ_RESPONSE_PENDING 0xffffu
|
||||
|
||||
// internally used to signal write response pending
|
||||
#define ATT_INTERNAL_WRITE_RESPONSE_PENDING 0xfffeu
|
||||
|
||||
/**
|
||||
@brief ATT Client Read Callback for Dynamic Data
|
||||
- if buffer == NULL, don't copy data, just return size of value
|
||||
- if buffer != NULL, copy data and return number bytes copied
|
||||
If ENABLE_ATT_DELAYED_READ_RESPONSE is defined, you may return ATT_READ_RESPONSE_PENDING if data isn't available yet
|
||||
@param con_handle of hci le connection
|
||||
@param attribute_handle to be read
|
||||
@param offset defines start of attribute value
|
||||
@param buffer
|
||||
@param buffer_size
|
||||
@return size of value if buffer is NULL, otherwise number of bytes copied
|
||||
*/
|
||||
typedef uint16_t (*att_read_callback_t)(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
|
||||
|
||||
/**
|
||||
@brief ATT Client Write Callback for Dynamic Data
|
||||
Each Prepared Write Request triggers a callback with transaction mode ATT_TRANSACTION_MODE_ACTIVE.
|
||||
On Execute Write, the callback will be called with ATT_TRANSACTION_MODE_VALIDATE and allows to validate all queued writes and return an application error.
|
||||
If none of the registered callbacks return an error for ATT_TRANSACTION_MODE_VALIDATE and the callback will be called with ATT_TRANSACTION_MODE_EXECUTE.
|
||||
Otherwise, all callbacks will be called with ATT_TRANSACTION_MODE_CANCEL.
|
||||
|
||||
If the additional validation step is not needed, just return 0 for all callbacks with transaction mode ATT_TRANSACTION_MODE_VALIDATE.
|
||||
|
||||
@param con_handle of hci le connection
|
||||
@param attribute_handle to be written
|
||||
@param transaction - ATT_TRANSACTION_MODE_NONE for regular writes. For prepared writes: ATT_TRANSACTION_MODE_ACTIVE, ATT_TRANSACTION_MODE_VALIDATE, ATT_TRANSACTION_MODE_EXECUTE, ATT_TRANSACTION_MODE_CANCEL
|
||||
@param offset into the value - used for queued writes and long attributes
|
||||
@param buffer
|
||||
@param buffer_size
|
||||
@param signature used for signed write commands
|
||||
@return 0 if write was ok, ATT_ERROR_PREPARE_QUEUE_FULL if no space in queue, ATT_ERROR_INVALID_OFFSET if offset is larger than max buffer
|
||||
*/
|
||||
typedef int (*att_write_callback_t)(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
|
||||
|
||||
// Read & Write Callbacks for handle range
|
||||
typedef struct att_service_handler {
|
||||
btstack_linked_item_t * item;
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
att_read_callback_t read_callback;
|
||||
att_write_callback_t write_callback;
|
||||
btstack_packet_handler_t packet_handler;
|
||||
} att_service_handler_t;
|
||||
|
||||
// MARK: ATT Operations
|
||||
|
||||
/**
|
||||
@brief setup ATT database
|
||||
@param db
|
||||
*/
|
||||
void att_set_db(uint8_t const * db);
|
||||
|
||||
/*
|
||||
@brief set callback for read of dynamic attributes
|
||||
@param callback
|
||||
*/
|
||||
void att_set_read_callback(att_read_callback_t callback);
|
||||
|
||||
/**
|
||||
@brief set callback for write of dynamic attributes
|
||||
@param callback
|
||||
*/
|
||||
void att_set_write_callback(att_write_callback_t callback);
|
||||
|
||||
/**
|
||||
@brief debug helper, dump ATT database to stdout using log_info
|
||||
*/
|
||||
void att_dump_attributes(void);
|
||||
|
||||
/**
|
||||
@brief process ATT request against database and put response into response buffer
|
||||
@param att_connection used for mtu and security properties
|
||||
@param request_buffer, request_len: ATT request from client
|
||||
@param response_buffer for result
|
||||
@return len of data in response buffer. 0 = no response,
|
||||
ATT_READ_RESPONSE_PENDING if it was returned at least once for dynamic data (requires ENABLE_ATT_DELAYED_READ_RESPONSE)
|
||||
*/
|
||||
uint16_t att_handle_request(att_connection_t * att_connection,
|
||||
uint8_t * request_buffer,
|
||||
uint16_t request_len,
|
||||
uint8_t * response_buffer);
|
||||
|
||||
/**
|
||||
@brief setup value notification in response buffer for a given handle and value
|
||||
@param att_connection
|
||||
@param attribute_handle
|
||||
@param value
|
||||
@param value_len
|
||||
@param response_buffer for notification
|
||||
*/
|
||||
uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
|
||||
uint16_t attribute_handle,
|
||||
const uint8_t *value,
|
||||
uint16_t value_len,
|
||||
uint8_t * response_buffer);
|
||||
|
||||
/**
|
||||
@brief setup value notification in response buffer for multiple handles and values
|
||||
@param att_connection
|
||||
@param attribute_handle
|
||||
@param value
|
||||
@param value_len
|
||||
@param response_buffer for notification
|
||||
*/
|
||||
uint16_t att_prepare_handle_value_multiple_notification(att_connection_t * att_connection,
|
||||
uint8_t num_attributes,
|
||||
const uint16_t * attribute_handles,
|
||||
const uint8_t ** values_data,
|
||||
const uint16_t * values_len,
|
||||
uint8_t * response_buffer);
|
||||
|
||||
/**
|
||||
@brief setup value indication in response buffer for a given handle and value
|
||||
@param att_connection
|
||||
@param attribute_handle
|
||||
@param value
|
||||
@param value_len
|
||||
@param response_buffer for indication
|
||||
*/
|
||||
uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
|
||||
uint16_t attribute_handle,
|
||||
const uint8_t *value,
|
||||
uint16_t value_len,
|
||||
uint8_t * response_buffer);
|
||||
|
||||
/**
|
||||
@brief transaction queue of prepared writes, e.g., after disconnect
|
||||
@return att_connection
|
||||
*/
|
||||
void att_clear_transaction_queue(att_connection_t * att_connection);
|
||||
|
||||
// att_read_callback helpers for a various data types
|
||||
|
||||
/**
|
||||
@brief Handle read of blob like data for att_read_callback
|
||||
@param blob of data
|
||||
@param blob_size of blob
|
||||
@param offset from att_read_callback
|
||||
@param buffer from att_read_callback
|
||||
@param buffer_size from att_read_callback
|
||||
@return value size for buffer == 0 and num bytes copied otherwise
|
||||
*/
|
||||
uint16_t att_read_callback_handle_blob(const uint8_t * blob, uint16_t blob_size, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
|
||||
|
||||
/**
|
||||
@brief Handle read of little endian unsigned 32 bit value for att_read_callback
|
||||
@param value
|
||||
@param offset from att_read_callback
|
||||
@param buffer from att_read_callback
|
||||
@param buffer_size from att_read_callback
|
||||
@return value size for buffer == 0 and num bytes copied otherwise
|
||||
*/
|
||||
uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
|
||||
|
||||
/**
|
||||
@brief Handle read of little endian unsigned 16 bit value for att_read_callback
|
||||
@param value
|
||||
@param offset from att_read_callback
|
||||
@param buffer from att_read_callback
|
||||
@param buffer_size from att_read_callback
|
||||
@return value size for buffer == 0 and num bytes copied otherwise
|
||||
*/
|
||||
uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
|
||||
|
||||
/**
|
||||
@brief Handle read of single byte for att_read_callback
|
||||
@param blob of data
|
||||
@param blob_size of blob
|
||||
@param offset from att_read_callback
|
||||
@param buffer from att_read_callback
|
||||
@param buffer_size from att_read_callback
|
||||
@return value size for buffer == 0 and num bytes copied otherwise
|
||||
*/
|
||||
uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
|
||||
|
||||
|
||||
// experimental client API
|
||||
/**
|
||||
@brief Get UUID for handle
|
||||
@param attribute_handle
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t att_uuid_for_handle(uint16_t attribute_handle);
|
||||
|
||||
/**
|
||||
@brief Get const value for handle
|
||||
@param attribute_handle
|
||||
@param out_value_len output variable that hold value len
|
||||
@return value
|
||||
*/
|
||||
|
||||
const uint8_t * gatt_server_get_const_value_for_handle(uint16_t attribute_handle, uint16_t * out_value_len);
|
||||
|
||||
// experimental GATT Server API
|
||||
|
||||
/**
|
||||
@brief Get handle range for primary service.
|
||||
@param uuid16
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@return false if not found
|
||||
*/
|
||||
bool gatt_server_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle);
|
||||
|
||||
/**
|
||||
@brief Get handle range for included service.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param uuid16
|
||||
@param out_included_service_handle
|
||||
@param out_included_service_start_handle
|
||||
@param out_included_service_end_handle
|
||||
@return false if not found
|
||||
*/
|
||||
bool gatt_server_get_included_service_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16,
|
||||
uint16_t * out_included_service_handle, uint16_t * out_included_service_start_handle, uint16_t * out_included_service_end_handle);
|
||||
|
||||
/**
|
||||
@brief Get value handle for characteristic.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param uuid16
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16);
|
||||
|
||||
/**
|
||||
@brief Get descriptor handle for characteristic.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param characteristic_uuid16
|
||||
@param descriptor_uuid16
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16, uint16_t descriptor_uuid16);
|
||||
|
||||
/**
|
||||
@brief Get client configuration handle for characteristic.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param characteristic_uuid16
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16);
|
||||
|
||||
/**
|
||||
@brief Get server configuration handle for characteristic.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param characteristic_uuid16
|
||||
@param descriptor_uuid16
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16);
|
||||
|
||||
|
||||
/**
|
||||
@brief Get handle range for primary service.
|
||||
@param uuid128
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@return false if not found
|
||||
*/
|
||||
bool gatt_server_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle);
|
||||
|
||||
/**
|
||||
@brief Get value handle.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param uuid128
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);
|
||||
|
||||
/**
|
||||
@brief Get client configuration handle.
|
||||
@param start_handle
|
||||
@param end_handle
|
||||
@param uuid128
|
||||
@return 0 if not found
|
||||
*/
|
||||
uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128);
|
||||
|
||||
/* API_END */
|
||||
|
||||
// non-user functionality for att_server
|
||||
|
||||
/**
|
||||
@brief Check if writes to handle should be persistent
|
||||
@param handle
|
||||
@return 1 if persistent
|
||||
*/
|
||||
bool att_is_persistent_ccc(uint16_t handle);
|
||||
|
||||
|
||||
|
||||
// auto-pts testing, returns response size
|
||||
#ifdef ENABLE_BTP
|
||||
uint16_t btp_att_get_attributes_by_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16, uint8_t * response_buffer, uint16_t response_buffer_size);
|
||||
uint16_t btp_att_get_attributes_by_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128, uint8_t * response_buffer, uint16_t response_buffer_size);
|
||||
uint16_t btp_att_get_attribute_value(att_connection_t * att_connection, uint16_t attribute_handle, uint8_t * response_buffer, uint16_t response_buffer_size);
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ATT_H
|
||||
@@ -0,0 +1,926 @@
|
||||
/*
|
||||
Copyright (C) 2015 BlueKitchen GmbH
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
4. Any redistribution, use, or modification is done solely for
|
||||
personal benefit and not for any commercial purpose or for
|
||||
monetary gain.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
|
||||
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Please inquire about commercial licensing options at
|
||||
contact@bluekitchen-gmbh.com
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
bluetooth.h
|
||||
|
||||
Numbers defined or derived from the official Bluetooth specification
|
||||
*/
|
||||
|
||||
#ifndef BLUETOOTH_H
|
||||
#define BLUETOOTH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
@brief hci connection handle type
|
||||
*/
|
||||
typedef uint16_t hci_con_handle_t;
|
||||
|
||||
/**
|
||||
@brief Length of a bluetooth device address.
|
||||
*/
|
||||
#define BD_ADDR_LEN 6
|
||||
|
||||
/**
|
||||
@brief Bluetooth address
|
||||
*/
|
||||
typedef uint8_t bd_addr_t[BD_ADDR_LEN];
|
||||
|
||||
/**
|
||||
Address types
|
||||
*/
|
||||
typedef enum {
|
||||
// Public Device Address
|
||||
BD_ADDR_TYPE_LE_PUBLIC = 0,
|
||||
// Random Device Address
|
||||
BD_ADDR_TYPE_LE_RANDOM = 1,
|
||||
// Public Identity Address (Corresponds to Resolved Private Address)
|
||||
BD_ADDR_TYPE_LE_PUBLIC_IDENTITY = 2,
|
||||
// Random (static) Identity Address (Corresponds to Resolved Private Address)
|
||||
BD_ADDR_TYPE_LE_RANDOM_IDENTITY = 3,
|
||||
// internal BTstack addr types for Classic connections
|
||||
BD_ADDR_TYPE_SCO = 0xfc,
|
||||
BD_ADDR_TYPE_ACL = 0xfd,
|
||||
BD_ADDR_TYPE_UNKNOWN = 0xfe, // also used as 'invalid'
|
||||
} bd_addr_type_t;
|
||||
|
||||
/**
|
||||
Link types for BR/EDR Connections
|
||||
*/
|
||||
typedef enum {
|
||||
HCI_LINK_TYPE_SCO = 0,
|
||||
HCI_LINK_TYPE_ACL = 1,
|
||||
HCI_LINK_TYPE_ESCO = 2,
|
||||
} hci_link_type_t;
|
||||
|
||||
|
||||
/**
|
||||
@brief link key
|
||||
*/
|
||||
#define LINK_KEY_LEN 16
|
||||
#define LINK_KEY_STR_LEN (LINK_KEY_LEN*2)
|
||||
typedef uint8_t link_key_t[LINK_KEY_LEN];
|
||||
|
||||
/**
|
||||
@brief link key type
|
||||
*/
|
||||
typedef enum {
|
||||
INVALID_LINK_KEY = 0xffff,
|
||||
COMBINATION_KEY = 0, // standard pairing
|
||||
LOCAL_UNIT_KEY, // ?
|
||||
REMOTE_UNIT_KEY, // ?
|
||||
DEBUG_COMBINATION_KEY, // SSP with debug
|
||||
UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P192, // SSP Simple Pairing
|
||||
AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P192, // SSP Passkey, Number confirm, OOB
|
||||
CHANGED_COMBINATION_KEY, // Link key changed using Change Connection Lnk Key
|
||||
UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256, // SSP Simpe Pairing
|
||||
AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256, // SSP Passkey, Number confirm, OOB
|
||||
} link_key_type_t;
|
||||
|
||||
/**
|
||||
LE Privacy 1.2
|
||||
*/
|
||||
typedef enum {
|
||||
LE_PRIVACY_MODE_NETWORK = 0,
|
||||
LE_PRIVACY_MODE_DEVICE = 1,
|
||||
} le_privacy_mode_t;
|
||||
|
||||
/**
|
||||
@brief Extended Inquiry Response
|
||||
*/
|
||||
#define EXTENDED_INQUIRY_RESPONSE_DATA_LEN 240
|
||||
|
||||
/**
|
||||
@brief Inquiry modes
|
||||
*/
|
||||
typedef enum {
|
||||
INQUIRY_MODE_STANDARD = 0,
|
||||
INQUIRY_MODE_RSSI,
|
||||
INQUIRY_MODE_RSSI_AND_EIR,
|
||||
} inquiry_mode_t;
|
||||
|
||||
/**
|
||||
@brief Page Scan Types
|
||||
*/
|
||||
typedef enum {
|
||||
PAGE_SCAN_MODE_STANDARD = 0,
|
||||
PAGE_SCAN_MODE_INTERLACED,
|
||||
} page_scan_type_t;
|
||||
|
||||
/**
|
||||
@brief Inquiry Scan Types
|
||||
*/
|
||||
typedef enum {
|
||||
INQUIRY_SCAN_MODE_STANDARD = 0,
|
||||
INQUIRY_SCAN_MODE_INTERLACED,
|
||||
} inquiry_scan_type_t;
|
||||
|
||||
/**
|
||||
Link Supervision Timeout Default, 0x7d00 * 0.625ms = 20s
|
||||
*/
|
||||
#define HCI_LINK_SUPERVISION_TIMEOUT_DEFAULT 0x7D00
|
||||
|
||||
/**
|
||||
Service Type used for QoS Setup and Flow Specification
|
||||
*/
|
||||
typedef enum {
|
||||
HCI_SERVICE_TYPE_NO_TRAFFIC = 0,
|
||||
HCI_SERVICE_TYPE_BEST_EFFORT,
|
||||
HCI_SERVICE_TYPE_GUARANTEED,
|
||||
HCI_SERVICE_TYPE_INVALID,
|
||||
} hci_service_type_t;
|
||||
|
||||
/**
|
||||
HCI Transport
|
||||
*/
|
||||
|
||||
/**
|
||||
packet types - used in BTstack and over the H4 UART interface
|
||||
*/
|
||||
#define HCI_COMMAND_DATA_PACKET 0x01
|
||||
#define HCI_ACL_DATA_PACKET 0x02
|
||||
#define HCI_SCO_DATA_PACKET 0x03
|
||||
#define HCI_EVENT_PACKET 0x04
|
||||
#define HCI_ISO_DATA_PACKET 0x05
|
||||
|
||||
/**
|
||||
Other assigned numbers, Assigned_Numbers_Host Controller Interface.pdf
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
HCI_AUDIO_CODING_FORMAT_U_LAW_LOG = 0x00,
|
||||
HCI_AUDIO_CODING_FORMAT_A_LAW_LOG,
|
||||
HCI_AUDIO_CODING_FORMAT_CVSD,
|
||||
HCI_AUDIO_CODING_FORMAT_TRANSPARENT, // Indicates that the controller does not do any transcoding or resampling. This is also used for test mode.
|
||||
HCI_AUDIO_CODING_FORMAT_LINEAR_PCM,
|
||||
HCI_AUDIO_CODING_FORMAT_MSBC,
|
||||
HCI_AUDIO_CODING_FORMAT_LC3,
|
||||
HCI_AUDIO_CODING_FORMAT_G_729A,
|
||||
HCI_AUDIO_CODING_FORMAT_RFU,
|
||||
HCI_AUDIO_CODING_FORMAT_VENDOR_SPECIFIC = 0xFF
|
||||
} hci_audio_coding_format_t;
|
||||
|
||||
/**
|
||||
HCI Layer
|
||||
*/
|
||||
|
||||
//
|
||||
// Error Codes rfom Bluetooth Core Specification
|
||||
//
|
||||
|
||||
/* ENUM_START: BLUETOOTH_ERROR_CODE */
|
||||
#define ERROR_CODE_SUCCESS 0x00
|
||||
#define ERROR_CODE_UNKNOWN_HCI_COMMAND 0x01
|
||||
#define ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02
|
||||
#define ERROR_CODE_HARDWARE_FAILURE 0x03
|
||||
#define ERROR_CODE_PAGE_TIMEOUT 0x04
|
||||
#define ERROR_CODE_AUTHENTICATION_FAILURE 0x05
|
||||
#define ERROR_CODE_PIN_OR_KEY_MISSING 0x06
|
||||
#define ERROR_CODE_MEMORY_CAPACITY_EXCEEDED 0x07
|
||||
#define ERROR_CODE_CONNECTION_TIMEOUT 0x08
|
||||
#define ERROR_CODE_CONNECTION_LIMIT_EXCEEDED 0x09
|
||||
#define ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED 0x0A
|
||||
#define ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS 0x0B
|
||||
#define ERROR_CODE_COMMAND_DISALLOWED 0x0C
|
||||
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
|
||||
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS 0x0E
|
||||
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR 0x0F
|
||||
#define ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED 0x10
|
||||
#define ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11
|
||||
#define ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS 0x12
|
||||
#define ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION 0x13
|
||||
#define ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES 0x14
|
||||
#define ERROR_CODE_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF 0x15
|
||||
#define ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16
|
||||
#define ERROR_CODE_REPEATED_ATTEMPTS 0x17
|
||||
#define ERROR_CODE_PAIRING_NOT_ALLOWED 0x18
|
||||
#define ERROR_CODE_UNKNOWN_LMP_PDU 0x19
|
||||
#define ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE_UNSUPPORTED_LMP_FEATURE 0x1A
|
||||
#define ERROR_CODE_SCO_OFFSET_REJECTED 0x1B
|
||||
#define ERROR_CODE_SCO_INTERVAL_REJECTED 0x1C
|
||||
#define ERROR_CODE_SCO_AIR_MODE_REJECTED 0x1D
|
||||
#define ERROR_CODE_INVALID_LMP_PARAMETERS_INVALID_LL_PARAMETERS 0x1E
|
||||
#define ERROR_CODE_UNSPECIFIED_ERROR 0x1F
|
||||
#define ERROR_CODE_UNSUPPORTED_LMP_PARAMETER_VALUE_UNSUPPORTED_LL_PARAMETER_VALUE 0x20
|
||||
#define ERROR_CODE_ROLE_CHANGE_NOT_ALLOWED 0x21
|
||||
#define ERROR_CODE_LMP_RESPONSE_TIMEOUT_LL_RESPONSE_TIMEOUT 0x22
|
||||
#define ERROR_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23
|
||||
#define ERROR_CODE_LMP_PDU_NOT_ALLOWED 0x24
|
||||
#define ERROR_CODE_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25
|
||||
#define ERROR_CODE_LINK_KEY_CANNOT_BE_CHANGED 0x26
|
||||
#define ERROR_CODE_REQUESTED_QOS_NOT_SUPPORTED 0x27
|
||||
#define ERROR_CODE_INSTANT_PASSED 0x28
|
||||
#define ERROR_CODE_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29
|
||||
#define ERROR_CODE_DIFFERENT_TRANSACTION_COLLISION 0x2A
|
||||
#define ERROR_CODE_RESERVED 0x2B
|
||||
#define ERROR_CODE_QOS_UNACCEPTABLE_PARAMETER 0x2C
|
||||
#define ERROR_CODE_QOS_REJECTED 0x2D
|
||||
#define ERROR_CODE_CHANNEL_CLASSIFICATION_NOT_SUPPORTED 0x2E
|
||||
#define ERROR_CODE_INSUFFICIENT_SECURITY 0x2F
|
||||
#define ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30
|
||||
// #define ERROR_CODE_RESERVED
|
||||
#define ERROR_CODE_ROLE_SWITCH_PENDING 0x32
|
||||
// #define ERROR_CODE_RESERVED
|
||||
#define ERROR_CODE_RESERVED_SLOT_VIOLATION 0x34
|
||||
#define ERROR_CODE_ROLE_SWITCH_FAILED 0x35
|
||||
#define ERROR_CODE_EXTENDED_INQUIRY_RESPONSE_TOO_LARGE 0x36
|
||||
#define ERROR_CODE_SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST 0x37
|
||||
#define ERROR_CODE_HOST_BUSY_PAIRING 0x38
|
||||
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND 0x39
|
||||
#define ERROR_CODE_CONTROLLER_BUSY 0x3A
|
||||
#define ERROR_CODE_UNACCEPTABLE_CONNECTION_PARAMETERS 0x3B
|
||||
#define ERROR_CODE_DIRECTED_ADVERTISING_TIMEOUT 0x3C
|
||||
#define ERROR_CODE_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE 0x3D
|
||||
#define ERROR_CODE_CONNECTION_FAILED_TO_BE_ESTABLISHED 0x3E
|
||||
#define ERROR_CODE_MAC_CONNECTION_FAILED 0x3F
|
||||
#define ERROR_CODE_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING 0x40
|
||||
|
||||
// BTstack defined ERRORS, mapped into BLuetooth status code range
|
||||
|
||||
#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED 0x50
|
||||
#define BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH 0x51
|
||||
#define BTSTACK_ACTIVATION_POWERON_FAILED 0x52
|
||||
#define BTSTACK_ACTIVATION_FAILED_UNKNOWN 0x53
|
||||
#define BTSTACK_NOT_ACTIVATED 0x54
|
||||
#define BTSTACK_BUSY 0x55
|
||||
#define BTSTACK_MEMORY_ALLOC_FAILED 0x56
|
||||
#define BTSTACK_ACL_BUFFERS_FULL 0x57
|
||||
|
||||
// l2cap errors - enumeration by the command that created them
|
||||
#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60
|
||||
#define L2CAP_COMMAND_REJECT_REASON_SIGNALING_MTU_EXCEEDED 0x61
|
||||
#define L2CAP_COMMAND_REJECT_REASON_INVALID_CID_IN_REQUEST 0x62
|
||||
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL 0x63
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_PENDING 0x64
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_PSM 0x65
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY 0x66
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES 0x67
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_ERTM_NOT_SUPPORTED 0x68
|
||||
|
||||
// should be L2CAP_CONNECTION_RTX_TIMEOUT
|
||||
#define L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT 0x69
|
||||
#define L2CAP_CONNECTION_BASEBAND_DISCONNECT 0x6A
|
||||
#define L2CAP_SERVICE_ALREADY_REGISTERED 0x6B
|
||||
#define L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU 0x6C
|
||||
#define L2CAP_SERVICE_DOES_NOT_EXIST 0x6D
|
||||
#define L2CAP_LOCAL_CID_DOES_NOT_EXIST 0x6E
|
||||
#define L2CAP_CONNECTION_RESPONSE_UNKNOWN_ERROR 0x6F
|
||||
|
||||
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
|
||||
#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71
|
||||
#define RFCOMM_NO_OUTGOING_CREDITS 0x72
|
||||
#define RFCOMM_AGGREGATE_FLOW_OFF 0x73
|
||||
#define RFCOMM_DATA_LEN_EXCEEDS_MTU 0x74
|
||||
|
||||
#define HFP_REMOTE_REJECTS_AUDIO_CONNECTION 0x7F
|
||||
|
||||
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
|
||||
#define SDP_QUERY_INCOMPLETE 0x81
|
||||
#define SDP_SERVICE_NOT_FOUND 0x82
|
||||
#define SDP_HANDLE_INVALID 0x83
|
||||
#define SDP_QUERY_BUSY 0x84
|
||||
|
||||
#define ATT_HANDLE_VALUE_INDICATION_IN_PROGRESS 0x90
|
||||
#define ATT_HANDLE_VALUE_INDICATION_TIMEOUT 0x91
|
||||
#define ATT_HANDLE_VALUE_INDICATION_DISCONNECT 0x92
|
||||
|
||||
#define GATT_CLIENT_NOT_CONNECTED 0x93
|
||||
#define GATT_CLIENT_BUSY 0x94
|
||||
#define GATT_CLIENT_IN_WRONG_STATE 0x95
|
||||
#define GATT_CLIENT_DIFFERENT_CONTEXT_FOR_ADDRESS_ALREADY_EXISTS 0x96
|
||||
#define GATT_CLIENT_VALUE_TOO_LONG 0x97
|
||||
#define GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED 0x98
|
||||
#define GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED 0x99
|
||||
|
||||
#define BNEP_SERVICE_ALREADY_REGISTERED 0xA0
|
||||
#define BNEP_CHANNEL_NOT_CONNECTED 0xA1
|
||||
#define BNEP_DATA_LEN_EXCEEDS_MTU 0xA2
|
||||
|
||||
// OBEX ERRORS
|
||||
#define OBEX_UNKNOWN_ERROR 0xB0
|
||||
#define OBEX_CONNECT_FAILED 0xB1
|
||||
#define OBEX_DISCONNECTED 0xB2
|
||||
#define OBEX_NOT_FOUND 0xB3
|
||||
#define OBEX_NOT_ACCEPTABLE 0xB4
|
||||
#define OBEX_ABORTED 0xB5
|
||||
|
||||
#define MESH_ERROR_APPKEY_INDEX_INVALID 0xD0
|
||||
/* ENUM_END */
|
||||
|
||||
|
||||
/* ENUM_START: AVRCP_BROWSING_ERROR_CODE */
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND 0x00 // Sent if TG received a PDU that it did not understand. Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INVALID_PARAMETER 0x01 // Sent if the TG received a PDU with a parameter ID that it did not understand. Sent if there is only one parameter ID in the PDU. Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_SPECIFIED_PARAMETER_NOT_FOUND 0x02 // Sent if the parameter ID is understood, but content is wrong or corrupted. Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INTERNAL_ERROR 0x03 // Sent if there are error conditions not covered by a more specific error code. Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_SUCCESS 0x04 // This is the status that should be returned if the operation was successful. Valid for All except where the response CType is AV/C REJECTED.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_UID_CHANGED 0x05 // The UIDs on the device have changed. Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_RESERVED_06 0x06 // Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INVALID_DIRECTION 0x07 // The Direction parameter is invalid. Valid for Change Path.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_NOT_A_DIRECTORY 0x08 // The UID provided does not refer to a folder item. Valid for Change Path.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_DOES_NOT_EXIST 0x09 // The UID provided does not refer to any currently valid. Valid for Change Path, PlayItem, AddToNowPlaying, GetItemAttributes.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INVALID_SCOPE 0x0a // The scope parameter is invalid. Valid for GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes,.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_RANGE_OUT_OF_BOUNDS 0x0b // The start of range provided is not valid. Valid for GetFolderItems.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_UID_IS_A_DIRECTORY 0x0c // The UID provided refers to a directory, which cannot be handled by this media player. Valid for PlayItem, AddToNowPlaying.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_MEDIA_IN_USES 0x0d // The media is not able to be used for this operation at this time. Valid for PlayItem, AddToNowPlaying.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_NOW_PLAYING_LIST_FULL 0x0e // No more items can be added to the Now Playing List. Valid for AddToNowPlaying.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_SEARCH_NOT_SUPPORTED 0x0f // The Browsed Media Player does not support search. Valid for Search.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_SEARCH_IN_PROGRESS 0x10 // A search operation is already in progress. Valid for Search.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_INVALID_PLAYER_ID 0x11 // The specified Player Id does not refer to a valid player. Valid for SetAddressedPlayer, SetBrowsedPlayer.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_PLAYER_NOT_BROWSABLE 0x12 // The Player Id supplied refers to a Media Player which does not support browsing. Valid for SetBrowsedPlayer.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_PLAYER_NOT_ADDRESSED 0x13 // The Player Id supplied refers to a player which is not currently addressed, and the command is not able to be performed if the player is not set as addressed. Valid for Search SetBrowsedPlayer.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_NO_VALID_SEARCH_RESULTS 0x14 // The Search result list does not contain valid entries, e.g. after being invalidated due to change of browsed player. Valid for GetFolderItems.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_NO_AVAILABLE_PLAYERS 0x15 // Valid for All.
|
||||
#define AVRCP_BROWSING_ERROR_CODE_ADDRESSED_PLAYER_CHANGED 0x16 // Valid for Register Notification.
|
||||
// 0x17-0xff Reserved
|
||||
/* ENUM_END */
|
||||
|
||||
// HCI roles
|
||||
typedef enum {
|
||||
HCI_ROLE_MASTER = 0,
|
||||
HCI_ROLE_SLAVE = 1,
|
||||
HCI_ROLE_INVALID = 0xff,
|
||||
} hci_role_t;
|
||||
|
||||
// packet sizes (max payload)
|
||||
#define HCI_ACL_DM1_SIZE 17
|
||||
#define HCI_ACL_DH1_SIZE 27
|
||||
#define HCI_ACL_2DH1_SIZE 54
|
||||
#define HCI_ACL_3DH1_SIZE 83
|
||||
#define HCI_ACL_DM3_SIZE 121
|
||||
#define HCI_ACL_DH3_SIZE 183
|
||||
#define HCI_ACL_DM5_SIZE 224
|
||||
#define HCI_ACL_DH5_SIZE 339
|
||||
#define HCI_ACL_2DH3_SIZE 367
|
||||
#define HCI_ACL_3DH3_SIZE 552
|
||||
#define HCI_ACL_2DH5_SIZE 679
|
||||
#define HCI_ACL_3DH5_SIZE 1021
|
||||
#define HCI_SCO_HV1_SIZE 10
|
||||
#define HCI_SCO_HV2_SIZE 20
|
||||
#define HCI_SCO_HV3_SIZE 30
|
||||
#define HCI_SCO_EV3_SIZE 30
|
||||
#define HCI_SCO_EV4_SIZE 120
|
||||
#define HCI_SCO_EV5_SIZE 180
|
||||
#define HCI_SCO_2EV3_SIZE 60
|
||||
#define HCI_SCO_2EV5_SIZE 360
|
||||
#define HCI_SCO_3EV3_SIZE 90
|
||||
#define HCI_SCO_3EV5_SIZE 540
|
||||
|
||||
#define LE_ADVERTISING_DATA_SIZE 31
|
||||
#define LE_EXTENDED_ADVERTISING_DATA_SIZE 229
|
||||
#define LE_EXTENDED_ADVERTISING_MAX_HANDLE 0xEFu
|
||||
#define LE_EXTENDED_ADVERTISING_MAX_CHUNK_LEN 251
|
||||
|
||||
// advertising event properties for extended advertising
|
||||
#define LE_ADVERTISING_PROPERTIES_CONNECTABLE (1u<<0)
|
||||
#define LE_ADVERTISING_PROPERTIES_SCANNABLE (1u<<1)
|
||||
#define LE_ADVERTISING_PROPERTIES_DIRECTED (1u<<2)
|
||||
#define LE_ADVERTISING_PROPERTIES_HIGH_DUTY_CYCLE (1u<<3)
|
||||
#define LE_ADVERTISING_PROPERTIES_LEGACY (1u<<4)
|
||||
#define LE_ADVERTISING_PROPERTIES_ANONYMOUS (1u<<5)
|
||||
#define LE_ADVERTISING_PROPERTIES_INCLUDE_TX_POWER (1u<<6)
|
||||
|
||||
|
||||
// SCO Packet Types
|
||||
#define SCO_PACKET_TYPES_NONE 0x0000
|
||||
#define SCO_PACKET_TYPES_HV1 0x0001
|
||||
#define SCO_PACKET_TYPES_HV2 0x0002
|
||||
#define SCO_PACKET_TYPES_HV3 0x0004
|
||||
#define SCO_PACKET_TYPES_EV3 0x0008
|
||||
#define SCO_PACKET_TYPES_EV4 0x0010
|
||||
#define SCO_PACKET_TYPES_EV5 0x0020
|
||||
#define SCO_PACKET_TYPES_2EV3 0x0040
|
||||
#define SCO_PACKET_TYPES_3EV3 0x0080
|
||||
#define SCO_PACKET_TYPES_2EV5 0x0100
|
||||
#define SCO_PACKET_TYPES_3EV5 0x0200
|
||||
#define SCO_PACKET_TYPES_ALL 0x03FF
|
||||
#define SCO_PACKET_TYPES_SCO 0x0007
|
||||
#define SCO_PACKET_TYPES_ESCO 0x03F8
|
||||
|
||||
// Link Policy Settings
|
||||
#define LM_LINK_POLICY_DISABLE_ALL_LM_MODES 0
|
||||
#define LM_LINK_POLICY_ENABLE_ROLE_SWITCH 1
|
||||
#define LM_LINK_POLICY_ENABLE_HOLD_MODE 2
|
||||
#define LM_LINK_POLICY_ENABLE_SNIFF_MODE 4
|
||||
|
||||
// ACL Connection Modes
|
||||
#define ACL_CONNECTION_MODE_ACTIVE 0
|
||||
#define ACL_CONNECTION_MODE_HOLD 1
|
||||
#define ACL_CONNECTION_MODE_SNIFF 2
|
||||
|
||||
/**
|
||||
Default INQ Mode
|
||||
*/
|
||||
#define GAP_IAC_GENERAL_INQUIRY 0x9E8B33L // General/Unlimited Inquiry Access Code (GIAC)
|
||||
#define GAP_IAC_LIMITED_INQUIRY 0x9E8B00L // Limited Dedicated Inquiry Access Code (LIAC)
|
||||
|
||||
/**
|
||||
SSP IO Capabilities
|
||||
*/
|
||||
#define SSP_IO_CAPABILITY_DISPLAY_ONLY 0
|
||||
#define SSP_IO_CAPABILITY_DISPLAY_YES_NO 1
|
||||
#define SSP_IO_CAPABILITY_KEYBOARD_ONLY 2
|
||||
#define SSP_IO_CAPABILITY_NO_INPUT_NO_OUTPUT 3
|
||||
#define SSP_IO_CAPABILITY_UNKNOWN 0xff
|
||||
|
||||
|
||||
/**
|
||||
SSP Authentication Requirements, see IO Capability Request Reply Command
|
||||
*/
|
||||
|
||||
// Numeric comparison with automatic accept allowed.
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_NO_BONDING 0x00
|
||||
|
||||
// Use IO Capabilities to deter- mine authentication procedure
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_NO_BONDING 0x01
|
||||
|
||||
// Numeric compar- ison with automatic accept allowed.
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_DEDICATED_BONDING 0x02
|
||||
|
||||
// Use IO Capabilities to determine authentication procedure
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_DEDICATED_BONDING 0x03
|
||||
|
||||
// Numeric Compari- son with automatic accept allowed.
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_NOT_REQUIRED_GENERAL_BONDING 0x04
|
||||
|
||||
// Use IO capabilities to determine authentication procedure.
|
||||
#define SSP_IO_AUTHREQ_MITM_PROTECTION_REQUIRED_GENERAL_BONDING 0x05
|
||||
|
||||
|
||||
// OGFs
|
||||
#define OGF_LINK_CONTROL 0x01
|
||||
#define OGF_LINK_POLICY 0x02
|
||||
#define OGF_CONTROLLER_BASEBAND 0x03
|
||||
#define OGF_INFORMATIONAL_PARAMETERS 0x04
|
||||
#define OGF_STATUS_PARAMETERS 0x05
|
||||
#define OGF_TESTING 0x06
|
||||
#define OGF_LE_CONTROLLER 0x08
|
||||
#define OGF_VENDOR 0x3f
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
L2CAP Layer
|
||||
*/
|
||||
|
||||
#define L2CAP_HEADER_SIZE 4
|
||||
|
||||
// minimum signaling MTU
|
||||
#define L2CAP_MINIMAL_MTU 48
|
||||
#define L2CAP_DEFAULT_MTU 672
|
||||
|
||||
// Minimum/default MTU
|
||||
#define L2CAP_LE_DEFAULT_MTU 23
|
||||
|
||||
// L2CAP Fixed Channel IDs
|
||||
#define L2CAP_CID_SIGNALING 0x0001
|
||||
#define L2CAP_CID_CONNECTIONLESS_CHANNEL 0x0002
|
||||
#define L2CAP_CID_ATTRIBUTE_PROTOCOL 0x0004
|
||||
#define L2CAP_CID_SIGNALING_LE 0x0005
|
||||
#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
|
||||
#define L2CAP_CID_BR_EDR_SECURITY_MANAGER 0x0007
|
||||
|
||||
// L2CAP Channels in Basic and Enhanced Retransmission Mode
|
||||
|
||||
// connection response result
|
||||
#define L2CAP_CONNECTION_RESULT_SUCCESS 0x0000
|
||||
#define L2CAP_CONNECTION_RESULT_PENDING 0x0001
|
||||
#define L2CAP_CONNECTION_RESULT_PSM_NOT_SUPPORTED 0x0002
|
||||
#define L2CAP_CONNECTION_RESULT_SECURITY_BLOCK 0x0003
|
||||
#define L2CAP_CONNECTION_RESULT_NO_RESOURCES_AVAILABLE 0x0004
|
||||
#define L2CAP_CONNECTION_RESULT_INVALID_SOURCE_CID 0x0006
|
||||
#define L2CAP_CONNECTION_RESULT_SOURCE_CID_ALREADY_ALLOCATED 0x0007
|
||||
|
||||
// L2CAP Channels in LE Credit-Based Flow-Control Mode
|
||||
|
||||
// connection response result
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_SUCCESS 0x0000
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_SPSM_NOT_SUPPORTED 0x0002
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_NO_RESOURCES_AVAILABLE 0x0004
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_INSUFFICIENT_AUTHENTICATION 0x0005
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_INSUFFICIENT_AUTHORIZATION 0x0006
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_ENCYRPTION_KEY_SIZE_TOO_SHORT 0x0007
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_INSUFFICIENT_ENCRYPTION 0x0008
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_INVALID_SOURCE_CID 0x0009
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_SOURCE_CID_ALREADY_ALLOCATED 0x000A
|
||||
#define L2CAP_CBM_CONNECTION_RESULT_UNACCEPTABLE_PARAMETERS 0x000B
|
||||
|
||||
|
||||
// L2CAP Channels in Enhanced Credit-Based Flow-Control Mode
|
||||
|
||||
// number of CIDs in single connection+reconfiguration request/response
|
||||
#define L2CAP_ECBM_MAX_CID_ARRAY_SIZE 5
|
||||
|
||||
// connection response result
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_SUCCESS 0x0000
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_SPSM_NOT_SUPPORTED 0x0002
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_SOME_REFUSED_INSUFFICIENT_RESOURCES_AVAILABLE 0x0004
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_INSUFFICIENT_AUTHENTICATION 0x0005
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_INSUFFICIENT_AUTHORIZATION 0x0006
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_ENCYRPTION_KEY_SIZE_TOO_SHORT 0x0007
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_INSUFFICIENT_ENCRYPTION 0x0008
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_SOME_REFUSED_INVALID_SOURCE_CID 0x0009
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_SOME_REFUSED_SOURCE_CID_ALREADY_ALOCATED 0x000A
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_UNACCEPTABLE_PARAMETERS 0x000B
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_REFUSED_INVALID_PARAMETERS 0x000C
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_PENDING_NO_FURTHER_INFORMATION 0x000D
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_PENDING_AUTHENTICATION 0x000E
|
||||
#define L2CAP_ECBM_CONNECTION_RESULT_ALL_PENDING_AUTHORIZATION 0x000F
|
||||
|
||||
|
||||
// Result for Reconfigure Request
|
||||
#define L2CAP_ECBM_RECONFIGURE_SUCCESS 0
|
||||
#define L2CAP_ECBM_RECONFIGURE_FAILED_MTU_REDUCTION_NOT_ALLOWED 1
|
||||
#define L2CAP_ECBM_RECONFIGURE_FAILED_MPS_REDUCTION_MULTIPLE_CHANNELS 2
|
||||
#define L2CAP_ECBM_RECONFIGURE_FAILED_DESTINATION_CID_INVALID 3
|
||||
#define L2CAP_ECBM_RECONFIGURE_FAILED_UNACCEPTABLE_PARAMETERS 4
|
||||
|
||||
/**
|
||||
SDP Protocol
|
||||
*/
|
||||
|
||||
// Device Vendor ID Sources
|
||||
#define DEVICE_ID_VENDOR_ID_SOURCE_BLUETOOTH 0x0001
|
||||
#define DEVICE_ID_VENDOR_ID_SOURCE_USB 0x0002
|
||||
|
||||
// OBEX
|
||||
#define SDP_vCard_2_1 0x01
|
||||
#define SDP_vCard_3_0 0x02
|
||||
#define SDP_vCal_1_0 0x03
|
||||
#define SDP_iCal_2_0 0x04
|
||||
#define SDP_vNote 0x05
|
||||
#define SDP_vMessage 0x06
|
||||
#define SDP_OBEXFileTypeAny 0xFF
|
||||
|
||||
/**
|
||||
RFCOMM Protocol
|
||||
*/
|
||||
|
||||
// Line Status
|
||||
#define LINE_STATUS_NO_ERROR 0x00
|
||||
#define LINE_STATUS_OVERRUN_ERROR 0x03
|
||||
#define LINE_STATUS_PARITY_ERORR 0x05
|
||||
#define LINE_STATUS_FRAMING_ERROR 0x09
|
||||
|
||||
// Modem Status Flags
|
||||
#define MODEM_STATUS_FC 0x02
|
||||
#define MODEM_STATUS_RTC 0x04
|
||||
#define MODEM_STATUS_RTR 0x08
|
||||
#define MODEM_STATUS_IC 0x40
|
||||
#define MODEM_STATUS_DV 0x80
|
||||
|
||||
typedef enum rpn_baud {
|
||||
RPN_BAUD_2400 = 0,
|
||||
RPN_BAUD_4800,
|
||||
RPN_BAUD_7200,
|
||||
RPN_BAUD_9600,
|
||||
RPN_BAUD_19200,
|
||||
RPN_BAUD_38400,
|
||||
RPN_BAUD_57600,
|
||||
RPN_BAUD_115200,
|
||||
RPN_BAUD_230400
|
||||
} rpn_baud_t;
|
||||
|
||||
typedef enum rpn_data_bits {
|
||||
RPN_DATA_BITS_5 = 0,
|
||||
RPN_DATA_BITS_6 = 0,
|
||||
RPN_DATA_BITS_7 = 0,
|
||||
RPN_DATA_BITS_8 = 0
|
||||
} rpn_data_bits_t;
|
||||
|
||||
typedef enum rpn_stop_bits {
|
||||
RPN_STOP_BITS_1_0 = 0,
|
||||
RPN_STOP_BITS_1_5
|
||||
} rpn_stop_bits_t;
|
||||
|
||||
typedef enum rpn_parity {
|
||||
RPN_PARITY_NONE = 0,
|
||||
RPN_PARITY_ODD = 1,
|
||||
RPN_PARITY_EVEN = 3,
|
||||
RPN_PARITY_MARK = 5,
|
||||
RPN_PARITY_SPACE = 7,
|
||||
} rpn_parity_t;
|
||||
|
||||
#define RPN_FLOW_CONTROL_XONXOFF_ON_INPUT 0x01
|
||||
#define RPN_FLOW_CONTROL_XONXOFF_ON_OUTPUT 0x02
|
||||
#define RPN_FLOW_CONTROL_RTR_ON_INPUT 0x04
|
||||
#define RPN_FLOW_CONTROL_RTR_ON_OUTPUT 0x08
|
||||
#define RPN_FLOW_CONTROL_RTC_ON_INPUT 0x10
|
||||
#define RPN_FLOW_CONTROL_RTC_ON_OUTPUT 0x20
|
||||
|
||||
#define RPN_PARAM_MASK_0_BAUD 0x01
|
||||
#define RPN_PARAM_MASK_0_DATA_BITS 0x02
|
||||
#define RPN_PARAM_MASK_0_STOP_BITS 0x04
|
||||
#define RPN_PARAM_MASK_0_PARITY 0x08
|
||||
#define RPN_PARAM_MASK_0_PARITY_TYPE 0x10
|
||||
#define RPN_PARAM_MASK_0_XON_CHAR 0x20
|
||||
#define RPN_PARAM_MASK_0_XOFF_CHAR 0x40
|
||||
#define RPN_PARAM_MASK_0_RESERVED 0x80
|
||||
|
||||
// @note: values are identical to rpn_flow_control_t
|
||||
#define RPN_PARAM_MASK_1_XONOFF_ON_INPUT 0x01
|
||||
#define RPN_PARAM_MASK_1_XONOFF_ON_OUTPUT 0x02
|
||||
#define RPN_PARAM_MASK_1_RTR_ON_INPUT 0x04
|
||||
#define RPN_PARAM_MASK_1_RTR_ON_OUTPUT 0x08
|
||||
#define RPN_PARAM_MASK_1_RTC_ON_INPUT 0x10
|
||||
#define RPN_PARAM_MASK_1_RTC_ON_OUTPUT 0x20
|
||||
#define RPN_PARAM_MASK_1_RESERVED_0 0x40
|
||||
#define RPN_PARAM_MASK_1_RESERVED_1 0x80
|
||||
|
||||
/**
|
||||
BNEP Protocol
|
||||
*/
|
||||
|
||||
#ifndef ETHER_ADDR_LEN
|
||||
#define ETHER_ADDR_LEN 6
|
||||
#endif
|
||||
|
||||
#ifndef ETHERTYPE_VLAN
|
||||
#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tag */
|
||||
#endif
|
||||
|
||||
#define BNEP_MTU_MIN 1691
|
||||
|
||||
|
||||
/**
|
||||
PAN Profile
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
BNEP_SECURITY_NONE = 0x0000,
|
||||
BNEP_SECURITY_SERVICE_LEVEL_ENFORCED,
|
||||
BNEP_SECURITY_802_1X
|
||||
} security_description_t;
|
||||
|
||||
typedef enum {
|
||||
PAN_NET_ACCESS_TYPE_PSTN = 0x0000,
|
||||
PAN_NET_ACCESS_TYPE_ISDN,
|
||||
PAN_NET_ACCESS_TYPE_DSL,
|
||||
PAN_NET_ACCESS_TYPE_CABLE_MODEM,
|
||||
PAN_NET_ACCESS_TYPE_10MB_ETHERNET,
|
||||
PAN_NET_ACCESS_TYPE_100MB_ETHERNET,
|
||||
PAN_NET_ACCESS_TYPE_4MB_TOKEN_RING,
|
||||
PAN_NET_ACCESS_TYPE_16MB_TOKEN_RING,
|
||||
PAN_NET_ACCESS_TYPE_100MB_TOKEN_RING,
|
||||
PAN_NET_ACCESS_TYPE_FDDI,
|
||||
PAN_NET_ACCESS_TYPE_GSM,
|
||||
PAN_NET_ACCESS_TYPE_CDMA,
|
||||
PAN_NET_ACCESS_TYPE_GPRS,
|
||||
PAN_NET_ACCESS_TYPE_3G,
|
||||
PAN_NET_ACCESS_TYPE_CELULAR,
|
||||
PAN_NET_ACCESS_TYPE_OTHER = 0xFFFE,
|
||||
PAN_NET_ACCESS_TYPE_NONE
|
||||
} net_access_type_t;
|
||||
|
||||
/**
|
||||
ATT
|
||||
*/
|
||||
|
||||
// Minimum/default MTU
|
||||
#define ATT_DEFAULT_MTU 23
|
||||
|
||||
// MARK: ATT Error Codes
|
||||
#define ATT_ERROR_SUCCESS 0x00
|
||||
#define ATT_ERROR_INVALID_HANDLE 0x01
|
||||
#define ATT_ERROR_READ_NOT_PERMITTED 0x02
|
||||
#define ATT_ERROR_WRITE_NOT_PERMITTED 0x03
|
||||
#define ATT_ERROR_INVALID_PDU 0x04
|
||||
#define ATT_ERROR_INSUFFICIENT_AUTHENTICATION 0x05
|
||||
#define ATT_ERROR_REQUEST_NOT_SUPPORTED 0x06
|
||||
#define ATT_ERROR_INVALID_OFFSET 0x07
|
||||
#define ATT_ERROR_INSUFFICIENT_AUTHORIZATION 0x08
|
||||
#define ATT_ERROR_PREPARE_QUEUE_FULL 0x09
|
||||
#define ATT_ERROR_ATTRIBUTE_NOT_FOUND 0x0a
|
||||
#define ATT_ERROR_ATTRIBUTE_NOT_LONG 0x0b
|
||||
#define ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE 0x0c
|
||||
#define ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH 0x0d
|
||||
#define ATT_ERROR_UNLIKELY_ERROR 0x0e
|
||||
#define ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0f
|
||||
#define ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
|
||||
#define ATT_ERROR_INSUFFICIENT_RESOURCES 0x11
|
||||
#define ATT_ERROR_VALUE_NOT_ALLOWED 0x13
|
||||
|
||||
// MARK: ATT Error Codes defined by BTstack
|
||||
#define ATT_ERROR_HCI_DISCONNECT_RECEIVED 0x1f
|
||||
#define ATT_ERROR_BONDING_INFORMATION_MISSING 0x70
|
||||
#define ATT_ERROR_DATA_MISMATCH 0x7e
|
||||
#define ATT_ERROR_TIMEOUT 0x7F
|
||||
#define ATT_ERROR_WRITE_RESPONSE_PENDING 0x100
|
||||
|
||||
// MARK: ATT Error Codes from Bluetooth Core Specification Supplement, Version 9 or later
|
||||
#define ATT_ERROR_WRITE_REQUEST_REJECTED 0xFC
|
||||
#define ATT_ERROR_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_IMPROPERLY_CONFIGURED 0xFD
|
||||
#define ATT_ERROR_PROCEDURE_ALREADY_IN_PROGRESS 0xFE
|
||||
#define ATT_ERROR_OUT_OF_RANGE 0xFF
|
||||
|
||||
// MARK: ATT Error Codes from Cycling Power Service spec
|
||||
#define CYCLING_POWER_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS 0x80
|
||||
#define CYCLING_POWER_ERROR_CODE_PROCEDURE_ALREADY_IN_PROGRESS 0xFE
|
||||
#define CYCLING_POWER_ERROR_CODE_CCC_DESCRIPTOR_IMPROPERLY_CONFIGURED 0xFD
|
||||
|
||||
// MARK: ATT Error Codes from Cycling Speed and Cadence Service spec
|
||||
#define CYCLING_SPEED_AND_CADENCE_ERROR_CODE_PROCEDURE_ALREADY_IN_PROGRESS 0x80
|
||||
#define CYCLING_SPEED_AND_CADENCE_ERROR_CODE_CCC_DESCRIPTOR_IMPROPERLY_CONFIGURED 0x81
|
||||
|
||||
|
||||
// MARK: Attribute Property Flags
|
||||
#define ATT_PROPERTY_BROADCAST 0x01
|
||||
#define ATT_PROPERTY_READ 0x02
|
||||
#define ATT_PROPERTY_WRITE_WITHOUT_RESPONSE 0x04
|
||||
#define ATT_PROPERTY_WRITE 0x08
|
||||
#define ATT_PROPERTY_NOTIFY 0x10
|
||||
#define ATT_PROPERTY_INDICATE 0x20
|
||||
#define ATT_PROPERTY_AUTHENTICATED_SIGNED_WRITE 0x40
|
||||
#define ATT_PROPERTY_EXTENDED_PROPERTIES 0x80
|
||||
|
||||
// MARK: Attribute Property Flag, BTstack extension
|
||||
// value is asked from client
|
||||
#define ATT_PROPERTY_DYNAMIC 0x100
|
||||
|
||||
// Security levels
|
||||
#define ATT_SECURITY_NONE 0
|
||||
#define ATT_SECURITY_ENCRYPTED 1
|
||||
#define ATT_SECURITY_AUTHENTICATED 2
|
||||
#define ATT_SECURITY_AUTHORIZED 3
|
||||
#define ATT_SECURITY_AUTHENTICATED_SC 4
|
||||
|
||||
// ATT Transaction Timeout of 30 seconds for Command/Response or Indication/Confirmation
|
||||
#define ATT_TRANSACTION_TIMEOUT_MS 30000
|
||||
|
||||
#define ATT_TRANSACTION_MODE_NONE 0x0
|
||||
#define ATT_TRANSACTION_MODE_ACTIVE 0x1
|
||||
#define ATT_TRANSACTION_MODE_EXECUTE 0x2
|
||||
#define ATT_TRANSACTION_MODE_CANCEL 0x3
|
||||
#define ATT_TRANSACTION_MODE_VALIDATE 0x4
|
||||
|
||||
// MARK: GATT UUIDs
|
||||
#define GATT_PRIMARY_SERVICE_UUID 0x2800
|
||||
#define GATT_SECONDARY_SERVICE_UUID 0x2801
|
||||
#define GATT_INCLUDE_SERVICE_UUID 0x2802
|
||||
#define GATT_CHARACTERISTICS_UUID 0x2803
|
||||
#define GATT_CHARACTERISTIC_EXTENDED_PROPERTIES 0x2900
|
||||
#define GATT_CHARACTERISTIC_USER_DESCRIPTION 0x2901
|
||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION 0x2902
|
||||
#define GATT_SERVER_CHARACTERISTICS_CONFIGURATION 0x2903
|
||||
#define GATT_CHARACTERISTIC_PRESENTATION_FORMAT 0x2904
|
||||
#define GATT_CHARACTERISTIC_AGGREGATE_FORMAT 0x2905
|
||||
#define GATT_CLIENT_SUPPORTED_FEATURES 0x2B29
|
||||
#define GATT_SERVER_SUPPORTED_FEATURES 0x2B3A
|
||||
|
||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NONE 0
|
||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION 1
|
||||
#define GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION 2
|
||||
|
||||
#define GATT_CLIENT_ANY_CONNECTION 0xffff
|
||||
#define GATT_CLIENT_ANY_VALUE_HANDLE 0x0000
|
||||
|
||||
// GAP Service and Characteristics
|
||||
#define GAP_SERVICE_UUID 0x1800
|
||||
#define GAP_DEVICE_NAME_UUID 0x2a00
|
||||
#define GAP_APPEARANCE_UUID 0x2a01
|
||||
#define GAP_PERIPHERAL_PRIVACY_FLAG 0x2a02
|
||||
#define GAP_RECONNECTION_ADDRESS_UUID 0x2a03
|
||||
#define GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS_UUID 0x2a04
|
||||
#define GAP_SERVICE_CHANGED 0x2a05
|
||||
|
||||
// Bluetooth GATT types
|
||||
|
||||
typedef struct {
|
||||
uint16_t year; // 0 - year is not known; or [1582,9999]
|
||||
uint8_t month; // 0 - month is not known; or [1,12]
|
||||
uint8_t day; // 0 - day is not known; or [1,31]
|
||||
uint8_t hours; // [0,23]
|
||||
uint8_t minutes; // [0,59]
|
||||
uint8_t seconds; // [0,59]
|
||||
} gatt_date_time_t;
|
||||
|
||||
typedef enum {
|
||||
GATT_MICROPHONE_CONTROL_MUTE_OFF = 0x00,
|
||||
GATT_MICROPHONE_CONTROL_MUTE_ON,
|
||||
GATT_MICROPHONE_CONTROL_MUTE_DISABLED
|
||||
} gatt_microphone_control_mute_t;
|
||||
|
||||
/**
|
||||
SM - LE Security Manager
|
||||
*/
|
||||
// Bluetooth Spec definitions
|
||||
typedef enum {
|
||||
SM_CODE_PAIRING_REQUEST = 0X01,
|
||||
SM_CODE_PAIRING_RESPONSE,
|
||||
SM_CODE_PAIRING_CONFIRM,
|
||||
SM_CODE_PAIRING_RANDOM,
|
||||
SM_CODE_PAIRING_FAILED,
|
||||
SM_CODE_ENCRYPTION_INFORMATION,
|
||||
SM_CODE_MASTER_IDENTIFICATION,
|
||||
SM_CODE_IDENTITY_INFORMATION,
|
||||
SM_CODE_IDENTITY_ADDRESS_INFORMATION,
|
||||
SM_CODE_SIGNING_INFORMATION,
|
||||
SM_CODE_SECURITY_REQUEST,
|
||||
SM_CODE_PAIRING_PUBLIC_KEY,
|
||||
SM_CODE_PAIRING_DHKEY_CHECK,
|
||||
SM_CODE_KEYPRESS_NOTIFICATION,
|
||||
} SECURITY_MANAGER_COMMANDS;
|
||||
|
||||
// IO Capability Values
|
||||
typedef enum {
|
||||
IO_CAPABILITY_DISPLAY_ONLY = 0,
|
||||
IO_CAPABILITY_DISPLAY_YES_NO,
|
||||
IO_CAPABILITY_KEYBOARD_ONLY,
|
||||
IO_CAPABILITY_NO_INPUT_NO_OUTPUT,
|
||||
IO_CAPABILITY_KEYBOARD_DISPLAY, // not used by secure simple pairing
|
||||
} io_capability_t;
|
||||
|
||||
// Authentication requirement flags
|
||||
#define SM_AUTHREQ_NO_BONDING 0x00
|
||||
#define SM_AUTHREQ_BONDING 0x01
|
||||
#define SM_AUTHREQ_MITM_PROTECTION 0x04
|
||||
#define SM_AUTHREQ_SECURE_CONNECTION 0x08
|
||||
#define SM_AUTHREQ_KEYPRESS 0x10
|
||||
#define SM_AUTHREQ_CT2 0x20
|
||||
|
||||
// Key distribution flags used by spec
|
||||
#define SM_KEYDIST_ENC_KEY 0x01
|
||||
#define SM_KEYDIST_ID_KEY 0x02
|
||||
#define SM_KEYDIST_SIGN 0x04
|
||||
#define SM_KEYDIST_LINK_KEY 0x08
|
||||
|
||||
// Key distribution flags used internally
|
||||
#define SM_KEYDIST_FLAG_ENCRYPTION_INFORMATION 0x01
|
||||
#define SM_KEYDIST_FLAG_MASTER_IDENTIFICATION 0x02
|
||||
#define SM_KEYDIST_FLAG_IDENTITY_INFORMATION 0x04
|
||||
#define SM_KEYDIST_FLAG_IDENTITY_ADDRESS_INFORMATION 0x08
|
||||
#define SM_KEYDIST_FLAG_SIGNING_IDENTIFICATION 0x10
|
||||
|
||||
// STK Generation Methods
|
||||
#define SM_STK_GENERATION_METHOD_JUST_WORKS 0x01
|
||||
#define SM_STK_GENERATION_METHOD_OOB 0x02
|
||||
#define SM_STK_GENERATION_METHOD_PASSKEY 0x04
|
||||
#define SM_STK_GENERATION_METHOD_NUMERIC_COMPARISON 0x08
|
||||
|
||||
// Pairing Failed Reasons
|
||||
#define SM_REASON_RESERVED 0x00
|
||||
#define SM_REASON_PASSKEY_ENTRY_FAILED 0x01
|
||||
#define SM_REASON_OOB_NOT_AVAILABLE 0x02
|
||||
#define SM_REASON_AUTHENTHICATION_REQUIREMENTS 0x03
|
||||
#define SM_REASON_CONFIRM_VALUE_FAILED 0x04
|
||||
#define SM_REASON_PAIRING_NOT_SUPPORTED 0x05
|
||||
#define SM_REASON_ENCRYPTION_KEY_SIZE 0x06
|
||||
#define SM_REASON_COMMAND_NOT_SUPPORTED 0x07
|
||||
#define SM_REASON_UNSPECIFIED_REASON 0x08
|
||||
#define SM_REASON_REPEATED_ATTEMPTS 0x09
|
||||
#define SM_REASON_INVALID_PARAMETERS 0x0a
|
||||
#define SM_REASON_DHKEY_CHECK_FAILED 0x0b
|
||||
#define SM_REASON_NUMERIC_COMPARISON_FAILED 0x0c
|
||||
#define SM_REASON_BR_EDR_PAIRING_IN_PROGRESS 0x0d
|
||||
#define SM_REASON_CROSS_TRANSPORT_KEY_DERIVATION_NOT_ALLOWED 0x0e
|
||||
#define SM_REASON_KEY_REJECTED 0x0f
|
||||
|
||||
// also, invalid parameters
|
||||
// and reserved
|
||||
|
||||
// Keypress Notifications
|
||||
#define SM_KEYPRESS_PASSKEY_ENTRY_STARTED 0x00
|
||||
#define SM_KEYPRESS_PASSKEY_DIGIT_ENTERED 0x01
|
||||
#define SM_KEYPRESS_PASSKEY_DIGIT_ERASED 0x02
|
||||
#define SM_KEYPRESS_PASSKEY_CLEARED 0x03
|
||||
#define SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED 0x04
|
||||
|
||||
|
||||
#endif
|
||||
@@ -49,11 +49,15 @@ static uint32_t pico_flash_bank_get_alignment(void * context) {
|
||||
static void pico_flash_bank_erase(void * context, int bank) {
|
||||
(void)(context);
|
||||
DEBUG_PRINT("erase: bank %d\n", bank);
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE);
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) {
|
||||
@@ -147,11 +151,15 @@ static void pico_flash_bank_write(void * context, int bank, uint32_t offset, con
|
||||
offset = 0;
|
||||
|
||||
// Now program the entire page
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE);
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
Copyright (C) 2014 BlueKitchen GmbH
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
4. Any redistribution, use, or modification is done solely for
|
||||
personal benefit and not for any commercial purpose or for
|
||||
monetary gain.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
|
||||
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Please inquire about commercial licensing options at
|
||||
contact@bluekitchen-gmbh.com
|
||||
|
||||
*/
|
||||
|
||||
#if defined ENABLE_CLASSIC
|
||||
|
||||
#define BTSTACK_FILE__ "hids_device.c"
|
||||
|
||||
/**
|
||||
Implementation of the GATT HIDS Device
|
||||
To use with your application, add '#import <hids.gatt>' to your .gatt file
|
||||
*/
|
||||
|
||||
#include "hids_device.h"
|
||||
|
||||
#include "ble/att_db.h"
|
||||
#include "ble/att_server.h"
|
||||
#include "bluetooth_gatt.h"
|
||||
#include "btstack_util.h"
|
||||
#include "btstack_debug.h"
|
||||
|
||||
#define HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS 0x80
|
||||
|
||||
// storage for 'generic' HID Device with single Input, Output, and Feature Report
|
||||
static hids_device_report_t hid_reports_generic_storage[3];
|
||||
|
||||
typedef struct {
|
||||
uint16_t con_handle;
|
||||
|
||||
uint8_t hid_country_code;
|
||||
const uint8_t * hid_descriptor;
|
||||
uint16_t hid_descriptor_size;
|
||||
|
||||
uint16_t hid_report_map_handle;
|
||||
uint8_t hid_protocol_mode;
|
||||
uint16_t hid_protocol_mode_value_handle;
|
||||
|
||||
uint16_t hid_boot_mouse_input_value_handle;
|
||||
uint16_t hid_boot_mouse_input_client_configuration_handle;
|
||||
uint16_t hid_boot_mouse_input_client_configuration_value;
|
||||
|
||||
uint16_t hid_boot_keyboard_input_value_handle;
|
||||
uint16_t hid_boot_keyboard_input_client_configuration_handle;
|
||||
uint16_t hid_boot_keyboard_input_client_configuration_value;
|
||||
|
||||
hids_device_report_t * hid_reports;
|
||||
|
||||
uint8_t hid_input_reports_num;
|
||||
uint8_t hid_output_reports_num;
|
||||
uint8_t hid_feature_reports_num;
|
||||
|
||||
uint16_t hid_control_point_value_handle;
|
||||
uint8_t hid_control_point_suspend;
|
||||
|
||||
btstack_context_callback_registration_t battery_callback;
|
||||
} hids_device_t;
|
||||
|
||||
static hids_device_t hids_device;
|
||||
|
||||
static btstack_packet_handler_t packet_handler;
|
||||
static att_service_handler_t hid_service;
|
||||
|
||||
// TODO: store hids device connection into list
|
||||
static hids_device_t * hids_device_get_instance_for_con_handle(uint16_t con_handle) {
|
||||
UNUSED(con_handle);
|
||||
return &hids_device;
|
||||
}
|
||||
|
||||
static hids_device_t * hids_device_create_instance(void) {
|
||||
memset(&hids_device, 0, sizeof(hids_device_t));
|
||||
return &hids_device;
|
||||
}
|
||||
|
||||
static hids_device_report_t * hids_device_get_report_for_client_configuration_handle(hids_device_t * device, uint16_t client_configuration_handle) {
|
||||
uint8_t pos;
|
||||
uint8_t total_reports = device->hid_input_reports_num + device->hid_output_reports_num + device->hid_feature_reports_num;
|
||||
for (pos = 0 ; pos < total_reports ; pos++) {
|
||||
if (device->hid_reports[pos].client_configuration_handle == client_configuration_handle) {
|
||||
return &device->hid_reports[pos];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hids_device_report_t *
|
||||
hids_device_get_report_for_id_and_type(hids_device_t *device, uint16_t report_id, hid_report_type_t type) {
|
||||
uint8_t pos;
|
||||
uint8_t total_reports = device->hid_input_reports_num + device->hid_output_reports_num + device->hid_feature_reports_num;
|
||||
for (pos = 0 ; pos < total_reports ; pos++) {
|
||||
if ((device->hid_reports[pos].type == type) && (device->hid_reports[pos].id == report_id)) {
|
||||
return &device->hid_reports[pos];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hids_device_emit_event_with_uint8(uint8_t event, hci_con_handle_t con_handle, uint8_t value) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet_handler) {
|
||||
return;
|
||||
}
|
||||
uint8_t buffer[6];
|
||||
buffer[0] = HCI_EVENT_HIDS_META;
|
||||
buffer[1] = 4;
|
||||
buffer[2] = event;
|
||||
little_endian_store_16(buffer, 3, (uint16_t) con_handle);
|
||||
buffer[5] = value;
|
||||
(*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static void hids_device_emit_event_with_uint8_uint8_t(uint8_t event, hci_con_handle_t con_handle, uint8_t value_1, uint8_t value_2) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet_handler) {
|
||||
return;
|
||||
}
|
||||
uint8_t buffer[7];
|
||||
buffer[0] = HCI_EVENT_HIDS_META;
|
||||
buffer[1] = 4;
|
||||
buffer[2] = event;
|
||||
little_endian_store_16(buffer, 3, (uint16_t) con_handle);
|
||||
buffer[5] = value_1;
|
||||
buffer[6] = value_2;
|
||||
(*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static void hids_device_emit_event(uint8_t event, hci_con_handle_t con_handle) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet_handler) {
|
||||
return;
|
||||
}
|
||||
uint8_t buffer[5];
|
||||
buffer[0] = HCI_EVENT_HIDS_META;
|
||||
buffer[1] = 4;
|
||||
buffer[2] = event;
|
||||
little_endian_store_16(buffer, 3, (uint16_t) con_handle);
|
||||
(*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
static void hids_device_can_send_now(void * context) {
|
||||
hci_con_handle_t con_handle = (hci_con_handle_t)(uintptr_t) context;
|
||||
// notify client
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet_handler) {
|
||||
return;
|
||||
}
|
||||
uint8_t buffer[5];
|
||||
buffer[0] = HCI_EVENT_HIDS_META;
|
||||
buffer[1] = 3;
|
||||
buffer[2] = HIDS_SUBEVENT_CAN_SEND_NOW;
|
||||
little_endian_store_16(buffer, 3, (uint16_t) con_handle);
|
||||
(*packet_handler)(HCI_EVENT_PACKET, 0, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
// ATT Client Read Callback for Dynamic Data
|
||||
// - if buffer == NULL, don't copy data, just return size of value
|
||||
// - if buffer != NULL, copy data and return number bytes copied
|
||||
static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS;
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_protocol_mode_value_handle) {
|
||||
log_info("Read protocol mode");
|
||||
return att_read_callback_handle_byte(instance->hid_protocol_mode, offset, buffer, buffer_size);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_report_map_handle) {
|
||||
log_info("Read report map");
|
||||
return att_read_callback_handle_blob(instance->hid_descriptor, instance->hid_descriptor_size, offset, buffer, buffer_size);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_boot_mouse_input_client_configuration_handle) {
|
||||
return att_read_callback_handle_little_endian_16(instance->hid_boot_mouse_input_client_configuration_value, offset, buffer, buffer_size);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_boot_keyboard_input_client_configuration_handle) {
|
||||
return att_read_callback_handle_little_endian_16(instance->hid_boot_keyboard_input_client_configuration_value, offset, buffer, buffer_size);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_control_point_value_handle) {
|
||||
if (buffer && (buffer_size >= 1u)) {
|
||||
buffer[0] = instance->hid_control_point_suspend;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
hids_device_report_t * report = hids_device_get_report_for_client_configuration_handle(instance, att_handle);
|
||||
if (report != NULL) {
|
||||
return att_read_callback_handle_little_endian_16(report->client_configuration_value, offset, buffer, buffer_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) {
|
||||
UNUSED(transaction_mode);
|
||||
UNUSED(buffer_size);
|
||||
UNUSED(offset);
|
||||
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return HIDS_DEVICE_ERROR_CODE_INAPPROPRIATE_CONNECTION_PARAMETERS;
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_boot_mouse_input_client_configuration_handle) {
|
||||
uint16_t new_value = little_endian_read_16(buffer, 0);
|
||||
instance->hid_boot_mouse_input_client_configuration_value = new_value;
|
||||
hids_device_emit_event_with_uint8(HIDS_SUBEVENT_BOOT_MOUSE_INPUT_REPORT_ENABLE, con_handle, (uint8_t) new_value);
|
||||
}
|
||||
if (att_handle == instance->hid_boot_keyboard_input_client_configuration_handle) {
|
||||
uint16_t new_value = little_endian_read_16(buffer, 0);
|
||||
instance->hid_boot_keyboard_input_client_configuration_value = new_value;
|
||||
hids_device_emit_event_with_uint8(HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE, con_handle, (uint8_t) new_value);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_protocol_mode_value_handle) {
|
||||
instance->hid_protocol_mode = buffer[0];
|
||||
log_info("Set protocol mode: %u", instance->hid_protocol_mode);
|
||||
hids_device_emit_event_with_uint8(HIDS_SUBEVENT_PROTOCOL_MODE, con_handle, instance->hid_protocol_mode);
|
||||
}
|
||||
|
||||
if (att_handle == instance->hid_control_point_value_handle) {
|
||||
if (buffer_size < 1u) {
|
||||
return ATT_ERROR_INVALID_OFFSET;
|
||||
}
|
||||
instance->hid_control_point_suspend = buffer[0];
|
||||
instance->con_handle = con_handle;
|
||||
log_info("Set suspend tp: %u", instance->hid_control_point_suspend);
|
||||
if (instance->hid_control_point_suspend == 0u) {
|
||||
hids_device_emit_event(HIDS_SUBEVENT_SUSPEND, con_handle);
|
||||
} else if (instance->hid_control_point_suspend == 1u) {
|
||||
hids_device_emit_event(HIDS_SUBEVENT_EXIT_SUSPEND, con_handle);
|
||||
}
|
||||
}
|
||||
|
||||
hids_device_report_t * report = hids_device_get_report_for_client_configuration_handle(instance, att_handle);
|
||||
if (report != NULL) {
|
||||
uint16_t new_value = little_endian_read_16(buffer, 0);
|
||||
report->client_configuration_value = new_value;
|
||||
log_info("Enable Report (type %u) notifications: %x", (uint8_t) report->type, new_value);
|
||||
|
||||
switch (report->type) {
|
||||
case HID_REPORT_TYPE_INPUT:
|
||||
hids_device_emit_event_with_uint8_uint8_t(HIDS_SUBEVENT_INPUT_REPORT_ENABLE, con_handle, report->id, (uint8_t) new_value);
|
||||
break;
|
||||
case HID_REPORT_TYPE_OUTPUT:
|
||||
hids_device_emit_event_with_uint8_uint8_t(HIDS_SUBEVENT_OUTPUT_REPORT_ENABLE, con_handle, report->id, (uint8_t) new_value);
|
||||
break;
|
||||
case HID_REPORT_TYPE_FEATURE:
|
||||
hids_device_emit_event_with_uint8_uint8_t(HIDS_SUBEVENT_FEATURE_REPORT_ENABLE, con_handle, report->id, (uint8_t) new_value);
|
||||
break;
|
||||
default:
|
||||
btstack_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hids_device_init_with_storage(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
|
||||
uint16_t num_reports, hids_device_report_t * report_storage) {
|
||||
|
||||
hids_device_t * instance = hids_device_create_instance();
|
||||
|
||||
btstack_assert(num_reports > 0);
|
||||
btstack_assert(report_storage != NULL);
|
||||
|
||||
instance->hid_country_code = hid_country_code;
|
||||
instance->hid_descriptor = hid_descriptor;
|
||||
instance->hid_descriptor_size = hid_descriptor_size;
|
||||
|
||||
// default
|
||||
instance->hid_protocol_mode = 1;
|
||||
|
||||
// get service handle range
|
||||
uint16_t start_handle = 0;
|
||||
uint16_t end_handle = 0xffff;
|
||||
int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE, &start_handle, &end_handle);
|
||||
btstack_assert(service_found != 0);
|
||||
UNUSED(service_found);
|
||||
|
||||
// get report map handle
|
||||
instance->hid_report_map_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP);
|
||||
|
||||
// get report map handle
|
||||
instance->hid_protocol_mode_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE);
|
||||
|
||||
// get value and client configuration handles for boot mouse input, boot keyboard input and report input
|
||||
instance->hid_boot_mouse_input_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT);
|
||||
instance->hid_boot_mouse_input_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT);
|
||||
|
||||
instance->hid_boot_keyboard_input_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT);
|
||||
instance->hid_boot_keyboard_input_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT);
|
||||
|
||||
instance->hid_control_point_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT);
|
||||
|
||||
log_info("hid_report_map_handle 0x%02x", instance->hid_report_map_handle);
|
||||
log_info("hid_protocol_mode_value_handle 0x%02x", instance->hid_protocol_mode_value_handle);
|
||||
log_info("hid_boot_mouse_input_value_handle 0x%02x", instance->hid_boot_mouse_input_value_handle);
|
||||
log_info("hid_boot_mouse_input_client_configuration_handle 0x%02x", instance->hid_boot_mouse_input_client_configuration_handle);
|
||||
log_info("hid_boot_keyboard_input_value_handle 0x%02x", instance->hid_boot_keyboard_input_value_handle);
|
||||
log_info("hid_boot_keyboard_input_client_configuration_handle 0x%02x", instance->hid_boot_keyboard_input_client_configuration_handle);
|
||||
log_info("hid_control_point_value_handle 0x%02x", instance->hid_control_point_value_handle);
|
||||
|
||||
instance->hid_reports = report_storage;
|
||||
|
||||
uint16_t hid_reports_num = num_reports;
|
||||
uint16_t assigned_reports_num = 0;
|
||||
uint16_t start_chr_handle = start_handle;
|
||||
|
||||
while ((start_chr_handle < end_handle) && (assigned_reports_num < hid_reports_num)) {
|
||||
// mandatory
|
||||
uint16_t chr_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
|
||||
if (chr_value_handle == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// optional
|
||||
uint16_t chr_client_configuration_handle = gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT);
|
||||
|
||||
// mandatory
|
||||
uint16_t report_reference_handle = gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_chr_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_REPORT, ORG_BLUETOOTH_DESCRIPTOR_REPORT_REFERENCE);
|
||||
if (report_reference_handle == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// get report id and type from report reference
|
||||
uint16_t report_reference_value_len;
|
||||
const uint8_t * report_reference_value = gatt_server_get_const_value_for_handle(report_reference_handle, &report_reference_value_len);
|
||||
if (report_reference_value == NULL) {
|
||||
break;
|
||||
}
|
||||
if (report_reference_value_len != 2) {
|
||||
break;
|
||||
}
|
||||
uint8_t report_id = report_reference_value[0];
|
||||
hid_report_type_t report_type = (hid_report_type_t) report_reference_value[1];
|
||||
|
||||
// store report info
|
||||
hids_device_report_t * report = &report_storage[assigned_reports_num];
|
||||
report->value_handle = chr_value_handle;
|
||||
report->client_configuration_handle = chr_client_configuration_handle;
|
||||
report->client_configuration_value = 0;
|
||||
report->id = report_id;
|
||||
report->type = report_type;
|
||||
|
||||
switch (report->type) {
|
||||
case HID_REPORT_TYPE_INPUT:
|
||||
instance->hid_input_reports_num++;
|
||||
break;
|
||||
case HID_REPORT_TYPE_OUTPUT:
|
||||
instance->hid_output_reports_num++;
|
||||
break;
|
||||
case HID_REPORT_TYPE_FEATURE:
|
||||
instance->hid_feature_reports_num++;
|
||||
break;
|
||||
default:
|
||||
btstack_unreachable();
|
||||
return;
|
||||
}
|
||||
log_info("hid_report_value_handle 0x%02x, id %u, type %u", report->value_handle, report->id, (uint8_t)report->type);
|
||||
if (report->client_configuration_handle != 0) {
|
||||
log_info("hid_report_client_configuration_handle 0x%02x", report->client_configuration_handle);
|
||||
}
|
||||
|
||||
assigned_reports_num++;
|
||||
start_chr_handle = report_reference_handle + 1;
|
||||
}
|
||||
|
||||
// register service with ATT Server
|
||||
hid_service.start_handle = start_handle;
|
||||
hid_service.end_handle = end_handle;
|
||||
hid_service.read_callback = &att_read_callback;
|
||||
hid_service.write_callback = &att_write_callback;
|
||||
att_server_register_service_handler(&hid_service);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Set up HIDS Device
|
||||
*/
|
||||
void hids_device_init(uint8_t country_code, const uint8_t * descriptor, uint16_t descriptor_size) {
|
||||
uint16_t hid_reports_num = sizeof(hid_reports_generic_storage) / sizeof(hids_device_report_t);
|
||||
hids_device_init_with_storage(country_code, descriptor, descriptor_size, hid_reports_num, hid_reports_generic_storage);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Register callback for the HIDS Device client.
|
||||
@param callback
|
||||
*/
|
||||
void hids_device_register_packet_handler(btstack_packet_handler_t callback) {
|
||||
packet_handler = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Request can send now event to send HID Report
|
||||
Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
|
||||
@param hid_cid
|
||||
*/
|
||||
void hids_device_request_can_send_now_event(hci_con_handle_t con_handle) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
instance->battery_callback.callback = &hids_device_can_send_now;
|
||||
instance->battery_callback.context = (void*)(uintptr_t) con_handle;
|
||||
att_server_register_can_send_now_callback(&instance->battery_callback, con_handle);
|
||||
}
|
||||
|
||||
uint8_t hids_device_send_input_report_for_id(hci_con_handle_t con_handle, uint16_t report_id, const uint8_t * report, uint16_t report_len) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
|
||||
hids_device_report_t * report_storage = hids_device_get_report_for_id_and_type(instance, report_id,
|
||||
HID_REPORT_TYPE_INPUT);
|
||||
if (report_storage == NULL) {
|
||||
return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
|
||||
}
|
||||
|
||||
return att_server_notify(con_handle, report_storage->value_handle, report, report_len);
|
||||
}
|
||||
|
||||
uint8_t hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len) {
|
||||
hids_device_t * device = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!device) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
|
||||
uint8_t pos;
|
||||
uint8_t total_reports = device->hid_input_reports_num + device->hid_output_reports_num + device->hid_feature_reports_num;
|
||||
for (pos = 0 ; pos < total_reports ; pos++) {
|
||||
hids_device_report_t * report_storage = &device->hid_reports[pos];
|
||||
if (report_storage->type == HID_REPORT_TYPE_INPUT) {
|
||||
return att_server_notify(con_handle, report_storage->value_handle, report, report_len);
|
||||
}
|
||||
}
|
||||
return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Send HID Boot Mouse Input Report
|
||||
*/
|
||||
uint8_t hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
return att_server_notify(con_handle, instance->hid_boot_mouse_input_value_handle, report, report_len);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Send HID Boot Mouse Input Report
|
||||
*/
|
||||
uint8_t hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len) {
|
||||
hids_device_t * instance = hids_device_get_instance_for_con_handle(con_handle);
|
||||
if (!instance) {
|
||||
log_error("no instance for handle 0x%02x", con_handle);
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
return att_server_notify(con_handle, instance->hid_boot_keyboard_input_value_handle, report, report_len);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright (C) 2014 BlueKitchen GmbH
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
4. Any redistribution, use, or modification is done solely for
|
||||
personal benefit and not for any commercial purpose or for
|
||||
monetary gain.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
|
||||
GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Please inquire about commercial licensing options at
|
||||
contact@bluekitchen-gmbh.com
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@title HID Service Server
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HIDS_DEVICE_H
|
||||
#define HIDS_DEVICE_H
|
||||
|
||||
#if defined ENABLE_CLASSIC
|
||||
|
||||
#include <sdkoverride/att_db.h>
|
||||
#include <stdint.h>
|
||||
#include "btstack_defines.h"
|
||||
#include "btstack_hid.h"
|
||||
#include "bluetooth.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* API_START */
|
||||
|
||||
typedef struct {
|
||||
uint16_t value_handle;
|
||||
uint16_t client_configuration_handle;
|
||||
uint16_t client_configuration_value;
|
||||
|
||||
hid_report_type_t type;
|
||||
uint16_t id;
|
||||
} hids_device_report_t;
|
||||
|
||||
/**
|
||||
@text Implementation of the GATT HIDS Device
|
||||
To use with your application, add '#import <hids.gatt>' to your .gatt file
|
||||
*/
|
||||
|
||||
/**
|
||||
@brief Set up HIDS Device with single INPUT, OUTPUT and FEATURE report
|
||||
*/
|
||||
void hids_device_init(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size);
|
||||
|
||||
/**
|
||||
@brief Set up HIDS Device for multiple instances of INPUT, OUTPUT and FEATURE reports
|
||||
*/
|
||||
void hids_device_init_with_storage(uint8_t hid_country_code, const uint8_t * hid_descriptor, uint16_t hid_descriptor_size,
|
||||
uint16_t num_reports, hids_device_report_t * report_storage);
|
||||
|
||||
/**
|
||||
@brief Register callback for the HIDS Device client.
|
||||
@param callback
|
||||
*/
|
||||
void hids_device_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
@brief Request can send now event to send HID Report
|
||||
Generates an HIDS_SUBEVENT_CAN_SEND_NOW subevent
|
||||
@param hid_cid
|
||||
*/
|
||||
void hids_device_request_can_send_now_event(hci_con_handle_t con_handle);
|
||||
|
||||
/**
|
||||
@brief Send HID Input Report for Report ID
|
||||
@param con_handle
|
||||
@param report_id
|
||||
@param report
|
||||
@param report_len
|
||||
@returns status
|
||||
*/
|
||||
uint8_t hids_device_send_input_report_for_id(hci_con_handle_t con_handle, uint16_t report_id, const uint8_t * report, uint16_t report_len);
|
||||
|
||||
/**
|
||||
@brief Send HID Input Report for first Input Report
|
||||
@param con_handle
|
||||
@param report
|
||||
@param report_len
|
||||
@returns status
|
||||
*/
|
||||
uint8_t hids_device_send_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
|
||||
|
||||
/**
|
||||
@brief Send HID Boot Mouse Input Report
|
||||
@param con_handle
|
||||
@param report
|
||||
@param report_len
|
||||
@returns status
|
||||
*/
|
||||
uint8_t hids_device_send_boot_mouse_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
|
||||
|
||||
/**
|
||||
@brief Send HID Boot Mouse Input Report
|
||||
@param con_handle
|
||||
@param report
|
||||
@param report_len
|
||||
@returns status
|
||||
*/
|
||||
uint8_t hids_device_send_boot_keyboard_input_report(hci_con_handle_t con_handle, const uint8_t * report, uint16_t report_len);
|
||||
|
||||
/* API_END */
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
// Taken from LWIP's inet_chksum.c just to set the -O2 flag
|
||||
|
||||
/*
|
||||
Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the lwIP TCP/IP stack.
|
||||
|
||||
Author: Adam Dunkels <adam@sics.se>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#pragma GCC optimize ("O2")
|
||||
/**
|
||||
An optimized checksum routine. Basically, it uses loop-unrolling on
|
||||
the checksum loop, treating the head and tail bytes specially, whereas
|
||||
the inner loop acts on 8 bytes at a time.
|
||||
|
||||
@arg start of buffer to be checksummed. May be an odd byte address.
|
||||
@len number of bytes in the buffer to be checksummed.
|
||||
@return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
|
||||
by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||
*/
|
||||
extern "C" u16_t lwip_standard_chksum(const void *dataptr, int len) {
|
||||
const u8_t *pb = (const u8_t *)dataptr;
|
||||
const u16_t *ps;
|
||||
u16_t t = 0;
|
||||
const u32_t *pl;
|
||||
u32_t sum = 0, tmp;
|
||||
/* starts at odd byte address? */
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
|
||||
if (odd && len > 0) {
|
||||
((u8_t *)&t)[1] = *pb++;
|
||||
len--;
|
||||
}
|
||||
|
||||
ps = (const u16_t *)(const void *)pb;
|
||||
|
||||
if (((mem_ptr_t)ps & 3) && len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
pl = (const u32_t *)(const void *)ps;
|
||||
|
||||
while (len > 7) {
|
||||
tmp = sum + *pl++; /* ping */
|
||||
if (tmp < sum) {
|
||||
tmp++; /* add back carry */
|
||||
}
|
||||
|
||||
sum = tmp + *pl++; /* pong */
|
||||
if (sum < tmp) {
|
||||
sum++; /* add back carry */
|
||||
}
|
||||
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* make room in upper bits */
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
ps = (const u16_t *)pl;
|
||||
|
||||
/* 16-bit aligned word remaining? */
|
||||
while (len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* dangling tail byte remaining? */
|
||||
if (len > 0) { /* include odd byte */
|
||||
((u8_t *)&t)[0] = *(const u8_t *)ps;
|
||||
}
|
||||
|
||||
sum += t; /* add end bytes */
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is probably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return (u16_t)sum;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
#include "pico/bootrom.h"
|
||||
#endif
|
||||
#include "pico/time.h"
|
||||
#include "pico/runtime_init.h"
|
||||
|
||||
#if LIB_PICO_PRINTF_PICO
|
||||
#include "pico/printf.h"
|
||||
#else
|
||||
#define weak_raw_printf printf
|
||||
#define weak_raw_vprintf vprintf
|
||||
#endif
|
||||
#if LIB_PICO_STDIO
|
||||
#include "pico/stdio.h"
|
||||
#endif
|
||||
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
#include "pico/bootrom.h"
|
||||
#endif
|
||||
|
||||
extern char __StackLimit; /* Set by linker. */
|
||||
|
||||
#define STDIO_HANDLE_STDIN 0
|
||||
#define STDIO_HANDLE_STDOUT 1
|
||||
#define STDIO_HANDLE_STDERR 2
|
||||
|
||||
void __attribute__((noreturn)) __weak _exit(__unused int status) {
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
reset_usb_boot(0, 0);
|
||||
#else
|
||||
while (1) {
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__weak void *_sbrk(int incr) {
|
||||
extern char end; /* Set by linker. */
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0) {
|
||||
heap_end = &end;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
char *next_heap_end = heap_end + incr;
|
||||
|
||||
if (__builtin_expect(next_heap_end > (&__StackLimit), false)) {
|
||||
#if PICO_USE_OPTIMISTIC_SBRK
|
||||
if (heap_end == &__StackLimit) {
|
||||
// errno = ENOMEM;
|
||||
return (char *) -1;
|
||||
}
|
||||
next_heap_end = &__StackLimit;
|
||||
#else
|
||||
return (char *) -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
heap_end = next_heap_end;
|
||||
return (void *) prev_heap_end;
|
||||
}
|
||||
#if 0
|
||||
static int64_t epoch_time_us_since_boot;
|
||||
|
||||
__weak int _gettimeofday(struct timeval *__restrict tv, __unused void *__restrict tz) {
|
||||
if (tv) {
|
||||
int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot;
|
||||
tv->tv_sec = (time_t)(us_since_epoch / 1000000);
|
||||
tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) {
|
||||
if (tv) {
|
||||
int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec;
|
||||
epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int _times(struct tms *tms) {
|
||||
#if CLOCKS_PER_SEC >= 1000000
|
||||
tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) * (CLOCKS_PER_SEC / 1000000));
|
||||
#else
|
||||
tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) / (1000000 / CLOCKS_PER_SEC));
|
||||
#endif
|
||||
tms->tms_stime = 0;
|
||||
tms->tms_cutime = 0;
|
||||
tms->tms_cstime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak pid_t _getpid(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int _kill(__unused pid_t pid, __unused int sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _read(int handle, char *buffer, int length) {
|
||||
#if LIB_PICO_STDIO
|
||||
if (handle == STDIO_HANDLE_STDIN) {
|
||||
return stdio_get_until(buffer, length, at_the_end_of_time);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _write(int handle, char *buffer, int length) {
|
||||
#if LIB_PICO_STDIO
|
||||
if (handle == STDIO_HANDLE_STDOUT || handle == STDIO_HANDLE_STDERR) {
|
||||
stdio_put_string(buffer, length, false, true);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _open(__unused const char *fn, __unused int oflag, ...) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _close(__unused int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t __attribute__((weak)) _lseek(__unused int fd, __unused off_t pos, __unused int whence) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _fstat(__unused int fd, __unused struct stat *buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _isatty(int fd) {
|
||||
return fd == STDIO_HANDLE_STDIN || fd == STDIO_HANDLE_STDOUT || fd == STDIO_HANDLE_STDERR;
|
||||
}
|
||||
|
||||
// exit is not useful... no desire to pull in __call_exitprocs
|
||||
void exit(int status) {
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
// incorrect warning from GCC 6
|
||||
GCC_Pragma("GCC diagnostic push")
|
||||
GCC_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
|
||||
void __weak __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
|
||||
weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
|
||||
failedexpr, file, line, func ? ", function: " : "",
|
||||
func ? func : "");
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
GCC_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
void runtime_init(void) {
|
||||
#ifndef NDEBUG
|
||||
if (__get_current_exception()) {
|
||||
// crap; started in exception handler
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
|
||||
// install core0 stack guard
|
||||
extern char __StackBottom;
|
||||
runtime_init_per_core_install_stack_guard(&__StackBottom);
|
||||
#endif
|
||||
|
||||
// todo maybe we want to do this in the future, but it does stuff like register_tm_clones
|
||||
// which we didn't do in previous SDKs
|
||||
//extern void __libc_init_array(void);
|
||||
//__libc_init_array();
|
||||
|
||||
// ... so instead just do the __preinit_array
|
||||
runtime_run_initializers();
|
||||
// ... and the __init_array
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
|
||||
(*p)();
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include <pico/time.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
|
||||
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
Expost absolute mouse HID descriptor and report
|
||||
Taken from @tobozo PR https://github.com/hathach/tinyusb/pull/1363
|
||||
TODO - remove once that PR merged with TinyUSB
|
||||
|
||||
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 "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
|
||||
// Absolute Mouse: same as the Standard (relative) Mouse Report but
|
||||
// with int16_t instead of int8_t for X and Y coordinates.
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
|
||||
int16_t x; /**< Current x position of the mouse. */
|
||||
int16_t y; /**< Current y position of the mouse. */
|
||||
int8_t wheel; /**< Current delta wheel movement on the mouse. */
|
||||
int8_t pan; // using AC Pan
|
||||
} hid_abs_mouse_report_t;
|
||||
|
||||
|
||||
// Absolute Mouse Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
/* Left, Right, Middle, Backward, Forward buttons */ \
|
||||
HID_REPORT_COUNT( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 3 bit padding */ \
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
/* X, Y absolute position [0, 32767] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_LOGICAL_MIN ( 0x00 ) ,\
|
||||
HID_LOGICAL_MAX_N( 0x7FFF, 2 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_REPORT_COUNT ( 2 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* Vertical wheel scroll [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
|
||||
/* Horizontal wheel scroll [-127, 127] */ \
|
||||
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
|
||||
HID_LOGICAL_MIN ( 0x81 ), \
|
||||
HID_LOGICAL_MAX ( 0x7f ), \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_REPORT_SIZE ( 8 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
|
||||
static inline bool tud_hid_abs_mouse_report(uint8_t report_id,
|
||||
uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) {
|
||||
hid_abs_mouse_report_t report = {
|
||||
.buttons = buttons,
|
||||
.x = x,
|
||||
.y = y,
|
||||
.wheel = vertical,
|
||||
.pan = horizontal
|
||||
};
|
||||
|
||||
return tud_hid_n_report(0, report_id, &report, sizeof(report));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
16-bit axis gamepad definition
|
||||
Copyright (c) 2024 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 "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
|
||||
#define TUD_HID_REPORT_DESC_GAMEPAD16(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 16 bit X, Y, Z, Rz, Rx, Ry (min -32767, max 32767 ) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
|
||||
HID_LOGICAL_MIN_N ( -32767, 2 ) ,\
|
||||
HID_LOGICAL_MAX_N ( 32767, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 6 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 8 bit DPad/Hat Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
|
||||
HID_LOGICAL_MIN ( 1 ) ,\
|
||||
HID_LOGICAL_MAX ( 8 ) ,\
|
||||
HID_PHYSICAL_MIN ( 0 ) ,\
|
||||
HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 32 bit Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 32 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 32 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// HID Gamepad Protocol Report.
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
int16_t x; ///< Delta x movement of left analog-stick
|
||||
int16_t y; ///< Delta y movement of left analog-stick
|
||||
int16_t z; ///< Delta z movement of right analog-joystick
|
||||
int16_t rz; ///< Delta Rz movement of right analog-joystick
|
||||
int16_t rx; ///< Delta Rx movement of analog left trigger
|
||||
int16_t ry; ///< Delta Ry movement of analog right trigger
|
||||
uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat
|
||||
uint32_t buttons; ///< Buttons mask for currently pressed buttons
|
||||
} hid_gamepad16_report_t;
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
@@ -12,6 +14,7 @@
|
||||
|
||||
#define tone2_wrap_target 0
|
||||
#define tone2_wrap 8
|
||||
#define tone2_pio_version 0
|
||||
|
||||
static const uint16_t tone2_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -32,6 +35,10 @@ static const struct pio_program tone2_program = {
|
||||
.instructions = tone2_program_instructions,
|
||||
.length = 9,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config tone2_program_get_default_config(uint offset) {
|
||||
|
||||
@@ -30,7 +30,7 @@ void __clearADCPin(pin_size_t p);
|
||||
|
||||
static uint32_t analogScale = 255;
|
||||
static uint32_t analogFreq = 1000;
|
||||
static uint32_t pwmInitted = 0;
|
||||
static uint64_t pwmInitted = 0;
|
||||
static bool scaleInitted = false;
|
||||
static bool adcInitted = false;
|
||||
static uint16_t analogWritePseudoScale = 1;
|
||||
@@ -79,7 +79,7 @@ extern "C" void analogWriteResolution(int res) {
|
||||
extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
CoreMutex m(&_dacMutex);
|
||||
|
||||
if ((pin > 29) || !m) {
|
||||
if ((pin >= __GPIOCNT) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal analogWrite pin (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
@@ -101,12 +101,12 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
}
|
||||
scaleInitted = true;
|
||||
}
|
||||
if (!(pwmInitted & (1 << pwm_gpio_to_slice_num(pin)))) {
|
||||
if (!(pwmInitted & (1LL << pwm_gpio_to_slice_num(pin)))) {
|
||||
pwm_config c = pwm_get_default_config();
|
||||
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / ((float)analogScale * analogFreq));
|
||||
pwm_config_set_wrap(&c, analogScale - 1);
|
||||
pwm_init(pwm_gpio_to_slice_num(pin), &c, true);
|
||||
pwmInitted |= 1 << pwm_gpio_to_slice_num(pin);
|
||||
pwmInitted |= 1LL << pwm_gpio_to_slice_num(pin);
|
||||
}
|
||||
|
||||
val <<= analogWritePseudoScale;
|
||||
@@ -125,17 +125,17 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
auto_init_mutex(_adcMutex);
|
||||
static uint8_t _readBits = 10;
|
||||
static uint8_t _lastADCMux = 0;
|
||||
static uint32_t _adcGPIOInit = 0;
|
||||
static uint64_t _adcGPIOInit = 0;
|
||||
|
||||
void __clearADCPin(pin_size_t p) {
|
||||
_adcGPIOInit &= ~(1 << p);
|
||||
_adcGPIOInit &= ~(1LL << p);
|
||||
}
|
||||
|
||||
extern "C" int analogRead(pin_size_t pin) {
|
||||
CoreMutex m(&_adcMutex);
|
||||
|
||||
pin_size_t maxPin = max(A0, A3);
|
||||
pin_size_t minPin = min(A0, A3);
|
||||
pin_size_t maxPin = __GPIOCNT;
|
||||
pin_size_t minPin = __FIRSTANALOGGPIO;
|
||||
|
||||
if ((pin < minPin) || (pin > maxPin) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal analogRead pin (%d)\n", pin);
|
||||
@@ -145,9 +145,9 @@ extern "C" int analogRead(pin_size_t pin) {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
if (!(_adcGPIOInit & (1 << pin))) {
|
||||
if (!(_adcGPIOInit & (1LL << pin))) {
|
||||
adc_gpio_init(pin);
|
||||
_adcGPIOInit |= 1 << pin;
|
||||
_adcGPIOInit |= 1LL << pin;
|
||||
}
|
||||
if (_lastADCMux != pin) {
|
||||
adc_select_input(pin - minPin);
|
||||
@@ -169,7 +169,7 @@ extern "C" float analogReadTemp(float vref) {
|
||||
_lastADCMux = 0;
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1); // Allow things to settle. Without this, readings can be erratic
|
||||
adc_select_input(4); // Temperature sensor
|
||||
adc_select_input(__GPIOCNT - __FIRSTANALOGGPIO); // Temperature sensor
|
||||
int v = adc_read();
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
float t = 27.0f - ((v * vref / 4096.0f) - 0.706f) / 0.001721f; // From the datasheet
|
||||
|
||||
@@ -23,10 +23,15 @@
|
||||
|
||||
extern void __clearADCPin(pin_size_t p);
|
||||
|
||||
static PinMode _pm[30];
|
||||
static PinMode _pm[__GPIOCNT];
|
||||
|
||||
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
|
||||
extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ulMode) {
|
||||
case INPUT:
|
||||
gpio_init(ulPin);
|
||||
@@ -72,20 +77,16 @@ extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ulPin > 29) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
_pm[ulPin] = ulMode;
|
||||
|
||||
if ((ulPin >= std::min(A0, A3)) && (ulPin <= std::max(A0, A3))) {
|
||||
if (ulPin >= __FIRSTANALOGGPIO) {
|
||||
__clearADCPin(ulPin);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
|
||||
extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
|
||||
if (ulPin > 29) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
@@ -109,7 +110,7 @@ extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
|
||||
|
||||
extern "C" PinStatus digitalRead(pin_size_t ulPin) __attribute__((weak, alias("__digitalRead")));
|
||||
extern "C" PinStatus __digitalRead(pin_size_t ulPin) {
|
||||
if (ulPin > 29) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in digitalRead (%d)\n", ulPin);
|
||||
return LOW;
|
||||
}
|
||||
|
||||
@@ -23,29 +23,40 @@
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <map>
|
||||
#include "_freertos.h"
|
||||
|
||||
|
||||
// Support nested IRQ disable/re-enable
|
||||
#ifndef maxIRQs
|
||||
#define maxIRQs 15
|
||||
#endif
|
||||
static uint32_t _irqStackTop[2] = { 0, 0 };
|
||||
static uint32_t _irqStack[2][maxIRQs];
|
||||
|
||||
extern "C" void interrupts() {
|
||||
auto core = get_core_num();
|
||||
if (!_irqStackTop[core]) {
|
||||
// ERROR
|
||||
return;
|
||||
if (__freeRTOSinitted) {
|
||||
__freertos_task_exit_critical();
|
||||
} else {
|
||||
auto core = get_core_num();
|
||||
if (!_irqStackTop[core]) {
|
||||
// ERROR
|
||||
return;
|
||||
}
|
||||
restore_interrupts(_irqStack[core][--_irqStackTop[core]]);
|
||||
}
|
||||
restore_interrupts(_irqStack[core][--_irqStackTop[core]]);
|
||||
}
|
||||
|
||||
extern "C" void noInterrupts() {
|
||||
auto core = get_core_num();
|
||||
if (_irqStackTop[core] == maxIRQs) {
|
||||
// ERROR
|
||||
panic("IRQ stack overflow");
|
||||
if (__freeRTOSinitted) {
|
||||
__freertos_task_enter_critical();
|
||||
} else {
|
||||
auto core = get_core_num();
|
||||
if (_irqStackTop[core] == maxIRQs) {
|
||||
// ERROR
|
||||
panic("IRQ stack overflow");
|
||||
}
|
||||
_irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts();
|
||||
}
|
||||
|
||||
_irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts();
|
||||
}
|
||||
|
||||
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
|
||||
@@ -77,7 +88,7 @@ static std::map<pin_size_t, CBInfo> _map;
|
||||
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
|
||||
(void) events;
|
||||
// Only need to lock around the std::map check, not the whole IRQ callback
|
||||
CoreMutex m(&_irqMutex, (FromISR | DebugEnable));
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeo
|
||||
uint64_t start = time_us_64();
|
||||
uint64_t abort = start + timeout;
|
||||
|
||||
if (pin > 29) {
|
||||
if (pin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pulseIn (%d)\n", pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
extern "C" uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
if (dataPin > 29) {
|
||||
if (dataPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal dataPin in shiftIn (%d)\n", dataPin);
|
||||
return 0;
|
||||
}
|
||||
if (clockPin > 29) {
|
||||
if (clockPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal clockPin in shiftIn (%d)\n", clockPin);
|
||||
return 0;
|
||||
}
|
||||
@@ -46,11 +46,11 @@ extern "C" uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bit
|
||||
|
||||
extern "C" void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val) {
|
||||
uint8_t i;
|
||||
if (dataPin > 29) {
|
||||
if (dataPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal dataPin in shiftOut (%d)\n", dataPin);
|
||||
return;
|
||||
}
|
||||
if (clockPin > 29) {
|
||||
if (clockPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal clockPin in shiftOut (%d)\n", clockPin);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,10 +66,14 @@ typedef enum {
|
||||
} wl_status_t;
|
||||
|
||||
/* Encryption modes */
|
||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
||||
enum wl_enc_type { /* Values map to 802.11 Cipher Algorithm Identifier */
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_WPA = ENC_TYPE_TKIP,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
ENC_TYPE_WPA2 = ENC_TYPE_CCMP,
|
||||
ENC_TYPE_GCMP = 6,
|
||||
ENC_TYPE_WPA3 = ENC_TYPE_GCMP,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
Bluetooth Audio (A2DP Source and Sink)
|
||||
======================================
|
||||
|
||||
The PicoW can be used as a Bluetooth Audio sink or source with the ``BluetoothAudio`` class.
|
||||
Operation is generally handled "automatically" in the background so while the audio is
|
||||
playing or streaming the main application can perform other operations (like displaying
|
||||
playback info, polling buttons for controls, etc.)
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
#include <BluetoothAudio.h>
|
||||
...
|
||||
|
||||
**Note about CPU usage:** Bluetooth SBC audio is a compressed format. That means
|
||||
that it takes non-trivial amounts of CPU to compress on send, or decompress on receive.
|
||||
Transmitting precompressed audio from, say, MP3 or AAC, requires first decompressing
|
||||
the source file into raw PCM and then re-compressing them in the SBC format. You may
|
||||
want to consider overclocking in this case to avoid underflow.
|
||||
|
||||
A2DPSink
|
||||
--------
|
||||
|
||||
This class implements slave sink-mode operation with player control (play, pause, etc.) and
|
||||
can play the received and decoded SBC audio to ``PWMAudio``, ``I2S``, or a user-created
|
||||
`BluetoothAudioConsumer`` class.
|
||||
|
||||
The ``A2DPSink.ino`` example demonstrates turning a PicoW into a Bluetooth headset with
|
||||
``PWMAudio``.
|
||||
|
||||
A2DPSource
|
||||
-----------
|
||||
|
||||
This class implements a master source-mode SBC Bluetooth A2DP audio connection which
|
||||
transmits audio using the standard ``Stream`` interface (like ``I2S`` or ``PWMAudio``.
|
||||
The main application connects to a Bluetooth speaker and then writes samples into a buffer
|
||||
that's automatically transmitted behind the scenes.
|
||||
|
||||
The ``A2DPSource.ino`` example shows how to connect to a Bluetooth speaker, transmit
|
||||
data, and respond to commands from the speaker.
|
||||
+2
-2
@@ -12,7 +12,7 @@ need to be periodically sampled to be read by applications, easily, such as:
|
||||
* Light dependent resistors (LDR), etc.
|
||||
|
||||
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A4``), and all
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A3``), and all
|
||||
recording is done at 16-bit levels (but be aware that the ADC in the Pico will only
|
||||
ever return values between 0...4095).
|
||||
|
||||
@@ -29,7 +29,7 @@ ADC Input API
|
||||
ADCInput(pin0 [, pin1, pin2, pin3])
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Creates an ADC input object which will record the pins specified in the code.
|
||||
Only pins ``A0`` ... ``A4`` can be used, and they must be specified in increasing
|
||||
Only pins ``A0`` ... ``A3`` can be used, and they must be specified in increasing
|
||||
order (i.e. ``ADCInput(A0, A1);`` is valid, but ``ADCInput(A1, A0)`` is not.
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords)
|
||||
|
||||
+4
-2
@@ -30,7 +30,7 @@ Analog Outputs
|
||||
--------------
|
||||
The RP2040 does not have any onboard DACs, so analog outputs are
|
||||
simulated using the standard method of using pulse width modulation
|
||||
(PWM) using the RP20400's hardware PWM units.
|
||||
(PWM) using the RP2040's hardware PWM units.
|
||||
|
||||
While up to 16 PWM channels can be generated, they are not independent
|
||||
and there are significant restrictions as to allowed pins in parallel.
|
||||
@@ -40,7 +40,9 @@ Analog Output Restrictions
|
||||
--------------------------
|
||||
|
||||
The PWM generator source clock restricts the legal combinations of
|
||||
frequency and ranges. For example, at 1MHz only about 6 bits of range
|
||||
frequency and ranges.
|
||||
At a CPU frequency of 133MHz, the 16 bit maximum range decreases by 1 bit for every doubling of the default PWM frequency of 1 kHz.
|
||||
For example, at 1MHz only about 6 bits of range
|
||||
are possible. When you define an ``analogWriteFreq`` and ``analogWriteRange``
|
||||
that can't be fulfilled by the hardware, the frequency will be preserved
|
||||
but the accuracy (range) will be reduced automatically. Your code will
|
||||
|
||||
@@ -120,7 +120,7 @@ Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and ma
|
||||
|
||||
|
||||
ESP32 Compatibility
|
||||
===================
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Simple ESP32 ``WiFiClientSecure`` compatibility is built-in, allow for some sketches to run without any modification.
|
||||
The following methods are implemented:
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Similar to the `BearSSL::WiFiClientSecure` method, sets the receive and transmit
|
||||
Setting Server Certificates
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not re-use the certificates included in the examples provided.**
|
||||
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not reuse the certificates included in the examples provided.**
|
||||
|
||||
This example command will generate a RSA 2048-bit key and certificate:
|
||||
|
||||
|
||||
+7
-5
@@ -2,9 +2,6 @@ Bluetooth on PicoW Support
|
||||
==========================
|
||||
|
||||
As of the Pico-SDK version 1.5.0, the PicoW has **BETA** Bluetooth support.
|
||||
So, since this core builds off the SDK the best that can be suggested it
|
||||
that we have **ALPHA** Bluetooth support. As such, bug reports are welcome,
|
||||
but Pull Requests fixing problems you find are seriously appreciated.
|
||||
|
||||
Enabling Bluetooth
|
||||
------------------
|
||||
@@ -24,6 +21,11 @@ Bluetooth Low Energy (BLE) HID device using the same API as their USB versions.
|
||||
The ``SerialBT`` library implements a very simple SPP (Serial Port Profile)
|
||||
Serial-compatible port.
|
||||
|
||||
Connect and use Bluetooth peripherals with the PicoW using the
|
||||
``BluetoothHIDMaster`` library.
|
||||
|
||||
``BluetoothAudio`` (A2DP) is also supported, both sink and source.
|
||||
|
||||
Writing Custom Bluetooth Applications
|
||||
-------------------------------------
|
||||
You may also write full applications using the ``BTStack`` standard callback
|
||||
@@ -40,8 +42,8 @@ For many BTStack examples, you simply need call the included
|
||||
called afterwards to start processing (in the background).
|
||||
|
||||
You will also need to acquire the BT ``async_context`` system lock before
|
||||
calling any BTStack APIs. See the ``libraries/PicoBluetoothHID`` helper
|
||||
class for an example of how to do this.
|
||||
calling any BTStack APIs. ``__lockBluetooth`` and ``unlockBluetooth`` are
|
||||
provided in the PicoW variant code.
|
||||
|
||||
Note that if you need to modify the system ``btstack_config.h`` file, do so
|
||||
in the ``tools/libpico`` directory and rebuild the Pico SDK static library.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
BOOTSEL Button
|
||||
==============
|
||||
|
||||
The BOOTSEL button on the Pico is not connected to a standard GPIO, so
|
||||
it cannot be read using the usual ``digitalRead`` function. It **can**,
|
||||
however, be read using a special (relatively slow) method.
|
||||
|
||||
The ``BOOTSEL`` object implements a simple way of reading the BOOTSEL
|
||||
button. Simply use the object ``BOOTSEL`` as a boolean (as a conditional
|
||||
in an ``if`` or ``while``, or assigning to a ``bool``):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// Print "BEEP" if the BOOTSEL button is pressed
|
||||
if (BOOTSEL) {
|
||||
Serial.println("BEEP!");
|
||||
// Wait until BOOTSEL is released
|
||||
while (BOOTSEL) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'3.2.0'
|
||||
version = u'4.0.3'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'3.2.0'
|
||||
release = u'4.0.3'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+41
-2
@@ -10,7 +10,8 @@ Contributing to the Core (Pull Requests)
|
||||
----------------------------------------
|
||||
|
||||
We use the standard GitHub Pull Request model. If you're unfamiliar with it,
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>` gives a simple overview of the process.
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>`__
|
||||
gives a simple overview of the process.
|
||||
|
||||
All pull requests have to pass a set of Continuous Integration (CI) checks
|
||||
which help make sure the code compiles under different configurations and has
|
||||
@@ -84,10 +85,47 @@ code that only runs on this core, use the following define.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
#if defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__)
|
||||
~~~ your changes ~~~
|
||||
#endif
|
||||
|
||||
Identifying RP2040, RP2530A, or RP2350B
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To check if a board is an original RP2040
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2040)
|
||||
...OG Pico code...
|
||||
#endif
|
||||
|
||||
For RP2350(A or B):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350)
|
||||
...Pico 2 code...
|
||||
#endif
|
||||
|
||||
For only RP2350A variants (using the compile options, not the onboard ID register):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350) && !defined(PICO_RP2350B)
|
||||
...RP2350A only code...
|
||||
#endif
|
||||
|
||||
For only RP2350B variants (again, at compile time as identified by the selected board
|
||||
and not the chip ID register):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350B)
|
||||
...48-GPIO version code here
|
||||
#endif
|
||||
|
||||
|
||||
Library Architectures
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -97,3 +135,4 @@ not know your new code is compatible here.
|
||||
|
||||
Add ``rp2040`` to ``architectures`` (in ``library.properties``) and
|
||||
``"rp2040"`` to ``platforms[]`` (in ``library.json``) to let the tools know.
|
||||
Note that even the RP2350 is identified as ``rp2040`` for this purpose.
|
||||
|
||||
@@ -6,6 +6,10 @@ Board-Specific Pins
|
||||
The Raspberry Pi Pico RP2040 chip supports up to 30 digital I/O pins,
|
||||
however not all boards provide access to all pins.
|
||||
|
||||
Pin Notation
|
||||
------------
|
||||
When using Analog or Digital I/Os, if you supply an integer it specifies the RP2040 GPIO pin to use. Using Dx or Ax notation (for example, D4 or A3) may be necessary on boards without a direct PCB pin to GPIO mapping.
|
||||
|
||||
Input Modes
|
||||
-----------
|
||||
The Raspberry Pi Pico has 3 Input modes settings for use with `pinMode`: `INPUT`, `INPUT_PULLUP` and `INPUT_PULLDOWN`
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
EthernetLWIP (Wired Ethernet) Support
|
||||
=====================================
|
||||
|
||||
Wired Ethernet interfaces are supported for all the internal networking
|
||||
libraries (``WiFiClient``, ``WiFiClientSecure``, ``WiFiServer``,
|
||||
``WiFiServerSecure``, ``WiFiUDP``, ``WebServer``, ``Updater``,
|
||||
``HTTPClient``, etc.).
|
||||
|
||||
Using these wired interfaces is very similar to using the Pico-W WiFi
|
||||
so most examples in the core only require minor modifications to use
|
||||
a wired interface.
|
||||
|
||||
Supported Wired Ethernet Modules
|
||||
--------------------------------
|
||||
|
||||
* Wiznet W5100(s)
|
||||
|
||||
* Wiznet W5500
|
||||
|
||||
* ENC28J60
|
||||
|
||||
|
||||
Enabling Wired Ethernet
|
||||
-----------------------
|
||||
|
||||
Simply replace the WiFi include at the top with:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5500lwIP.h> // Or W5100lwIP.h or ENC28J60.h
|
||||
|
||||
|
||||
And add a global Ethernet object of the same type:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
Wiznet5500lwIP eth(1); // Parameter is the Chip Select pin
|
||||
|
||||
In your ``setup()`` you may adjust the SPI pins you're using to
|
||||
match your hardware (be sure they are legal for the RP2040!), or
|
||||
skip this if you're using the default ones:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
void setup() {
|
||||
SPI.setRX(0);
|
||||
SPI.setCS(1);
|
||||
SPI.setSCK(2);
|
||||
SPI.setTX(3);
|
||||
....
|
||||
}
|
||||
|
||||
And finally replace the ``WiFi.begin()`` and ``WiFi.connected()``
|
||||
calls with ``eth.begin()`` and ``eth.connected()``:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
void setup() {
|
||||
....
|
||||
// WiFi.begin(SSID, PASS)
|
||||
eth.begin();
|
||||
|
||||
//while (!WiFi.connected()) {
|
||||
while (!eth.connected()) {
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.print("IP address: ");
|
||||
//Serial.println(WiFi.localIP());
|
||||
Serial.println(eth.localIP());
|
||||
|
||||
....
|
||||
}
|
||||
|
||||
Adjusting LWIP Polling
|
||||
----------------------
|
||||
|
||||
LWIP operates in a polling mode for the wired Ethernet devices. By default it will run
|
||||
every 20ms, meaning that on average it will take half that time (10ms) before a packet
|
||||
received in the Ethernet module is received and operated upon by the Pico. This gives
|
||||
very low CPU utilization but in some cases this latency can affect performance.
|
||||
|
||||
Adding a call to ``lwipPollingPeriod(XXX)`` (where ``XXXX`` is the polling period in
|
||||
milliseconds) can adjust this setting on the fly. Note that if you set it too low, the
|
||||
Pico may not have enough time to service the Ethernet port before the timer fires again,
|
||||
leading to a lock up and hang.
|
||||
|
||||
|
||||
Using Interrupt-Driven Handling
|
||||
-------------------------------
|
||||
|
||||
The WizNet and ENC28J60 devices support generating an interrupt when a packet is received,
|
||||
removing the need for polling and decreasing latency. Simply specify the SPI object to use and the
|
||||
interrupt pin when instantiating the Ethernet object:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5100lwIP.h>
|
||||
Wiznet5100lwIP eth(SS /* Chip Select*/, SPI /* SPI interface */, 17 /* Interrupt GPIO */ );
|
||||
|
||||
|
||||
Adjusting SPI Speed
|
||||
-------------------
|
||||
|
||||
By default a 4MHz clock will be used to clock data into and out of the Ethernet module.
|
||||
Depending on the module and your wiring, a higher SPI clock may increase performance (but
|
||||
too high of a clock will cause communications problems or hangs).
|
||||
|
||||
This value may be adjusted using the ``eth.setSPISpeed(hz)`` call **before** starting the
|
||||
device. (You may also use custom ``SPISettings`` instead via ``eth.setSPISettings(spis)```)
|
||||
|
||||
For example, to set the W5500 to use a 30MHZ clock:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5500lwIP.h>
|
||||
Wiznet5500lwIP eth(1);
|
||||
|
||||
void setup() {
|
||||
eth.setSPISpeed(30000000);
|
||||
lwipPollingPeriod(3);
|
||||
...
|
||||
eth.begin();
|
||||
...
|
||||
}
|
||||
|
||||
Using the WIZnet W5100S-EVB-Pico
|
||||
--------------------------------
|
||||
|
||||
You can use the onboard Ethernet chip with these drivers, in interrupt mode, by utilizing the following options:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5100lwIP.h>
|
||||
Wiznet5100lwIP eth(17, SPI, 21); // Note chip select is **17**
|
||||
|
||||
void setup() {
|
||||
// Set SPI to the onboard Wiznet chip
|
||||
SPI.setRX(16);
|
||||
SPI.setCS(17);
|
||||
SPI.setSCK(18);
|
||||
SPI.setTX(19);
|
||||
...
|
||||
eth.begin();
|
||||
...
|
||||
}
|
||||
|
||||
Example Code
|
||||
------------
|
||||
|
||||
The following examples allow switching between WiFi and Ethernet:
|
||||
|
||||
* ``WebServer/AdvancedWebServer``
|
||||
|
||||
* ``HTTPClient/BasicHTTPSClient``
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
The same restrictions for ``WiFi`` apply to these Ethernet classes, namely:
|
||||
|
||||
* Only core 0 may run any networking related code.
|
||||
|
||||
* In FreeRTOS, only the ``setup`` and ``loop`` task can call networking libraries, not any tasks.
|
||||
|
||||
Special Thanks
|
||||
--------------
|
||||
|
||||
* LWIPEthernet classes come from the ESP8266 Arduino team
|
||||
|
||||
* Individual Ethernet drivers were written by Nicholas Humfrey
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
FatFSUSB
|
||||
========
|
||||
|
||||
When the onboard flash memory is used as a ``FatFS`` filesystem, the
|
||||
``FatFSUSB`` can be used to allow exporting it to a PC as a standard
|
||||
memory stick. The PC can then access, add, and remove files as if the
|
||||
Pico was a USB memory stick, and upon ejection the Pico can access
|
||||
any new files just as if it made them itself.
|
||||
|
||||
(Note, if you are using LittleFS then you need to use ``SingleFileDrive``
|
||||
to export a single file, not this class, because the PC does not
|
||||
understand the LittleFS disk format.)
|
||||
|
||||
Callbacks, Interrupt Safety, and File Operations
|
||||
------------------------------------------------
|
||||
|
||||
The ``FatFSUSB`` library allows your application to get a callback
|
||||
when a PC attempts to mount or unmount the Pico as a FAT drive.
|
||||
|
||||
When the drive is being used by the Pico (i.e. any ``File`` is open for
|
||||
read or write, the ``FatFS`` is not ``end()`` -ed and still mounted,
|
||||
etc.) the host may not access it. Conversely, while the host PC is
|
||||
connected to the drive no ``FatFS`` access by the Pico is allowed.
|
||||
|
||||
Your ``driveReady`` callback will be called when the PC attempts to mount
|
||||
the drive. If you have any files open, then this callback can report back
|
||||
that the drive is not yet ready. When you complete file processing, the PC
|
||||
can re-attempt to mount the drive and your callback can return ``true`` .
|
||||
|
||||
The ``onPlug`` callback will generally ``FatFS.end()`` and set a
|
||||
global flag letting your application know not to touch the filesystem until
|
||||
the flag is cleared by the ``onUnplug`` callback (which will also do a
|
||||
``FatFS.begin()`` call).
|
||||
|
||||
Failing to close all files **and** ``FatFS.end()`` before granting the
|
||||
PC access to flash memory will result in corruption. FAT does not allow multiple
|
||||
writers to access the same drive. Even mounting and only reading files from
|
||||
the PC may cause hidden writes (things like access time, etc.) which would
|
||||
also cause corruption.
|
||||
|
||||
See the included ``Listfiles-USB`` sketch for an example of working with
|
||||
these limitations.
|
||||
+131
-55
@@ -18,12 +18,12 @@ The following diagram shows the flash layout used in Arduino-Pico:
|
||||
|
||||
::
|
||||
|
||||
|---------------------|-------------|----|
|
||||
^ ^ ^
|
||||
Sketch File system EEPROM
|
||||
|----|---------------------|-------------|----|
|
||||
^ ^ ^ ^
|
||||
OTA Sketch File system EEPROM
|
||||
|
||||
The file system size is configurable via the IDE menus, rom 64k up to 15MB
|
||||
(assuming you have an RP2040 boad with that much flash)
|
||||
The file system size is configurable via the IDE menus, from 64k up to 15MB
|
||||
(assuming you have an RP2040 board with that much flash)
|
||||
|
||||
**Note:** to use any of file system functions in the sketch, add the
|
||||
following include to the sketch:
|
||||
@@ -33,31 +33,68 @@ following include to the sketch:
|
||||
#include "LittleFS.h" // LittleFS is declared
|
||||
// #include <SDFS.h>
|
||||
// #include <SD.h>
|
||||
// #include <FatFS.h>
|
||||
|
||||
|
||||
Compatible Filesystem APIs
|
||||
--------------------------
|
||||
|
||||
LittleFS is an onboard filesystem that sets asidesome program flash for
|
||||
LittleFS is an onboard filesystem that sets aside some program flash for
|
||||
use as a filesystem without requiring any external hardware.
|
||||
|
||||
SDFS is a filesystem for SD cards, based on [SdFat 2.0](https://github.com/earlephilhower/ESP8266SdFat).
|
||||
It supports FAT16 and FAT32 formatted cards, and requires an external
|
||||
SD card reader.
|
||||
|
||||
SD is the Arduino supported, somewhat old and limited SD card filesystem.
|
||||
SD is the Arduino-supported, somewhat old and limited SD card filesystem.
|
||||
It is recommended to use SDFS for new applications instead of SD.
|
||||
|
||||
All three of these filesystems can open and manipulate ``File`` and ``Dir``
|
||||
FatFS implements a wear-leveled, FTL-backed FAT filesystem in the onboard
|
||||
flash which can be easily accessed over USB as a standard memory stick
|
||||
via FatFSUSB.
|
||||
|
||||
All of these filesystems can open and manipulate ``File`` and ``Dir``
|
||||
objects with the same code because the implement a common end-user
|
||||
filesystem API.
|
||||
|
||||
FatFS File System Caveats and Warnings
|
||||
--------------------------------------
|
||||
|
||||
The FAT filesystem is ubiquitous, but it is also around 50 years old and ill
|
||||
suited to SPI flash memory due to having "hot spots" like the FAT copies that
|
||||
are rewritten many times over. SPI flash allows a high, but limited, number
|
||||
of writes before losing the ability to write safely. Applications like
|
||||
data loggers where many writes occur could end up wearing out the SPI flash
|
||||
sector that holds the FAT **years** before coming close to the write limits of
|
||||
the data sectors.
|
||||
|
||||
To circumvent this issue, the FatFS implementation here uses a flash translation
|
||||
layer (FTL) developed for SPI flash on embedded systems. This allows for the
|
||||
same LBA to be written over and over by the FAT filesystem, but use different
|
||||
flash locations. For more information see
|
||||
[SPIFTL](https://github.com/earlephilhower/SPIFTL). In this mode the Pico
|
||||
flash appears as a normal, 512-byte sector drive to the FAT.
|
||||
|
||||
What this means, practically, is that about 5KB of RAM per megabyte of flash
|
||||
is required for housekeeping. Writes can also become very slow if most of the
|
||||
flash LBA range is used (i.e. if the FAT drive is 99% full) due to the need
|
||||
for garbage collection processes to move data around and preserve the flash
|
||||
lifetime.
|
||||
|
||||
Alternatively, if an FTL is not desired or memory is tight, FatFS can use the
|
||||
raw flash directly. In this mode sectors are 4K in size and flash is mapped
|
||||
1:1 to sectors, so things like the FAT table updates will all use the same
|
||||
physical flash bits. For low-utilization operations this may be fine, but if
|
||||
significant writes are done (from the Pico or the PC host) this may wear out
|
||||
portions of flash very quickly , rendering it unusable.
|
||||
|
||||
LittleFS File System Limitations
|
||||
--------------------------------
|
||||
|
||||
The LittleFS implementation for the RP2040 supports filenames of up
|
||||
to 31 characters + terminating zero (i.e. ``char filename[32]``), and
|
||||
as many subdirectories as space permits.
|
||||
to 254 characters + terminating zero (i.e. ``char filename[255]`` or
|
||||
better ``char filename[LFS_NAME_MAX]`` ), and as many subdirectories
|
||||
as space permits.
|
||||
|
||||
Filenames are assumed to be in the root directory if no initial "/" is
|
||||
present.
|
||||
@@ -75,22 +112,28 @@ Uploading Files to the LittleFS File System
|
||||
menu item to **Tools** menu for uploading the contents of sketch data
|
||||
directory into a new LittleFS flash file system.
|
||||
|
||||
**IDE 1.x**
|
||||
|
||||
- Download the tool: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
- In your Arduino sketchbook directory, create ``tools`` directory if
|
||||
it doesn't exist yet.
|
||||
- Unpack the tool into ``tools`` directory (the path will look like
|
||||
``<home_dir>/Arduino/tools/PicoLittleFS/tool/picolittlefs.jar``)
|
||||
- In your Arduino sketchbook directory, create ``tools`` directory if it doesn't exist yet.
|
||||
- Unpack the tool into ``tools`` directory (the path will look like ``<home_dir>/Arduino/tools/PicoLittleFS/tool/picolittlefs.jar``)
|
||||
If upgrading, overwrite the existing JAR file with the newer version.
|
||||
- Restart Arduino IDE.
|
||||
- Open a sketch (or create a new one and save it).
|
||||
- Go to sketch directory (choose Sketch > Show Sketch Folder).
|
||||
- Create a directory named ``data`` and any files you want in the file
|
||||
system there.
|
||||
- Create a directory named ``data`` and any files you want in the file system there.
|
||||
- Make sure you have selected a board, port, and closed Serial Monitor.
|
||||
- Double check theSerial Monitor is closed. Uploads will fail if the Serial
|
||||
Monitor has control of the serial port.
|
||||
- Select ``Tools > Pico LittleFS Data Upload``. This should start
|
||||
uploading the files into the flash file system.
|
||||
- Double check the Serial Monitor is closed. Uploads will fail if the Serial Monitor has control of the serial port.
|
||||
- Select ``Tools > Pico LittleFS Data Upload``. This should start uploading the files into the flash file system.
|
||||
|
||||
**IDE 2.x**
|
||||
|
||||
- Download the new tool: https://github.com/earlephilhower/arduino-littlefs-upload/releases
|
||||
- Exit the IDE, if running
|
||||
- Copy the VSIX file manually to (Linux/Mac) ``~/.arduinoIDE/plugins/`` (you may need to make this directory yourself beforehand) or to (Windows) ``C:\Users\<username>\.arduinoIDE\``
|
||||
- Restart the IDE
|
||||
- Double check the Serial Monitor is closed. Uploads will fail if the Serial Monitor has control of the serial port.
|
||||
- Enter ``[Ctrl]`` + ``[Shift]`` + ``[P]`` to bring up the command palette, then select/type ``Upload LittleFS to Pico/ESP8266``
|
||||
|
||||
SD Library Information
|
||||
----------------------
|
||||
@@ -109,8 +152,50 @@ second SPI port, ``SPI1``. Just use the following call in place of
|
||||
SD.begin(cspin, SPI1);
|
||||
|
||||
|
||||
File system object (LittleFS/SD/SDFS)
|
||||
-------------------------------------
|
||||
Using VFS (Virtual File System) for POSIX support
|
||||
-------------------------------------------------
|
||||
The ``VFS`` library enables sketches to use standard POSIX file I/O operations using
|
||||
standard ``FILE *`` operations. Include the ``VFS`` library in your application and
|
||||
add a call to map the ``VFS.root()`` to your filesystem. I.e.:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <VFS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
VFS.root(LittleFS);
|
||||
FILE *fp = fopen("/thisfilelivesonflash.txt", "w");
|
||||
fprintf(fp, "Hello!\n");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
Multiple filesystems can be ``VFS.map()`` into the VFS namespace under different directory
|
||||
names. For example, the following will make files on ``/sd`` reside on an external\
|
||||
SD card and files on ``/lfs`` live in internal flash.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <VFS.h>
|
||||
#include <LittleFS.h>
|
||||
#include <SDFS.h>
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
SDFS.begin();
|
||||
VFS.map("/lfs", LittleFS);
|
||||
VFS.map("/sd", SDFS);
|
||||
FILE *onSD = fopen("/sd/thislivesonsd.txt", "wb");
|
||||
....
|
||||
}
|
||||
|
||||
See the examples in the ``VFS`` library for more information.
|
||||
|
||||
|
||||
|
||||
File system object (LittleFS/SD/SDFS/FatFS)
|
||||
-------------------------------------------
|
||||
|
||||
setConfig
|
||||
~~~~~~~~~
|
||||
@@ -125,14 +210,22 @@ setConfig
|
||||
c2.setCSPin(12);
|
||||
SDFS.setConfig(c2);
|
||||
|
||||
FatFSConfig c3;
|
||||
c3.setUseFTL(false); // Directly access flash memory
|
||||
c3.setDirEntries(256); // We need 256 root directory entries on a format()
|
||||
c3.setFATCopies(1); // Only 1 FAT to save 4K of space and extra writes
|
||||
FatFS.setConfig(c3);
|
||||
FatFS.format(); // Format using these settings, erasing everything
|
||||
|
||||
This method allows you to configure the parameters of a filesystem
|
||||
before mounting. All filesystems have their own ``*Config`` (i.e.
|
||||
``SDFSConfig`` or ``LittleFSConfig`` with their custom set of options.
|
||||
All filesystems allow explicitly enabling/disabling formatting when
|
||||
mounts fail. If you do not call this ``setConfig`` method before
|
||||
perforing ``begin()``, you will get the filesystem's default
|
||||
behavior and configuration. By default, SPIFFS will autoformat the
|
||||
filesystem if it cannot mount it, while SDFS will not.
|
||||
behavior and configuration. By default, LittleFS and FatFS will autoformat the
|
||||
filesystem if it cannot mount it, while SDFS will not. FatFS will also use
|
||||
the built-in FTL to support 512 byte sectors and higher write lifetime.
|
||||
|
||||
begin
|
||||
~~~~~
|
||||
@@ -144,11 +237,10 @@ begin
|
||||
|
||||
This method mounts file system. It must be called before any
|
||||
other FS APIs are used. Returns *true* if file system was mounted
|
||||
successfully, false otherwise. With no options it will format SPIFFS
|
||||
if it is unable to mount it on the first try.
|
||||
successfully, false otherwise.
|
||||
|
||||
Note that LittleFS will automatically format the filesystem
|
||||
if one is not detected. This is configurable via ``setConfig``
|
||||
if one is not detected. This is configurable via ``setConfig``.
|
||||
|
||||
end
|
||||
~~~
|
||||
@@ -181,8 +273,8 @@ open
|
||||
|
||||
Opens a file. ``path`` should be an absolute path starting with a slash
|
||||
(e.g. ``/dir/filename.txt``). ``mode`` is a string specifying access
|
||||
mode. It can be one of "r", "w", "a", "r+", "w+", "a+". Meaning of these
|
||||
modes is the same as for ``fopen`` C function.
|
||||
mode. It can be one of "r", "w", "a", "r+", "w+", "a+". The meaning of these
|
||||
modes is the same as for the ``fopen`` C function.
|
||||
|
||||
::
|
||||
|
||||
@@ -258,8 +350,6 @@ openDir
|
||||
or LittleFS.openDir(path)
|
||||
|
||||
Opens a directory given its absolute path. Returns a *Dir* object.
|
||||
Please note the previous discussion on the difference in behavior between
|
||||
LittleFS and SPIFFS for this call.
|
||||
|
||||
remove
|
||||
~~~~~~
|
||||
@@ -283,8 +373,8 @@ rename
|
||||
Renames file from ``pathFrom`` to ``pathTo``. Paths must be absolute.
|
||||
Returns *true* if file was renamed successfully.
|
||||
|
||||
info **DEPRECATED**
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
info
|
||||
~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
@@ -293,9 +383,8 @@ info **DEPRECATED**
|
||||
|
||||
Fills `FSInfo structure <#filesystem-information-structure>`__ with
|
||||
information about the file system. Returns ``true`` if successful,
|
||||
``false`` otherwise. Because this cannot report information about
|
||||
filesystemd greater than 4MB, don't use it in new code. Use ``info64``
|
||||
instead which uses 64-bit fields for filesystem sizes.
|
||||
``false`` otherwise. ``ìnfo()`` has been updated to support filesystems
|
||||
greater than 4GB and ``FSInfo64`` and ``info64()`` have been discarded.
|
||||
|
||||
Filesystem information structure
|
||||
--------------------------------
|
||||
@@ -303,8 +392,8 @@ Filesystem information structure
|
||||
.. code:: cpp
|
||||
|
||||
struct FSInfo {
|
||||
size_t totalBytes;
|
||||
size_t usedBytes;
|
||||
uint64_t totalBytes;
|
||||
uint64_t usedBytes;
|
||||
size_t blockSize;
|
||||
size_t pageSize;
|
||||
size_t maxOpenFiles;
|
||||
@@ -319,19 +408,6 @@ block size - ``pageSize`` — filesystem logical page size - ``maxOpenFiles``
|
||||
``maxPathLength`` — max file name length (including one byte for zero
|
||||
termination)
|
||||
|
||||
info64
|
||||
~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
FSInfo64 fsinfo;
|
||||
SDFS.info(fsinfo);
|
||||
or LittleFS(fsinfo);
|
||||
|
||||
Performs the same operation as ``info`` but allows for reporting greater than
|
||||
4GB for filesystem size/used/etc. Should be used with the SD and SDFS
|
||||
filesystems since most SD cards today are greater than 4GB in size.
|
||||
|
||||
setTimeCallback(time_t (\*cb)(void))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -550,8 +626,8 @@ close
|
||||
Close the file. No other operations should be performed on *File* object
|
||||
after ``close`` function was called.
|
||||
|
||||
openNextFile (compatibiity method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
openNextFile (compatibility method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
@@ -562,8 +638,8 @@ openNextFile (compatibiity method, not recommended for new code)
|
||||
Opens the next file in the directory pointed to by the File. Only valid
|
||||
when ``File.isDirectory() == true``.
|
||||
|
||||
rewindDirectory (compatibiity method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
rewindDirectory (compatibility method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
Bluetooth HID Master
|
||||
====================
|
||||
|
||||
The PicoW can connect to a Bluetooth Classic or Bluetooth BLE keyboard,
|
||||
mouse, or joystick and receive input events from it. As opposed to
|
||||
the ``Keyboard``, ``Mouse``, and ``Joystick`` libraries, which make
|
||||
the PicoW into a peripheral others can use, this lets the PicoW use the
|
||||
same kinds of peripherals in a master rols.
|
||||
|
||||
BTDeviceInfo Class
|
||||
------------------
|
||||
|
||||
The ``BluetoothHCI`` class implements a scanning function for classic
|
||||
and BLE devices and can return a ``std::vector`` of discovered devices to an application.
|
||||
Iterate over the list using any of the STL iteration methods (i.e. ``for (auto e : list)``).
|
||||
The elements of this list are ``BTDeviceInfo`` objects which have the following
|
||||
member functions:
|
||||
|
||||
``BTDeviceInfo::deviceClass()`` returns the Bluetooth BLE UUID or the Blustooth device
|
||||
class for the device. This specifies the general class of the device (keyboard, mouse,
|
||||
etc.).
|
||||
|
||||
``BTDeviceInfo::address()`` and ``BTDeviceInfo::addressString()`` return the
|
||||
Bluetooth address as a binary array or a string that can be used to ``print``.
|
||||
|
||||
``BTDeviceInfo::addressType()`` returns whether the BLE address is random or not, and
|
||||
is not generally needed by a user application.
|
||||
|
||||
``BTDeviceInfo::rssi()`` returns an approximate dB level for the device. Less
|
||||
negative is stronger signal.
|
||||
|
||||
``BTDeviceInfo::name()`` returns the advertised name of the device, if present. Some
|
||||
devices or scans do not return names for valid devices.
|
||||
|
||||
|
||||
BluetoothHCI Class
|
||||
------------------
|
||||
|
||||
The ``BluetoothHCI`` class is responsible for scanning for devices and the lower-level
|
||||
housekeeping for a master-mode Bluetooth application. Most applications will not need
|
||||
to access it directly, but it can be used to discover nearby BT devices. As
|
||||
part of the application Bluetooth setup, call ``BluetoothHCI::install()`` and then
|
||||
``BluetoothHCI::begin()`` to start BT processing. Your application is still responsible
|
||||
for all the non-default HCI initialization and customization. See the ``BluetoothScanner.ino``
|
||||
example for more info.
|
||||
|
||||
|
||||
BluetoothHIDMaster Operation
|
||||
----------------------------
|
||||
|
||||
Most applications will use the ``BluetoothHIDMaster`` class and, after connecting, receive
|
||||
callbacks from the Bluetooth stack when input events (key presses, mouse moves, button
|
||||
mashes) occur.
|
||||
|
||||
Application flow will generally be:
|
||||
1. Install the appropriate callbacks using the ``BluetoothHIDMaster::onXXX`` methods
|
||||
2. Start the Bluetooth processing with ``BluetoothHIDMaster::begin()`` or ``BluetoothHIDMaster::beginBLE()``
|
||||
3. Connect to the first device found with ``BluetoothHIDMaster::connectXXX()`` and start receiving callbacks.
|
||||
4. Callbacks will come at interrupt time and set global state variables, which the main ``loop()`` will process
|
||||
|
||||
Callback Event Handlers
|
||||
-----------------------
|
||||
The main application is informed of new inputs via a standard callback mechanism. These callbacks run at
|
||||
interrupt time and should not do significant work, ``delay()``, or allocate or free memory. The most common
|
||||
way of handling this is setting global ``volatile`` flags and variables that the main ``loop()`` will poll
|
||||
and process.
|
||||
|
||||
Mouse Callbacks
|
||||
~~~~~~~~~~~~~~~
|
||||
The ``BluetoothHIDMaster::onMouseMove`` callback gets the delta X, Y, and wheel reported by the device.
|
||||
The ``BluetoothHIDMaster::onMouseButton`` gets a button number and state (up or down) and will be called
|
||||
each time an individual button is reported changed by the mouse.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void mouseMoveCB(void *cbdata, int dx, int dy, int dw) {
|
||||
// Process the deltas, adjust global mouse state
|
||||
}
|
||||
|
||||
void mouseButtonCB(void *cbdata, int butt, bool down) {
|
||||
// Set the global button array with this new info
|
||||
}
|
||||
|
||||
|
||||
Meyboard Callbacks
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
The `BluetoothHIDMaster::onKeyDown`` callback receives the raw HID key (**NOT ASCII**) sent by the device on a key press
|
||||
while `BluetoothHIDMaster::onKeyUp`` gets the same when a key is released. Note that up to 6 keys can be pressed at any
|
||||
one time. For media keys ("consumer keys" in the USB HID documentation) the ``BluetoothHIDMaster::onConsumerKeyDown`` and
|
||||
``BluetoothHIDMaster::onConsumerKeyUp`` perform the same function (and receive the consumer key IDs defined by the
|
||||
USB HID spec and not ASCII).
|
||||
|
||||
To convert the key press and release (including SHIFT handling), use a ``HIDKeyStream`` object. Simply write the raw
|
||||
HID key and the up/down state to the stream and read back the ASCII for use in an application.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
HIDKeyStream keystream;
|
||||
|
||||
void keyDownCB(void *cbdata, int key) {
|
||||
keystream.write((uint8_t )key);
|
||||
keystream.write((uint8_t) true); // Keystream now has 1 ASCII character to read out and use
|
||||
char ascii = keystream.read();
|
||||
// ....
|
||||
}
|
||||
|
||||
void keyUpCB(void *cbdata, int key) {
|
||||
// Normally don't do anything on this, the character was read in the keyDownCB
|
||||
}
|
||||
|
||||
void consumerKeyDownCB(void *cbdata, int key) {
|
||||
// switch(key) and use cases from the USB Consumer Key page
|
||||
}
|
||||
|
||||
void consumerKeyUpCB(void *cbdata, int key) {
|
||||
// switch(key) and use cases from the USB Consumer Key page
|
||||
}
|
||||
|
||||
|
||||
Joystick Callbacks
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
A single ``BluetoothHIDMaster::onJoystick`` callback gets activated every time a report from a joystick is processed.
|
||||
It receives (potentially, if supported by the device) 4 analog axes, one 8-way digital hat switch position, and up
|
||||
to 32 button states at a time.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void joystickCB(void *cbdata, int x, int y, int z, int rz, uint8_t hat, uint32_t buttons) {
|
||||
// HAT 0 = UP and continues clockwise. If no hat direction it is set to 0x0f.
|
||||
// Use "buttons & (1 << buttonNumber)" to look at the individual button states
|
||||
// ...
|
||||
}
|
||||
|
||||
PianoKeyboard Example
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
See the ``PianoKeyboard.ino`` and ``PianoKeyboardBLE.ino`` examples for more information on callback operation.
|
||||
|
||||
|
||||
BluetoothHIDMaster::onXXX Callback Installers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void BluetoothHIDMaster::onMouseMove(void (*)(void *, int, int, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onMouseButton(void (*)(void *, int, bool), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onKeyDown(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onKeyUp(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onConsumerKeyDown(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onConsumerKeyUp(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onJoystick(void (*)(void *, int, int, int, int, uint8_t, uint32_t), void *cbData = nullptr);
|
||||
|
||||
BluetoothHIDMaster Class
|
||||
------------------------
|
||||
|
||||
bool BluetoothHIDMaster::begin()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Installs and configures the Bluetooth Classic stack and starts processing events. No connections are made at this point.
|
||||
When running in Classic mode, no BLE devices can be detected or used.
|
||||
|
||||
|
||||
bool BluetoothHIDMaster::begin(const char *BLEName)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Installs and configures the Bluetooth BLE stack and starts processing events. No connections are made at this point.
|
||||
When running in BLE mode, no Classic devices can be detected or used.
|
||||
|
||||
bool BluetoothHIDMaster::connected()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack is up and running and a connection to a device is currently active.
|
||||
|
||||
void BluetoothHIDMaster::end()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Disables the Bluetooth stack. Note that with the current Bluetooth implementation restarting the stack (i.e. calling ``begin()`` after ``end()``) is not stable and will not work. Consider storing state and rebooting completely if this is necessary.
|
||||
|
||||
bool BluetoothHIDMaster::running()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack is running at all. Does not indicate if there is an active connection or not.
|
||||
|
||||
bool BluetoothHIDMaster::hciRunning()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack has passed the initial HCI start up phase. Until this returns ``true`` no Bluetooth operations can be performed.
|
||||
|
||||
std::vector<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Passes through the ``BluetoothHCI::scan()`` function to manually scan for a list of nearby devices. If you want to connect to the first found device, this is not needed.
|
||||
|
||||
bool BluetoothHIDMaster::connect(const uint8_t *addr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the connection process to the Bluetooth Classic device with the given MAC. Note that this returns immediately, but it may take several seconds until ``connected()`` reports that the connection has been established.
|
||||
|
||||
bool BluetoothHIDMaster::connectKeyboard(), connectMouse(), connectJoystick(), connectAny()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Connect to the first found specified Bluetooth Classic device type (or any HID device) in pairing mode. No need to call ``scan()`` or have an address.
|
||||
|
||||
bool BluetoothHIDMaster::connectBLE(const uint8_t *addr, int addrType)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the connection process to the Bluetooth BLE device with the given MAC. Note that this returns immediately, but it may take several seconds until ``connected()`` reports that the connection has been established.
|
||||
|
||||
bool BluetoothHIDMaster::connectBLE()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Connect to the first found BLE device that has a HID service UUID (keyboard, mouse, or joystick)
|
||||
|
||||
bool BluetoothHIDMaster::disconnect()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Shuts down the connection to the currently connected device.
|
||||
|
||||
void BluetoothHIDMaster::clearPairing()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Erases all Bluetooth keys from memory. This effectively "forgets" all pairing between devices and can help avoid issues with the beta Bluetooth stack in the SDK.
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
HTTPClient Library
|
||||
==================
|
||||
|
||||
A simple HTTP requestor that can handle both HTTP and HTTP requests is
|
||||
A simple HTTP requester that can handle both HTTP and HTTPS requests is
|
||||
included as the ``HTTPClient`` library.
|
||||
|
||||
Check the examples for use under HTTP and HTTPS configurations. In general,
|
||||
|
||||
+32
-1
@@ -40,6 +40,16 @@ bool setDATA(pin_size_t pin)
|
||||
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setMCLK(pin_size_t pin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the MCLK pin of the I2S device and enables MCLK output. Any pin may be used.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setMCLKmult(int mult)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the sample rate to MCLK multiplier value. Only multiples of 64 are valid.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setBitsPerSample(int bits)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Specify how many bits per audio sample to read or write. Note that
|
||||
@@ -58,12 +68,28 @@ Sets the word clock frequency, but does not start the I2S device if not
|
||||
already running. May be called after ``I2S::begin()`` to change the
|
||||
sample rate on-the-fly.
|
||||
|
||||
bool setSysClk(int samplerate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Changes the PICO system clock to optimise for the desired samplerate.
|
||||
The clock changes to 147.6 MHz for samplerates that are a multiple of 8 kHz, and 135.6 MHz for multiples of 11.025 kHz.
|
||||
Note that using ``setSysClk()`` may affect the timing of other sysclk-dependent functions.
|
||||
Should be called before any I2S functions and any other sysclk dependent initialisations.
|
||||
|
||||
bool setLSBJFormat()
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Enables LSB-J format for I2S output. In this mode the MSB comes out at the
|
||||
same time as the LRCLK changes, and not the normal 1-cycle delay. Useful for
|
||||
DAC chips like the PT8211.
|
||||
|
||||
bool setTDMFormat()
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Enabled TDM formatted multi-channel output. Be sure to set the number of channels to
|
||||
the expected value (8 normally) and the bits per sample to 32.
|
||||
|
||||
bool setTDMChannels(int channels)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the number of TDM channels between frame syncs. Generally should be set to 8.
|
||||
|
||||
bool swapClocks()
|
||||
~~~~~~~~~~~~~~~~~
|
||||
Certain boards are hardwired with the WCLK before the BCLK, instead of the normal
|
||||
@@ -84,6 +110,11 @@ void flush()
|
||||
~~~~~~~~~~~~
|
||||
Waits until all the I2S buffers have been output.
|
||||
|
||||
void getOverUnderflow()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns a flag indicating if the I2S system ran our of data to send on output,
|
||||
or had to throw away data on input.
|
||||
|
||||
size_t write(uint8_t/int8_t/int16_t/int32_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
|
||||
@@ -112,7 +143,7 @@ many bytes were actually written.
|
||||
|
||||
int availableForWrite()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the number of L/R samples that can be written without
|
||||
Returns the amount of bytes that can be written without
|
||||
potentially blocking.
|
||||
|
||||
int read()
|
||||
|
||||
+3
-7
@@ -1,15 +1,11 @@
|
||||
IDE Menus
|
||||
=========
|
||||
|
||||
Model
|
||||
Board
|
||||
-----
|
||||
Use the boards menu to select your model of RP2040 board. There will be two
|
||||
options: `Boardname` and `Boardname (Picoprobe)`. If you want to use a
|
||||
Picoprobe to upload your sketches and not the default automatic UF2 upload,
|
||||
use the `(Picoprobe)` option, otherwise use the normal name. No functional
|
||||
or code changes are done because of this.
|
||||
Use the boards menu to select your model of RP2040 board.
|
||||
|
||||
There is also a `Generic` board which allows you to individually select
|
||||
There is also a `Generic RP2040` board which allows you to individually select
|
||||
things such as flash size or boot2 flash type. Use this if your board isn't
|
||||
yet fully supported and isn't working with the normal `Raspberry Pi Pico`
|
||||
option.
|
||||
|
||||
+16
-7
@@ -2,12 +2,12 @@ Arduino-Pico
|
||||
============
|
||||
|
||||
This is the documentation for the Raspberry Pi Pico Arduino core,
|
||||
Arduino-Pico. Arduino-Pico is a community port of the RP2040
|
||||
(Raspberry Pi Pico processor) to the Arduino ecosystem, intended
|
||||
to make it easier and more fun to use and program the Raspberry Pi
|
||||
Pico / RP2040 based boards.
|
||||
Arduino-Pico. Arduino-Pico is a community port of Arduino to the
|
||||
RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2
|
||||
processor), intended to make it easier and more fun to use and
|
||||
program the Raspberry Pi Pico / RP2040 / RP2350 based boards.
|
||||
|
||||
This Arduino core uses a custom toolset with GCC 10.3 and Newlib 4.0.0
|
||||
This Arduino core uses a custom toolset with GCC 12.3 and Newlib 4.0.0
|
||||
and doesn't require any system-installed prerequisites.
|
||||
|
||||
For the latest version, always check https://github.com/earlephilhower/arduino-pico
|
||||
@@ -26,10 +26,11 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
|
||||
Pin (Re)Assignment <pins>
|
||||
|
||||
RP2040 Helper <rp2040>
|
||||
RP2040/RP2350 Helper <rp2040>
|
||||
|
||||
Analog I/O <analog>
|
||||
Digital I/O <digital>
|
||||
BOOTSEL Button <bootsel>
|
||||
EEPROM <eeprom>
|
||||
I2S Audio <i2s>
|
||||
PWM Audio <pwm>
|
||||
@@ -43,13 +44,20 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
USB (Arduino and Adafruit_TinyUSB) <usb>
|
||||
Multicore Processing <multicore>
|
||||
|
||||
Bluetooth (Alpha/Beta) <bluetooth>
|
||||
RP2350 Specific Notes <rp2350>
|
||||
RP2350 PSRAM <psram>
|
||||
|
||||
Bluetooth <bluetooth>
|
||||
Bluetooth HID Master <hidmaster>
|
||||
Bluetooth Audio (A2DP) <a2dp>
|
||||
|
||||
Single File USB Drive <singlefile>
|
||||
FatFSUSB - full FS access over USB <fatfsusb>
|
||||
|
||||
FreeRTOS SMP (multicore) <freertos>
|
||||
|
||||
WiFi (Pico-W Support) <wifi>
|
||||
Ethernet (Wired) <ethernet>
|
||||
WiFiClient <wificlient>
|
||||
WiFiServer <wifiserver>
|
||||
WiFiUDP <wifiudp>
|
||||
@@ -65,4 +73,5 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
Ported/Optimized Libraries <libraries>
|
||||
Using Pico-SDK <sdk>
|
||||
|
||||
|
||||
Licenses <license>
|
||||
|
||||
+27
-21
@@ -26,9 +26,7 @@ Arduino IDE Installation Warning
|
||||
the actual Arduino application 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 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 are present.
|
||||
it suggests. Otherwise the Pico board may not be detected.
|
||||
|
||||
**Note for Linux Users**: If you installed the Arduino IDE using Flatpak, which
|
||||
is common in Pop!_OS, Fedora, and Mint, among others, you may need to configure
|
||||
@@ -38,6 +36,22 @@ prevent the Arduino IDE from accessing. For Arduino IDE V2, override the filesys
|
||||
restriction using ``flatpak override --user --filesystem=host cc.arduino.IDE2`` . For
|
||||
For Arduino IDE < V2, use ``flatpak override --user --filesystem=host cc.arduino.arduinoide``.
|
||||
|
||||
Installing via Arduino CLI
|
||||
--------------------------
|
||||
To install using the Arduino command line tool (arduino-cli):
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli config add board_manager.additional_urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install rp2040:rp2040
|
||||
|
||||
To list the supported boards:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli board listall | grep rp2040
|
||||
|
||||
Installing via GIT
|
||||
------------------
|
||||
To install via GIT (for latest and greatest versions):
|
||||
@@ -125,11 +139,13 @@ Uploading Filesystem Images
|
||||
---------------------------
|
||||
The onboard flash filesystem for the Pico, LittleFS, lets you upload a filesystem image from the sketch directory for your sketch to use. Download the needed plugin from
|
||||
|
||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
* `IDE 1.x`: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
* `IDE 2.x`: https://github.com/earlephilhower/arduino-littlefs-upload/releases
|
||||
|
||||
To install, follow the directions in
|
||||
|
||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||
* `IDE 1.x`: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||
* `IDE 2.x`: https://github.com/earlephilhower/arduino-littlefs-upload/blob/main/README.md
|
||||
|
||||
For detailed usage information, please check the repo documentation available at
|
||||
|
||||
@@ -143,12 +159,6 @@ So for the first sketch you will need to rebuild (with the ``Upload Method->Pico
|
||||
|
||||
After the initial upload, as long as the running binary was built using the ``Picotool`` upload method, then the normal upload process should work.
|
||||
|
||||
Under MacOS, it may be necessary to install the USB support libraries from a command terminal before the ``Picotool`` upload method can be used:
|
||||
|
||||
.. code::
|
||||
|
||||
brew install libusb
|
||||
|
||||
For Ubuntu and other Linux operating systems you may need to add the following lines to a new `udev` config file(``99-picotool.rules``) to allow normal users to access the special USB device the Pico exports:
|
||||
|
||||
.. code::
|
||||
@@ -174,11 +184,9 @@ The first line creates a file with the USB vendor and ID of the Picoprobe and te
|
||||
|
||||
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
||||
|
||||
Uploading Sketches with pico-debug
|
||||
----------------------------------
|
||||
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.
|
||||
Uploading Sketches with OpenOCD
|
||||
-------------------------------
|
||||
Under Windows and macOS, any user should be able to access OpenOCD 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`):
|
||||
|
||||
@@ -189,10 +197,8 @@ To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes
|
||||
|
||||
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.
|
||||
Once CMSIS-DAP permissions are set up properly, then select the Upload Method "Picoprobe/Debugprobe (CMSIS-DAP)" in the Tools menu.
|
||||
|
||||
When first connecting the USB port to your PC, you must copy pico-debug-gimmecache.uf2 to the Pi Pico to load pico-debug into RAM; after this, upload as normal.
|
||||
|
||||
Debugging with Picoprobe/pico-debug, OpenOCD, and GDB
|
||||
Debugging with Picoprobe/Debugprobe, 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, 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".
|
||||
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.
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ In addition, it contains code from additional open source projects:
|
||||
* The `Pico-SDK <https://github.com/raspberrypi/pico-sdk>`_ and `Pico-Extras <https://github.com/raspberrypi/pico-extras>`_ are by Raspberry Pi (Trading) Ltd. and licensed under the BSD 3-Clause license.
|
||||
* `Arduino-Pico <https://github.com/earlephilhower/arduino-pico>`_ core files are licenses 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>`_ .
|
||||
* `UF2CONV.PY <https://github.com/microsoft/uf2>`_ is by Microsoft Corporatio and licensed under the MIT license.
|
||||
* `UF2CONV.PY <https://github.com/microsoft/uf2>`_ is by Microsoft Corporation and licensed under the MIT license.
|
||||
* Some filesystem code taken from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`_ and licensed under the LGPL.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user