Compare commits

..

4 commits

Author SHA1 Message Date
Scott Shawcroft
4d8fec111d
Update Feather RP2350 JSON 2024-09-17 09:30:08 -07:00
Scott Shawcroft
73eab6e224
Merge remote-tracking branch 'origin/master' into adafruit_rp2350 2024-09-17 09:25:19 -07:00
ladyada
28c3505f10
init feather rp2350 addition 2024-09-16 16:41:59 -07:00
Scott Shawcroft
42dc80a18c
Add xosc delay for RP2350 2024-09-16 16:41:52 -07:00
465 changed files with 7600 additions and 43680 deletions

View file

@ -1,42 +0,0 @@
# Run whenever it is manually triggered, a pull request or a push is done that modifes the libpico configuration
name: libpico Builder
on:
pull_request:
paths:
- tools/libpico/**
workflow_dispatch:
push:
paths:
- tools/libpico/**
jobs:
build-libpico:
name: Build libpico precompiled libraries
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: false
- name: Get submodules for pico-sdk
run: cd pico-sdk && git submodule update --init --recursive
- name: Install dependencies
run: |
sudo apt update
sudo apt install cmake make build-essential wget
# Automatically get correct toolchain
cd tools && python3 get.py && cd ..
# add to PATH
echo "$GITHUB_WORKSPACE/system/riscv32-unknown-elf/bin" >> "$GITHUB_PATH"
echo "$GITHUB_WORKSPACE/system/arm-none-eabi/bin" >> "$GITHUB_PATH"
- name: Build libpico
run: |
cd tools/libpico
./make-libpico.sh
- uses: actions/upload-artifact@v4
with:
name: libpico
path: |
tools/libpico/build-rp2040/*.a
tools/libpico/build-rp2350/*.a
tools/libpico/build-rp2350-riscv/*.a

View file

@ -10,17 +10,22 @@ jobs:
# Consistent style, spelling # Consistent style, spelling
astyle: astyle:
name: Spelling, Style, Boards, Package, PIO name: Spelling, Style, Boards, Package
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: false submodules: false
- name: Run codespell - name: Run codespell
uses: codespell-project/actions-codespell@v2 uses: codespell-project/actions-codespell@master
with: 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,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h 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,froms 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
- name: Check boards.txt was not edited after makeboards.py - name: Check boards.txt was not edited after makeboards.py
run: | run: |
./tools/makeboards.py ./tools/makeboards.py
@ -33,15 +38,6 @@ jobs:
./tests/restyle.sh ./tests/restyle.sh
# If anything changed, GIT should return an error and fail the test # If anything changed, GIT should return an error and fail the test
git diff --exit-code git diff --exit-code
- name: Check compiled PIO files
run: |
(cd ./tools && ./get.py)
./tools/makepio.py
# If anything changed, GIT should return an error and fail the test
git diff -w --exit-code
- name: Check package references
run: |
./tests/ci/pkgrefs_test.sh
# Build all examples on linux (core and Arduino IDE) # Build all examples on linux (core and Arduino IDE)
build-linux: build-linux:
@ -105,37 +101,6 @@ jobs:
cd .. cd ..
bash ./tests/build-rp2350.sh bash ./tests/build-rp2350.sh
# Build all rp2350-riscv examples on linux (core and Arduino IDE)
build-rp2350-riscv-linux:
name: Build RP2350-RISCV ${{ matrix.chunk }}
runs-on: ubuntu-latest
strategy:
matrix:
chunk: [0, 1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Cache Linux toolchain
id: cache-linux
uses: actions/cache@v4
with:
path: ./tools/dist
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
- name: Build Sketches
env:
BUILD_PARITY: custom
mod: 6
rem: ${{ matrix.chunk }}
run: |
cd pico-sdk
git submodule update --init
cd ..
bash ./tests/build-rp2350-riscv.sh
# Build TinyUSB examples, requires custom build command line # Build TinyUSB examples, requires custom build command line
build-tinyusb: build-tinyusb:
name: Build TinyUSB Examples name: Build TinyUSB Examples
@ -200,7 +165,7 @@ jobs:
name: Mac name: Mac
strategy: strategy:
matrix: matrix:
os: [macOS-13, macOS-14] os: [macOS-12, macOS-14]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -268,14 +233,11 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade platformio pip install --upgrade platformio
rm -rf ~/.platformio/platforms/raspberrypi*
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
pio pkg install --global --tool symlink://. pio pkg install --global --tool symlink://.
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/. cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
- name: Build Multicore Example - name: Build Multicore Example
run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
- name: Build Multicore Example (RISC-V)
run: pio ci -v --board=rpipico2 -O "board_build.mcu = rp2350-riscv" -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
- name: Build Fade Example - 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 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 - name: Build TinyUSB Example
@ -325,7 +287,6 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade platformio pip install --upgrade platformio
rm -rf ~/.platformio/platforms/raspberrypi*
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
pio pkg install --global --tool symlink://. pio pkg install --global --tool symlink://.
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/. cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.

7
.gitignore vendored
View file

@ -3,10 +3,5 @@ system
tools/dist tools/dist
docs/_build docs/_build
ota/build ota/build
ota/build-rp2350 tools/libpico/build
ota/build-rp2350-riscv
tools/libpico/boot
tools/libpico/build-rp2040
tools/libpico/build-rp2350
tools/libpico/build-rp2350-riscv
platform.local.txt platform.local.txt

9
.gitmodules vendored
View file

@ -10,6 +10,9 @@
[submodule "libraries/LittleFS/lib/littlefs"] [submodule "libraries/LittleFS/lib/littlefs"]
path = libraries/LittleFS/lib/littlefs path = libraries/LittleFS/lib/littlefs
url = https://github.com/littlefs-project/littlefs.git url = https://github.com/littlefs-project/littlefs.git
[submodule "libraries/SdFat"]
path = libraries/ESP8266SdFat
url = https://github.com/earlephilhower/ESP8266SdFat.git
[submodule "libraries/Keyboard"] [submodule "libraries/Keyboard"]
path = libraries/HID_Keyboard path = libraries/HID_Keyboard
url = https://github.com/earlephilhower/Keyboard.git url = https://github.com/earlephilhower/Keyboard.git
@ -43,9 +46,3 @@
[submodule "cores/rp2040/tlsf"] [submodule "cores/rp2040/tlsf"]
path = lib/tlsf path = lib/tlsf
url = https://github.com/earlephilhower/tlsf.git url = https://github.com/earlephilhower/tlsf.git
[submodule "libraries/ESPHost"]
path = libraries/ESPHost
url = https://github.com/Networking-for-Arduino/ESPHost.git
[submodule "libraries/SdFat"]
path = libraries/SdFat
url = https://github.com/greiman/SdFat.git

View file

@ -29,8 +29,8 @@ sphinx:
# fail_on_warning: true # fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub # Optionally build your docs in additional formats such as PDF and ePub
formats: # formats:
- pdf # - pdf
# - epub # - epub
# Optional but recommended, declare the Python requirements required # Optional but recommended, declare the Python requirements required

@ -1 +1 @@
Subproject commit 82928635c893189343cf8eb78569f0c4136fded0 Subproject commit ece6e68f29c6f406a4434659bcbcfe558baaa3a9

View file

@ -4,7 +4,7 @@
Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
This is a port of Arduino to the RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2 processor). It uses the bare Raspberry Pi Pico SDK and a custom GCC 14.2/Newlib 4.3 toolchain and supports ARM and RISC-V cores. This is a port of 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 # Documentation
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information. See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
@ -16,16 +16,13 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Raspberry Pi Pico * Raspberry Pi Pico
* Raspberry Pi Pico W * Raspberry Pi Pico W
* Raspberry Pi Pico 2 * Raspberry Pi Pico 2
* Raspberry Pi Pico 2W
* 0xCB Helios * 0xCB Helios
* Adafruit Feather RP2040 * Adafruit Feather RP2040
* Adafruit Feather RP2040 SCORPIO * Adafruit Feather RP2040 SCORPIO
* Adafruit Floppsy RP2040
* Adafruit ItsyBitsy RP2040 * Adafruit ItsyBitsy RP2040
* Adafruit KB2040 * Adafruit KB2040
* Adafruit Macropad RP2040 * Adafruit Macropad RP2040
* Adafruit Metro RP2040 * Adafruit Metro RP2040
* Adafruit Metro RP2350
* Adafruit QTPy RP2040 * Adafruit QTPy RP2040
* Adafruit STEMMA Friend RP2040 * Adafruit STEMMA Friend RP2040
* Adafruit Trinkey RP2040 QT * Adafruit Trinkey RP2040 QT
@ -33,8 +30,6 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Amken Revelop * Amken Revelop
* Amken Revelop Plus * Amken Revelop Plus
* Amken Revelop eS * Amken Revelop eS
* Architeuthis Flux Jumperless
* Architeuthis Flux Jumperless V5
* Arduino Nano RP2040 Connect * Arduino Nano RP2040 Connect
* ArtronShop RP2 Nano * ArtronShop RP2 Nano
* Breadstick Raspberry * Breadstick Raspberry
@ -45,8 +40,7 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Cytron Maker Nano RP2040 * Cytron Maker Nano RP2040
* Cytron Maker Uno RP2040 * Cytron Maker Uno RP2040
* Cytron Motion 2350 Pro * Cytron Motion 2350 Pro
* Datanoise PicoADK v1 * DatanoiseTV PicoADK+
* Datanoise PicoADK v2 (RP2350)
* Degz Suibo RP2040 * Degz Suibo RP2040
* DeRuiLab FlyBoard2040 Core * DeRuiLab FlyBoard2040 Core
* DFRobot Beetle RP2040 * DFRobot Beetle RP2040
@ -69,21 +63,13 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Melopero Cookie RP2040 * Melopero Cookie RP2040
* Melopero Shake RP2040 * Melopero Shake RP2040
* METE HOCA Akana R1 * METE HOCA Akana R1
* Makerbase MKSTHR36
* Makerbase MKSTHR42
* MyMakers RP2040
* Neko Systems BL2040 Mini * Neko Systems BL2040 Mini
* Olimex RP2040-Pico30
* Newsan Archi * Newsan Archi
* nullbits Bit-C PRO * nullbits Bit-C PRO
* Olimex Pico2XL
* Olimex Pico2XXL
* Olimex RP2040-Pico30
* Pimoroni PGA2040 * Pimoroni PGA2040
* Pimoroni Pico Plus 2 * Pimoroni Pico Plus 2
* Pimoroni Pico Plus 2W
* Pimoroni Plasma2040 * Pimoroni Plasma2040
* Pimoroni Plasma2350
* Pimoroni Servo2040
* Pimoroni Tiny2040 * Pimoroni Tiny2040
* Pimoroni Tiny2350 * Pimoroni Tiny2350
* Pintronix PinMax * Pintronix PinMax
@ -93,18 +79,14 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Sea-Picro * Sea-Picro
* Seeed Indicator RP2040 * Seeed Indicator RP2040
* Seeed XIAO RP2040 * Seeed XIAO RP2040
* Seeed XIAO RP2350
* Silicognition RP2040-Shim * Silicognition RP2040-Shim
* Solder Party RP2040 Stamp * Solder Party RP2040 Stamp
* Solder Party RP2350 Stamp * Solder Party RP2350 Stamp
* Solder Party RP2350 Stamp XL * Solder Party RP2350 Stamp XL
* SparkFun IoT RedBoard RP2350
* SparkFun MicroMod RP2040 * SparkFun MicroMod RP2040
* SparkFun ProMicro RP2040 * SparkFun ProMicro RP2040
* SparkFun ProMicro RP2350 * SparkFun ProMicro RP2350
* SparkFun Thing Plus RP2040 * SparkFun Thing Plus RP2040
* SparkFun Thing Plus RP2350
* SparkFun XRP Controller
* uPesy RP2040 DevKit * uPesy RP2040 DevKit
* VCC-GND YD-RP2040 * VCC-GND YD-RP2040
* Viyalab Mizu RP2040 * Viyalab Mizu RP2040
@ -116,10 +98,7 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Waveshare RP2040 Matrix * Waveshare RP2040 Matrix
* Waveshare RP2040 PiZero * Waveshare RP2040 PiZero
* WIZnet W5100S-EVB-Pico * WIZnet W5100S-EVB-Pico
* WIZnet W5100S-EVB-Pico2
* WIZnet W5500-EVB-Pico * WIZnet W5500-EVB-Pico
* WIZnet W5500-EVB-Pico2
* WIZnet W55RP20-EVB-Pico
* WIZnet WizFi360-EVB-Pico * WIZnet WizFi360-EVB-Pico
* Generic RP2040 (configurable flash, I/O pins) * Generic RP2040 (configurable flash, I/O pins)
* Generic RP2350 (configurable flash, I/O pins) * Generic RP2350 (configurable flash, I/O pins)
@ -146,9 +125,6 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Peripherals: SPI master/slave, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input/output, Servo * 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 * printf (i.e. debug) output over USB serial
* Transparent use of PSRAM globals and heap (RP2350 only) * Transparent use of PSRAM globals and heap (RP2350 only)
* ARM or RISC-V (Hazard3) support for the RP2350
* Semihosted serial and file system access
* GPROF profiling support
The RP2040 PIO state machines (SMs) are used to generate jitter-free: The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* Servos * Servos
@ -156,7 +132,7 @@ The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* I2S Input * I2S Input
* I2S Output * I2S Output
* Software UARTs (Serial ports) * Software UARTs (Serial ports)
* Software SPIs
# Installing via Arduino Boards Manager # Installing via Arduino Boards Manager
## Windows-specific Notes ## Windows-specific Notes
@ -285,7 +261,6 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
* [Xoshiro-cpp](https://github.com/Reputeless/Xoshiro-cpp) is copyright (c) 2020 Ryo Suzuki and distributed under the MIT license. * [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. * [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. * [TLSF memory manager for PSRAM from Espressif fork](https://github.com/espressif/tlsf) of [original](https://github.com/mattconte/tlsf) by Matthew Conte is copyright Matthew Conte and licensed under the MIT license.
* [ESPHost library](https://github.com/Networking-for-Arduino/ESPHost) is LGPL licensed by its maintainers.
-Earle F. Philhower, III -Earle F. Philhower, III
earlephilhower@yahoo.com earlephilhower@yahoo.com

12440
boards.txt

File diff suppressed because it is too large Load diff

View file

@ -1,4 +0,0 @@
.section .boot2, "ax"
.global __boot2_entry_point
__boot2_entry_point:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,4 +0,0 @@
.section .boot2, "ax"
.global __boot2_entry_point
__boot2_entry_point:

View file

@ -27,30 +27,17 @@
#include "RP2040Version.h" #include "RP2040Version.h"
#include "api/ArduinoAPI.h" #include "api/ArduinoAPI.h"
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them #include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
#include <pico.h>
#undef PICO_RP2350A // Set in the RP2350 SDK boards file, overridden in the variant pins_arduino.h
#include <pins_arduino.h> #include <pins_arduino.h>
#include <hardware/gpio.h> // Required for the port*Register macros #include <hardware/gpio.h> // Required for the port*Register macros
#include "debug_internal.h" #include "debug_internal.h"
// Chip sanity checking. SDK uses interesting way of separating 2350A from 2350B, see https://github.com/raspberrypi/pico-sdk/issues/2364
#if (!defined(PICO_RP2040) && !defined(PICO_RP2350)) || defined(PICO_RP2040) && defined(PICO_RP2350)
#error Invalid core definition. Either PICO_RP2040 or PICO_RP2350 must be defined.
#endif
#if defined(PICO_RP2350) && !defined(PICO_RP2350A)
#error Invalid RP2350 definition. Need to set PICO_RP2350A=0/1 for A/B variant
#endif
#if defined(PICO_RP2350B)
#error Do not define PICO_RP2350B. Use PICO_RP2350A=0 to indicate RP2350B. See the SDK for more details
#endif
// Try and make the best of the old Arduino abs() macro. When in C++, use // Try and make the best of the old Arduino abs() macro. When in C++, use
// the sane std::abs() call, but for C code use their macro since stdlib abs() // the sane std::abs() call, but for C code use their macro since stdlib abs()
// is int but their macro "works" for everything (with potential side effects) // is int but their macro "works" for everything (with potential side effects)
#ifdef abs #ifdef abs
#undef abs #undef abs
#endif // abs #endif // abs
#if defined(__cplusplus) && !defined(__riscv) #ifdef __cplusplus
using std::abs; using std::abs;
using std::round; using std::round;
#else #else
@ -123,7 +110,7 @@ extern bool __isFreeRTOS;
#endif #endif
#ifndef PGM_VOID_P #ifndef PGM_VOID_P
#define PGM_VOID_P const void * #define PGM_VOID_P void *
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -139,7 +126,6 @@ extern const String emptyString;
#endif #endif
#include "SerialUART.h" #include "SerialUART.h"
#include "SerialSemi.h"
#include "RP2040Support.h" #include "RP2040Support.h"
#include "SerialPIO.h" #include "SerialPIO.h"
#include "Bootsel.h" #include "Bootsel.h"
@ -165,14 +151,10 @@ constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
#define PSRAM __attribute__((section("\".psram\""))) #define PSRAM __attribute__((section("\".psram\"")))
// General GPIO/ADC layout info // General GPIO/ADC layout info
#if defined(PICO_RP2350) && !PICO_RP2350A #ifdef PICO_RP2350B
#define __GPIOCNT 48 #define __GPIOCNT 48
#define __FIRSTANALOGGPIO 40 #define __FIRSTANALOGGPIO 40
#else #else
#define __GPIOCNT 30 #define __GPIOCNT 30
#define __FIRSTANALOGGPIO 26 #define __FIRSTANALOGGPIO 26
#endif #endif
#ifdef __cplusplus
using namespace arduino;
#endif

View file

@ -1,21 +0,0 @@
// Abstract class for audio output devices to allow easy swapping between output devices
#pragma once
#include <Print.h>
class AudioOutputBase : public Print {
public:
virtual ~AudioOutputBase() { }
virtual bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0) = 0;
virtual bool setBitsPerSample(int bps) = 0;
virtual bool setFrequency(int freq) = 0;
virtual bool setStereo(bool stereo = true) = 0;
virtual bool begin() = 0;
virtual bool end() = 0;
virtual bool getUnderflow() = 0;
virtual void onTransmit(void(*)(void *), void *) = 0;
// From Print
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
virtual int availableForWrite() = 0;
};

View file

@ -26,9 +26,7 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
// Must disable interrupts, as interrupt handlers may be in flash, and we // Must disable interrupts, as interrupt handlers may be in flash, and we
// are about to temporarily disable flash access! // are about to temporarily disable flash access!
if (!__isFreeRTOS) { noInterrupts();
noInterrupts();
}
rp2040.idleOtherCore(); rp2040.idleOtherCore();
// Set chip select to Hi-Z // Set chip select to Hi-Z
@ -55,9 +53,7 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
rp2040.resumeOtherCore(); rp2040.resumeOtherCore();
if (!__isFreeRTOS) { interrupts();
interrupts();
}
return button_state; return button_state;
} }

View file

@ -20,21 +20,10 @@
#pragma once #pragma once
/**
@brief Wrapper class for polling the BOOTSEL button
*/
class __Bootsel { class __Bootsel {
public: public:
__Bootsel() { } __Bootsel() { }
/**
@brief Get state of the BOOTSEL pin
@returns True if BOOTSEL pushed
*/
operator bool(); operator bool();
}; };
/**
@brief BOOTSEL accessor instance
*/
extern __Bootsel BOOTSEL; extern __Bootsel BOOTSEL;

View file

@ -1,2 +1 @@
#include "api/IPAddress.h" #include "api/IPAddress.h"
using arduino::IPAddress;

View file

@ -33,6 +33,7 @@
static std::map<const pio_program_t *, int> __pioMap[PIOCNT]; static std::map<const pio_program_t *, int> __pioMap[PIOCNT];
static bool __pioAllocated[PIOCNT]; static bool __pioAllocated[PIOCNT];
static bool __pioHighGPIO[PIOCNT];
auto_init_mutex(_pioMutex); auto_init_mutex(_pioMutex);
PIOProgram::PIOProgram(const pio_program_t *pgm) { PIOProgram::PIOProgram(const pio_program_t *pgm) {
@ -53,16 +54,26 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
CoreMutex m(&_pioMutex); CoreMutex m(&_pioMutex);
PIO pi[PIOCNT] = { PIOS }; PIO pi[PIOCNT] = { PIOS };
uint gpioBaseNeeded = ((start + cnt) >= 32) ? 16 : 0; #if 0
DEBUGV("PIOProgram %p: Searching for base=%d, pins %d-%d\n", _pgm, gpioBaseNeeded, start, start + cnt - 1); 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 // If it's already loaded into PIO IRAM, try and allocate in that specific PIO
for (int o = 0; o < PIOCNT; o++) { for (int o = 0; o < PIOCNT; o++) {
auto p = __pioMap[o].find(_pgm); auto p = __pioMap[o].find(_pgm);
if ((p != __pioMap[o].end()) && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) { if ((p != __pioMap[o].end()) && (__pioHighGPIO[o] == needsHigh)) {
int idx = pio_claim_unused_sm(pi[o], false); int idx = pio_claim_unused_sm(pi[o], false);
if (idx >= 0) { if (idx >= 0) {
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1); 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]; _pio = pi[o];
_sm = idx; _sm = idx;
*pio = pi[o]; *pio = pi[o];
@ -75,12 +86,12 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
// Not in any PIO IRAM, so try and add // Not in any PIO IRAM, so try and add
for (int o = 0; o < PIOCNT; o++) { for (int o = 0; o < PIOCNT; o++) {
if (__pioAllocated[o] && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) { if (__pioAllocated[o] && (__pioHighGPIO[o] == needsHigh)) {
DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]); DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]);
if (pio_can_add_program(pi[o], _pgm)) { if (pio_can_add_program(pi[o], _pgm)) {
int idx = pio_claim_unused_sm(pi[o], false); int idx = pio_claim_unused_sm(pi[o], false);
if (idx >= 0) { if (idx >= 0) {
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1); 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); int off = pio_add_program(pi[o], _pgm);
__pioMap[o].insert({_pgm, off}); __pioMap[o].insert({_pgm, off});
_pio = pi[o]; _pio = pi[o];
@ -112,7 +123,8 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
} }
assert(!__pioAllocated[o]); assert(!__pioAllocated[o]);
__pioAllocated[o] = true; __pioAllocated[o] = true;
DEBUGV("PIOProgram %p: Allocating new PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1); __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}); __pioMap[o].insert({_pgm, off});
_pio = pi[o]; _pio = pi[o];
_sm = idx; _sm = idx;

View file

@ -19,10 +19,6 @@
*/ */
#include <Arduino.h> #include <Arduino.h>
#include <pico/runtime.h>
#ifdef PICO_RP2040
#include <hardware/structs/psm.h> #include <hardware/structs/psm.h>
extern "C" void boot_double_tap_check(); extern "C" void boot_double_tap_check();
@ -35,19 +31,3 @@ void RP2040::enableDoubleResetBootloader() {
boot_double_tap_check(); boot_double_tap_check();
} }
} }
#endif
#ifdef __PROFILE
Stream *__profileFile;
int __writeProfileCB(const void *data, int len) {
return __profileFile->write((const char *)data, len);
}
#ifdef __PROFILE
extern "C" void runtime_init_setup_profiling();
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
#endif
#endif

View file

@ -18,17 +18,10 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once
#include <hardware/clocks.h> #include <hardware/clocks.h>
#include <hardware/irq.h> #include <hardware/irq.h>
#include <hardware/pio.h> #include <hardware/pio.h>
#include <pico/unique_id.h> #include <pico/unique_id.h>
#ifdef PICO_RP2350
#include <hardware/regs/powman.h>
#else
#include <hardware/regs/vreg_and_chip_reset.h>
#endif
#include <hardware/exception.h> #include <hardware/exception.h>
#include <hardware/watchdog.h> #include <hardware/watchdog.h>
#include <hardware/structs/rosc.h> #include <hardware/structs/rosc.h>
@ -47,13 +40,6 @@
extern "C" volatile bool __otherCoreIdled; extern "C" volatile bool __otherCoreIdled;
extern "C" {
#ifdef __PROFILE
typedef int (*profileWriteCB)(const void *data, int len);
extern void _writeProfile(profileWriteCB writeCB);
#endif
}
class _MFIFO { class _MFIFO {
public: public:
_MFIFO() { /* noop */ }; _MFIFO() { /* noop */ };
@ -182,166 +168,90 @@ extern "C" void loop1() __attribute__((weak));
extern "C" bool core1_separate_stack; extern "C" bool core1_separate_stack;
extern "C" uint32_t* core1_separate_stack_address; extern "C" uint32_t* core1_separate_stack_address;
/**
@brief RP2040/RP2350 helper function for HW-specific features
*/
class RP2040 { class RP2040 {
public: public:
RP2040() { /* noop */ } RP2040() { /* noop */ }
~RP2040() { /* noop */ } ~RP2040() { /* noop */ }
void begin(int cpuid) { void begin() {
_epoch[cpuid] = 0; _epoch = 0;
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) { if (!__isFreeRTOS) {
// Enable SYSTICK exception // Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler); exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7; systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF; systick_hw->rvr = 0x00FFFFFF;
} else { } else {
#endif int off = 0;
// Only start 1 instance of the PIO SM _ccountPgm = new PIOProgram(&ccount_program);
if (cpuid == 0) { _ccountPgm->prepare(&_pio, &_sm, &off);
int off = 0; ccount_program_init(_pio, _sm, off);
_ccountPgm = new PIOProgram(&ccount_program); pio_sm_set_enabled(_pio, _sm, true);
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
}
#if !defined(__riscv) && !defined(__PROFILE)
} }
#endif
} }
/** // Convert from microseconds to PIO clock cycles
@brief Convert from microseconds to PIO clock cycles
@returns the PIO cycles for a given microsecond delay
*/
static int usToPIOCycles(int us) { static int usToPIOCycles(int us) {
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow // Parenthesis needed to guarantee order of operations to avoid 32bit overflow
return (us * (clock_get_hz(clk_sys) / 1'000'000)); return (us * (clock_get_hz(clk_sys) / 1'000'000));
} }
/** // Get current clock frequency
@brief Gets the active CPU speed (may differ from F_CPU
@returns CPU frequency in Hz
*/
static int f_cpu() { static int f_cpu() {
return clock_get_hz(clk_sys); return clock_get_hz(clk_sys);
} }
/** // Get current CPU core number
@brief Get the core ID that is currently executing this code
@returns 0 for Core 0, 1 for Core 1
*/
static int cpuid() { static int cpuid() {
return sio_hw->cpuid; return sio_hw->cpuid;
} }
/** // Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
@brief CPU cycle counter epoch (24-bit cycle). For internal use volatile uint64_t _epoch = 0;
*/
volatile uint64_t _epoch[2] = {};
/**
@brief Get the count of CPU clock cycles since power on.
@details
The 32-bit count will overflow every 4 billion cycles, so consider using ``getCycleCount64`` for
longer measurements
@returns CPU clock cycles since power up
*/
inline uint32_t getCycleCount() { inline uint32_t getCycleCount() {
#if !defined(__riscv) && !defined(__PROFILE)
// Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
if (!__isFreeRTOS) { if (!__isFreeRTOS) {
uint32_t epoch; uint32_t epoch;
uint32_t ctr; uint32_t ctr;
do { do {
epoch = (uint32_t)_epoch[sio_hw->cpuid]; epoch = (uint32_t)_epoch;
ctr = systick_hw->cvr; ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch[sio_hw->cpuid]); } while (epoch != (uint32_t)_epoch);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */ return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
} else { } else {
#endif
return ccount_read(_pio, _sm); return ccount_read(_pio, _sm);
#if !defined(__riscv) && !defined(__PROFILE)
} }
#endif
} }
/**
@brief Get the count of CPU clock cycles since power on as a 64-bit quantrity
@returns CPU clock cycles since power up
*/
inline uint64_t getCycleCount64() { inline uint64_t getCycleCount64() {
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) { if (!__isFreeRTOS) {
uint64_t epoch; uint64_t epoch;
uint64_t ctr; uint64_t ctr;
do { do {
epoch = _epoch[sio_hw->cpuid]; epoch = _epoch;
ctr = systick_hw->cvr; ctr = systick_hw->cvr;
} while (epoch != _epoch[sio_hw->cpuid]); } while (epoch != _epoch);
return epoch + (1LL << 24) - ctr; return epoch + (1LL << 24) - ctr;
} else { } else {
#endif
return ccount_read(_pio, _sm); return ccount_read(_pio, _sm);
#if !defined(__riscv) && !defined(__PROFILE)
} }
#endif
} }
/**
@brief Gets total unused heap (dynamic memory)
@details
Note that the allocations of the size of the total free heap may fail due to fragmentation.
For example, ``getFreeHeap`` can report 100KB available, but an allocation of 90KB may fail
because there may not be a contiguous 90KB space available
@returns Free heap in bytes
*/
inline int getFreeHeap() { inline int getFreeHeap() {
return getTotalHeap() - getUsedHeap(); return getTotalHeap() - getUsedHeap();
} }
/**
@brief Gets total used heap (dynamic memory)
@returns Used heap in bytes
*/
inline int getUsedHeap() { inline int getUsedHeap() {
struct mallinfo m = mallinfo(); struct mallinfo m = mallinfo();
return m.uordblks; return m.uordblks;
} }
/**
@brief Gets total heap (dynamic memory) compiled into the program
@returns Total heap size in bytes
*/
inline int getTotalHeap() { inline int getTotalHeap() {
return &__StackLimit - &__bss_end__; return &__StackLimit - &__bss_end__;
} }
/**
@brief On the RP2350, returns the amount of heap (dynamic memory) available in PSRAM
@returns Total free heap in PSRAM, or 0 if no PSRAM present
*/
inline int getFreePSRAMHeap() { inline int getFreePSRAMHeap() {
return getTotalPSRAMHeap() - getUsedPSRAMHeap(); return getTotalPSRAMHeap() - getUsedPSRAMHeap();
} }
/**
@brief On the RP2350, returns the total amount of PSRAM heap (dynamic memory) used
@returns Bytes used in PSRAM, or 0 if no PSRAM present
*/
inline int getUsedPSRAMHeap() { inline int getUsedPSRAMHeap() {
#if defined(RP2350_PSRAM_CS) #if defined(RP2350_PSRAM_CS)
extern size_t __psram_total_used(); extern size_t __psram_total_used();
@ -351,11 +261,6 @@ public:
#endif #endif
} }
/**
@brief On the RP2350, gets total heap (dynamic memory) compiled into the program
@returns Total PSRAM heap size in bytes, or 0 if no PSRAM present
*/
inline int getTotalPSRAMHeap() { inline int getTotalPSRAMHeap() {
#if defined(RP2350_PSRAM_CS) #if defined(RP2350_PSRAM_CS)
extern size_t __psram_total_space(); extern size_t __psram_total_space();
@ -365,29 +270,12 @@ public:
#endif #endif
} }
/**
@brief Gets the current stack pointer in a ARM/RISC-V safe manner
@returns Current SP
*/
inline uint32_t getStackPointer() { inline uint32_t getStackPointer() {
uint32_t *sp; uint32_t *sp;
#if defined(__riscv)
asm volatile("mv %0, sp" : "=r"(sp));
#else
asm volatile("mov %0, sp" : "=r"(sp)); asm volatile("mov %0, sp" : "=r"(sp));
#endif
return (uint32_t)sp; return (uint32_t)sp;
} }
/**
@brief Calculates approximately how much stack space is still available for the running core. Handles multiprocessing and separate stacks.
@details
Not valid in FreeRTOS. Use the FreeRTOS internal functions to access this information.
@returns Approximation of the amount of stack available for use on the specific core
*/
inline int getFreeStack() { inline int getFreeStack() {
const unsigned int sp = getStackPointer(); const unsigned int sp = getStackPointer();
uint32_t ref = 0x20040000; uint32_t ref = 0x20040000;
@ -401,11 +289,6 @@ public:
return sp - ref; return sp - ref;
} }
/**
@brief On the RP2350, gets the size of attached PSRAM
@returns PSRAM size in bytes, or 0 if no PSRAM present
*/
inline size_t getPSRAMSize() { inline size_t getPSRAMSize() {
#if defined(RP2350_PSRAM_CS) #if defined(RP2350_PSRAM_CS)
extern size_t __psram_size; extern size_t __psram_size;
@ -415,48 +298,20 @@ public:
#endif #endif
} }
/**
@brief Freezes the other core in a flash-write-safe state. Not generally needed by applications
@details
When the external flash chip is erasing or writing, the Pico cannot fetch instructions from it.
In this case both the core doing the writing and the other core (if active) need to run from a
routine that's contained in RAM. This call forces the other core into a tight, RAM-based loop
safe for this operation. When flash erase/write is completed, ``resumeOtherCore`` to return
it to operation.
Be sure to disable any interrupts or task switches before calling to avoid deadlocks.
If the second core is not started, this is a no-op.
*/
void idleOtherCore() { void idleOtherCore() {
fifo.idleOtherCore(); fifo.idleOtherCore();
} }
/**
@brief Resumes normal operation of the other core
*/
void resumeOtherCore() { void resumeOtherCore() {
fifo.resumeOtherCore(); fifo.resumeOtherCore();
} }
/**
@brief Hard resets the 2nd core (CORE1).
@details
Because core1 will restart with the heap and global variables not in the same state as
power-on, this call may not work as desired and a full CPU reset may be necessary in
certain cases.
*/
void restartCore1() { void restartCore1() {
multicore_reset_core1(); multicore_reset_core1();
fifo.clear(); fifo.clear();
multicore_launch_core1(main1); multicore_launch_core1(main1);
} }
/**
@brief Warm-reboots the chip in normal mode
*/
void reboot() { void reboot() {
watchdog_reboot(0, 0, 10); watchdog_reboot(0, 0, 10);
while (1) { while (1) {
@ -464,16 +319,10 @@ public:
} }
} }
/**
@brief Warm-reboots the chip in normal mode
*/
inline void restart() { inline void restart() {
reboot(); reboot();
} }
/**
@brief Warm-reboots the chip into the USB bootloader mode
*/
inline void rebootToBootloader() { inline void rebootToBootloader() {
reset_usb_boot(0, 0); reset_usb_boot(0, 0);
while (1) { while (1) {
@ -481,93 +330,16 @@ public:
} }
} }
#ifdef PICO_RP2040
static void enableDoubleResetBootloader(); static void enableDoubleResetBootloader();
#endif
/**
@brief Starts the hardware watchdog timer. The CPU will reset if the watchdog is not fed every delay_ms
@param [in] delay_ms Milliseconds without a wdt_reset before rebooting
*/
void wdt_begin(uint32_t delay_ms) { void wdt_begin(uint32_t delay_ms) {
watchdog_enable(delay_ms, 1); watchdog_enable(delay_ms, 1);
} }
/**
@brief Feeds the watchdog timer, resetting it for another delay_ms countdown
*/
void wdt_reset() { void wdt_reset() {
watchdog_update(); watchdog_update();
} }
/**
@brief Best-effort reasons for chip reset
*/
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
/**
@brief Attempts to determine the reason for the last chip reset. May not always be able to determine accurately
@returns Reason for reset
*/
resetReason_t getResetReason(void) {
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
if (watchdog_caused_reboot() && watchdog_enable_caused_reboot()) { // watchdog timer
return WDT_RESET;
}
if (*WD_reason_reg & WATCHDOG_REASON_TIMER_BITS) { // soft reset() or reboot()
return SOFT_RESET;
}
#ifdef PICO_RP2350
// **** RP2350 is untested ****
io_rw_32 *rrp = (io_rw_32 *)(POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET);
if (*rrp & POWMAN_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset (brownout is separately detected on RP2350)
return PWRON_RESET;
}
if (*rrp & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { // RUN pin
return RUN_PIN_RESET;
}
if ((*rrp & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_HZD_SYS_RESET_REQ_BITS)) { // DEBUG port
return DEBUG_RESET;
}
if (*rrp & POWMAN_CHIP_RESET_HAD_GLITCH_DETECT_BITS) { // power supply glitch
return GLITCH_RESET;
}
if (*rrp & POWMAN_CHIP_RESET_HAD_BOR_BITS) { // power supply brownout reset
return BROWNOUT_RESET;
}
#else
io_rw_32 *rrp = (io_rw_32 *)(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET);
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset or brown-out detection
return PWRON_RESET;
}
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { // RUN pin
return RUN_PIN_RESET;
}
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { // DEBUG port
return DEBUG_RESET; // **** untested **** debug reset may just cause a rebootToBootloader()
}
#endif
return UNKNOWN_RESET;
}
/**
@brief Get unique ID string for the running board
@returns String with the unique board ID as determined by the SDK
*/
const char *getChipID() { const char *getChipID() {
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 }; static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
if (!id[0]) { if (!id[0]) {
@ -578,17 +350,6 @@ public:
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("Os") #pragma GCC optimize ("Os")
/**
@brief Perform a memcpy using a DMA engine for speed
@details
Uses the DMA to copy to and from RAM. Only works on 4-byte aligned, 4-byte multiple length
sources and destination (i.e. word-aligned, word-length). Falls back to normal memcpy otherwise.
@param [out] dest Memcpy destination, 4-byte aligned
@param [in] src Memcpy source, 4-byte aligned
@param [in] n Count in bytes to transfer (should be a multiple of 4 bytes)
*/
void *memcpyDMA(void *dest, const void *src, size_t n) { void *memcpyDMA(void *dest, const void *src, size_t n) {
// Allocate a DMA channel on 1st call, reuse it every call after // Allocate a DMA channel on 1st call, reuse it every call after
if (memcpyDMAChannel < 1) { if (memcpyDMAChannel < 1) {
@ -617,34 +378,16 @@ public:
} }
#pragma GCC pop_options #pragma GCC pop_options
/** // Multicore comms FIFO
@brief Multicore communications FIFO
*/
_MFIFO fifo; _MFIFO fifo;
/**
@brief Return a 32-bit from the hardware random number generator
@returns Random value using appropriate hardware (RP2350 has true RNG, RP2040 has a less true RNG method)
*/
uint32_t hwrand32() { uint32_t hwrand32() {
return get_rand_32(); return get_rand_32();
} }
/**
@brief Determines if code is running on a Pico or a PicoW
@details
Code compiled for the RP2040 PicoW can run on the RP2040 Pico. This call lets an application
identify if the current device is really a Pico or PicoW and handle appropriately. For
the RP2350, this runtime detection is not available and the call returns whether it was
compiled for the CYW43 WiFi driver
@returns True if running on a PicoW board with CYW43 WiFi chip.
*/
bool isPicoW() { bool isPicoW() {
#if !defined(PICO_CYW43_SUPPORTED) #if !defined(ARDUINO_RASPBERRY_PI_PICO_W)
return false; return false;
#else #else
extern bool __isPicoW; extern bool __isPicoW;
@ -652,25 +395,10 @@ public:
#endif #endif
} }
#ifdef __PROFILE
void writeProfiling(Stream *f) {
extern Stream *__profileFile;
extern int __writeProfileCB(const void *data, int len);
__profileFile = f;
_writeProfile(__writeProfileCB);
}
size_t getProfileMemoryUsage() {
extern int __profileMemSize;
return (size_t) __profileMemSize;
}
#endif
private: private:
static void __no_inline_not_in_flash_func(_SystickHandler)() { static void _SystickHandler() {
rp2040._epoch[sio_hw->cpuid] += 1LL << 24; rp2040._epoch += 1LL << 24;
} }
PIO _pio; PIO _pio;
int _sm; int _sm;

View file

@ -1,5 +1,5 @@
#pragma once #pragma once
#define ARDUINO_PICO_MAJOR 4 #define ARDUINO_PICO_MAJOR 4
#define ARDUINO_PICO_MINOR 5 #define ARDUINO_PICO_MINOR 0
#define ARDUINO_PICO_REVISION 4 #define ARDUINO_PICO_REVISION 2
#define ARDUINO_PICO_VERSION_STR "4.5.4" #define ARDUINO_PICO_VERSION_STR "4.0.2"

View file

@ -1,297 +0,0 @@
/*
SemiFS.h - File system wrapper for Semihosting ARM
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "Semihosting.h"
#include "FS.h"
#include "FSImpl.h"
using namespace fs;
namespace semifs {
class SemiFSFileImpl;
class SemiFSConfig : public FSConfig {
public:
static constexpr uint32_t FSId = 0x53454d49;
SemiFSConfig() : FSConfig(FSId, false) { }
};
class SemiFSFileImpl : public FileImpl {
public:
SemiFSFileImpl(int fd, const char *name, bool writable)
: _fd(fd), _opened(true), _writable(writable) {
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
strcpy(_name.get(), name);
}
~SemiFSFileImpl() override {
flush();
close();
}
int availableForWrite() override {
return 1; // TODO - not implemented? _opened ? _fd->availableSpaceForWrite() : 0;
}
size_t write(const uint8_t *buf, size_t size) override {
if (_opened) {
uint32_t a[3];
a[0] = _fd;
a[1] = (uint32_t)buf;
a[2] = size;
return 0 == Semihost(SEMIHOST_SYS_WRITE, a) ? size : -1;
}
return -1; // some kind of error
}
int read(uint8_t* buf, size_t size) override {
if (_opened) {
uint32_t a[3];
a[0] = _fd;
a[1] = (uint32_t)buf;
a[2] = size;
int ret = Semihost(SEMIHOST_SYS_READ, a);
if (ret == 0) {
return size;
} else if (ret == (int)size) {
return -1;
} else {
return ret;
}
}
return -1;
}
void flush() override {
/* noop */
}
bool seek(uint32_t pos, SeekMode mode) override {
if (!_opened || (mode != SeekSet)) {
// No seek cur/end in semihost
return false;
}
uint32_t a[2];
a[0] = _fd;
a[1] = pos;
return !Semihost(SEMIHOST_SYS_SEEK, a);
}
size_t position() const override {
return 0; // Not available semihost
}
size_t size() const override {
if (!_opened) {
return 0;
}
uint32_t a;
a = _fd;
int ret = Semihost(SEMIHOST_SYS_FLEN, &a);
if (ret < 0) {
return 0;
}
return ret;
}
bool truncate(uint32_t size) override {
return false; // Not allowed
}
void close() override {
if (_opened) {
uint32_t a = _fd;
Semihost(SEMIHOST_SYS_CLOSE, &a);
_opened = false;
}
}
const char* name() const override {
if (!_opened) {
DEBUGV("SemiFSFileImpl::name: file not opened\n");
return nullptr;
} else {
const char *p = _name.get();
const char *slash = strrchr(p, '/');
// For names w/o any path elements, return directly
// If there are slashes, return name after the last slash
// (note that strrchr will return the address of the slash,
// so need to increment to ckip it)
return (slash && slash[1]) ? slash + 1 : p;
}
}
const char* fullName() const override {
return _opened ? _name.get() : nullptr;
}
bool isFile() const override {
return _opened; // Could look at ISTTY but that's not the sense here. Just differentiating between dirs and files
}
bool isDirectory() const override {
return false;
}
time_t getLastWrite() override {
return getCreationTime(); // TODO - FatFS doesn't seem to report both filetimes
}
time_t getCreationTime() override {
time_t ftime = 0;
return ftime;
}
protected:
int _fd;
std::shared_ptr<char> _name;
bool _opened;
bool _writable;
};
class SemiFSImpl : public FSImpl {
public:
SemiFSImpl() {
/* noop */
}
FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override {
if (!path || !path[0]) {
DEBUGV("SemiFSImpl::open() called with invalid filename\n");
return FileImplPtr();
}
// Mode conversion https://developer.arm.com/documentation/dui0471/m/what-is-semihosting-/sys-open--0x01-?lang=en
int mode = 1; // "rb"
if (accessMode == AM_READ) {
mode = 1; // "rb"
} else if (accessMode == AM_WRITE) {
if (openMode & OM_APPEND) {
mode = 9; // "ab";
} else {
mode = 5; // "wb";
}
} else {
if (openMode & OM_TRUNCATE) {
mode = 7; // "w+b";
} else if (openMode & OM_APPEND) {
mode = 3; // "r+b"
} else {
mode = 11; // "a+b";
}
}
uint32_t a[3];
a[0] = (uint32_t)path;
a[1] = mode;
a[2] = strlen(path);
int handle = Semihost(SEMIHOST_SYS_OPEN, a);
if (handle < 0) {
return FileImplPtr();
}
return std::make_shared<SemiFSFileImpl>(handle, path, (accessMode & AM_WRITE) ? true : false);
}
bool exists(const char* path) override {
File f = open(path, OM_DEFAULT, AM_READ);
return f ? true : false;
}
DirImplPtr openDir(const char* path) override {
// No directories
return DirImplPtr();
}
bool rename(const char* pathFrom, const char* pathTo) override {
uint32_t a[4];
a[0] = (uint32_t)pathFrom;
a[1] = strlen(pathFrom);
a[2] = (uint32_t)pathTo;
a[3] = strlen(pathTo);
return !Semihost(SEMIHOST_SYS_RENAME, a);
}
bool info(FSInfo& info) override {
// Not available
return false;
}
bool remove(const char* path) override {
uint32_t a[2];
a[0] = (uint32_t)path;
a[1] = strlen(path);
return !Semihost(SEMIHOST_SYS_REMOVE, a);
}
bool mkdir(const char* path) override {
// No mkdir
return false;
}
bool rmdir(const char* path) override {
// No rmdir
return false;
}
bool stat(const char *path, FSStat *st) override {
if (!path || !path[0]) {
return false;
}
uint32_t a[3];
a[0] = (uint32_t)path;
a[1] = 0; // READ
a[2] = strlen(path);
int fn = Semihost(SEMIHOST_SYS_OPEN, a);
if (fn < 0) {
return false;
}
bzero(st, sizeof(*st));
a[0] = fn;
st->size = Semihost(SEMIHOST_SYS_FLEN, a);
a[0] = fn;
Semihost(SEMIHOST_SYS_CLOSE, a);
return true;
}
bool setConfig(const FSConfig &cfg) override {
return true;
}
bool begin() override {
/* noop */
return true;
}
void end() override {
/* noop */
}
bool format() override {
return false;
}
};
}; // namespace sdfs
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SEMIFS)
extern FS SemiFS;
using semifs::SemiFSConfig;
#endif

View file

@ -1,6 +0,0 @@
#include "Semihosting.h"
#include "SerialSemi.h"
#include "SemiFS.h"
SerialSemiClass SerialSemi;
FS SemiFS = FS(FSImplPtr(new semifs::SemiFSImpl()));

View file

@ -1,113 +0,0 @@
/*
Semihosting.h - Semihosting for Serial and FS access via GDB
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
// Be sure to only use this library with GDB and to enable the ARM semihosting support
// (gdb) monitor arm semihosting enable
// Input/output will be handled by OpenOCD
/**
@brief Semihosting host API opcodes, from https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations?lang=en
*/
typedef enum {
SEMIHOST_SYS_CLOSE = 0x02,
SEMIHOST_SYS_CLOCK = 0x10,
SEMIHOST_SYS_ELAPSED = 0x30,
SEMIHOST_SYS_ERRNO = 0x13,
SEMIHOST_SYS_FLEN = 0x0C,
SEMIHOST_SYS_GET_CMDLINE = 0x15,
SEMIHOST_SYS_HEAPINFO = 0x16,
SEMIHOST_SYS_ISERROR = 0x08,
SEMIHOST_SYS_ISTTY = 0x09,
SEMIHOST_SYS_OPEN = 0x01,
SEMIHOST_SYS_READ = 0x06,
SEMIHOST_SYS_READC = 0x07,
SEMIHOST_SYS_REMOVE = 0x0E,
SEMIHOST_SYS_RENAME = 0x0F,
SEMIHOST_SYS_SEEK = 0x0A,
SEMIHOST_SYS_SYSTEM = 0x12,
SEMIHOST_SYS_TICKFREQ = 0x31,
SEMIHOST_SYS_TIME = 0x11,
SEMIHOST_SYS_TMPNAM = 0x0D,
SEMIHOST_SYS_WRITE = 0x05,
SEMIHOST_SYS_WRITEC = 0x03,
SEMIHOST_SYS_WRITE0 = 0x04
} SEMIHOST_OPCODES;
#ifdef __arm__
/**
@brief Execute a semihosted request, from https://github.com/ErichStyger/mcuoneclipse/blob/master/Examples/MCUXpresso/FRDM-K22F/FRDM-K22F_Semihosting/source/McuSemihost.c
@param [in] reason Opcode to execute
@param [in] arg Any arguments for the opcode
@returns Result of operation
*/
static inline int __attribute__((always_inline)) Semihost(int reason, void *arg) {
int value;
__asm volatile(
"mov r0, %[rsn] \n" /* place semihost operation code into R0 */
"mov r1, %[arg] \n" /* R1 points to the argument array */
"bkpt 0xAB \n" /* call debugger */
"mov %[val], r0 \n" /* debugger has stored result code in R0 */
: [val] "=r"(value) /* outputs */
: [rsn] "r"(reason), [arg] "r"(arg) /* inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" /* clobber */
);
return value; /* return result code, stored in R0 */
}
#else
/**
@brief Execute a semihosted request, from https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/n-5VQ9PHZ4w/m/KbzH5t9MBgAJ
@param [in] reason Opcode to execute
@param [in] argPack Any arguments for the opcode
@returns Result of operation
*/
static inline int __attribute__((always_inline)) Semihost(int reason, void *argPack) {
register int value asm("a0") = reason;
register void *ptr asm("a1") = argPack;
asm volatile(
// Force 16-byte alignment to make sure that the 3 instructions fall
// within the same virtual page.
" .balign 16 \n"
" .option push \n"
// Force non-compressed RISC-V instructions
" .option norvc \n"
// semihosting e-break sequence
" slli x0, x0, 0x1f \n" // # Entry NOP
" ebreak \n" // # Break to debugger
" srai x0, x0, 0x7 \n" // # NOP encoding the semihosting call number 7
" .option pop \n"
/*mark (value) as an output operand*/
: "=r"(value) /* Outputs */
// The semihosting call number is passed in a0, and the argument in a1.
: "0"(value), "r"(ptr) /* Inputs */
// The "memory" clobber makes GCC assume that any memory may be arbitrarily read or written by the asm block,
// so will prevent the compiler from reordering loads or stores across it, or from caching memory values in registers across it.
// The "memory" clobber also prevents the compiler from removing the asm block as dead code.
: "memory" /* Clobbers */
);
return value;
}
#endif

View file

@ -68,10 +68,13 @@ static PIOProgram *_getRxProgram(int bits) {
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static int __not_in_flash_func(_parity)(int data) { // TODO - this works, but there must be a faster/better way...
data ^= data >> 4; static int _parity(int bits, int data) {
data &= 0xf; int p = 0;
return (0x6996 >> data) & 1; for (int b = 0; b < bits; b++) {
p ^= (data & (1 << b)) ? 1 : 0;
}
return p;
} }
// We need to cache generated SerialPIOs so we can add data to them from // We need to cache generated SerialPIOs so we can add data to them from
@ -95,16 +98,20 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
} }
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) { while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
uint32_t decode = _rxPIO->rxf[_rxSM]; uint32_t decode = _rxPIO->rxf[_rxSM];
uint32_t val = decode >> (32 - _rxBits - 1); decode >>= 33 - _rxBits;
uint32_t val = 0;
for (int b = 0; b < _bits + 1; b++) {
val |= (decode & (1 << (b * 2))) ? 1 << b : 0;
}
if (_parity == UART_PARITY_EVEN) { if (_parity == UART_PARITY_EVEN) {
int p = ::_parity(val); int p = ::_parity(_bits, val);
int r = (val & (1 << _bits)) ? 1 : 0; int r = (val & (1 << _bits)) ? 1 : 0;
if (p != r) { if (p != r) {
// TODO - parity error // TODO - parity error
continue; continue;
} }
} else if (_parity == UART_PARITY_ODD) { } else if (_parity == UART_PARITY_ODD) {
int p = ::_parity(val); int p = ::_parity(_bits, val);
int r = (val & (1 << _bits)) ? 1 : 0; int r = (val & (1 << _bits)) ? 1 : 0;
if (p == r) { if (p == r) {
// TODO - parity error // TODO - parity error
@ -227,7 +234,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
_writer = 0; _writer = 0;
_reader = 0; _reader = 0;
_rxBits = _bits + (_parity != UART_PARITY_NONE ? 1 : 0); _rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
_rxPgm = _getRxProgram(_rxBits); _rxPgm = _getRxProgram(_rxBits);
int off; int off;
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) { if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
@ -242,7 +249,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
// Put phase divider into OSR w/o using add'l program memory // Put phase divider into OSR w/o using add'l program memory
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 3); pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 7 /* insns in PIO halfbit loop */);
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false)); pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
// Join the TX FIFO to the RX one now that we don't need it // Join the TX FIFO to the RX one now that we don't need it
@ -371,10 +378,10 @@ size_t SerialPIO::write(uint8_t c) {
if (_parity == UART_PARITY_NONE) { if (_parity == UART_PARITY_NONE) {
val |= 7 << _bits; // Set 2 stop bits, the HW will only transmit the required number val |= 7 << _bits; // Set 2 stop bits, the HW will only transmit the required number
} else if (_parity == UART_PARITY_EVEN) { } else if (_parity == UART_PARITY_EVEN) {
val |= ::_parity(c) << _bits; val |= ::_parity(_bits, c) << _bits;
val |= 7 << (_bits + 1); val |= 7 << (_bits + 1);
} else { } else {
val |= (1 ^ ::_parity(c)) << _bits; val |= (1 ^ ::_parity(_bits, c)) << _bits;
val |= 7 << (_bits + 1); val |= 7 << (_bits + 1);
} }
val <<= 1; // Start bit = low val <<= 1; // Start bit = low

View file

@ -29,7 +29,7 @@
extern "C" typedef struct uart_inst uart_inst_t; extern "C" typedef struct uart_inst uart_inst_t;
class SerialPIO : public arduino::HardwareSerial { class SerialPIO : public HardwareSerial {
public: public:
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32); SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);

View file

@ -1,98 +0,0 @@
/*
SerialSemi.h - Serial port over Semihosting for ARM
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "Semihosting.h"
#include "Arduino.h"
#include "api/HardwareSerial.h"
class SerialSemiClass : public arduino::HardwareSerial {
public:
SerialSemiClass() {
/* noop */
}
~SerialSemiClass() {
/* noop */
}
void begin(unsigned long baudIgnored = 115200) override {
(void)baudIgnored;
}
void begin(unsigned long baudIgnored, uint16_t configIgnored) override {
(void)baudIgnored;
(void)configIgnored;
}
void end() override {
/* noop */
}
virtual int peek() override {
// Can't really peek on SH, so fake it best we can
if (!_peeked) {
_peekedChar = read();
_peeked = true;
}
return _peekedChar;
}
virtual int read() override {
if (_peeked) {
_peeked = false;
return _peekedChar;
}
return Semihost(SEMIHOST_SYS_READC, nullptr);
}
virtual int available() override {
// Can't really tell with SH, so always true. Buyer beware
return 1;
}
virtual int availableForWrite() override {
// Can't really tell with SH, so always true. Buyer beware
return 1;
}
virtual void flush() override {
/* noop */
}
virtual size_t write(uint8_t c) override {
int32_t param = c;
Semihost(SEMIHOST_SYS_WRITEC, &param);
return 1;
}
using Print::write;
operator bool() override {
return true;
}
private:
bool _peeked = false;
uint8_t _peekedChar;
};
extern SerialSemiClass SerialSemi;

View file

@ -32,20 +32,15 @@ extern void serialEvent1() __attribute__((weak));
extern void serialEvent2() __attribute__((weak)); extern void serialEvent2() __attribute__((weak));
bool SerialUART::setRX(pin_size_t pin) { bool SerialUART::setRX(pin_size_t pin) {
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B #ifdef PICO_RP2350B
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29, 31, 33, 35, 45, 47}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29, 33, 45}) /* UART0 */,
__bitset({5, 7, 9, 11, 21, 23, 25, 27, 37, 39, 41, 43}) /* UART1 */ __bitset({5, 9, 21, 25, 37, 41}) /* UART1 */
};
#elif defined(PICO_RP2350)
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29}) /* UART0 */,
__bitset({5, 7, 9, 11, 21, 23, 25, 27}) /* UART1 */
}; };
#else #else
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
__bitset({5, 9, 21, 25}) /* UART1 */ __bitset({5, 9, 21, 25}) /* UART1 */
}; };
#endif #endif
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) { if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
_rx = pin; _rx = pin;
return true; return true;
@ -64,13 +59,9 @@ bool SerialUART::setRX(pin_size_t pin) {
} }
bool SerialUART::setTX(pin_size_t pin) { bool SerialUART::setTX(pin_size_t pin) {
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B #ifdef PICO_RP2350B
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28, 30, 32, 34, 44, 46}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28, 32, 44}) /* UART0 */,
__bitset({4, 6, 8, 10, 20, 22, 24, 26, 36, 38, 40, 42}) /* UART1 */ __bitset({4, 8, 20, 24, 36, 40}) /* UART1 */
};
#elif defined(PICO_RP2350)
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28}) /* UART0 */,
__bitset({4, 6, 8, 10, 20, 22, 24, 26}) /* UART1 */
}; };
#else #else
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
@ -95,7 +86,7 @@ bool SerialUART::setTX(pin_size_t pin) {
} }
bool SerialUART::setRTS(pin_size_t pin) { bool SerialUART::setRTS(pin_size_t pin) {
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B #ifdef PICO_RP2350B
constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */,
__bitset({7, 11, 23, 27, 39, 43}) /* UART1 */ __bitset({7, 11, 23, 27, 39, 43}) /* UART1 */
}; };
@ -122,7 +113,7 @@ bool SerialUART::setRTS(pin_size_t pin) {
} }
bool SerialUART::setCTS(pin_size_t pin) { bool SerialUART::setCTS(pin_size_t pin) {
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B #ifdef PICO_RP2350B
constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */, constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */,
__bitset({6, 10, 22, 26, 38, 42}) /* UART1 */ __bitset({6, 10, 22, 26, 38, 42}) /* UART1 */
}; };
@ -179,41 +170,6 @@ SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size
static void _uart0IRQ(); static void _uart0IRQ();
static void _uart1IRQ(); static void _uart1IRQ();
// Does the selected TX/RX need UART_AUX function (rp2350)
static gpio_function_t __gpioFunction(int pin) {
switch (pin) {
#if defined(PICO_RP2350) && !PICO_RP2350A
case 2:
case 3:
case 6:
case 7:
case 10:
case 11:
case 14:
case 15:
case 18:
case 19:
case 22:
case 23:
case 26:
case 27:
case 30:
case 31:
case 34:
case 35:
case 38:
case 39:
case 42:
case 43:
case 46:
case 47:
return GPIO_FUNC_UART_AUX;
#endif
default:
return GPIO_FUNC_UART;
}
}
void SerialUART::begin(unsigned long baud, uint16_t config) { void SerialUART::begin(unsigned long baud, uint16_t config) {
if (_running) { if (_running) {
end(); end();
@ -224,9 +180,9 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
_fcnTx = gpio_get_function(_tx); _fcnTx = gpio_get_function(_tx);
_fcnRx = gpio_get_function(_rx); _fcnRx = gpio_get_function(_rx);
gpio_set_function(_tx, __gpioFunction(_tx)); gpio_set_function(_tx, GPIO_FUNC_UART);
gpio_set_outover(_tx, _invertTX ? 1 : 0); gpio_set_outover(_tx, _invertTX ? 1 : 0);
gpio_set_function(_rx, __gpioFunction(_rx)); gpio_set_function(_rx, GPIO_FUNC_UART);
gpio_set_inover(_rx, _invertRX ? 1 : 0); gpio_set_inover(_rx, _invertRX ? 1 : 0);
if (_rts != UART_PIN_NOT_DEFINED) { if (_rts != UART_PIN_NOT_DEFINED) {
_fcnRts = gpio_get_function(_rts); _fcnRts = gpio_get_function(_rts);

View file

@ -29,7 +29,7 @@
extern "C" typedef struct uart_inst uart_inst_t; extern "C" typedef struct uart_inst uart_inst_t;
#define UART_PIN_NOT_DEFINED (255u) #define UART_PIN_NOT_DEFINED (255u)
class SerialUART : public arduino::HardwareSerial { class SerialUART : public HardwareSerial {
public: public:
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED); SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);

View file

@ -24,7 +24,7 @@
#include "api/HardwareSerial.h" #include "api/HardwareSerial.h"
#include <stdarg.h> #include <stdarg.h>
class SerialUSB : public arduino::HardwareSerial { class SerialUSB : public HardwareSerial {
public: public:
SerialUSB() { } SerialUSB() { }
void begin(unsigned long baud = 115200) override; void begin(unsigned long baud = 115200) override;

View file

@ -22,18 +22,9 @@
#include "SerialPIO.h" #include "SerialPIO.h"
/**
@brief Implements a UART port using PIO for input and output
*/
class SoftwareSerial : public SerialPIO { class SoftwareSerial : public SerialPIO {
public: public:
/** // Note the rx/tx pins are swapped in PIO vs SWSerial
@brief Constructs a PIO-based UART
@param [in] rx GPIO for RX pin or -1 for transmit-only
@param [in] tx GPIO for TX pin or -1 for receive-only
@param [in] invert True to invert the receive and transmit lines
*/
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) { SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
_invert = invert; _invert = invert;
} }
@ -41,37 +32,18 @@ public:
~SoftwareSerial() { ~SoftwareSerial() {
} }
/**
@brief Starts the PIO UART
@param [in] baud Serial bit rate
*/
virtual void begin(unsigned long baud = 115200) override { virtual void begin(unsigned long baud = 115200) override {
begin(baud, SERIAL_8N1); begin(baud, SERIAL_8N1);
}; };
/**
@brief Starts the PIO UART
@param [in] baud Serial bit rate
@param [in] config Start/Stop/Len configuration (i.e. SERIAL_8N1 or SERIAL_7E2)
*/
void begin(unsigned long baud, uint16_t config) override { void begin(unsigned long baud, uint16_t config) override {
setInvertTX(_invert); setInvertTX(_invert);
setInvertRX(_invert); setInvertRX(_invert);
SerialPIO::begin(baud, config); SerialPIO::begin(baud, config);
} }
/**
@brief No-op on this core
*/
void listen() { /* noop */ } void listen() { /* noop */ }
/**
@brief No-op on this core
@returns True always
*/
bool isListening() { bool isListening() {
return true; return true;
} }

View file

@ -71,7 +71,10 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
return; // Weird deadlock case return; // Weird deadlock case
} }
unsigned int delay = (RP2040::f_cpu() + frequency) / (frequency * 2) - 3; // rounded int us = 1'000'000 / frequency / 2;
if (us < 5) {
us = 5;
}
auto entry = _toneMap.find(pin); auto entry = _toneMap.find(pin);
Tone *newTone; Tone *newTone;
if (entry == _toneMap.end()) { if (entry == _toneMap.end()) {
@ -96,9 +99,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin); tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin);
} }
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
pio_sm_put_blocking(newTone->pio, newTone->sm, delay); pio_sm_put_blocking(newTone->pio, newTone->sm, RP2040::usToPIOCycles(us));
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_pull(false, false));
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_mov(pio_x, pio_osr));
pio_sm_set_enabled(newTone->pio, newTone->sm, true); pio_sm_set_enabled(newTone->pio, newTone->sm, true);
_toneMap.insert({pin, newTone}); _toneMap.insert({pin, newTone});

View file

@ -31,7 +31,7 @@ typedef struct {
static FMMap *_map = nullptr; static FMMap *_map = nullptr;
SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) { SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
if (!_map) { if (!_map) {
_map = (FMMap *)calloc(16, sizeof(FMMap)); _map = (FMMap *)calloc(sizeof(FMMap), 16);
} }
// Pre-existing map // Pre-existing map
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {

View file

@ -30,36 +30,32 @@ extern bool __isFreeRTOS;
// FreeRTOS has been set up // FreeRTOS has been set up
extern volatile bool __freeRTOSinitted; extern volatile bool __freeRTOSinitted;
#ifdef __cplusplus
extern "C" { extern "C" {
#endif // __cplusplus struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */ typedef struct QueueDefinition * QueueHandle_t;
typedef struct QueueDefinition * QueueHandle_t; typedef QueueHandle_t SemaphoreHandle_t;
typedef QueueHandle_t SemaphoreHandle_t; typedef int32_t BaseType_t;
typedef int32_t BaseType_t;
extern bool __freertos_check_if_in_isr() __attribute__((weak)); extern bool __freertos_check_if_in_isr() __attribute__((weak));
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak)); extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
extern SemaphoreHandle_t _freertos_recursive_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(SemaphoreHandle_t mtx) __attribute__((weak));
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __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 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(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __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 void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak)); extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak)); extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_idle_other_core() __attribute__((weak)); extern void __freertos_idle_other_core() __attribute__((weak));
extern void __freertos_resume_other_core() __attribute__((weak)); extern void __freertos_resume_other_core() __attribute__((weak));
extern void __freertos_task_exit_critical() __attribute__((weak)); extern void __freertos_task_exit_critical() __attribute__((weak));
extern void __freertos_task_enter_critical() __attribute__((weak)); extern void __freertos_task_enter_critical() __attribute__((weak));
#ifdef __cplusplus
} }
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false); extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
#endif // __cplusplus

View file

@ -28,7 +28,7 @@ static const struct pio_program ccount_program = {
.instructions = ccount_program_instructions, .instructions = ccount_program_instructions,
.length = 2, .length = 2,
.origin = -1, .origin = -1,
.pio_version = ccount_pio_version, .pio_version = 0,
#if PICO_PIO_VERSION > 0 #if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0 .used_gpio_ranges = 0x0
#endif #endif

View file

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if defined(PICO_CYW43_SUPPORTED) #if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <lwip/netif.h> #include <lwip/netif.h>
extern "C" { extern "C" {
@ -25,12 +25,6 @@ extern "C" {
#include <cyw43_stats.h> #include <cyw43_stats.h>
} }
#include <pico/cyw43_arch.h> #include <pico/cyw43_arch.h>
#include <pico/cyw43_driver.h>
#include <pico/lwip_nosys.h>
#include <hardware/resets.h>
#include <hardware/gpio.h>
#include <hardware/adc.h>
#include <hardware/clocks.h>
#include <Arduino.h> #include <Arduino.h>
// From cyw43_ctrl.c // From cyw43_ctrl.c
@ -107,100 +101,4 @@ extern "C" void __wrap_cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
(void) itf; (void) itf;
} }
#ifndef WIFICC
#define WIFICC CYW43_COUNTRY_WORLDWIDE
#endif
// Taken from https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
// also discussion in https://github.com/earlephilhower/arduino-pico/issues/849
static bool CheckPicoW() {
#ifdef PICO_RP2040
adc_init();
auto dir = gpio_get_dir(29);
auto fnc = gpio_get_function(29);
adc_gpio_init(29);
adc_select_input(3);
auto adc29 = adc_read();
gpio_set_function(29, fnc);
gpio_set_dir(29, dir);
dir = gpio_get_dir(25);
fnc = gpio_get_function(25);
gpio_init(25);
gpio_set_dir(25, GPIO_IN);
auto gp25 = gpio_get(25);
gpio_set_function(25, fnc);
gpio_set_dir(25, dir);
if (gp25) {
return true; // Can't tell, so assume yes
} else if (adc29 < 200) {
return true; // PicoW
} else {
return false;
}
#else
return true;
#endif
}
bool __isPicoW = true;
extern "C" void init_cyw43_wifi() {
__isPicoW = CheckPicoW();
if (__isPicoW) {
// Fix for overclocked CPU: SPI communication breaks down with default "div by 2" speed
// So, divide clock by 4 for anything including and above 250MHz CPU frequency.
if (clock_get_hz(clk_sys) >= 250000000) {
cyw43_set_pio_clock_divisor(4, 0); // div by 4.0
}
cyw43_arch_init_with_country(WIFICC);
}
}
extern "C" void __lockBluetooth() {
async_context_acquire_lock_blocking(cyw43_arch_async_context());
}
extern "C" void __unlockBluetooth() {
async_context_release_lock(cyw43_arch_async_context());
}
extern "C" void __pinMode(pin_size_t pin, PinMode mode);
extern "C" void __digitalWrite(pin_size_t pin, PinStatus val);
extern "C" PinStatus __digitalRead(pin_size_t pin);
extern "C" void cyw43_pinMode(pin_size_t pin, PinMode mode) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
__pinMode(pin, mode);
} else {
// TBD - There is no GPIO direction control in the driver
}
}
extern "C" void cyw43_digitalWrite(pin_size_t pin, PinStatus val) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
__digitalWrite(pin, val);
} else {
cyw43_arch_gpio_put(pin - 64, val == HIGH ? 1 : 0);
}
}
extern "C" PinStatus cyw43_digitalRead(pin_size_t pin) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
return __digitalRead(pin);
} else {
return cyw43_arch_gpio_get(pin - 64) ? HIGH : LOW;
}
}
#endif #endif

View file

@ -1,37 +0,0 @@
/*
CYW43 TCP/Ethernet wrappers
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <Arduino.h>
#include <pico/cyw43_driver.h>
extern bool __isPicoW;
#ifdef __cplusplus
extern "C" {
#endif
void init_cyw43_wifi();
void __lockBluetooth();
void __unlockBluetooth();
void cyw43_pinMode(pin_size_t pin, PinMode mode);
void cyw43_digitalWrite(pin_size_t pin, PinStatus val);
PinStatus cyw43_digitalRead(pin_size_t pin);
#ifdef __cplusplus
}
#endif

View file

@ -1,470 +0,0 @@
/* -
Copyright (c) 1983, 1992, 1993
The Regents of the University of California. 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.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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.
*/
// This code is built as a C file because otherwise G++ would add profiling
// code to the preamble of these functions as well, leading to an infinite
// loop in the mcount routine. Because the Arduino IDE can't (easily)
// apply different compile parameters to different files, we set all C++
// files to "-pg" but leave all C files uninstrumented.
// Original code and organization taken from https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/
#include <Arduino.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
// Frequency of sampling PC
#ifndef GMON_HZ
#define GMON_HZ 10000
#endif
// Fraction of text space to allocate for histogram counters here, 1/2
#ifndef HISTFRACTION
#ifdef PICO_RP2350
#define HISTFRACTION 4 // Every 8 bytes of .text
#else
#define HISTFRACTION 8 // Every 16 bytes of .text
#endif
#endif
// Fraction of text space to allocate for from hash buckets.
// The value of HASHFRACTION is based on the minimum number of bytes
// of separation between two subroutine call points in the object code.
// Given MIN_SUBR_SEPARATION bytes of separation the value of
// HASHFRACTION is calculated as:
//
// HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
//
// For example, on the VAX, the shortest two call sequence is:
//
// calls $0,(r0)
// calls $0,(r0)
//
// which is separated by only three bytes, thus HASHFRACTION is
// calculated as:
//
// HASHFRACTION = 3 / (2 * 2 - 1) = 1
//
// Note that the division above rounds down, thus if MIN_SUBR_FRACTION
// is less than three, this algorithm will not work!
//
// In practice, however, call instructions are rarely at a minimal
// distance. Hence, we will define HASHFRACTION to be 2 across all
// architectures. This saves a reasonable amount of space for
// profiling data structures without (in practice) sacrificing
// any granularity.
#ifndef HASHFRACTION
#define HASHFRACTION 2
#endif
// Percent of text space to allocate for tostructs with a minimum.
#ifndef ARCDENSITY
#define ARCDENSITY 2 // This is in percentage, relative to text size!
#endif
#define MINARCS 50
#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER))) - 2)
// Histogram counters are unsigned shorts (according to the kernel)
typedef uint16_t HISTCOUNTER; //#define HISTCOUNTER unsigned short
// In the original profiler code selfpc and count are full 32 bits each
// so the structure actually comes to 12 bytes due to padding (with 2
// bytes wasted per entry). We don't have that much to spare on the Picos,
// so limit the recorded address to 16MB (which is the flash address
// window, anyway) and the counts to 16M (saturating). This saves 4 bytes
// (33%) per entry at the cost of some logic to expand/pack it.
struct tostruct {
uint8_t selfpc[3]; // Callee address/program counter. The caller address is in froms[] array which points to tos[] array
uint8_t count[3]; // How many times it has been called
uint16_t link; // Link to next entry in hash table. For tos[0] this points to the last used entry
};
typedef enum { PROFILE_NOT_INIT = 0, PROFILE_ON, PROFILE_OFF } PROFILE_State;
struct profinfo {
PROFILE_State state; // Profiling state
uint16_t *counter; // Profiling counters
size_t lowpc, highpc; // Range to be profiled
uint32_t scale; // Scale value of bins
};
// Global profinfo for profil() call
static struct profinfo prof = { PROFILE_NOT_INIT, 0, 0, 0, 0 };
// Possible states of profiling
typedef enum { GMON_PROF_ON = 0, GMON_PROF_BUSY, GMON_PROF_ERROR, GMON_PROF_OFF } GMON_State;
// The profiling data structures are housed in this structure.
struct gmonparam {
int state;
uint16_t *kcount; // Histogram PC sample array
size_t kcountsize; // Size of kcount[] array in bytes
uint16_t *froms; // Array of hashed 'from' addresses. The 16bit value is an index into the tos[] array
size_t fromssize; // Size of froms[] array in bytes
struct tostruct *tos; // to struct, contains histogram counter
size_t tossize; // Size of tos[] array in bytes
long tolimit;
size_t lowpc; // Low program counter of area
size_t highpc; // High program counter
size_t textsize; // Code size
};
static struct gmonparam _gmonparam = { GMON_PROF_OFF, NULL, 0, NULL, 0, NULL, 0, 0L, 0, 0, 0};
static bool already_setup = false; // Flag to indicate if we need to init
static bool _perf_in_setup = false; // Are we currently trying to initialize? (avoid infinite recursion)
int __profileMemSize = 0; // Memory allocated by the profiler to store tables
static int s_scale = 0;
#define SCALE_1_TO_1 0x10000L
// Convert an addr to an index
static inline __attribute__((always_inline)) size_t profidx(size_t pc, size_t base, size_t scale) {
size_t i = (pc - base) / 2;
return (unsigned long long int) i * scale / 65536;
}
// Sample the current program counter periodically
#if defined(__riscv)
// TODO - systick-like handler
#else
static void __no_inline_not_in_flash_func(_SystickHandler)(void) {
static size_t pc, idx; // Ensure in heap, not on stack
extern volatile bool __otherCoreIdled;
if (!__otherCoreIdled && (prof.state == PROFILE_ON)) {
pc = ((uint32_t*)(__builtin_frame_address(0)))[14]; // Get SP and use it to get the return address from stack
if ((pc >= prof.lowpc) && (pc < prof.highpc)) {
idx = profidx(pc, prof.lowpc, prof.scale);
prof.counter[idx]++;
}
}
}
#endif
// Convert an index into an address
static inline __attribute__((always_inline)) size_t profaddr(size_t idx, size_t base, size_t scale) {
return base + ((((unsigned long long)(idx) << 16) / (unsigned long long)(scale)) << 1);
}
// Start or stop profiling
// Profiling goes into the SAMPLES buffer of size SIZE (which is treated as an array of uint16_ts of size size/2).
// Each bin represents a range of pc addresses from OFFSET. The number of pc addresses in a bin depends on SCALE.
// (A scale of 65536 maps each bin to two addresses, A scale of 32768 maps each bin to 4 addresses, a scale of
// 1 maps each bin to 128k address). Scale may be 1 - 65536, or zero to turn off profiling
static int __no_inline_not_in_flash_func(profile_ctl)(char *samples, size_t size, size_t offset, uint32_t scale) {
size_t maxbin;
if (scale > 65536) {
return -1;
}
prof.state = PROFILE_OFF;
if (scale) {
bzero(samples, size);
bzero(&prof, sizeof(prof));
maxbin = size >> 1;
prof.counter = (uint16_t*)samples;
prof.lowpc = offset;
prof.highpc = profaddr(maxbin, offset, scale);
prof.scale = scale;
prof.state = PROFILE_ON;
}
return 0;
}
// Control profiling. Profiling is what mcount checks to see if all the data structures are ready.
static void __no_inline_not_in_flash_func(moncontrol)(int mode) {
if (mode) { // Start
profile_ctl((char *)_gmonparam.kcount, _gmonparam.kcountsize, _gmonparam.lowpc, s_scale);
_gmonparam.state = GMON_PROF_ON;
} else { // Stop
profile_ctl((char *)NULL, 0, 0, 0);
_gmonparam.state = GMON_PROF_OFF;
}
}
// General rounding functions
static inline __attribute__((always_inline)) size_t rounddown(size_t x, size_t y) {
return (x / y) * y;
}
static inline __attribute__((always_inline)) size_t roundup(size_t x, size_t y) {
return ((x + y - 1) / y) * y;
}
// Allocate memory and set boundaries before any sampling is performed
void __no_inline_not_in_flash_func(monstartup)(size_t lowpc, size_t highpc) {
register size_t o;
char *cp;
struct gmonparam *p = &_gmonparam;
// Round lowpc and highpc to multiples of the density we're using so the rest of the scaling (here and in gprof) stays in ints.
p->lowpc = rounddown(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->highpc = roundup(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->textsize = p->highpc - p->lowpc;
p->kcountsize = p->textsize / HISTFRACTION;
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
if (p->tolimit < MINARCS) {
p->tolimit = MINARCS;
} else if (p->tolimit > MAXARCS) {
p->tolimit = MAXARCS;
}
p->tossize = p->tolimit * sizeof(struct tostruct);
__profileMemSize = p->kcountsize + p->fromssize + p->tossize;
#ifdef RP2350_PSRAM_CS
cp = pmalloc(__profileMemSize);
#else
cp = malloc(__profileMemSize);
#endif
if (cp == NULL) {
// OOM
already_setup = false;
return;
}
// Zero out cp as value will be added there
bzero(cp, p->kcountsize + p->fromssize + p->tossize);
p->tos = (struct tostruct *)cp;
cp += p->tossize;
p->kcount = (uint16_t *)cp;
cp += p->kcountsize;
p->froms = (uint16_t *)cp;
p->tos[0].link = 0;
o = p->highpc - p->lowpc;
if (p->kcountsize < o) {
s_scale = ((float)p->kcountsize / o) * SCALE_1_TO_1;
} else {
s_scale = SCALE_1_TO_1;
}
moncontrol(1); // Start
}
// Accessors for the selfpc and count fields
static inline __attribute__((always_inline)) void setselfpc(struct tostruct *x, size_t d) {
x->selfpc[0] = d & 0xff;
x->selfpc[1] = (d >> 8) & 0xff;
x->selfpc[2] = (d >> 16) & 0xff;
}
static inline __attribute__((always_inline))void setcount(struct tostruct *x, size_t d) {
x->count[0] = d & 0xff;
x->count[1] = (d >> 8) & 0xff;
x->count[2] = (d >> 16) & 0xff;
}
static inline __attribute__((always_inline)) uint32_t getselfpc(const struct tostruct *x) {
return 0x10000000 | ((uint32_t)x->selfpc[0]) | (((uint32_t)x->selfpc[1]) << 8) | (((uint32_t)x->selfpc[2]) << 16);
}
static inline __attribute__((always_inline)) uint32_t getcount(const struct tostruct *x) {
return ((uint32_t)x->count[0]) | (((uint32_t)x->count[1]) << 8) | (((uint32_t)x->count[2]) << 16);
}
// Called by the GCC function shim (gprof_shim.S) on function entry to record an arc hit
void __no_inline_not_in_flash_func(_mcount_internal)(uint32_t *frompcindex, uint32_t *selfpc) {
register struct tostruct *top;
register struct tostruct *prevtop;
register long toindex;
struct gmonparam *p = &_gmonparam;
if (_perf_in_setup) {
// Avoid infinite recursion
return;
}
if (!already_setup) {
extern char __flash_binary_start; // Start of flash
extern char __etext; // End of .text
already_setup = true;
_perf_in_setup = true;
monstartup((uint32_t)&__flash_binary_start, (uint32_t)&__etext);
_perf_in_setup = false;
}
// Check that we are profiling and that we aren't recursively invoked.
if (p->state != GMON_PROF_ON) {
return;
}
p->state++;
// Check that frompcindex is a reasonable pc value.
frompcindex = (uint32_t*)((long)frompcindex - (long)p->lowpc);
if ((unsigned long)frompcindex > p->textsize) {
goto done;
}
frompcindex = (uint32_t*)&p->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*p->froms))];
toindex = *((uint16_t*)frompcindex); // Get froms[] value
if (toindex == 0) {
// First time traversing this arc
toindex = ++p->tos[0].link; // The link of tos[0] points to the last used record in the array
if (toindex >= p->tolimit) { // More tos[] entries than we can handle!
goto overflow;
}
*((uint16_t*)frompcindex) = (uint16_t)toindex; // Store new 'to' value into froms[]
top = &p->tos[toindex];
setselfpc(top, (uint32_t)selfpc);
setcount(top, 1);
top->link = 0;
goto done;
}
top = &p->tos[toindex];
if (getselfpc(top) == (size_t)selfpc) {
// Arc at front of chain; usual case.
uint32_t cnt = getcount(top) + 1;
if (cnt >= 1 << 24) {
cnt = (1 << 24) - 1;
}
setcount(top, cnt);
goto done;
}
// Have to go looking down chain for it. top points to what we are looking at, prevtop points to previous top. We know it is not at the head of the chain.
for (; /* goto done */;) {
if (top->link == 0) {
// top is end of the chain and none of the chain had top->selfpc == selfpc, so we allocate a new tostruct and link it to the head of the chain.
toindex = ++p->tos[0].link;
if (toindex >= p->tolimit) {
goto overflow;
}
top = &p->tos[toindex];
setselfpc(top, (uint32_t)selfpc);
setcount(top, 1);
top->link = *((uint16_t*)frompcindex);
*(uint16_t*)frompcindex = (uint16_t)toindex;
goto done;
}
// Otherwise, check the next arc on the chain.
prevtop = top;
top = &p->tos[top->link];
if (getselfpc(top) == (size_t)selfpc) {
// Increment its count, move it to the head of the chain.
uint32_t cnt = getcount(top) + 1;
if (cnt >= 1 << 24) {
cnt = (1 << 24) - 1;
}
setcount(top, cnt);
toindex = prevtop->link;
prevtop->link = top->link;
top->link = *((uint16_t*)frompcindex);
*((uint16_t*)frompcindex) = (uint16_t)toindex;
goto done;
}
}
done:
p->state--;
return;
overflow:
p->state++; // Halt further profiling
return;
}
// Write out the GMON.OUT file using internal state
void _writeProfile(int (*writeCB)(const void *data, int len)) {
struct gmonhdr { // GMON.OUT header
size_t lpc; // base pc address of sample buffer
size_t hpc; // max pc address of sampled buffer
int ncnt; // size of sample buffer (plus this header)
int version; // version number
int profrate; // profiling clock rate
int spare[3]; // reserved
};
const unsigned int GMONVERSION = 0x00051879;
struct rawarc { // Per-arc on-disk data format
size_t raw_frompc;
size_t raw_selfpc;
long raw_count;
};
int fromindex;
int endfrom;
size_t frompc;
int toindex;
struct rawarc rawarc;
const int BS = 64;
struct rawarc rawarcbuff[BS];
int rawarcbuffptr = 0;
struct gmonparam *p = &_gmonparam;
struct gmonhdr hdr;
moncontrol(0); // Stop
hdr.lpc = p->lowpc;
hdr.hpc = p->highpc;
hdr.ncnt = p->kcountsize + sizeof(hdr);
hdr.version = GMONVERSION;
hdr.profrate = GMON_HZ;
writeCB((void *)&hdr, sizeof(hdr));
writeCB((void *)p->kcount, p->kcountsize);
endfrom = p->fromssize / sizeof(*p->froms);
for (fromindex = 0; fromindex < endfrom; fromindex++) {
if (p->froms[fromindex] == 0) {
continue;
}
frompc = p->lowpc;
frompc += fromindex * HASHFRACTION * sizeof(*p->froms);
for (toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].link) {
rawarc.raw_frompc = frompc;
rawarc.raw_selfpc = getselfpc(&p->tos[toindex]);
rawarc.raw_count = getcount(&p->tos[toindex]);
// Buffer up writes because Semihosting is really slow per write call
rawarcbuff[rawarcbuffptr++] = rawarc;
if (rawarcbuffptr == BS) {
writeCB((void *)rawarcbuff, BS * sizeof(struct rawarc));
rawarcbuffptr = 0;
}
}
}
// Write any remaining bits
if (rawarcbuffptr) {
writeCB((void *)rawarcbuff, rawarcbuffptr * sizeof(struct rawarc));
}
}
// These are referenced by RP2040Support.cpp and called by the runtime init SDK
// Install a periodic PC sampler at the specified frequency
#if defined(__riscv)
void runtime_init_setup_profiling() {
// TODO - is there an equivalent? Or do we need to build a timer IRQ here?
}
#else
#include <hardware/exception.h>
#include <hardware/structs/systick.h>
void runtime_init_setup_profiling() {
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = (F_CPU / GMON_HZ) - 1;
}
#endif

View file

@ -1,58 +0,0 @@
#if defined(__riscv)
// Originally from https://github.com/sbzpro/riscv-gprof
# define RSIZE 4
.section .text
.align 2
.globl _mcount
_mcount:
addi sp,sp,-4*RSIZE
sw ra, 3*RSIZE(sp)
mv a1,ra
call _mcount_internal; //jal _mcount_internal
lw ra, 3*RSIZE(sp)
addi sp,sp,4*RSIZE
ret
#else
/*
* profiler.S
* Implements the gprof profiler arc counting function.
* Created on: 06.08.2015
* Author: Erich Styger
* Modified for RP2040/RP2350 on Dec 3 2024 by Earle F. Philhower, III.
*/
.syntax unified
.arch armv7-m
.cpu cortex-m0plus
.text
.thumb
.thumb_func
.align 2
.globl __gnu_mcount_nc
.type __gnu_mcount_nc, %function
.section .time_critical
__gnu_mcount_nc:
// LR = to return to
// SP = to-replace-LR with
push {r0, r1, r2, r3}
push {lr}
// Swap 24/0
ldr r0, [sp, #20]
ldr r1, [sp, #0]
str r0, [sp, #0]
str r1, [sp, #20]
mov r1, lr
ldr r0, [sp, #0] /* caller - at the top of the stack */
bl _mcount_internal /* when __gnu_mcount_nc is called */
pop {r0}
mov lr, r0
pop {r0, r1, r2, r3}
pop {pc}
.end __gnu_mcount_nc
#endif

View file

@ -99,7 +99,7 @@ static SemaphoreHandle_t __getFreeRTOSRecursiveMutex(_LOCK_T lock) {
return __get_freertos_mutex_for_ptr((mutex_t *)l, true); return __get_freertos_mutex_for_ptr((mutex_t *)l, true);
} }
void __retarget_lock_init(_LOCK_T lock) { void __retarget_lock_init(_LOCK_T *lock) {
if (__freeRTOSinitted) { if (__freeRTOSinitted) {
mutex_t *l = (mutex_t *)lock; mutex_t *l = (mutex_t *)lock;
if ((l == &__lock___at_quick_exit_mutex) || (l == &__lock___tz_mutex) || (l == &__lock___dd_hash_mutex) || (l == &__lock___arc4random_mutex)) { if ((l == &__lock___at_quick_exit_mutex) || (l == &__lock___tz_mutex) || (l == &__lock___dd_hash_mutex) || (l == &__lock___arc4random_mutex)) {
@ -113,7 +113,7 @@ void __retarget_lock_init(_LOCK_T lock) {
} }
} }
void __retarget_lock_init_recursive(_LOCK_T lock) { void __retarget_lock_init_recursive(_LOCK_T *lock) {
if (__freeRTOSinitted) { if (__freeRTOSinitted) {
recursive_mutex_t *l = (recursive_mutex_t *)lock; recursive_mutex_t *l = (recursive_mutex_t *)lock;
if ((l == &__lock___sinit_recursive_mutex) || (l == &__lock___sfp_recursive_mutex) || (l == &__lock___atexit_recursive_mutex) || (l == &__lock___malloc_recursive_mutex) || (l == &__lock___env_recursive_mutex)) { if ((l == &__lock___sinit_recursive_mutex) || (l == &__lock___sfp_recursive_mutex) || (l == &__lock___atexit_recursive_mutex) || (l == &__lock___malloc_recursive_mutex) || (l == &__lock___env_recursive_mutex)) {

View file

@ -26,7 +26,9 @@
#include <lwip/dns.h> #include <lwip/dns.h>
#include <lwip/raw.h> #include <lwip/raw.h>
#include <lwip/timeouts.h> #include <lwip/timeouts.h>
#ifdef PICO_RP2040
#include <pico/cyw43_arch.h> #include <pico/cyw43_arch.h>
#endif
#include <pico/mutex.h> #include <pico/mutex.h>
#include <sys/lock.h> #include <sys/lock.h>
#include "_xoshiro.h" #include "_xoshiro.h"
@ -44,7 +46,7 @@ public:
if (ethernet_arch_lwip_gpio_mask) { if (ethernet_arch_lwip_gpio_mask) {
ethernet_arch_lwip_gpio_mask(); ethernet_arch_lwip_gpio_mask();
} }
#if defined(PICO_CYW43_SUPPORTED) #if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (rp2040.isPicoW()) { if (rp2040.isPicoW()) {
cyw43_arch_lwip_begin(); cyw43_arch_lwip_begin();
return; return;
@ -58,7 +60,7 @@ public:
} }
~LWIPMutex() { ~LWIPMutex() {
#if defined(PICO_CYW43_SUPPORTED) #if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (rp2040.isPicoW()) { if (rp2040.isPicoW()) {
cyw43_arch_lwip_end(); cyw43_arch_lwip_end();
} else { } else {
@ -68,7 +70,7 @@ public:
} else { } else {
recursive_mutex_exit(&__lwipMutex); recursive_mutex_exit(&__lwipMutex);
} }
#if defined(PICO_CYW43_SUPPORTED) #if defined(ARDUINO_RASPBERRY_PI_PICO_W)
} }
#endif #endif
if (ethernet_arch_lwip_gpio_unmask) { if (ethernet_arch_lwip_gpio_unmask) {

View file

@ -22,11 +22,7 @@
#include "RP2040USB.h" #include "RP2040USB.h"
#include <pico/stdlib.h> #include <pico/stdlib.h>
#include <pico/multicore.h> #include <pico/multicore.h>
#include <hardware/vreg.h>
#include <reent.h> #include <reent.h>
#ifdef RP2350_PSRAM_CS
#include "psram.h"
#endif
RP2040 rp2040; RP2040 rp2040;
extern "C" { extern "C" {
@ -51,14 +47,9 @@ void initVariant() { }
// Optional 2nd core setup and loop // Optional 2nd core setup and loop
bool core1_separate_stack __attribute__((weak)) = false; bool core1_separate_stack __attribute__((weak)) = false;
bool core1_disable_systick __attribute__((weak)) = false;
extern void setup1() __attribute__((weak)); extern void setup1() __attribute__((weak));
extern void loop1() __attribute__((weak)); extern void loop1() __attribute__((weak));
extern "C" void main1() { extern "C" void main1() {
if (!core1_disable_systick) {
// Don't install the SYSTICK exception handler. rp2040.getCycleCount will not work properly on core1
rp2040.begin(1);
}
rp2040.fifo.registerCore(); rp2040.fifo.registerCore();
if (setup1) { if (setup1) {
setup1(); setup1();
@ -89,51 +80,19 @@ static struct _reent *_impure_ptr1 = nullptr;
extern "C" int main() { extern "C" int main() {
#if (defined(PICO_RP2040) && (F_CPU != 125000000)) || (defined(PICO_RP2350) && (F_CPU != 150000000)) #if (defined(PICO_RP2040) && (F_CPU != 125000000)) || (defined(PICO_RP2350) && (F_CPU != 150000000))
#if defined(PICO_RP2040)
// From runtime_init_clocks() to bump up RP2040 V for 200Mhz+ operation
if ((F_CPU > 133000000) && (vreg_get_voltage() < VREG_VOLTAGE_1_15)) {
vreg_set_voltage(VREG_VOLTAGE_1_15);
// wait for voltage to settle; must use CPU cycles as TIMER is not yet clocked correctly
busy_wait_at_least_cycles((uint32_t)((SYS_CLK_VREG_VOLTAGE_AUTO_ADJUST_DELAY_US * (uint64_t)XOSC_HZ) / 1000000));
}
#endif
#if defined(RP2350_PSRAM_CS) && (F_CPU > 150000000)
// Need to increase the qmi divider before upping sysclk to ensure we keep the output sck w/in legal bounds
psram_reinit_timing(F_CPU);
// Per datasheet, need to do a dummy access and memory barrier before it takes effect
extern uint8_t __psram_start__;
volatile uint8_t *x = &__psram_start__;
*x ^= 0xff;
*x ^= 0xff;
asm volatile("" ::: "memory");
#endif
set_sys_clock_khz(F_CPU / 1000, true); set_sys_clock_khz(F_CPU / 1000, true);
#if defined(RP2350_PSRAM_CS) && (F_CPU < 150000000)
psram_reinit_timing();
// Per datasheet, need to do a dummy access and memory barrier before it takes effect
extern uint8_t __psram_start__;
volatile uint8_t *x = &__psram_start__;
*x ^= 0xff;
*x ^= 0xff;
asm volatile("" ::: "memory");
#endif #endif
#endif // over/underclock
// Let rest of core know if we're using FreeRTOS // Let rest of core know if we're using FreeRTOS
__isFreeRTOS = initFreeRTOS ? true : false; __isFreeRTOS = initFreeRTOS ? true : false;
// Allocate impure_ptr (newlib temps) if there is a 2nd core running // Allocate impure_ptr (newlib temps) if there is a 2nd core running
if (!__isFreeRTOS && (setup1 || loop1)) { if (!__isFreeRTOS && (setup1 || loop1)) {
_impure_ptr1 = (struct _reent*)calloc(1, sizeof(struct _reent)); _impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
_REENT_INIT_PTR(_impure_ptr1); _REENT_INIT_PTR(_impure_ptr1);
} }
rp2040.begin(0); rp2040.begin();
initVariant(); initVariant();
@ -175,6 +134,7 @@ extern "C" int main() {
} }
rp2040.fifo.registerCore(); rp2040.fifo.registerCore();
} }
if (!__isFreeRTOS) { if (!__isFreeRTOS) {
if (setup1 || loop1) { if (setup1 || loop1) {
delay(1); // Needed to make Picoprobe upload start 2nd core delay(1); // Needed to make Picoprobe upload start 2nd core
@ -244,10 +204,3 @@ void hexdump(const void* mem, uint32_t len, uint8_t cols) {
} }
const String emptyString = ""; const String emptyString = "";
extern "C" void __attribute__((__noreturn__)) __wrap___stack_chk_fail() {
while (true) {
panic("*** stack smashing detected ***: terminated\n");
}
}

View file

@ -76,13 +76,10 @@ extern "C" void *pcalloc(size_t count, size_t size) {
#else #else
// No PSRAM, always fail // No PSRAM, always fail
extern "C" void *pmalloc(size_t size) { extern "C" void *pmalloc(size_t size) {
(void) size;
return nullptr; return nullptr;
} }
extern "C" void *pcalloc(size_t count, size_t size) { extern "C" void *pcalloc(size_t count, size_t size) {
(void) count;
(void) size;
return nullptr; return nullptr;
} }
#endif #endif
@ -91,7 +88,7 @@ extern "C" void *__wrap_realloc(void *mem, size_t size) {
void *rc; void *rc;
noInterrupts(); noInterrupts();
#ifdef RP2350_PSRAM_CS #ifdef RP2350_PSRAM_CS
if (mem && (mem < __ram_start)) { if (mem < __ram_start) {
rc = __psram_realloc(mem, size); rc = __psram_realloc(mem, size);
} else { } else {
rc = __real_realloc(mem, size); rc = __real_realloc(mem, size);
@ -106,7 +103,7 @@ extern "C" void *__wrap_realloc(void *mem, size_t size) {
extern "C" void __wrap_free(void *mem) { extern "C" void __wrap_free(void *mem) {
noInterrupts(); noInterrupts();
#ifdef RP2350_PSRAM_CS #ifdef RP2350_PSRAM_CS
if (mem && (mem < __ram_start)) { if (mem < __ram_start) {
__psram_free(mem); __psram_free(mem);
} else { } else {
__real_free(mem); __real_free(mem);

View file

@ -73,25 +73,20 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
start: start:
set x, 18 ; Preload bit counter...overwritten by the app set x, 18 ; Preload bit counter...we'll shift in the start bit and stop bit, and each bit will be double-recorded (to be fixed by RP2040 code)
wait 0 pin 0 ; Stall until start bit is asserted wait 0 pin 0 ; Stall until start bit is asserted
bitloop:
; Delay until 1/2 way into the bit time ; Delay until 1/2 way into the bit time
mov y, osr mov y, osr
wait_mid_start: wait_half:
jmp y-- wait_mid_start jmp y-- wait_half
bitloop: ; Read in the bit
mov y, osr in pins, 1 ; Shift data bit into ISR
bitloop1: jmp x-- bitloop ; Loop all bits
jmp y-- bitloop1
mov y, osr push ; Stuff it and wait for next start
bitloop2:
jmp y-- bitloop2
in pins, 1
jmp x-- bitloop
push
% c-sdk { % c-sdk {
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) { static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {

View file

@ -32,7 +32,7 @@ static const struct pio_program pio_tx_program = {
.instructions = pio_tx_program_instructions, .instructions = pio_tx_program_instructions,
.length = 6, .length = 6,
.origin = -1, .origin = -1,
.pio_version = pio_tx_pio_version, .pio_version = 0,
#if PICO_PIO_VERSION > 0 #if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0 .used_gpio_ranges = 0x0
#endif #endif
@ -71,7 +71,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_target 0
#define pio_rx_wrap 10 #define pio_rx_wrap 6
#define pio_rx_pio_version 0 #define pio_rx_pio_version 0
static const uint16_t pio_rx_program_instructions[] = { static const uint16_t pio_rx_program_instructions[] = {
@ -80,22 +80,18 @@ static const uint16_t pio_rx_program_instructions[] = {
0x2020, // 1: wait 0 pin, 0 0x2020, // 1: wait 0 pin, 0
0xa047, // 2: mov y, osr 0xa047, // 2: mov y, osr
0x0083, // 3: jmp y--, 3 0x0083, // 3: jmp y--, 3
0xa047, // 4: mov y, osr 0x4001, // 4: in pins, 1
0x0085, // 5: jmp y--, 5 0x0042, // 5: jmp x--, 2
0xa047, // 6: mov y, osr 0x8020, // 6: push block
0x0087, // 7: jmp y--, 7
0x4001, // 8: in pins, 1
0x0044, // 9: jmp x--, 4
0x8020, // 10: push block
// .wrap // .wrap
}; };
#if !PICO_NO_HARDWARE #if !PICO_NO_HARDWARE
static const struct pio_program pio_rx_program = { static const struct pio_program pio_rx_program = {
.instructions = pio_rx_program_instructions, .instructions = pio_rx_program_instructions,
.length = 11, .length = 7,
.origin = -1, .origin = -1,
.pio_version = pio_rx_pio_version, .pio_version = 0,
#if PICO_PIO_VERSION > 0 #if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0 .used_gpio_ranges = 0x0
#endif #endif

View file

@ -23,7 +23,6 @@
#include <errno.h> #include <errno.h>
#include <_syslist.h> #include <_syslist.h>
#include <sys/times.h> #include <sys/times.h>
#include <sys/unistd.h>
#include <pico/stdlib.h> #include <pico/stdlib.h>
#include <pico/multicore.h> #include <pico/multicore.h>

View file

@ -195,7 +195,10 @@ static size_t __no_inline_not_in_flash_func(get_psram_size)(void) {
/// ///
/// @note This function expects interrupts to be enabled on entry /// @note This function expects interrupts to be enabled on entry
static void __no_inline_not_in_flash_func(set_psram_timing)(uint32_t sysHz) { 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 // 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 // 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; volatile uint8_t clockDivider = (sysHz + SFE_PSRAM_MAX_SCK_HZ - 1) / SFE_PSRAM_MAX_SCK_HZ;
@ -280,7 +283,7 @@ static void __no_inline_not_in_flash_func(runtime_init_setup_psram)(/*uint32_t p
// check our interrupts and setup the timing // check our interrupts and setup the timing
restore_interrupts(intr_stash); restore_interrupts(intr_stash);
set_psram_timing((uint32_t)clock_get_hz(clk_sys)); set_psram_timing();
// and now stash interrupts again // and now stash interrupts again
intr_stash = save_and_disable_interrupts(); intr_stash = save_and_disable_interrupts();
@ -320,11 +323,8 @@ static void __no_inline_not_in_flash_func(runtime_init_setup_psram)(/*uint32_t p
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_psram, PICO_RUNTIME_INIT_PSRAM); PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_psram, PICO_RUNTIME_INIT_PSRAM);
// update timing -- used if the system clock/timing was changed. // update timing -- used if the system clock/timing was changed.
void psram_reinit_timing(uint32_t hz) { void psram_reinit_timing() {
if (!hz) { set_psram_timing();
hz = (uint32_t)clock_get_hz(clk_sys);
}
set_psram_timing(hz);
} }
static bool __psram_heap_init() { static bool __psram_heap_init() {

View file

@ -31,7 +31,7 @@
#include <Arduino.h> #include <Arduino.h>
void psram_reinit_timing(uint32_t hz = 0); void psram_reinit_timing();
void *__psram_malloc(size_t size); void *__psram_malloc(size_t size);
void __psram_free(void *ptr); void __psram_free(void *ptr);
void *__psram_realloc(void *ptr, size_t size); void *__psram_realloc(void *ptr, size_t size);

View file

@ -1,383 +0,0 @@
/*
* Copyright (c) 2011 ARM Ltd
* 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 company may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
*/
#if defined(PICO_RP2350) && defined(__arm__)
/* Prototype: void *memcpy (void *dst, const void *src, size_t count). */
/* Use the version of memcpy implemented using LDRD and STRD.
This version is tuned for Cortex-A15.
This might not be the best for other ARMv7-A CPUs,
but there is no predefine to distinguish between
different CPUs in the same architecture,
and this version is better than the plain memcpy provided in newlib.
Therefore, we use this version for all ARMv7-A CPUS. */
/* To make the same code compile for both ARM and Thumb instruction
sets, switch to unified syntax at the beginning of this function.
However, by using the same code, we may be missing optimization
opportunities. For instance, in LDRD/STRD instructions, the first
destination register must be even and the second consecutive in
ARM state, but not in Thumb state. */
.syntax unified
#if defined (__thumb__)
.thumb
.thumb_func
#endif
#ifdef __native_client__
#define SFI_BREG(reg) sfi_breg reg,
#define IT(insn)
#ifdef __thumb__
#error "thumb and native_client are not compatible!"
#endif
.p2align 4
#else
#define SFI_BREG(reg)
#define IT(insn) insn
#endif
.global __wrap_memcpy
.type __wrap_memcpy, %function
// .section .time_critical.memcpy // Actually slows down a bit because RAM and program RAM conflict
__wrap_memcpy:
/* Assumes that n >= 0, and dst, src are valid pointers.
If there is at least 8 bytes to copy, use LDRD/STRD.
If src and dst are misaligned with different offsets,
first copy byte by byte until dst is aligned,
and then copy using LDRD/STRD and shift if needed.
When less than 8 left, copy a word and then byte by byte. */
/* Save registers (r0 holds the return value):
optimized push {r0, r4, r5, lr}.
To try and improve performance, stack layout changed,
i.e., not keeping the stack looking like users expect
(highest numbered register at highest address). */
push {r0, lr}
strd r4, r5, [sp, #-8]!
/* TODO: Add debug frame directives.
We don't need exception unwind directives, because the code below
does not throw any exceptions and does not call any other functions.
Generally, newlib functions like this lack debug information for
assembler source. */
/* Get copying of tiny blocks out of the way first. */
/* Is there at least 4 bytes to copy? */
subs r2, r2, #4
blt copy_less_than_4 /* If n < 4. */
/* Check word alignment. */
ands ip, r0, #3 /* ip = last 2 bits of dst. */
bne dst_not_word_aligned /* If dst is not word-aligned. */
/* Get here if dst is word-aligned. */
ands ip, r1, #3 /* ip = last 2 bits of src. */
bne src_not_word_aligned /* If src is not word-aligned. */
word_aligned:
/* Get here if source and dst both are word-aligned.
The number of bytes remaining to copy is r2+4. */
/* Is there is at least 64 bytes to copy? */
subs r2, r2, #60
blt copy_less_than_64 /* If r2 + 4 < 64. */
/* First, align the destination buffer to 8-bytes,
to make sure double loads and stores don't cross cache line boundary,
as they are then more expensive even if the data is in the cache
(require two load/store issue cycles instead of one).
If only one of the buffers is not 8-bytes aligned,
then it's more important to align dst than src,
because there is more penalty for stores
than loads that cross cacheline boundary.
This check and realignment are only worth doing
if there is a lot to copy. */
/* Get here if dst is word aligned,
i.e., the 2 least significant bits are 0.
If dst is not 2w aligned (i.e., the 3rd bit is not set in dst),
then copy 1 word (4 bytes). */
ands r3, r0, #4
beq 11f /* If dst already two-word aligned. */
SFI_BREG(r1) \
ldr r3, [r1], #4
SFI_BREG(r0) \
str r3, [r0], #4
subs r2, r2, #4
blt copy_less_than_64
11:
/* TODO: Align to cacheline (useful for PLD optimization). */
/* Every loop iteration copies 64 bytes. */
1:
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
SFI_BREG(r1) \
ldrd r4, r5, [r1, \offset]
SFI_BREG(r0) \
strd r4, r5, [r0, \offset]
.endr
add r0, r0, #64
add r1, r1, #64
subs r2, r2, #64
bge 1b /* If there is more to copy. */
copy_less_than_64:
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
Restore the count if there is more than 7 bytes to copy. */
adds r2, r2, #56
blt copy_less_than_8
/* Copy 8 bytes at a time. */
2:
SFI_BREG(r1) \
ldrd r4, r5, [r1], #8
SFI_BREG(r0) \
strd r4, r5, [r0], #8
subs r2, r2, #8
bge 2b /* If there is more to copy. */
copy_less_than_8:
/* Get here if less than 8 bytes to copy, -8 <= r2 < 0.
Check if there is more to copy. */
cmn r2, #8
beq return /* If r2 + 8 == 0. */
/* Restore the count if there is more than 3 bytes to copy. */
adds r2, r2, #4
blt copy_less_than_4
/* Copy 4 bytes. */
SFI_BREG(r1) \
ldr r3, [r1], #4
SFI_BREG(r0) \
str r3, [r0], #4
copy_less_than_4:
/* Get here if less than 4 bytes to copy, -4 <= r2 < 0. */
/* Restore the count, check if there is more to copy. */
adds r2, r2, #4
beq return /* If r2 == 0. */
/* Get here with r2 is in {1,2,3}={01,10,11}. */
/* Logical shift left r2, insert 0s, update flags. */
lsls r2, r2, #31
/* Copy byte by byte.
Condition ne means the last bit of r2 is 0.
Condition cs means the second to last bit of r2 is set,
i.e., r2 is 1 or 3. */
IT(itt ne)
SFI_BREG(r1) \
ldrbne r3, [r1], #1
SFI_BREG(r0) \
strbne r3, [r0], #1
IT(itttt cs)
SFI_BREG(r1) \
ldrbcs r4, [r1], #1
SFI_BREG(r1) \
ldrbcs r5, [r1]
SFI_BREG(r0) \
strbcs r4, [r0], #1
SFI_BREG(r0) \
strbcs r5, [r0]
return:
/* Restore registers: optimized pop {r0, r4, r5, pc} */
ldrd r4, r5, [sp], #8
#ifdef __native_client__
pop {r0, lr}
sfi_bx lr
#else
pop {r0, pc} /* This is the only return point of memcpy. */
#endif
#ifndef __ARM_FEATURE_UNALIGNED
/* The following assembly macro implements misaligned copy in software.
Assumes that dst is word aligned, src is at offset "pull" bits from
word, push = 32 - pull, and the number of bytes that remain to copy
is r2 + 4, r2 >= 0. */
/* In the code below, r2 is the number of bytes that remain to be
written. The number of bytes read is always larger, because we have
partial words in the shift queue. */
.macro miscopy pull push shiftleft shiftright
/* Align src to the previous word boundary. */
bic r1, r1, #3
/* Initialize the shift queue. */
SFI_BREG(r1) \
ldr r5, [r1], #4 /* Load a word from source. */
subs r2, r2, #4
blt 6f /* Go to misaligned copy of less than 8 bytes. */
/* Get here if there is more than 8 bytes to copy.
The number of bytes to copy is r2+8, r2 >= 0. */
/* Save registers: push { r6, r7 }.
We need additional registers for LDRD and STRD, because in ARM state
the first destination register must be even and the second
consecutive. */
strd r6, r7, [sp, #-8]!
subs r2, r2, #56
blt 4f /* Go to misaligned copy of less than 64 bytes. */
3:
/* Get here if there is more than 64 bytes to copy.
The number of bytes to copy is r2+64, r2 >= 0. */
/* Copy 64 bytes in every iteration.
Use a partial word from the shift queue. */
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
mov r6, r5, \shiftleft #\pull
SFI_BREG(r1) \
ldrd r4, r5, [r1, \offset]
orr r6, r6, r4, \shiftright #\push
mov r7, r4, \shiftleft #\pull
orr r7, r7, r5, \shiftright #\push
SFI_BREG(r0) \
strd r6, r7, [r0, \offset]
.endr
add r1, r1, #64
add r0, r0, #64
subs r2, r2, #64
bge 3b
4:
/* Get here if there is less than 64 bytes to copy (-64 <= r2 < 0)
and they are misaligned. */
/* Restore the count if there is more than 7 bytes to copy. */
adds r2, r2, #56
/* If less than 8 bytes to copy,
restore registers saved for this loop: optimized poplt { r6, r7 }. */
itt lt
ldrdlt r6, r7, [sp], #8
blt 6f /* Go to misaligned copy of less than 8 bytes. */
5:
/* Copy 8 bytes at a time.
Use a partial word from the shift queue. */
mov r6, r5, \shiftleft #\pull
SFI_BREG(r1) \
ldrd r4, r5, [r1], #8
orr r6, r6, r4, \shiftright #\push
mov r7, r4, \shiftleft #\pull
orr r7, r7, r5, \shiftright #\push
SFI_BREG(r0) \
strd r6, r7, [r0], #8
subs r2, r2, #8
bge 5b /* If there is more to copy. */
/* Restore registers saved for this loop: optimized pop { r6, r7 }. */
ldrd r6, r7, [sp], #8
6:
/* Get here if there less than 8 bytes to copy (-8 <= r2 < 0)
and they are misaligned. */
/* Check if there is more to copy. */
cmn r2, #8
beq return
/* Check if there is less than 4 bytes to copy. */
cmn r2, #4
itt lt
/* Restore src offset from word-align. */
sublt r1, r1, #(\push / 8)
blt copy_less_than_4
/* Use a partial word from the shift queue. */
mov r3, r5, \shiftleft #\pull
/* Load a word from src, but without writeback
(this word is not fully written to dst). */
SFI_BREG(r1) \
ldr r5, [r1]
/* Restore src offset from word-align. */
add r1, r1, #(\pull / 8)
/* Shift bytes to create one dst word and store it. */
orr r3, r3, r5, \shiftright #\push
SFI_BREG(r0) \
str r3, [r0], #4
/* Use single byte copying of the remaining bytes. */
b copy_less_than_4
.endm
#endif /* not __ARM_FEATURE_UNALIGNED */
dst_not_word_aligned:
/* Get here when dst is not aligned and ip has the last 2 bits of dst,
i.e., ip is the offset of dst from word.
The number of bytes that remains to copy is r2 + 4,
i.e., there are at least 4 bytes to copy.
Write a partial word (0 to 3 bytes), such that dst becomes
word-aligned. */
/* If dst is at ip bytes offset from a word (with 0 < ip < 4),
then there are (4 - ip) bytes to fill up to align dst to the next
word. */
rsb ip, ip, #4 /* ip = #4 - ip. */
cmp ip, #2
/* Copy byte by byte with conditionals. */
IT(itt gt)
SFI_BREG(r1) \
ldrbgt r3, [r1], #1
SFI_BREG(r0) \
strbgt r3, [r0], #1
IT(itt ge)
SFI_BREG(r1) \
ldrbge r4, [r1], #1
SFI_BREG(r0) \
strbge r4, [r0], #1
SFI_BREG(r1) \
ldrb lr, [r1], #1
SFI_BREG(r0) \
strb lr, [r0], #1
/* Update the count.
ip holds the number of bytes we have just copied. */
subs r2, r2, ip /* r2 = r2 - ip. */
blt copy_less_than_4 /* If r2 < ip. */
/* Get here if there are more than 4 bytes to copy.
Check if src is aligned. If beforehand src and dst were not word
aligned but congruent (same offset), then now they are both
word-aligned, and we can copy the rest efficiently (without
shifting). */
ands ip, r1, #3 /* ip = last 2 bits of src. */
beq word_aligned /* If r1 is word-aligned. */
src_not_word_aligned:
/* Get here when src is not word-aligned, but dst is word-aligned.
The number of bytes that remains to copy is r2+4. */
#ifdef __ARM_FEATURE_UNALIGNED
/* Copy word by word using LDR when alignment can be done in hardware,
i.e., SCTLR.A is set, supporting unaligned access in LDR and STR. */
subs r2, r2, #60
blt 8f
7:
/* Copy 64 bytes in every loop iteration. */
.irp offset, #0, #4, #8, #12, #16, #20, #24, #28, #32, #36, #40, #44, #48, #52, #56, #60
SFI_BREG(r1) \
ldr r3, [r1, \offset]
SFI_BREG(r0) \
str r3, [r0, \offset]
.endr
add r0, r0, #64
add r1, r1, #64
subs r2, r2, #64
bge 7b
8:
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
Check if there is more than 3 bytes to copy. */
adds r2, r2, #60
blt copy_less_than_4
9:
/* Get here if there is less than 64 but at least 4 bytes to copy,
where the number of bytes to copy is r2+4. */
SFI_BREG(r1) \
ldr r3, [r1], #4
SFI_BREG(r0) \
str r3, [r0], #4
subs r2, r2, #4
bge 9b
b copy_less_than_4
#else /* not __ARM_FEATURE_UNALIGNED */
/* ip has last 2 bits of src,
i.e., ip is the offset of src from word, and ip > 0.
Compute shifts needed to copy from src to dst. */
cmp ip, #2
beq miscopy_16_16 /* If ip == 2. */
bge miscopy_24_8 /* If ip == 3. */
/* Get here if ip == 1. */
/* Endian independent macros for shifting bytes within registers. */
#ifndef __ARMEB__
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsr shiftright=lsl
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsr shiftright=lsl
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsr shiftright=lsl
#else /* not __ARMEB__ */
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsl shiftright=lsr
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsl shiftright=lsr
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsl shiftright=lsr
#endif /* not __ARMEB__ */
#endif /* not __ARM_FEATURE_UNALIGNED */
#endif /* memcpy */

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -4,7 +4,7 @@
SPDX-License-Identifier: BSD-3-Clause SPDX-License-Identifier: BSD-3-Clause
*/ */
#if defined(PICO_CYW43_SUPPORTED) #if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <btstack.h> #include <btstack.h>
#include <pico/btstack_flash_bank.h> #include <pico/btstack_flash_bank.h>
#include <hardware/flash.h> #include <hardware/flash.h>
@ -49,15 +49,11 @@ static uint32_t pico_flash_bank_get_alignment(void * context) {
static void pico_flash_bank_erase(void * context, int bank) { static void pico_flash_bank_erase(void * context, int bank) {
(void)(context); (void)(context);
DEBUG_PRINT("erase: bank %d\n", bank); DEBUG_PRINT("erase: bank %d\n", bank);
if (!__isFreeRTOS) { noInterrupts();
noInterrupts();
}
rp2040.idleOtherCore(); rp2040.idleOtherCore();
flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE); flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE);
rp2040.resumeOtherCore(); rp2040.resumeOtherCore();
if (!__isFreeRTOS) { interrupts();
interrupts();
}
} }
static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) { static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) {
@ -151,15 +147,11 @@ static void pico_flash_bank_write(void * context, int bank, uint32_t offset, con
offset = 0; offset = 0;
// Now program the entire page // Now program the entire page
if (!__isFreeRTOS) { noInterrupts();
noInterrupts();
}
rp2040.idleOtherCore(); rp2040.idleOtherCore();
flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE); flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE);
rp2040.resumeOtherCore(); rp2040.resumeOtherCore();
if (!__isFreeRTOS) { interrupts();
interrupts();
}
} }
} }

View file

@ -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

View file

@ -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

View file

@ -18,19 +18,18 @@
; Side-set pin 0 is used for Tone output ; Side-set pin 0 is used for Tone output
; OSR == Halfcycle count - 3 ; OSR == Halfcycle count
.program tone2 .program tone2
.side_set 1 opt .side_set 1 opt
; pull ; TXFIFO -> OSR, or X -> OSR if no new period pull ; TXFIFO -> OSR, or X -> OSR if no new period
; mov x, osr ; OSR -> X mov x, osr ; OSR -> X
.wrap_target
high: high:
pull noblock ; Potentially grab new HALFCYCLECOUNT, OTW copy from backup in X pull noblock ; Potentially grab new HALFCYCLECOUNT, OTW copy from backup in X
mov x, osr side 1 ; OSR -> X mov x, osr ; OSR -> X
mov y, osr ; HALFCYCLECOUNT -> Y mov y, osr side 1 ; HALFCYCLECOUNT -> Y
highloop: highloop:
jmp y-- highloop ; while (y--) { /* noop delay */ } jmp y-- highloop ; while (y--) { /* noop delay */ }
@ -39,7 +38,7 @@ low:
lowloop: lowloop:
jmp y-- lowloop ; while (y--) { /* noop delay */ } jmp y-- lowloop ; while (y--) { /* noop delay */ }
.wrap ; GOTO high jmp high ; GOTO high
% c-sdk { % c-sdk {
static inline void tone2_program_init(PIO pio, uint sm, uint offset, uint pin) { static inline void tone2_program_init(PIO pio, uint sm, uint offset, uint pin) {

View file

@ -13,26 +13,29 @@
// ----- // // ----- //
#define tone2_wrap_target 0 #define tone2_wrap_target 0
#define tone2_wrap 5 #define tone2_wrap 8
#define tone2_pio_version 0 #define tone2_pio_version 0
static const uint16_t tone2_program_instructions[] = { static const uint16_t tone2_program_instructions[] = {
// .wrap_target // .wrap_target
0x8080, // 0: pull noblock 0x80a0, // 0: pull block
0xb827, // 1: mov x, osr side 1 0xa027, // 1: mov x, osr
0xa047, // 2: mov y, osr 0x8080, // 2: pull noblock
0x0083, // 3: jmp y--, 3 0xa027, // 3: mov x, osr
0xb047, // 4: mov y, osr side 0 0xb847, // 4: mov y, osr side 1
0x0085, // 5: jmp y--, 5 0x0085, // 5: jmp y--, 5
0xb047, // 6: mov y, osr side 0
0x0087, // 7: jmp y--, 7
0x0002, // 8: jmp 2
// .wrap // .wrap
}; };
#if !PICO_NO_HARDWARE #if !PICO_NO_HARDWARE
static const struct pio_program tone2_program = { static const struct pio_program tone2_program = {
.instructions = tone2_program_instructions, .instructions = tone2_program_instructions,
.length = 6, .length = 9,
.origin = -1, .origin = -1,
.pio_version = tone2_pio_version, .pio_version = 0,
#if PICO_PIO_VERSION > 0 #if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0 .used_gpio_ranges = 0x0
#endif #endif

View file

@ -22,6 +22,7 @@
#include <CoreMutex.h> #include <CoreMutex.h>
#include <hardware/gpio.h> #include <hardware/gpio.h>
#include <hardware/sync.h> #include <hardware/sync.h>
#include <map>
#include "_freertos.h" #include "_freertos.h"
@ -58,34 +59,51 @@ extern "C" void noInterrupts() {
} }
} }
auto_init_mutex(_irqMutex);
static uint64_t _gpioIrqEnabled = 0; // Sized to work with RP2350B, 48 GPIOs
static uint64_t _gpioIrqUseParam;
void *_gpioIrqCB[__GPIOCNT];
void *_gpioIrqCBParam[__GPIOCNT];
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and // Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
// dispatch to the real callback manually // dispatch to the real callback manually
auto_init_mutex(_irqMutex);
class CBInfo {
public:
CBInfo(voidFuncPtr cb) : _cb(cb), _useParam(false), _param(nullptr) { };
CBInfo(voidFuncPtrParam cbParam, void *param) : _cbParam(cbParam), _useParam(true), _param(param) { };
void callback() {
if (_useParam && _cbParam) {
_cbParam(_param);
} else if (_cb) {
_cb();
}
}
private:
union {
voidFuncPtr _cb;
voidFuncPtrParam _cbParam;
};
bool _useParam;
void *_param;
};
static std::map<pin_size_t, CBInfo> _map;
void _gpioInterruptDispatcher(uint gpio, uint32_t events) { void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
(void) events; (void) events;
uint64_t mask = 1LL << gpio; // Only need to lock around the std::map check, not the whole IRQ callback
if (_gpioIrqEnabled & mask) { CoreMutex m(&_irqMutex);
if (_gpioIrqUseParam & mask) { if (m) {
voidFuncPtr cb = (voidFuncPtr)_gpioIrqCB[gpio]; auto irq = _map.find(gpio);
cb(); if (irq != _map.end()) {
} else { auto cb = irq->second;
voidFuncPtrParam cb = (voidFuncPtrParam)_gpioIrqCB[gpio]; cb.callback();
cb(_gpioIrqCBParam[gpio]);
} }
} }
} }
// To be called when appropriately protected w/IRQ and mutex protects // To be called when appropriately protected w/IRQ and mutex protects
static void _detachInterruptInternal(pin_size_t pin) { static void _detachInterruptInternal(pin_size_t pin) {
uint64_t mask = 1LL << pin; auto irq = _map.find(pin);
if (_gpioIrqEnabled & mask) { if (irq != _map.end()) {
gpio_set_irq_enabled(pin, 0x0f /* all */, false); gpio_set_irq_enabled(pin, 0x0f /* all */, false);
_gpioIrqEnabled &= ~mask; _map.erase(pin);
} }
} }
@ -94,7 +112,7 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
if (!m) { if (!m) {
return; return;
} }
uint64_t mask = 1LL << pin;
uint32_t events; uint32_t events;
switch (mode) { switch (mode) {
case LOW: events = 1; break; case LOW: events = 1; break;
@ -106,9 +124,8 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
} }
noInterrupts(); noInterrupts();
_detachInterruptInternal(pin); _detachInterruptInternal(pin);
_gpioIrqEnabled |= mask; CBInfo cb(callback);
_gpioIrqUseParam &= ~mask; // No parameter _map.insert({pin, cb});
_gpioIrqCB[pin] = (void *)callback;
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher); gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts(); interrupts();
} }
@ -118,7 +135,7 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
if (!m) { if (!m) {
return; return;
} }
uint64_t mask = 1LL << pin;
uint32_t events; uint32_t events;
switch (mode) { switch (mode) {
case LOW: events = 1; break; case LOW: events = 1; break;
@ -130,10 +147,8 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
} }
noInterrupts(); noInterrupts();
_detachInterruptInternal(pin); _detachInterruptInternal(pin);
_gpioIrqEnabled |= mask; CBInfo cb(callback, param);
_gpioIrqUseParam &= ~mask; // No parameter _map.insert({pin, cb});
_gpioIrqCB[pin] = (void *)callback;
_gpioIrqCBParam[pin] = param;
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher); gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts(); interrupts();
} }

View file

@ -56,9 +56,9 @@ extern "C" void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOr
} }
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST) { if (bitOrder == LSBFIRST) {
digitalWrite(dataPin, !!(val & (1 << i)) ? HIGH : LOW); digitalWrite(dataPin, !!(val & (1 << i)));
} else { } else {
digitalWrite(dataPin, !!(val & (1 << (7 - i))) ? HIGH : LOW); digitalWrite(dataPin, !!(val & (1 << (7 - i))));
} }
digitalWrite(clockPin, HIGH); digitalWrite(clockPin, HIGH);

View file

@ -12,9 +12,9 @@ need to be periodically sampled to be read by applications, easily, such as:
* Light dependent resistors (LDR), etc. * Light dependent resistors (LDR), etc.
Up to 4 (or 8 in the case of the RP2350B) analog samples can be recorded by the Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A3``), and all
hardware (``A0`` ... ``A3``), and all recording is done at 16-bit levels (but be recording is done at 16-bit levels (but be aware that the ADC in the Pico will only
aware that the ADC in the Pico will only ever return values between 0...4095). ever return values between 0...4095).
The interface for the ``ADCInput`` device is very similar to the ``I2S`` input The interface for the ``ADCInput`` device is very similar to the ``I2S`` input
device, and most code can be ported simply by instantiating a ``ADCInput`` device, and most code can be ported simply by instantiating a ``ADCInput``
@ -26,12 +26,11 @@ allowed while in use.
ADC Input API ADC Input API
------------- -------------
ADCInput(pin0 [, pin1, pin2, pin3[, pin4, pin5, pin6, pin7]) ADCInput(pin0 [, pin1, pin2, pin3])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Creates an ADC input object which will record the pins specified in the code. Creates an ADC input object which will record the pins specified in the code.
Only pins ``A0`` ... ``A3`` (``A7`` on RP2350B) can be used, and they must be Only pins ``A0`` ... ``A3`` can be used, and they must be specified in increasing
specified in increasing order (i.e. ``ADCInput(A0, A1);`` is valid, order (i.e. ``ADCInput(A0, A1);`` is valid, but ``ADCInput(A1, A0)`` is not.
but ``ADCInput(A1, A0)`` is not.
bool setBuffers(size_t buffers, size_t bufferWords) bool setBuffers(size_t buffers, size_t bufferWords)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = u'4.5.4' version = u'4.0.2'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = u'4.5.4' release = u'4.0.2'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View file

@ -112,7 +112,7 @@ For only RP2350A variants (using the compile options, not the onboard ID registe
.. code:: cpp .. code:: cpp
#if defined(PICO_RP2350A) && PICO_RP2350A #if defined(PICO_RP2350) && !defined(PICO_RP2350B)
...RP2350A only code... ...RP2350A only code...
#endif #endif
@ -121,7 +121,7 @@ and not the chip ID register):
.. code:: cpp .. code:: cpp
#if defined(PICO_RP2350A) && !PICO_RP2350A #if defined(PICO_RP2350B)
...48-GPIO version code here ...48-GPIO version code here
#endif #endif

View file

@ -135,29 +135,6 @@ directory into a new LittleFS flash file system.
- Double check the Serial Monitor is closed. Uploads will fail if the Serial Monitor has control of the serial port. - 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`` - Enter ``[Ctrl]`` + ``[Shift]`` + ``[P]`` to bring up the command palette, then select/type ``Upload LittleFS to Pico/ESP8266``
Downloading Files from a LittleFS System
----------------------------------------
Using ``gdb`` it is possible to dump the flash data making up the filesystem and then extract
it using the ``mklittlefs`` tool. A working ``OpenOCD`` setup, DebugProbe, and ``gdb`` are required.
To download the raw filesystem, from within ``GDB`` run:
.. code::
^C (break)
(gdb) dump binary memory littlefs.bin &_FS_start &_FS_end
It may take a few seconds as ``GDB`` reads out the flash to the file. Once the raw file is downloaded it can be extracted using the ``mklittlefs`` tool from the BASH/Powershell/command line
.. code::
$ <path-to-mklittlefs>/mklittlefs -u output-dir littlefs.bin
Directory <output-dir> does not exists. Try to create it.
gmon.out > <output-dir>/gmon.out size: 24518 Bytes
gmon.bak > <output-dir>/gmon.bak size: 1 Bytes
The defaults built into ``mklittlefs`` should be appropriate for normal LittleFS filesystems built on the device or using the upload tool.
SD Library Information SD Library Information
---------------------- ----------------------
The included ``SD`` library is the Arduino standard one. Please refer to The included ``SD`` library is the Arduino standard one. Please refer to
@ -174,23 +151,6 @@ second SPI port, ``SPI1``. Just use the following call in place of
SD.begin(cspin, SPI1); SD.begin(cspin, SPI1);
Enabling SDIO operation for SD
------------------------------
SDIO support is available thanks to SdFat implementing a PIO-based SDIO controller.
This mode can significantly increase IO performance to SD cards but it requires that
all 4 DAT0..DAT3 lines to be wired to the Pico (most SD breakout boards only provide
1-but SPI mode of operation).
To enable SDIO mode, simply specify the SD_CLK, SD_CMD, and SD_DAT0 GPIO pins. The clock
and command pins can be any GPIO (not limited to legal SPI pins). The DAT0 pin can be any
GPIO with remaining DAT1...3 pins consecutively connected.
..code:: cpp
SD.begin(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO);
No other changes are required in the application to take advantage of this high
performance mode.
Using VFS (Virtual File System) for POSIX support Using VFS (Virtual File System) for POSIX support
------------------------------------------------- -------------------------------------------------

View file

@ -30,12 +30,6 @@ I2S(INPUT)
Creates an I2S input port. Needs to be connected up to the Creates an I2S input port. Needs to be connected up to the
desired pins (see below) and started before any input can happen. desired pins (see below) and started before any input can happen.
I2S(INPUT_PULLUP)
~~~~~~~~~~~~~~~~~
Creates a bi-directional I2S input and output port. Needs to be
connected up to the desired pins (see below) and started before
any input or output can happen.
bool setBCLK(pin_size_t pin) bool setBCLK(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1`` Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1``
@ -43,18 +37,7 @@ due to limitations of the PIO state machines. Call this before ``I2S::begin()``
bool setDATA(pin_size_t pin) bool setDATA(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DOUT or DIN pin of the I2S device. Any pin may be used. In bi-directional Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
operation, must use ``I2S::setDOUT()`` and ``I2S::setDIN`` instead.
Call before ``I2S::begin()``
bool setDOUT(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DOUT pin of the I2S device. Any pin may be used.
Call before ``I2S::begin()``
bool setDIN(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DIN pin of the I2S device. Any pin may be used.
Call before ``I2S::begin()`` Call before ``I2S::begin()``
bool setMCLK(pin_size_t pin) bool setMCLK(pin_size_t pin)
@ -88,7 +71,7 @@ sample rate on-the-fly.
bool setSysClk(int samplerate) bool setSysClk(int samplerate)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Changes the PICO system clock to optimise for the desired samplerate. Changes the PICO system clock to optimise for the desired samplerate.
The clock changes to 153.6 MHz for samplerates that are a multiple of 8 kHz, and 135.6 MHz for multiples of 11.025 kHz. 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. 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. Should be called before any I2S functions and any other sysclk dependent initialisations.
@ -132,14 +115,6 @@ void getOverUnderflow()
Returns a flag indicating if the I2S system ran our of data to send on output, Returns a flag indicating if the I2S system ran our of data to send on output,
or had to throw away data on input. or had to throw away data on input.
void getOverflow()
~~~~~~~~~~~~~~~~~~~~~~~
Returns a flag indicating if the I2S system had to throw away data on input.
void getUnderflow()
~~~~~~~~~~~~~~~~~~~~~~~
Returns a flag indicating if the I2S system ran our of data to send on output.
size_t write(uint8_t/int8_t/int16_t/int32_t) 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 Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
@ -164,7 +139,7 @@ size_t write(const uint8_t \*buffer, size_t size)
Transfers number of bytes from an application buffer to the I2S output buffer. Transfers number of bytes from an application buffer to the I2S output buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes**. Will not block, so check the return value to find out how of **4 bytes**. Will not block, so check the return value to find out how
many 32-bit words were actually written. many bytes were actually written.
int availableForWrite() int availableForWrite()
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
@ -181,13 +156,6 @@ int peek()
Returns the next sample to be read from the I2S buffer (without actually Returns the next sample to be read from the I2S buffer (without actually
removing it). removing it).
size_t read(uint8_t \*buffer, size_t size)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transfers number of bytes from the I2S input buffer to an application buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes**. Will not block, so check the return value to find out how
many 32-bit words were actually read.
void onTransmit(void (\*fn)(void)) void onTransmit(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when an I2S DMA buffer is fully transmitted. Sets a callback to be called when an I2S DMA buffer is fully transmitted.

View file

@ -7,7 +7,7 @@ RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2
processor), intended to make it easier and more fun to use and processor), intended to make it easier and more fun to use and
program the Raspberry Pi Pico / RP2040 / RP2350 based boards. program the Raspberry Pi Pico / RP2040 / RP2350 based boards.
This Arduino core uses a custom toolset with GCC 14.2 and Newlib 4.3 This Arduino core uses a custom toolset with GCC 12.3 and Newlib 4.0.0
and doesn't require any system-installed prerequisites. and doesn't require any system-installed prerequisites.
For the latest version, always check https://github.com/earlephilhower/arduino-pico For the latest version, always check https://github.com/earlephilhower/arduino-pico
@ -43,8 +43,6 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
File Systems (SD, SDFS, LittleFS) <fs> File Systems (SD, SDFS, LittleFS) <fs>
USB (Arduino and Adafruit_TinyUSB) <usb> USB (Arduino and Adafruit_TinyUSB) <usb>
Multicore Processing <multicore> Multicore Processing <multicore>
Semihosting <semihosting>
Profiling (GPROF) <profiling>
RP2350 Specific Notes <rp2350> RP2350 Specific Notes <rp2350>
RP2350 PSRAM <psram> RP2350 PSRAM <psram>

View file

@ -16,25 +16,6 @@ not necessarily simultaneously!).
See the ``Multicore.ino`` example in the ``rp2040`` example directory for a See the ``Multicore.ino`` example in the ``rp2040`` example directory for a
quick introduction. quick introduction.
Core 1 Operation
----------------
By default, core1 (the second core) has no non-user written code running on it.
No interrupts, exceptions, or other background processing is done (but the core
is still subject to hardware stalls due to on-die memory resource conflicts).
When flash erase or write operations (i.e. ``LittleFS`` or ``EEPROM``) are called
from core0, core1 **will** be paused.
If ``rp2040.getCycleCount`` is needed to operate on the second core, then a
periodic (once ever 16M clock cycles) ``SYSTICK`` exception will happen behind
the scenes. For extremely time-critical operations this may not be desirable
and can be disabled by defining a new ``bool`` variable to ``true`` anywhere
in your sketch:
.. code:: cpp
bool core1_disable_systick = true;
Stack Sizes Stack Sizes
----------- -----------
@ -86,9 +67,6 @@ void rp2040.restartCore1()
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
Hard resets Core1 from Core 0 and restarts its operation from ``setup1()``. Hard resets Core1 from Core 0 and restarts its operation from ``setup1()``.
This can cause unpredictable behavior because globals and the heap
are shared between cores and not re-initialized with this call. Use with
extreme caution.
Communicating Between Cores Communicating Between Cores
--------------------------- ---------------------------

View file

@ -1,6 +1,8 @@
OTA Updates OTA Updates
=========== ===========
**NOTE:** OTA is not yet supported on the RP2350. PRs gladly accepted!
Introduction Introduction
------------ ------------
@ -235,7 +237,7 @@ Requirements
Implementation Overview Implementation Overview
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
Updates with a web browser are implemented using ``HTTPUpdateServer`` class together with ``WebServer`` and ``LEAmDNS`` or ``SimpleMDNS`` classes. The following code is required to get it work: Updates with a web browser are implemented using ``HTTPUpdateServer`` class together with ``WebServer`` and ``LEAmDNS`` classes. The following code is required to get it work:
setup() setup()

View file

@ -156,53 +156,6 @@ platform <https://github.com/maxgerhardt/platform-raspberrypi/blob/77e0d3a29d1db
; Flash Size: 2MB (Sketch: 0.5MB, FS:1.5MB) ; Flash Size: 2MB (Sketch: 0.5MB, FS:1.5MB)
board_build.filesystem_size = 1.5m board_build.filesystem_size = 1.5m
PSRAM size
----------
For RP2350 based boards, this controls how much PSRAM the firmware will think it has available in bytes, mapped at starting address 0x11000000.
To learn more about PSRAM usage, see: :doc:`RP2350 PSRAM Support <psram>`
.. code:: ini
; PSRAM size: 1MB
board_upload.psram_length = 1048576
; PSRAM size: 2MB
board_upload.psram_length = 2097152
; PSRAM size: 4MB
board_upload.psram_length = 4194304
PSRAM chip select (CS)
----------------------
For RP2350 based boards, this controls what chip-select (also called: slave-select / SS) pin to use when wanting to talk to the PSRAM chip.
Note that it's not needed to set this with a board that is known to have a PSRAM chip on-board, such as a "Sparkfun Thing Plus 2350". The ``pins_arduino.h`` of that variant already has the correct definition.
To learn more about PSRAM usage, see: :doc:`RP2350 PSRAM Support <psram>`
.. code:: ini
; PSRAM CS is at GP47
build_flags =
-DRP2350_PSRAM_CS=47
Boot2 Source
------------
Boot2 is the second stage bootloader and predominantly used on the RP2040.
Its main purpose is to configure the communication with the Flash at the highest, safest speed it can.
All known boards have their correct value already configured. However, when choosing ``board = generic``,
you can freely configure the Boot2 to be for a different flash.
For possible Boot2 filenames, `please see here <https://github.com/earlephilhower/arduino-pico/tree/master/boot2/rp2040>`__.
.. code:: ini
; expect an ISSI IS25LP080 flash, SPI frequency = CPU frequency divided by 2
board_build.arduino.earlephilhower.boot2_source = boot2_is25lp080_2_padded_checksum.S
CPU Speed CPU Speed
--------- ---------
@ -309,18 +262,6 @@ default Pico SDK USB stack. To change it, add
Note that the special "No USB" setting is also supported, through the Note that the special "No USB" setting is also supported, through the
shortcut-define ``PIO_FRAMEWORK_ARDUINO_NO_USB``. shortcut-define ``PIO_FRAMEWORK_ARDUINO_NO_USB``.
USB Customization
-----------------
If you want to change the USB VID, PID, product or manufacturer name that the device will appear under, configure them as follows:
.. code:: ini
board_build.arduino.earlephilhower.usb_manufacturer = Custom Manufacturer
board_build.arduino.earlephilhower.usb_product = Ultra Cool Product
board_build.arduino.earlephilhower.usb_vid = 0xABCD
board_build.arduino.earlephilhower.usb_pid = 0x1337
IP Stack IP Stack
-------- --------
@ -368,19 +309,6 @@ local copy of the core (with e.g. some modifications) on disk (`see documentatio
Note that this can only be done for versions that have the PlatformIO Note that this can only be done for versions that have the PlatformIO
builder script it in, so versions before 1.9.2 are not supported. builder script it in, so versions before 1.9.2 are not supported.
Selecting the CPU architecture
------------------------------
By default Platform.IO will build for the onboard ARM cores on the RP2350. To build RISC-V binaries
adjust the ``board_build.mcu`` option accordingly:
.. code:: ini
; RP2350 based (RISC-V)
[env:rpipico2-riscv]
board = rpipico2
board_build.mcu = rp2350-riscv
Examples Examples
-------- --------

View file

@ -1,76 +0,0 @@
Profiling Applications with GPROF
=================================
Applications running on the Pico can be profiled using GNU GPROF to show where the CPU is using its time
on the device and how often certain functions are called. It does this by recompiling the application
and adding a small preamble to each function built to identify what functions call what others (and
how frequently). It also uses the ``SYSTICK`` exception timer to sample and record the PC 10,000 times
per second. When an application is complete, the recorded date can be dumped to the host PC as a
``gmon.,out`` file which can be processed by ``arm-none-eabi-gprof`` into useful date.
s histogram of PCs and tally of function caller/callees can take a significant amount of RAM, from 100KB
to 10000KB depending on the size of the application. As such, while the RP2040 **may** be able to
profile small applications, this is only really recommended on the RP2350 with external PSRAM. The
profiler will automatically use PSRAM when available. Call ``rp2040.getProfileMemoryUsage()`` to get the
memory allocated at runtime.
Profiling also adds processing overhead in terms of the periodic sampling and the function preambles.
In most cases there is no reason to enable (and many reasons to disable) profiling when an application
is deployed to the field.
To transfer the ``GMON.OUT`` data from the Pico to the host HP can be done by having the application
write it out to an SD card or a LittleFS filesystem which is then manually dumped, but for ease of use
semihosting can be used to allow the Pico (under the control of OpenOCD and GDB) to write the
``gmon.out`` file directly on the host PC, ready for use.
**NOTE** Semihosting only works when connected to an OpenOCD + GDB debug session. Running an application
compiled for Semihosting without the debugger will cause a panic and hang the chip.
As of now, only ARM has support for Semihosting or GPROF.
Enabling Profiling in an Application
------------------------------------
The ``Tools->Profiling->Enabled`` menu needs to be selected to enable profiling support in GCC. This will
add the necessary preamble to every function compiled (**Note** that the ``libpico`` and ``libc`` will not
be instrumented because they are pre-built so calls from them will not be fully instrumented. However,
PC data will still be grabbed and decoded from them at runtime.)
The application will automatically start collecting profiling data even before ``setup`` starts in this
mode. It will continue collecting data until you stop and write out the profiling data using
``rp2040.writeProfiling()`` to dump to the host, a file, serial port, etc.
For example, an application which does all its processing in ``setup()`` might look like:
.. code:: cpp
#include <SemiFS.h>
void setup() {
SerialSemi.printf("BEGIN\n");
do_some_work_that_takes_a_long_time_with_many_function_calls();
// Do lots of other work...
// Now all done...
SerialSemi.printf("Writing GMON.OUT\n");
SemiFS.begin();
File gmon = SemiFS.open("gmon.out", "w");
rp2040.writeProfiling(&gmon);
gmon.close();
SerialSemi.printf("END\n");
}
void loop() {}
Collecting and Analyzing Profile Data
-------------------------------------
Running this application under `semihosting <semihosting>`_ GDB and OpenOCD generates a ``gmon.out`` file
in the OpenOCD current working directory. This file, combined with the ``ELF`` binary build in the
IDE and loaded through GDB, can produce profiler output using
.. code::
$ /path/to/arm-none-eabi/bin/arm-none-eabi-gprof /path/to/sketch.ino.elf /path/to/gmon.out
See the ``rp2040/Profiling.ino`` example for more details.

View file

@ -53,7 +53,7 @@ The following example will **NOT** work:
Using PSRAM for dynamic allocations Using PSRAM for dynamic allocations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PSRAM can also be used as a heap for dynamic allocations using ``pmalloc`` and PSRAM can also be used as a heap for dynamica allocations using ``pmalloc`` and
``pcalloc``. These calls function exactly like normal ``malloc`` and ``calloc`` ``pcalloc``. These calls function exactly like normal ``malloc`` and ``calloc``
except they allocate space from PSRAM. except they allocate space from PSRAM.

View file

@ -57,11 +57,6 @@ void rp2040.wdt_reset()
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
Reloads the watchdog's counter with the amount of time set by wdt_begin. Reloads the watchdog's counter with the amount of time set by wdt_begin.
RP2040::resetReason_t rp2040.getResetReason()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns the reason for the last reset, defined in enum ``RP2040::resetReason_t``.
See example ```ResetReason``` for some details.
Memory Information Memory Information
------------------ ------------------
@ -95,8 +90,8 @@ doing any WiFi calls.
Bootloader Bootloader
---------- ----------
void rp2040.enableDoubleResetBootloader() (Pico/RP2040 only) void rp2040.enableDoubleResetBootloader()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Add a call anywhere in the sketch to ``rp2040.enableDoubleResetBootloader()`` and Add a call anywhere in the sketch to ``rp2040.enableDoubleResetBootloader()`` and
the core will check for a double-tap on reset, and if found will start the USB the core will check for a double-tap on reset, and if found will start the USB
bootloader. bootloader.

View file

@ -6,14 +6,8 @@ is supported by the core with some minor caveats:
* PSRAM is supported via a new ``pmalloc`` call and ``PSRAM`` variable decorator. * PSRAM is supported via a new ``pmalloc`` call and ``PSRAM`` variable decorator.
* Both RP2350A and RP2350B (48 GPIOs) are supported. * Both RP2350A and RP2350B (48 GPIOs) are supported.
* Only ARM mode is available. For RISC-V (Hazard3), please use the raw SDK.
ARM and RISC-V Modes * OTA is not yet supported.
~~~~~~~~~~~~~~~~~~~~
Either set of cores can be used on the RP2350, ARM Cortex-M33 or RISC-V Hazard3.
Select the desired core from the IDE menus under ``Tools->CPU Architecture``.
As of the initial release, all libraries should work under the new RISC-V mode with
the exception of FreeRTOS. If not, patches are always welcome.
P2350-E9 Errata ("Increased leakage current on Bank 0 GPIO when pad input is enabled") P2350-E9 Errata ("Increased leakage current on Bank 0 GPIO when pad input is enabled")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -1,59 +0,0 @@
Semihosting Support
===================
Using special debugger breakpoints and commands, the Pico can read and write to the debugging console as well
as read and write files on a development PC. The ``Semihosting`` library allows applications to use the
semihosting support as a normal filesystem or serial port.
**NOTE** Semihosting only works when connected to an OpenOCD + GDB debug session. Running an application
compiled for Semihosting without the debugger will cause a panic and hang the chip.
As of now, only ARM has support for Semihosting.
Running Semihosting on the Development Host
-------------------------------------------
Start OpenOCD normally from inside a directory that you can read and write files within (i.e. do not run from
``C:\\Program Files\\..`` on Windows where general users aren't allowed to write). The starting
directory will be where the Pico will read and write files using the ``SemiFS`` class.
Be sure to keep the terminal window you ran OpenOCD in open, because all ``SerialSemi`` input and output
will go to **that** terminal and not ``gdb``'s.
Start GDB normally and connect to the OpenOCD debugger and enable semihosting support
.. code::
(gdb) target extended-remote localhost:3333
(gdb) monitor arm semihosting enable
At this point load and run your ``ELF`` application as normal. Again, all ``SerialSemi`` output will go
to the **OpenOCD** window, not GDB.
See the ``hellosemi`` example in the ``Semihosting`` library.
SerialSemi - Serial over Semihosting
------------------------------------
Simply include ``<Semihosting.h>`` in your application and use ``SerialSemi`` as you would any other
``Serial`` port with the following limitations:
* Baud rate, bit width, etc. are all ignored
* Input is limited because ``read`` may hang indefinitely in the host and ``available`` is not part of the spec
``SerialSemi`` can also be selected as the debug output port in the IDE, in which case ``::printf`` will write
to the debugger directly.
SemiFS - Host filesystem access through Semihosting
---------------------------------------------------
Use ``SemiFS`` the same way as any other file system. Note that only file creation and renaming are supported, with
no provision for iterating over directories or listing files. In most cases simply opening a ``File`` and writing out
a debug dump is all that's needed:
.. code::
SemiFS.begin();
File f = SemiFS.open("debug.dmp", "w");
f.write(buffer, size);
f.close();
SerialSemi.printf("Debug dump now available on host.\n");

View file

@ -28,19 +28,6 @@ pin itself, as is the standard way in Arduino.
* The interrupt calls (``attachInterrupt``, and ``detachInterrpt``) are not implemented. * The interrupt calls (``attachInterrupt``, and ``detachInterrpt``) are not implemented.
Software SPI (Master Only)
==========================
Similar to ``SoftwareSerial``, ``SoftwareSPI`` creates a PIO based SPI interface that
can be used in the same manner as the hardware SPI devices. The constructor takes the
pins desired, which can be any GPIO pins with the rule that if hardware CS is used then
it must be on pin ``SCK + 1``. Construct a ``SoftwareSPI`` object in your code as
follows and use it as needed (i.e. pass it into ``SD.begin(_CS, softwareSPI);``
.. code:: cpp
#include <SoftwareSPI.h>
SoftwareSPI softSPI(_sck, _miso, _mosi); // no HW CS support, any selection of pins can be used
SPI Slave (SPISlave) SPI Slave (SPISlave)
==================== ====================

View file

@ -44,7 +44,7 @@ Please note that WiFi on the Pico W is a work-in-progress and there are some imp
* FreeRTOS is supported only on core 0 and from within ``setup`` and ``loop``, not tasks, due to the requirement for a very different LWIP implementation. PRs always appreciated! * FreeRTOS is supported only on core 0 and from within ``setup`` and ``loop``, not tasks, due to the requirement for a very different LWIP implementation. PRs always appreciated!
* LEAmDNS (``MDNS``) is not supported in FreeRTOS due to internal IRQ-time memory allocations. Instead, use the SimpleMDNS library ( ``#include <SimpleMDNS.h>`` ) which has no such allocations. * LEAmDNS (``MDNS``) is not supported in FreeRTOS due to internal IRQ-time memory allocations.
The WiFi library borrows much work from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`__ , especially the ``WiFiClient`` and ``WiFiServer`` classes. The WiFi library borrows much work from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`__ , especially the ``WiFiClient`` and ``WiFiServer`` classes.

View file

@ -1,2 +1,2 @@
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile // Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
#define BEARSSL_GIT aca1383 #define BEARSSL_GIT c2c9d9d

View file

@ -21,56 +21,50 @@ extern unsigned long __lwip_rand(void);
// Common settings used in most of the pico_w examples // Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
#define NO_SYS 1 #define NO_SYS 1
#define LWIP_SOCKET 0 #define LWIP_SOCKET 0
#define MEM_LIBC_MALLOC 0 #define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4 #define MEM_ALIGNMENT 4
#define MEM_SIZE (__LWIP_MEMMULT * 16384) #define MEM_SIZE (__LWIP_MEMMULT * 16384)
#define MEMP_NUM_TCP_SEG (32) #define MEMP_NUM_TCP_SEG (32)
#define MEMP_NUM_ARP_QUEUE (10) #define MEMP_NUM_ARP_QUEUE (10)
#define PBUF_POOL_SIZE (__LWIP_MEMMULT > 1 ? 32 : 24) #define PBUF_POOL_SIZE (__LWIP_MEMMULT > 1 ? 32 : 24)
#define LWIP_ARP 7 #define LWIP_ARP 2
#define LWIP_ETHERNET 1 #define LWIP_ETHERNET 1
#define LWIP_ICMP 1 #define LWIP_ICMP 1
#define LWIP_RAW 1 #define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS) #define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460 #define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS) #define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1 #define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1 #define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1 #define LWIP_NETIF_HOSTNAME 1
#define LWIP_NUM_NETIF_CLIENT_DATA 5 #define LWIP_NETCONN 0
#define LWIP_NETCONN 0 #define LWIP_STATS 0
#define LWIP_STATS 0 #define LWIP_STATS_DISPLAY 0
#define LWIP_STATS_DISPLAY 0 #define MEM_STATS 0
#define MEM_STATS 0 #define SYS_STATS 0
#define SYS_STATS 0 #define MEMP_STATS 0
#define MEMP_STATS 0 #define LINK_STATS 0
#define LINK_STATS 0 #define LWIP_CHKSUM_ALGORITHM 0
#define LWIP_CHKSUM_ALGORITHM 0 #define LWIP_DHCP 1
#define LWIP_DHCP 1 #define LWIP_IPV4 1
#define LWIP_IPV4 1 #define LWIP_TCP 1
#define LWIP_TCP 1 #define LWIP_UDP 1
#define LWIP_UDP 1 #define LWIP_DNS 1
#define LWIP_DNS 1 #define LWIP_TCP_KEEPALIVE 1
#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 #define LWIP_NETIF_TX_SINGLE_PBUF 1
#define LWIP_TCP_KEEPALIVE 1 #define DHCP_DOES_ARP_CHECK 0
#define LWIP_NETIF_TX_SINGLE_PBUF 1 #define LWIP_DHCP_DOES_ACD_CHECK 0
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#define LWIP_IGMP 1
#define LWIP_MDNS_RESPONDER 1
#define MDNS_MAX_SERVICES 4
// See #1285 // See #1285
#define MEMP_NUM_UDP_PCB (__LWIP_MEMMULT * 7) #define MEMP_NUM_UDP_PCB (__LWIP_MEMMULT * 6)
#define MEMP_NUM_TCP_PCB (__LWIP_MEMMULT * 5) #define MEMP_NUM_TCP_PCB (__LWIP_MEMMULT * 5)
#if LWIP_IPV6 #if LWIP_IPV6
#define LWIP_IPV6_DHCP6 1 #define LWIP_IPV6_DHCP6 1
#define LWIP_IPV6_MLD 1
#endif #endif
// NTP // NTP

View file

@ -12,8 +12,8 @@
#define _PICO_VERSION_H #define _PICO_VERSION_H
#define PICO_SDK_VERSION_MAJOR 2 #define PICO_SDK_VERSION_MAJOR 2
#define PICO_SDK_VERSION_MINOR 1 #define PICO_SDK_VERSION_MINOR 0
#define PICO_SDK_VERSION_REVISION 2 #define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "2.1.2-develop" #define PICO_SDK_VERSION_STRING "2.0.0"
#endif #endif

View file

@ -12,8 +12,8 @@
#define _PICO_VERSION_H #define _PICO_VERSION_H
#define PICO_SDK_VERSION_MAJOR 2 #define PICO_SDK_VERSION_MAJOR 2
#define PICO_SDK_VERSION_MINOR 1 #define PICO_SDK_VERSION_MINOR 0
#define PICO_SDK_VERSION_REVISION 2 #define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "2.1.2-develop" #define PICO_SDK_VERSION_STRING "2.0.0"
#endif #endif

View file

@ -14,7 +14,6 @@ File KEYWORD1
timeval KEYWORD1 timeval KEYWORD1
time_t KEYWORD1 time_t KEYWORD1
SoftwareSerial KEYWORD1 SoftwareSerial KEYWORD1
AudioOutputBase KEYWORD1
####################################### #######################################
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
@ -66,9 +65,6 @@ getUsedPSRAMHeap KEYWORD2
getTotalPSRAMHeap KEYWORD2 getTotalPSRAMHeap KEYWORD2
getTotalPSRAM KEYWORD2 getTotalPSRAM KEYWORD2
getProfileMemoryUsage KEYWORD2
writeProfiling KEYWORD2
getChipID KEYWORD2 getChipID KEYWORD2
hwrand32 KEYWORD2 hwrand32 KEYWORD2
@ -87,9 +83,6 @@ digitalReadFast KEYWORD2
enableDoubleResetBootloader KEYWORD2 enableDoubleResetBootloader KEYWORD2
SerialSemi KEYWORD2
SemiFS KEYWORD2
openDir KEYWORD2 openDir KEYWORD2
next KEYWORD2 next KEYWORD2
getLastWrite KEYWORD2 getLastWrite KEYWORD2

View file

@ -15,7 +15,6 @@
-iwithprefixbefore/pico-sdk/src/common/pico_util/include -iwithprefixbefore/pico-sdk/src/common/pico_util/include
-iwithprefixbefore/pico-sdk/src/common/pico_stdlib_headers/include -iwithprefixbefore/pico-sdk/src/common/pico_stdlib_headers/include
-iwithprefixbefore/pico-sdk/src/common/pico_usb_reset_interface_headers/include -iwithprefixbefore/pico-sdk/src/common/pico_usb_reset_interface_headers/include
-iwithprefixbefore/pico-sdk/src/rp2_common/boot_bootrom_headers/include
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/include -iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/include
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include -iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_adc/include -iwithprefixbefore/pico-sdk/src/rp2_common/hardware_adc/include
@ -43,18 +42,15 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_vreg/include -iwithprefixbefore/pico-sdk/src/rp2_common/hardware_vreg/include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_watchdog/include -iwithprefixbefore/pico-sdk/src/rp2_common/hardware_watchdog/include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_xosc/include -iwithprefixbefore/pico-sdk/src/rp2_common/hardware_xosc/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_aon_timer/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_async_context/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_async_context/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_bootrom/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_bootrom/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_double/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_double/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_flash/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_float/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_float/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_int64_ops/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_int64_ops/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_lwip/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_lwip/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_multicore/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_multicore/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_common/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_compiler/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_compiler/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_sections/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_sections/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_panic/include -iwithprefixbefore/pico-sdk/src/rp2_common/pico_platform_panic/include

View file

@ -67,5 +67,3 @@
-Wl,--wrap=cyw43_tcpip_link_status -Wl,--wrap=cyw43_tcpip_link_status
-Wl,--wrap=cyw43_cb_tcpip_init -Wl,--wrap=cyw43_cb_tcpip_init
-Wl,--wrap=cyw43_cb_tcpip_deinit -Wl,--wrap=cyw43_cb_tcpip_deinit
-Wl,--wrap=__stack_chk_fail

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,6 +1,5 @@
-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
-DCYW43_LWIP=1 -DCYW43_LWIP=1
-DCYW43_PIO_CLOCK_DIV_DYNAMIC=1
-DCFG_TUSB_MCU=OPT_MCU_RP2040 -DCFG_TUSB_MCU=OPT_MCU_RP2040
-DARM_MATH_CM0_FAMILY -DARM_MATH_CM0_FAMILY
-DARM_MATH_CM0_PLUS -DARM_MATH_CM0_PLUS

View file

@ -10,6 +10,5 @@
-iwithprefixbefore/pico-sdk/lib/btstack/src -iwithprefixbefore/pico-sdk/lib/btstack/src
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include -iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include -iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/yxml
-iwithprefixbefore/pico-sdk/lib/btstack/platform/embedded -iwithprefixbefore/pico-sdk/lib/btstack/platform/embedded
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include -iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more