Compare commits
@@ -17,7 +17,7 @@ jobs:
|
||||
with:
|
||||
submodules: false
|
||||
- name: Run codespell
|
||||
uses: codespell-project/actions-codespell@master
|
||||
uses: codespell-project/actions-codespell@v2
|
||||
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
|
||||
ignore_words_list: ser,dout,shiftIn,acount
|
||||
@@ -101,6 +101,37 @@ jobs:
|
||||
cd ..
|
||||
bash ./tests/build-rp2350.sh
|
||||
|
||||
# Build all rp2350-riscv examples on linux (core and Arduino IDE)
|
||||
build-rp2350-riscv-linux:
|
||||
name: Build RP2350-RISCV ${{ matrix.chunk }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketches
|
||||
env:
|
||||
BUILD_PARITY: custom
|
||||
mod: 6
|
||||
rem: ${{ matrix.chunk }}
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build-rp2350-riscv.sh
|
||||
|
||||
# Build TinyUSB examples, requires custom build command line
|
||||
build-tinyusb:
|
||||
name: Build TinyUSB Examples
|
||||
@@ -234,10 +265,13 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg update --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg install --global --tool symlink://.
|
||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||
- name: Build Multicore Example
|
||||
run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
- name: Build Multicore Example (RISC-V)
|
||||
run: pio ci -v --board=rpipico2 -O "board_build.mcu = rp2350-riscv" -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
- name: Build Fade Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
||||
- name: Build TinyUSB Example
|
||||
@@ -288,6 +322,7 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg update --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg install --global --tool symlink://.
|
||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||
- name: Build Every Variant
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
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 12.3/Newlib 4.0 toolchain.
|
||||
This is a port of Arduino to the RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2 processor). It uses the bare Raspberry Pi Pico SDK and a custom GCC 14.2/Newlib 4.3 toolchain and supports ARM and RISC-V cores.
|
||||
|
||||
# Documentation
|
||||
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
||||
@@ -30,6 +30,8 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
* Amken Revelop
|
||||
* Amken Revelop Plus
|
||||
* Amken Revelop eS
|
||||
* Architeuthis Flux Jumperless
|
||||
* Architeuthis Flux Jumperless V5
|
||||
* Arduino Nano RP2040 Connect
|
||||
* ArtronShop RP2 Nano
|
||||
* Breadstick Raspberry
|
||||
@@ -80,6 +82,7 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
* Sea-Picro
|
||||
* Seeed Indicator RP2040
|
||||
* Seeed XIAO RP2040
|
||||
* Seeed XIAO RP2350
|
||||
* Silicognition RP2040-Shim
|
||||
* Solder Party RP2040 Stamp
|
||||
* Solder Party RP2350 Stamp
|
||||
@@ -126,6 +129,7 @@ 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
|
||||
* printf (i.e. debug) output over USB serial
|
||||
* Transparent use of PSRAM globals and heap (RP2350 only)
|
||||
* ARM or RISC-V (Hazard3) support for the RP2350
|
||||
|
||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||
* Servos
|
||||
|
||||
+1489
-74
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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
|
||||
@@ -0,0 +1,4 @@
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
@@ -37,7 +37,7 @@
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif // abs
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) && !defined(__riscv)
|
||||
using std::abs;
|
||||
using std::round;
|
||||
#else
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
#include <hardware/irq.h>
|
||||
#include <hardware/pio.h>
|
||||
#include <pico/unique_id.h>
|
||||
#ifdef PICO_RP2350
|
||||
#include <hardware/regs/powman.h>
|
||||
#else
|
||||
#include <hardware/regs/vreg_and_chip_reset.h>
|
||||
#endif
|
||||
#include <hardware/exception.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <hardware/structs/rosc.h>
|
||||
@@ -175,18 +180,22 @@ public:
|
||||
|
||||
void begin() {
|
||||
_epoch = 0;
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
// Enable SYSTICK exception
|
||||
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
|
||||
systick_hw->csr = 0x7;
|
||||
systick_hw->rvr = 0x00FFFFFF;
|
||||
} else {
|
||||
#endif
|
||||
int off = 0;
|
||||
_ccountPgm = new PIOProgram(&ccount_program);
|
||||
_ccountPgm->prepare(&_pio, &_sm, &off);
|
||||
ccount_program_init(_pio, _sm, off);
|
||||
pio_sm_set_enabled(_pio, _sm, true);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert from microseconds to PIO clock cycles
|
||||
@@ -208,6 +217,7 @@ public:
|
||||
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
|
||||
volatile uint64_t _epoch = 0;
|
||||
inline uint32_t getCycleCount() {
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
uint32_t epoch;
|
||||
uint32_t ctr;
|
||||
@@ -217,11 +227,15 @@ public:
|
||||
} while (epoch != (uint32_t)_epoch);
|
||||
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
|
||||
} else {
|
||||
#endif
|
||||
return ccount_read(_pio, _sm);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64_t getCycleCount64() {
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
uint64_t epoch;
|
||||
uint64_t ctr;
|
||||
@@ -231,8 +245,11 @@ public:
|
||||
} while (epoch != _epoch);
|
||||
return epoch + (1LL << 24) - ctr;
|
||||
} else {
|
||||
#endif
|
||||
return ccount_read(_pio, _sm);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getFreeHeap() {
|
||||
@@ -272,7 +289,11 @@ public:
|
||||
|
||||
inline uint32_t getStackPointer() {
|
||||
uint32_t *sp;
|
||||
#if defined(__riscv)
|
||||
asm volatile("mv %0, sp" : "=r"(sp));
|
||||
#else
|
||||
asm volatile("mov %0, sp" : "=r"(sp));
|
||||
#endif
|
||||
return (uint32_t)sp;
|
||||
}
|
||||
|
||||
@@ -340,6 +361,61 @@ public:
|
||||
watchdog_update();
|
||||
}
|
||||
|
||||
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_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;
|
||||
}
|
||||
|
||||
const char *getChipID() {
|
||||
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||
if (!id[0]) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 4
|
||||
#define ARDUINO_PICO_MINOR 0
|
||||
#define ARDUINO_PICO_REVISION 3
|
||||
#define ARDUINO_PICO_VERSION_STR "4.0.3"
|
||||
#define ARDUINO_PICO_MINOR 2
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "4.2.0"
|
||||
|
||||
@@ -100,6 +100,8 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
}
|
||||
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, 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);
|
||||
|
||||
_toneMap.insert({pin, newTone});
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef struct {
|
||||
static FMMap *_map = nullptr;
|
||||
SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
||||
if (!_map) {
|
||||
_map = (FMMap *)calloc(sizeof(FMMap), 16);
|
||||
_map = (FMMap *)calloc(16, sizeof(FMMap));
|
||||
}
|
||||
// Pre-existing map
|
||||
for (int i = 0; i < 16; i++) {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Flash wrappers to protect PSRAM access on the RP2350
|
||||
|
||||
Copyright (c) 2024 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <hardware/flash.h>
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#include <hardware/structs/qmi.h>
|
||||
#endif
|
||||
|
||||
#if defined(PICO_RP2350) && defined(RP2350_PSRAM_CS)
|
||||
static void __no_inline_not_in_flash_func(flushcache)() {
|
||||
// From https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
|
||||
// Perform clean-by-set/way on all lines
|
||||
for (uint32_t i = 0; i < 2048; ++i) {
|
||||
// Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff):
|
||||
*(volatile uint8_t*)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE) + i * 8u + 0x1u) = 0;
|
||||
}
|
||||
}
|
||||
#elif defined(PICO_RP2350)
|
||||
static void __no_inline_not_in_flash_func(flushcache)() {
|
||||
// Null
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" {
|
||||
extern void __real_flash_range_erase(uint32_t flash_offs, size_t count);
|
||||
void __wrap_flash_range_erase(uint32_t flash_offs, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_range_erase(flash_offs, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_range_program(uint32_t flash_offs, const uint8_t *data, size_t count);
|
||||
void __wrap_flash_range_program(uint32_t flash_offs, const uint8_t *data, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_range_program(flash_offs, data, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_get_unique_id(uint8_t *id_out);
|
||||
void __wrap_flash_get_unique_id(uint8_t *id_out) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_get_unique_id(id_out);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count);
|
||||
void __wrap_flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_do_cmd(txbuf, rxbuf, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -99,7 +99,7 @@ static SemaphoreHandle_t __getFreeRTOSRecursiveMutex(_LOCK_T lock) {
|
||||
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) {
|
||||
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)) {
|
||||
@@ -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) {
|
||||
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)) {
|
||||
|
||||
@@ -88,7 +88,7 @@ extern "C" int main() {
|
||||
|
||||
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
|
||||
if (!__isFreeRTOS && (setup1 || loop1)) {
|
||||
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
|
||||
_impure_ptr1 = (struct _reent*)calloc(1, sizeof(struct _reent));
|
||||
_REENT_INIT_PTR(_impure_ptr1);
|
||||
}
|
||||
|
||||
@@ -134,7 +134,6 @@ extern "C" int main() {
|
||||
}
|
||||
rp2040.fifo.registerCore();
|
||||
}
|
||||
|
||||
if (!__isFreeRTOS) {
|
||||
if (setup1 || loop1) {
|
||||
delay(1); // Needed to make Picoprobe upload start 2nd core
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* 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
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -1,926 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -1,524 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
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
|
||||
@@ -23,8 +23,8 @@
|
||||
.program tone2
|
||||
.side_set 1 opt
|
||||
|
||||
pull ; TXFIFO -> OSR, or X -> OSR if no new period
|
||||
mov x, osr ; OSR -> X
|
||||
; pull ; TXFIFO -> OSR, or X -> OSR if no new period
|
||||
; mov x, osr ; OSR -> X
|
||||
|
||||
high:
|
||||
pull noblock ; Potentially grab new HALFCYCLECOUNT, OTW copy from backup in X
|
||||
|
||||
@@ -13,27 +13,25 @@
|
||||
// ----- //
|
||||
|
||||
#define tone2_wrap_target 0
|
||||
#define tone2_wrap 8
|
||||
#define tone2_wrap 6
|
||||
#define tone2_pio_version 0
|
||||
|
||||
static const uint16_t tone2_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0x80a0, // 0: pull block
|
||||
0x8080, // 0: pull noblock
|
||||
0xa027, // 1: mov x, osr
|
||||
0x8080, // 2: pull noblock
|
||||
0xa027, // 3: mov x, osr
|
||||
0xb847, // 4: mov y, osr side 1
|
||||
0xb847, // 2: mov y, osr side 1
|
||||
0x0083, // 3: jmp y--, 3
|
||||
0xb047, // 4: mov y, osr side 0
|
||||
0x0085, // 5: jmp y--, 5
|
||||
0xb047, // 6: mov y, osr side 0
|
||||
0x0087, // 7: jmp y--, 7
|
||||
0x0002, // 8: jmp 2
|
||||
0x0000, // 6: jmp 0
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tone2_program = {
|
||||
.instructions = tone2_program_instructions,
|
||||
.length = 9,
|
||||
.length = 7,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
|
||||
@@ -87,15 +87,22 @@ static std::map<pin_size_t, CBInfo> _map;
|
||||
|
||||
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
|
||||
(void) events;
|
||||
|
||||
// Only need to lock around the std::map check, not the whole IRQ callback
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
auto cb = irq->second;
|
||||
cb.callback();
|
||||
CBInfo *cb;
|
||||
{
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq == _map.end()) {
|
||||
return;
|
||||
}
|
||||
cb = &irq->second;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
cb->callback();
|
||||
}
|
||||
|
||||
// To be called when appropriately protected w/IRQ and mutex protects
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'4.0.3'
|
||||
version = u'4.2.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'4.0.3'
|
||||
release = u'4.2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+1
-1
@@ -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
|
||||
program the Raspberry Pi Pico / RP2040 / RP2350 based boards.
|
||||
|
||||
This Arduino core uses a custom toolset with GCC 12.3 and Newlib 4.0.0
|
||||
This Arduino core uses a custom toolset with GCC 14.2 and Newlib 4.3
|
||||
and doesn't require any system-installed prerequisites.
|
||||
|
||||
For the latest version, always check https://github.com/earlephilhower/arduino-pico
|
||||
|
||||
@@ -156,6 +156,22 @@ platform <https://github.com/maxgerhardt/platform-raspberrypi/blob/77e0d3a29d1db
|
||||
; Flash Size: 2MB (Sketch: 0.5MB, FS:1.5MB)
|
||||
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
|
||||
|
||||
CPU Speed
|
||||
---------
|
||||
|
||||
@@ -262,6 +278,18 @@ default Pico SDK USB stack. To change it, add
|
||||
Note that the special "No USB" setting is also supported, through the
|
||||
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
|
||||
--------
|
||||
|
||||
@@ -309,6 +337,19 @@ 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
|
||||
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
|
||||
--------
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ The following example will **NOT** work:
|
||||
Using PSRAM for dynamic allocations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
PSRAM can also be used as a heap for dynamica allocations using ``pmalloc`` and
|
||||
PSRAM can also be used as a heap for dynamic allocations using ``pmalloc`` and
|
||||
``pcalloc``. These calls function exactly like normal ``malloc`` and ``calloc``
|
||||
except they allocate space from PSRAM.
|
||||
|
||||
|
||||
@@ -57,6 +57,11 @@ void rp2040.wdt_reset()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
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
|
||||
------------------
|
||||
|
||||
+8
-1
@@ -6,7 +6,14 @@ is supported by the core with some minor caveats:
|
||||
|
||||
* PSRAM is supported via a new ``pmalloc`` call and ``PSRAM`` variable decorator.
|
||||
* 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
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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")
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
|
||||
#define BEARSSL_GIT c2c9d9d
|
||||
#define BEARSSL_GIT 5b7f3d5
|
||||
|
||||
@@ -67,3 +67,8 @@
|
||||
-Wl,--wrap=cyw43_tcpip_link_status
|
||||
-Wl,--wrap=cyw43_cb_tcpip_init
|
||||
-Wl,--wrap=cyw43_cb_tcpip_deinit
|
||||
|
||||
-Wl,--wrap=flash_range_erase
|
||||
-Wl,--wrap=flash_range_program
|
||||
-Wl,--wrap=flash_get_unique_id
|
||||
-Wl,--wrap=flash_do_cmd
|
||||
|
||||
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,336 @@
|
||||
/* Based on GCC ARM embedded samples.
|
||||
Defines the following symbols for use by code:
|
||||
__exidx_start
|
||||
__exidx_end
|
||||
__etext
|
||||
__data_start__
|
||||
__preinit_array_start
|
||||
__preinit_array_end
|
||||
__init_array_start
|
||||
__init_array_end
|
||||
__fini_array_start
|
||||
__fini_array_end
|
||||
__data_end__
|
||||
__bss_start__
|
||||
__bss_end__
|
||||
__end__
|
||||
end
|
||||
__HeapLimit
|
||||
__StackLimit
|
||||
__StackTop
|
||||
__stack (== StackTop)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = __FLASH_LENGTH__
|
||||
PSRAM(rwx) : ORIGIN = 0x11000000, LENGTH = __PSRAM_LENGTH__
|
||||
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = __RAM_LENGTH__
|
||||
SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
|
||||
SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
|
||||
}
|
||||
|
||||
PROVIDE ( _EEPROM_start = __EEPROM_START__ );
|
||||
PROVIDE ( _FS_start = __FS_START__ );
|
||||
PROVIDE ( _FS_end = __FS_END__ );
|
||||
|
||||
ENTRY(_entry_point)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.flash_begin : {
|
||||
__flash_binary_start = .;
|
||||
} > FLASH
|
||||
|
||||
.ota : {
|
||||
/* Start image with OTA */
|
||||
KEEP (*(.OTA))
|
||||
*ota.o
|
||||
} > FLASH
|
||||
|
||||
.partition : {
|
||||
. = __flash_binary_start + 0x2ff0;
|
||||
LONG(__FS_START__)
|
||||
LONG(__FS_END__)
|
||||
LONG(__EEPROM_START__)
|
||||
LONG(__FLASH_LENGTH__)
|
||||
} > FLASH
|
||||
|
||||
/* The bootrom will enter the image at the point indicated in your
|
||||
IMAGE_DEF, which is usually the reset handler of your vector table.
|
||||
|
||||
The debugger will use the ELF entry point, which is the _entry_point
|
||||
symbol, and in our case is *different from the bootrom's entry point.*
|
||||
This is used to go back through the bootrom on debugger launches only,
|
||||
to perform the same initial flash setup that would be performed on a
|
||||
cold boot.
|
||||
*/
|
||||
|
||||
.text : {
|
||||
KEEP (*(.vectors))
|
||||
__logical_binary_start = .;
|
||||
KEEP (*(.binary_info_header))
|
||||
__binary_info_header_end = .;
|
||||
KEEP (*(.embedded_block))
|
||||
__embedded_block_end = .;
|
||||
KEEP (*(.reset))
|
||||
/* TODO revisit this now memset/memcpy/float in ROM */
|
||||
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
|
||||
* FLASH ... we will include any thing excluded here in .data below by default */
|
||||
*(.init)
|
||||
*libgcc.a:cmse_nonsecure_call.o
|
||||
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
|
||||
*(.fini)
|
||||
/* Pull all c'tors into .text */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
/* Followed by destructors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(SORT(.preinit_array.*)))
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
*(SORT(.fini_array.*))
|
||||
*(.fini_array)
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
*(.eh_frame*)
|
||||
. = ALIGN(4);
|
||||
} > FLASH
|
||||
|
||||
/* Note the boot2 section is optional, and should be discarded if there is
|
||||
no reference to it *inside* the binary, as it is not called by the
|
||||
bootrom. (The bootrom performs a simple best-effort XIP setup and
|
||||
leaves it to the binary to do anything more sophisticated.) However
|
||||
there is still a size limit of 256 bytes, to ensure the boot2 can be
|
||||
stored in boot RAM.
|
||||
|
||||
Really this is a "XIP setup function" -- the name boot2 is historic and
|
||||
refers to its dual-purpose on RP2040, where it also handled vectoring
|
||||
from the bootrom into the user image.
|
||||
*/
|
||||
/*
|
||||
.boot2 : {
|
||||
__boot2_start__ = .;
|
||||
*(.boot2)
|
||||
__boot2_end__ = .;
|
||||
} > FLASH
|
||||
|
||||
ASSERT(__boot2_end__ - __boot2_start__ <= 256,
|
||||
"ERROR: Pico second stage bootloader must be no more than 256 bytes in size")
|
||||
*/
|
||||
.rodata : {
|
||||
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
|
||||
*(.srodata*)
|
||||
. = ALIGN(4);
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
|
||||
. = ALIGN(4);
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* Machine inspectable binary information */
|
||||
. = ALIGN(4);
|
||||
__binary_info_start = .;
|
||||
.binary_info :
|
||||
{
|
||||
KEEP(*(.binary_info.keep.*))
|
||||
*(.binary_info.*)
|
||||
} > FLASH
|
||||
__binary_info_end = .;
|
||||
. = ALIGN(4);
|
||||
|
||||
.ram_vector_table (NOLOAD): {
|
||||
*(.ram_vector_table)
|
||||
} > RAM
|
||||
|
||||
.uninitialized_data (NOLOAD): {
|
||||
. = ALIGN(4);
|
||||
*(.uninitialized_data*)
|
||||
} > RAM
|
||||
|
||||
.data : {
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
|
||||
*(.time_critical*)
|
||||
|
||||
/* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
|
||||
*(.text*)
|
||||
. = ALIGN(4);
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
|
||||
. = ALIGN(4);
|
||||
*(.after_data.*)
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__mutex_array_start = .);
|
||||
KEEP(*(SORT(.mutex_array.*)))
|
||||
KEEP(*(.mutex_array))
|
||||
PROVIDE_HIDDEN (__mutex_array_end = .);
|
||||
|
||||
*(.jcr)
|
||||
. = ALIGN(4);
|
||||
} > RAM AT> FLASH
|
||||
|
||||
.tdata : {
|
||||
. = ALIGN(4);
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
/* All data end */
|
||||
__tdata_end = .;
|
||||
} > RAM AT> FLASH
|
||||
PROVIDE(__data_end__ = .);
|
||||
|
||||
/* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
|
||||
__etext = LOADADDR(.data);
|
||||
|
||||
.tbss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
__tls_base = .;
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon)
|
||||
|
||||
__tls_end = .;
|
||||
} > RAM
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
__tbss_end = .;
|
||||
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
|
||||
*(COMMON)
|
||||
PROVIDE(__global_pointer$ = . + 2K);
|
||||
*(.sbss*)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (NOLOAD):
|
||||
{
|
||||
__end__ = .;
|
||||
end = __end__;
|
||||
KEEP(*(.heap*))
|
||||
/* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however
|
||||
to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */
|
||||
. = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* Start and end symbols must be word-aligned */
|
||||
.scratch_x : {
|
||||
__scratch_x_start__ = .;
|
||||
*(.scratch_x.*)
|
||||
. = ALIGN(4);
|
||||
__scratch_x_end__ = .;
|
||||
} > SCRATCH_X AT > FLASH
|
||||
__scratch_x_source__ = LOADADDR(.scratch_x);
|
||||
|
||||
.scratch_y : {
|
||||
__scratch_y_start__ = .;
|
||||
*(.scratch_y.*)
|
||||
. = ALIGN(4);
|
||||
__scratch_y_end__ = .;
|
||||
} > SCRATCH_Y AT > FLASH
|
||||
__scratch_y_source__ = LOADADDR(.scratch_y);
|
||||
|
||||
/* .stack*_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later
|
||||
*
|
||||
* stack1 section may be empty/missing if platform_launch_core1 is not used */
|
||||
|
||||
/* by default we put core 0 stack at the end of scratch Y, so that if core 1
|
||||
* stack is not used then all of SCRATCH_X is free.
|
||||
*/
|
||||
.stack1_dummy (NOLOAD):
|
||||
{
|
||||
*(.stack1*)
|
||||
} > SCRATCH_X
|
||||
.stack_dummy (NOLOAD):
|
||||
{
|
||||
KEEP(*(.stack*))
|
||||
} > SCRATCH_Y
|
||||
|
||||
.flash_end : {
|
||||
KEEP(*(.embedded_end_block*))
|
||||
PROVIDE(__flash_binary_end = .);
|
||||
} > FLASH = 0xaa
|
||||
|
||||
.psram (NOLOAD) : {
|
||||
__psram_start__ = .;
|
||||
*(.psram*)
|
||||
. = ALIGN(4096);
|
||||
__psram_heap_start__ = .;
|
||||
} > PSRAM
|
||||
|
||||
/* stack limit is poorly named, but historically is maximum heap ptr */
|
||||
__StackLimit = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
|
||||
__StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
|
||||
__StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
|
||||
__StackBottom = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/* picolibc and LLVM */
|
||||
PROVIDE (__heap_start = __end__);
|
||||
PROVIDE (__heap_end = __HeapLimit);
|
||||
PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
|
||||
PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1));
|
||||
PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
|
||||
|
||||
/* TLSF */
|
||||
PROVIDE (__psram_start = __psram_start__);
|
||||
PROVIDE (__psram_heap_start = __psram_heap_start__);
|
||||
|
||||
/* llvm-libc */
|
||||
PROVIDE (_end = __end__);
|
||||
PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
|
||||
|
||||
ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary")
|
||||
ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary")
|
||||
|
||||
/* todo assert on extra code */
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
-DCFG_TUSB_MCU=OPT_MCU_RP2040
|
||||
-DCFG_TUSB_OS=OPT_OS_PICO
|
||||
-DLIB_BOOT_STAGE2_HEADERS=1
|
||||
-DLIB_PICO_ATOMIC=1
|
||||
-DLIB_PICO_BIT_OPS=1
|
||||
-DLIB_PICO_BIT_OPS_PICO=1
|
||||
-DLIB_PICO_CLIB_INTERFACE=1
|
||||
-DLIB_PICO_CRT0=1
|
||||
-DLIB_PICO_CXX_OPTIONS=1
|
||||
-DLIB_PICO_DIVIDER=1
|
||||
-DLIB_PICO_DIVIDER_COMPILER=1
|
||||
-DLIB_PICO_DOUBLE=1
|
||||
-DLIB_PICO_DOUBLE_PICO=1
|
||||
-DLIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1
|
||||
-DLIB_PICO_FLOAT=1
|
||||
-DLIB_PICO_FLOAT_PICO=1
|
||||
-DLIB_PICO_FLOAT_PICO_VFP=1
|
||||
-DLIB_PICO_INT64_OPS=1
|
||||
-DLIB_PICO_INT64_OPS_COMPILER=1
|
||||
-DLIB_PICO_MEM_OPS=1
|
||||
-DLIB_PICO_MEM_OPS_COMPILER=1
|
||||
-DLIB_PICO_NEWLIB_INTERFACE=1
|
||||
-DLIB_PICO_PLATFORM=1
|
||||
-DLIB_PICO_PLATFORM_COMPILER=1
|
||||
-DLIB_PICO_PLATFORM_PANIC=1
|
||||
-DLIB_PICO_PLATFORM_SECTIONS=1
|
||||
-DLIB_PICO_RUNTIME=1
|
||||
-DLIB_PICO_RUNTIME_INIT=1
|
||||
-DLIB_PICO_STANDARD_BINARY_INFO=1
|
||||
-DLIB_PICO_STANDARD_LINK=1
|
||||
-DLIB_PICO_SYNC=1
|
||||
-DLIB_PICO_SYNC_CRITICAL_SECTION=1
|
||||
-DLIB_PICO_SYNC_MUTEX=1
|
||||
-DLIB_PICO_SYNC_SEM=1
|
||||
-DLIB_PICO_TIME=1
|
||||
-DLIB_PICO_TIME_ADAPTER=1
|
||||
-DLIB_PICO_UNIQUE_ID=1
|
||||
-DLIB_PICO_UTIL=1
|
||||
-DLIB_TINYUSB_BOARD=1
|
||||
-DLIB_TINYUSB_DEVICE=1
|
||||
-DPICO_32BIT=1
|
||||
-DPICO_BOARD=\"solderparty_rp2350_stamp_xl\"
|
||||
-DPICO_BUILD=1
|
||||
-DPICO_COPY_TO_RAM=0
|
||||
-DPICO_CXX_ENABLE_EXCEPTIONS=0
|
||||
-DPICO_NO_FLASH=0
|
||||
-DPICO_NO_HARDWARE=0
|
||||
-DPICO_ON_DEVICE=1
|
||||
-DPICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1
|
||||
-DPICO_RP2040_USB_DEVICE_UFRAME_FIX=1
|
||||
-DPICO_RP2350=1
|
||||
-DPICO_RISCV=1
|
||||
-DPICO_USE_BLOCKED_RAM=0
|
||||
@@ -0,0 +1,10 @@
|
||||
-iwithprefixbefore/include/rp2350
|
||||
-iwithprefixbefore/include/rp2350/pico_base
|
||||
-iwithprefixbefore/pico-sdk/src/rp2350/hardware_regs/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2350/hardware_structs/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2350/pico_platform/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_riscv/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_riscv_platform_timer/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_hazard3/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_sha256/include
|
||||
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_sha256/include
|
||||
@@ -0,0 +1 @@
|
||||
-Wl,--wrap=__ctzdi2
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -133,7 +133,7 @@ SECTIONS
|
||||
refers to its dual-purpose on RP2040, where it also handled vectoring
|
||||
from the bootrom into the user image.
|
||||
*/
|
||||
|
||||
/*
|
||||
.boot2 : {
|
||||
__boot2_start__ = .;
|
||||
*(.boot2)
|
||||
@@ -142,7 +142,7 @@ SECTIONS
|
||||
|
||||
ASSERT(__boot2_end__ - __boot2_start__ <= 256,
|
||||
"ERROR: Pico second stage bootloader must be no more than 256 bytes in size")
|
||||
|
||||
*/
|
||||
.rodata : {
|
||||
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
|
||||
*(.srodata*)
|
||||
|
||||
Binary file not shown.
@@ -39,7 +39,7 @@
|
||||
-DLIB_TINYUSB_BOARD=1
|
||||
-DLIB_TINYUSB_DEVICE=1
|
||||
-DPICO_32BIT=1
|
||||
-DPICO_BOARD=\"pico2\"
|
||||
-DPICO_BOARD=\"solderparty_rp2350_stamp_xl\"
|
||||
-DPICO_BUILD=1
|
||||
-DPICO_COPY_TO_RAM=0
|
||||
-DPICO_CXX_ENABLE_EXCEPTIONS=0
|
||||
|
||||
@@ -97,3 +97,5 @@
|
||||
-Wl,--wrap=tanhf
|
||||
-Wl,--wrap=trunc
|
||||
-Wl,--wrap=truncf
|
||||
|
||||
-Wl,--wrap=memcpy
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
#include "ADCInput.h"
|
||||
#include <hardware/adc.h>
|
||||
|
||||
ADCInput::ADCInput(pin_size_t p0, pin_size_t p1, pin_size_t p2, pin_size_t p3) {
|
||||
ADCInput::ADCInput(pin_size_t p0, pin_size_t p1, pin_size_t p2, pin_size_t p3, pin_size_t p4, pin_size_t p5, pin_size_t p6, pin_size_t p7) {
|
||||
_running = false;
|
||||
setPins(p0, p1, p2, p3);
|
||||
setPins(p0, p1, p2, p3, p4, p5, p6, p7);
|
||||
_freq = 48000;
|
||||
_arb = nullptr;
|
||||
_cb = nullptr;
|
||||
@@ -49,19 +49,30 @@ bool ADCInput::setBuffers(size_t buffers, size_t bufferWords) {
|
||||
|
||||
int ADCInput::_mask(pin_size_t p) {
|
||||
switch (p) {
|
||||
#if !defined(PICO_RP2350B)
|
||||
case 26: return 1;
|
||||
case 27: return 2;
|
||||
case 28: return 4;
|
||||
case 29: return 8;
|
||||
#else // Starts at 40 and there are 8 of them
|
||||
case 40: return 1;
|
||||
case 41: return 2;
|
||||
case 42: return 4;
|
||||
case 43: return 8;
|
||||
case 44: return 16;
|
||||
case 45: return 32;
|
||||
case 46: return 64;
|
||||
case 47: return 128;
|
||||
#endif
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ADCInput::setPins(pin_size_t pin0, pin_size_t pin1, pin_size_t pin2, pin_size_t pin3) {
|
||||
bool ADCInput::setPins(pin_size_t pin0, pin_size_t pin1, pin_size_t pin2, pin_size_t pin3, pin_size_t pin4, pin_size_t pin5, pin_size_t pin6, pin_size_t pin7) {
|
||||
if (_running) {
|
||||
return false;
|
||||
}
|
||||
_pinMask = _mask(pin0) | _mask(pin1) | _mask(pin2) | _mask(pin3);
|
||||
_pinMask = _mask(pin0) | _mask(pin1) | _mask(pin2) | _mask(pin3) | _mask(pin4) | _mask(pin5) | _mask(pin6) | _mask(pin7);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -94,10 +105,17 @@ bool ADCInput::begin() {
|
||||
// Set up the GPIOs to go to ADC
|
||||
adc_init();
|
||||
int cnt = 0;
|
||||
for (int mask = 1, pin = 26; pin <= 29; mask <<= 1, pin++) {
|
||||
#if !defined(PICO_RP2350B)
|
||||
int startpin = 26;
|
||||
int maxpin = 29;
|
||||
#else
|
||||
int startpin = 40;
|
||||
int maxpin = 47;
|
||||
#endif
|
||||
for (int mask = 1, pin = startpin; pin <= maxpin; mask <<= 1, pin++) {
|
||||
if (_pinMask & mask) {
|
||||
if (!cnt) {
|
||||
adc_select_input(pin - 26);
|
||||
adc_select_input(pin - startpin);
|
||||
}
|
||||
cnt++;
|
||||
adc_gpio_init(pin);
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
|
||||
class ADCInput : public Stream {
|
||||
public:
|
||||
ADCInput(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255);
|
||||
ADCInput(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255, pin_size_t pin4 = 255, pin_size_t pin5 = 255, pin_size_t pin6 = 255, pin_size_t pin7 = 255);
|
||||
virtual ~ADCInput();
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords);
|
||||
bool setFrequency(int newFreq);
|
||||
bool setPins(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255);
|
||||
bool setPins(pin_size_t pin0, pin_size_t pin1 = 255, pin_size_t pin2 = 255, pin_size_t pin3 = 255, pin_size_t pin4 = 255, pin_size_t pin5 = 255, pin_size_t pin6 = 255, pin_size_t pin7 = 255);
|
||||
|
||||
bool begin(long sampleRate) {
|
||||
setFrequency(sampleRate);
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: 446e0af7a9...a529a74e4f
+1
-1
Submodule libraries/ESP8266SdFat updated: c6b7f4a6fb...9e1457101c
+1
-1
Submodule libraries/ESPHost updated: a3184ba0f9...80c0fa89b1
@@ -38,6 +38,7 @@ void ps() {
|
||||
|
||||
void blink(void *param) {
|
||||
(void) param;
|
||||
delay(500);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
while (true) {
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
@@ -49,12 +50,17 @@ void blink(void *param) {
|
||||
|
||||
|
||||
void setup() {
|
||||
TaskHandle_t blinkTask;
|
||||
Serial.begin(115200);
|
||||
xTaskCreate(blink, "BLINK", 128, nullptr, 1, nullptr);
|
||||
xTaskCreate(blink, "BLINK", 256, nullptr, 1, &blinkTask);
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
|
||||
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
|
||||
vTaskCoreAffinitySet(blinkTask, 1 << 0);
|
||||
#endif
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
volatile int val= 0;
|
||||
volatile int val = 0;
|
||||
void loop() {
|
||||
Serial.printf("C0: Blue leader standing by...\n");
|
||||
ps();
|
||||
|
||||
@@ -35,6 +35,8 @@ StackType_t xStack_B[ STACK_SIZE ];
|
||||
SemaphoreHandle_t xSemaphore = NULL;
|
||||
StaticSemaphore_t xMutexBuffer;
|
||||
|
||||
TaskHandle_t ledOnTask, ledOffTask;
|
||||
|
||||
void setup() {
|
||||
SERIAL_PORT.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
@@ -44,13 +46,22 @@ void setup() {
|
||||
the xMutexBuffer variable. */
|
||||
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
|
||||
|
||||
xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A);
|
||||
xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B);
|
||||
}
|
||||
ledOnTask = xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A);
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
|
||||
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
|
||||
vTaskCoreAffinitySet(ledOnTask, 1 << 0);
|
||||
#endif
|
||||
ledOffTask = xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B);
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
|
||||
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
|
||||
vTaskCoreAffinitySet(ledOffTask, 1 << 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_ON(void *pvParameters)
|
||||
{
|
||||
(void) pvParameters;
|
||||
delay(100);
|
||||
while (1)
|
||||
{
|
||||
xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY );
|
||||
@@ -65,6 +76,7 @@ void led_ON(void *pvParameters)
|
||||
void led_OFF(void *pvParameters)
|
||||
{
|
||||
(void) pvParameters;
|
||||
delay(100);
|
||||
while (1)
|
||||
{
|
||||
xSemaphoreTake( xSemaphore, ( TickType_t ) portMAX_DELAY );
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifndef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/mpu_wrappers_v2_asm.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#ifdef PICO_RP2040
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/port.c"
|
||||
#else
|
||||
#ifndef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/port.c"
|
||||
#else
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/port.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifdef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/portASM.S"
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifdef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portContext.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifndef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portasm.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifndef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure/portmacro.h"
|
||||
#else
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/portmacro.h"
|
||||
#endif
|
||||
#else
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/portmacro.h"
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifndef __riscv
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/non_secure//rp2040_config.h"
|
||||
#else
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2350_RISC-V/include/rp2040_config.h"
|
||||
#endif
|
||||
#else
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/rp2040_config.h"
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
// Interfaces for the main core to use FreeRTOS mutexes
|
||||
extern "C" {
|
||||
extern volatile bool __otherCoreIdled;
|
||||
static UBaseType_t __savedIrqs[configNUMBER_OF_CORES];
|
||||
|
||||
SemaphoreHandle_t __freertos_mutex_create() {
|
||||
return xSemaphoreCreateMutex();
|
||||
@@ -93,11 +94,19 @@ extern "C" {
|
||||
}
|
||||
|
||||
void __freertos_task_exit_critical() {
|
||||
taskEXIT_CRITICAL();
|
||||
if (portGET_CRITICAL_NESTING_COUNT() == 1U && portCHECK_IF_IN_ISR()) {
|
||||
taskEXIT_CRITICAL_FROM_ISR(__savedIrqs[portGET_CORE_ID()]);
|
||||
} else {
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
void __freertos_task_enter_critical() {
|
||||
taskENTER_CRITICAL();
|
||||
if (portGET_CRITICAL_NESTING_COUNT() == 0U && portCHECK_IF_IN_ISR()) {
|
||||
__savedIrqs[portGET_CORE_ID()] = taskENTER_CRITICAL_FROM_ISR();
|
||||
} else {
|
||||
taskENTER_CRITICAL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sdkoverride/bluetooth.h>
|
||||
#include <bluetooth.h>
|
||||
#include <_needsbt.h>
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
@@ -35,8 +35,8 @@
|
||||
#define HID_REPORT_TYPE_OUTPUT HID_REPORT_TYPE_OUTPUT_BT
|
||||
#define HID_REPORT_TYPE_FEATURE HID_REPORT_TYPE_FEATURE_BT
|
||||
#define hid_report_type_t hid_report_type_t_bt
|
||||
#include <sdkoverride/hids_device.h>
|
||||
#include <sdkoverride/att_db.h>
|
||||
#include <ble/gatt-service/hids_device.h>
|
||||
#include <ble/att_db.h>
|
||||
#include <btstack.h>
|
||||
#undef hid_report_type_t
|
||||
#undef HID_REPORT_TYPE_FEATURE
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sdkoverride/bluetooth.h>
|
||||
#include <bluetooth.h>
|
||||
#include <_needsbt.h>
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
@@ -33,8 +33,8 @@
|
||||
#define HID_REPORT_TYPE_OUTPUT HID_REPORT_TYPE_OUTPUT_BT
|
||||
#define HID_REPORT_TYPE_FEATURE HID_REPORT_TYPE_FEATURE_BT
|
||||
#define hid_report_type_t hid_report_type_t_bt
|
||||
#include <sdkoverride/hids_device.h>
|
||||
#include <sdkoverride/att_db.h>
|
||||
#include <ble/gatt-service/hids_device.h>
|
||||
#include <ble/att_db.h>
|
||||
#include <btstack.h>
|
||||
#undef hid_report_type_t
|
||||
#undef HID_REPORT_TYPE_FEATURE
|
||||
|
||||
@@ -465,7 +465,6 @@ public:
|
||||
if (_opened && _fd) {
|
||||
lfs_file_close(_fs->getFS(), _getFD());
|
||||
_opened = false;
|
||||
DEBUGV("lfs_file_close: fd=%p\n", _getFD());
|
||||
if (_timeCallback && (_flags & LFS_O_WRONLY)) {
|
||||
// If the file opened with O_CREAT, write the creation time attribute
|
||||
if (_creation) {
|
||||
|
||||
@@ -119,7 +119,7 @@ bool PWMAudio::begin() {
|
||||
|
||||
if (_stereo && (_pin & 1)) {
|
||||
// Illegal, need to have consecutive pins on the same PWM slice
|
||||
Serial.printf("ERROR: PWMAudio stereo mode requires pin be even\n");
|
||||
DEBUGV("ERROR: PWMAudio stereo mode requires pin be even\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ bool PWMAudio::begin() {
|
||||
_wasHolding = false;
|
||||
|
||||
if (!_bufferWords) {
|
||||
_bufferWords = 16;
|
||||
_bufferWords = 64;
|
||||
}
|
||||
|
||||
setPWMFrequency(_freq);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <LittleFS.h>
|
||||
#include "blink_100_1000_rp2040.h"
|
||||
#include "blink_500_500_rp2350.h"
|
||||
#include "blink_250_250_rp2350-riscv.h"
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
#ifdef PICO_RP2350
|
||||
#ifndef __riscv
|
||||
const unsigned char blink[] = {
|
||||
0x00, 0x20, 0x08, 0x20, 0x49, 0x01, 0x00, 0x10, 0x13, 0x01, 0x00, 0x10,
|
||||
0x15, 0x01, 0x00, 0x10, 0x11, 0x01, 0x00, 0x10, 0x11, 0x01, 0x00, 0x10,
|
||||
@@ -5682,3 +5683,4 @@ const unsigned char blink[] = {
|
||||
0xfc, 0x26, 0xff, 0xff, 0x79, 0x35, 0x12, 0xab
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
This sketch establishes a TCP connection to a "quote of the day" service.
|
||||
It sends a "hello" message, and then prints received data.
|
||||
*/
|
||||
|
||||
#include <W55RP20lwIP.h>
|
||||
|
||||
const char* host = "djxmmx.net";
|
||||
const uint16_t port = 17;
|
||||
|
||||
Wiznet55rp20lwIP eth(1 /* chip select */);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(5000);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println("Starting Ethernet port");
|
||||
|
||||
// Start the Ethernet port
|
||||
if (!eth.begin()) {
|
||||
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
while (!eth.connected()) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("Ethernet connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(eth.localIP());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static bool wait = false;
|
||||
|
||||
Serial.print("connecting to ");
|
||||
Serial.print(host);
|
||||
Serial.print(':');
|
||||
Serial.println(port);
|
||||
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
if (!client.connect(host, port)) {
|
||||
Serial.println("connection failed");
|
||||
delay(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
// This will send a string to the server
|
||||
Serial.println("sending data to server");
|
||||
if (client.connected()) {
|
||||
client.println("hello from RP2040");
|
||||
}
|
||||
|
||||
// wait for data to be available
|
||||
unsigned long timeout = millis();
|
||||
while (client.available() == 0) {
|
||||
if (millis() - timeout > 5000) {
|
||||
Serial.println(">>> Client Timeout !");
|
||||
client.stop();
|
||||
delay(60000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Read all the lines of the reply from server and print them to Serial
|
||||
Serial.println("receiving from remote server");
|
||||
// not testing 'client.connected()' since we do not need to send data here
|
||||
while (client.available()) {
|
||||
char ch = static_cast<char>(client.read());
|
||||
Serial.print(ch);
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
Serial.println();
|
||||
Serial.println("closing connection");
|
||||
client.stop();
|
||||
|
||||
if (wait) {
|
||||
delay(300000); // execute once every 5 minutes, don't flood remote service
|
||||
}
|
||||
wait = true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
W55RP20lwIP KEYWORD1
|
||||
Wiznet55rp20lwIP KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -0,0 +1,10 @@
|
||||
name=lwIP_w55rp20
|
||||
version=1
|
||||
author=Nicholas Humfrey
|
||||
maintainer=esp8266/Arduino
|
||||
sentence=Ethernet driver
|
||||
paragraph=Wiznet55rp20 ethernet drivers for lwIP and esp8266 Arduino from https://github.com/njh/W5500MacRaw
|
||||
category=Communication
|
||||
url=https://github.com/esp8266/Arduino
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <LwipIntfDev.h>
|
||||
#include <utility/w55rp20.h>
|
||||
#include <LwipEthernet.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
using Wiznet55rp20lwIP = LwipIntfDev<Wiznet55rp20>;
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
Copyright (c) 2024, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
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. Neither the name of the copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
COPYRIGHT HOLDER 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.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5500MacRaw
|
||||
|
||||
#include <SPI.h>
|
||||
#include "wiznet_pio_spi.h"
|
||||
#include "w55rp20.h"
|
||||
#include <LwipEthernet.h>
|
||||
|
||||
wiznet_pio_spi_config_t wiznet_pio_spi_config;
|
||||
wiznet_pio_spi_handle_t wiznet_pio_spi_handle = NULL;
|
||||
|
||||
uint8_t Wiznet55rp20::wizchip_read(uint8_t block, uint16_t address) {
|
||||
uint8_t ret;
|
||||
uint8_t spi_data[3];
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeRead;
|
||||
|
||||
spi_data[0] = (address & 0x00FF00) >> 8;
|
||||
spi_data[1] = (address & 0x0000FF) >> 0;
|
||||
spi_data[2] = block;
|
||||
(*wiznet_pio_spi_handle)->write_buffer(spi_data, 3);
|
||||
ret = (*wiznet_pio_spi_handle)->read_byte();
|
||||
|
||||
wizchip_cs_deselect();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::wizchip_read_word(uint8_t block, uint16_t address) {
|
||||
return ((uint16_t)wizchip_read(block, address) << 8) + wizchip_read(block, address + 1);
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_read_buf(uint8_t block, uint16_t address, uint8_t* pBuf, uint16_t len) {
|
||||
uint8_t spi_data[3];
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeRead;
|
||||
|
||||
spi_data[0] = (address & 0x00FF00) >> 8;
|
||||
spi_data[1] = (address & 0x0000FF) >> 0;
|
||||
spi_data[2] = block;
|
||||
(*wiznet_pio_spi_handle)->write_buffer(spi_data, 3);
|
||||
(*wiznet_pio_spi_handle)->read_buffer(pBuf, len);
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_write(uint8_t block, uint16_t address, uint8_t wb) {
|
||||
uint8_t spi_data[4];
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeWrite;
|
||||
|
||||
spi_data[0] = (address & 0x00FF00) >> 8;
|
||||
spi_data[1] = (address & 0x0000FF) >> 0;
|
||||
spi_data[2] = block;
|
||||
spi_data[3] = wb;
|
||||
(*wiznet_pio_spi_handle)->write_buffer(spi_data, 4);
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_write_word(uint8_t block, uint16_t address, uint16_t word) {
|
||||
wizchip_write(block, address, (uint8_t)(word >> 8));
|
||||
wizchip_write(block, address + 1, (uint8_t)word);
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_write_buf(uint8_t block, uint16_t address, const uint8_t* pBuf,
|
||||
uint16_t len) {
|
||||
uint8_t spi_data[3];
|
||||
|
||||
wizchip_cs_select();
|
||||
|
||||
block |= AccessModeWrite;
|
||||
|
||||
spi_data[0] = (address & 0x00FF00) >> 8;
|
||||
spi_data[1] = (address & 0x0000FF);
|
||||
spi_data[2] = block;
|
||||
(*wiznet_pio_spi_handle)->write_buffer(spi_data, 3);
|
||||
(*wiznet_pio_spi_handle)->write_buffer(pBuf, len);
|
||||
|
||||
wizchip_cs_deselect();
|
||||
}
|
||||
|
||||
void Wiznet55rp20::setSn_CR(uint8_t cr) {
|
||||
// Write the command to the Command Register
|
||||
wizchip_write(BlockSelectSReg, Sn_CR, cr);
|
||||
|
||||
// Now wait for the command to complete
|
||||
while (wizchip_read(BlockSelectSReg, Sn_CR))
|
||||
;
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::getSn_TX_FSR() {
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do {
|
||||
val1 = wizchip_read_word(BlockSelectSReg, Sn_TX_FSR);
|
||||
if (val1 != 0) {
|
||||
val = wizchip_read_word(BlockSelectSReg, Sn_TX_FSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::getSn_RX_RSR() {
|
||||
uint16_t val = 0, val1 = 0;
|
||||
do {
|
||||
val1 = wizchip_read_word(BlockSelectSReg, Sn_RX_RSR);
|
||||
if (val1 != 0) {
|
||||
val = wizchip_read_word(BlockSelectSReg, Sn_RX_RSR);
|
||||
}
|
||||
} while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_send_data(const uint8_t* wizdata, uint16_t len) {
|
||||
uint16_t ptr = 0;
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
ptr = getSn_TX_WR();
|
||||
wizchip_write_buf(BlockSelectTxBuf, ptr, wizdata, len);
|
||||
|
||||
ptr += len;
|
||||
|
||||
setSn_TX_WR(ptr);
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_recv_data(uint8_t* wizdata, uint16_t len) {
|
||||
uint16_t ptr;
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
ptr = getSn_RX_RD();
|
||||
wizchip_read_buf(BlockSelectRxBuf, ptr, wizdata, len);
|
||||
ptr += len;
|
||||
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_recv_ignore(uint16_t len) {
|
||||
uint16_t ptr;
|
||||
|
||||
ptr = getSn_RX_RD();
|
||||
ptr += len;
|
||||
setSn_RX_RD(ptr);
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizchip_sw_reset() {
|
||||
setMR(MR_RST);
|
||||
getMR(); // for delay
|
||||
|
||||
setSHAR(_mac_address);
|
||||
}
|
||||
|
||||
int8_t Wiznet55rp20::wizphy_getphylink() {
|
||||
int8_t tmp;
|
||||
if (getPHYCFGR() & PHYCFGR_LNK_ON) {
|
||||
tmp = PHY_LINK_ON;
|
||||
} else {
|
||||
tmp = PHY_LINK_OFF;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int8_t Wiznet55rp20::wizphy_getphypmode() {
|
||||
int8_t tmp = 0;
|
||||
if (getPHYCFGR() & PHYCFGR_OPMDC_PDOWN) {
|
||||
tmp = PHY_POWER_DOWN;
|
||||
} else {
|
||||
tmp = PHY_POWER_NORM;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void Wiznet55rp20::wizphy_reset() {
|
||||
uint8_t tmp = getPHYCFGR();
|
||||
tmp &= PHYCFGR_RST;
|
||||
setPHYCFGR(tmp);
|
||||
tmp = getPHYCFGR();
|
||||
tmp |= ~PHYCFGR_RST;
|
||||
setPHYCFGR(tmp);
|
||||
}
|
||||
|
||||
int8_t Wiznet55rp20::wizphy_setphypmode(uint8_t pmode) {
|
||||
uint8_t tmp = 0;
|
||||
tmp = getPHYCFGR();
|
||||
if ((tmp & PHYCFGR_OPMD) == 0) {
|
||||
return -1;
|
||||
}
|
||||
tmp &= ~PHYCFGR_OPMDC_ALLA;
|
||||
if (pmode == PHY_POWER_DOWN) {
|
||||
tmp |= PHYCFGR_OPMDC_PDOWN;
|
||||
} else {
|
||||
tmp |= PHYCFGR_OPMDC_ALLA;
|
||||
}
|
||||
setPHYCFGR(tmp);
|
||||
wizphy_reset();
|
||||
tmp = getPHYCFGR();
|
||||
if (pmode == PHY_POWER_DOWN) {
|
||||
if (tmp & PHYCFGR_OPMDC_PDOWN) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (tmp & PHYCFGR_OPMDC_ALLA) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Wiznet55rp20::Wiznet55rp20(int8_t cs, SPIClass& spi, int8_t intr) : _spi(spi), _cs(cs), _intr(intr) {
|
||||
}
|
||||
|
||||
bool Wiznet55rp20::begin(const uint8_t* mac_address, netif *net) {
|
||||
wiznet_pio_spi_config.clock_div_major = 4;
|
||||
wiznet_pio_spi_config.clock_div_minor = 0;
|
||||
wiznet_pio_spi_config.data_in_pin = WIZNET_PIO_SPI_MISO_PIN;
|
||||
wiznet_pio_spi_config.data_out_pin = WIZNET_PIO_SPI_MOSI_PIN;
|
||||
wiznet_pio_spi_config.clock_pin = WIZNET_PIO_SPI_SCK_PIN;
|
||||
|
||||
if (wiznet_pio_spi_handle != NULL) {
|
||||
wiznet_pio_spi_close(wiznet_pio_spi_handle);
|
||||
}
|
||||
wiznet_pio_spi_handle = wiznet_pio_spi_open(&wiznet_pio_spi_config);
|
||||
(*wiznet_pio_spi_handle)->set_active(wiznet_pio_spi_handle);
|
||||
|
||||
_netif = net;
|
||||
memcpy(_mac_address, mac_address, 6);
|
||||
|
||||
pinMode(WIZNET_PIO_SPI_CS_PIN, OUTPUT);
|
||||
wizchip_cs_deselect();
|
||||
|
||||
wizchip_sw_reset();
|
||||
|
||||
// Use the full 16Kb of RAM for Socket 0
|
||||
setSn_RXBUF_SIZE(16);
|
||||
setSn_TXBUF_SIZE(16);
|
||||
|
||||
// Set our local MAC address
|
||||
setSHAR(_mac_address);
|
||||
|
||||
// Open Socket 0 in MACRaw mode
|
||||
setSn_MR(Sn_MR_MACRAW);
|
||||
setSn_CR(Sn_CR_OPEN);
|
||||
if (getSn_SR() != SOCK_MACRAW) {
|
||||
// Failed to put socket 0 into MACRaw mode
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_intr >= 0) {
|
||||
setSn_IR(0xff); // Clear everything
|
||||
setSIMR(1);
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
void Wiznet55rp20::end() {
|
||||
setSn_CR(Sn_CR_CLOSE);
|
||||
|
||||
// clear all interrupt of the socket
|
||||
setSn_IR(0xFF);
|
||||
|
||||
// Wait for socket to change to closed
|
||||
while (getSn_SR() != SOCK_CLOSED)
|
||||
;
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::readFrame(uint8_t* buffer, uint16_t bufsize) {
|
||||
uint16_t data_len = readFrameSize();
|
||||
|
||||
if (data_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_len > bufsize) {
|
||||
// Packet is bigger than buffer - drop the packet
|
||||
discardFrame(data_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return readFrameData(buffer, data_len);
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::readFrameSize() {
|
||||
setSn_IR(Sn_IR_RECV);
|
||||
|
||||
uint16_t len = getSn_RX_RSR();
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t head[2];
|
||||
uint16_t data_len = 0;
|
||||
|
||||
wizchip_recv_data(head, 2);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
data_len = head[0];
|
||||
data_len = (data_len << 8) + head[1];
|
||||
data_len -= 2;
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
void Wiznet55rp20::discardFrame(uint16_t framesize) {
|
||||
wizchip_recv_ignore(framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::readFrameData(uint8_t* buffer, uint16_t framesize) {
|
||||
wizchip_recv_data(buffer, framesize);
|
||||
setSn_CR(Sn_CR_RECV);
|
||||
|
||||
// let lwIP deal with mac address filtering
|
||||
return framesize;
|
||||
}
|
||||
|
||||
uint16_t Wiznet55rp20::sendFrame(const uint8_t* buf, uint16_t len) {
|
||||
ethernet_arch_lwip_gpio_mask(); // So we don't fire an IRQ and interrupt the send w/a receive!
|
||||
|
||||
// Wait for space in the transmit buffer
|
||||
while (1) {
|
||||
uint16_t freesize = getSn_TX_FSR();
|
||||
if (getSn_SR() == SOCK_CLOSED) {
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
return -1;
|
||||
}
|
||||
if (len <= freesize) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
wizchip_send_data(buf, len);
|
||||
setSn_CR(Sn_CR_SEND);
|
||||
|
||||
while (1) {
|
||||
uint8_t tmp = getSn_IR();
|
||||
if (tmp & Sn_IR_SENDOK) {
|
||||
setSn_IR(Sn_IR_SENDOK);
|
||||
// Packet sent ok
|
||||
break;
|
||||
} else if (tmp & Sn_IR_TIMEOUT) {
|
||||
setSn_IR(Sn_IR_TIMEOUT);
|
||||
// There was a timeout
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
Copyright (c) 2024, WIZnet Co., Ltd.
|
||||
Copyright (c) 2016, Nicholas Humfrey
|
||||
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. Neither the name of the copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
COPYRIGHT HOLDER 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.
|
||||
|
||||
*/
|
||||
|
||||
// original sources: https://github.com/njh/W5500MacRaw
|
||||
|
||||
#ifndef W55RP20_H
|
||||
#define W55RP20_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <LwipEthernet.h>
|
||||
|
||||
#define WIZNET_PIO_SPI_MOSI_PIN 23
|
||||
#define WIZNET_PIO_SPI_MISO_PIN 22
|
||||
#define WIZNET_PIO_SPI_SCK_PIN 21
|
||||
#define WIZNET_PIO_SPI_CS_PIN 20
|
||||
|
||||
class Wiznet55rp20 {
|
||||
public:
|
||||
/**
|
||||
Constructor that uses the default hardware SPI pins
|
||||
@param cs the Arduino Chip Select / Slave Select pin (default 10)
|
||||
*/
|
||||
Wiznet55rp20(int8_t cs = SS, SPIClass& spi = SPI, int8_t intr = -1);
|
||||
//Wiznet55rp20();
|
||||
|
||||
/**
|
||||
Initialise the Ethernet controller
|
||||
Must be called before sending or receiving Ethernet frames
|
||||
|
||||
@param address the local MAC address for the Ethernet interface
|
||||
@return Returns true if setting up the Ethernet interface was successful
|
||||
*/
|
||||
bool begin(const uint8_t* address, netif *net);
|
||||
|
||||
/**
|
||||
Shut down the Ethernet controlled
|
||||
*/
|
||||
void end();
|
||||
|
||||
/**
|
||||
Send an Ethernet frame
|
||||
@param data a pointer to the data to send
|
||||
@param datalen the length of the data in the packet
|
||||
@return the number of bytes transmitted
|
||||
*/
|
||||
uint16_t sendFrame(const uint8_t* data, uint16_t datalen);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame
|
||||
@param buffer a pointer to a buffer to write the packet to
|
||||
@param bufsize the available space in the buffer
|
||||
@return the length of the received packet
|
||||
or 0 if no packet was received
|
||||
*/
|
||||
uint16_t readFrame(uint8_t* buffer, uint16_t bufsize);
|
||||
|
||||
/**
|
||||
Check physical link
|
||||
@return true when physical link is up
|
||||
*/
|
||||
bool isLinked() {
|
||||
ethernet_arch_lwip_gpio_mask();
|
||||
ethernet_arch_lwip_begin();
|
||||
auto ret = wizphy_getphylink() == PHY_LINK_ON;
|
||||
ethernet_arch_lwip_end();
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Report whether ::isLinked() API is implemented
|
||||
@return true when ::isLinked() API is implemented
|
||||
*/
|
||||
constexpr bool isLinkDetectable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool needsSPI() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr bool interruptIsPossible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr PinStatus interruptMode() {
|
||||
return LOW;
|
||||
}
|
||||
|
||||
/**
|
||||
Read an Ethernet frame size
|
||||
@return the length of data do receive
|
||||
or 0 if no frame was received
|
||||
*/
|
||||
uint16_t readFrameSize();
|
||||
|
||||
/**
|
||||
discard an Ethernet frame
|
||||
@param framesize readFrameSize()'s result
|
||||
*/
|
||||
void discardFrame(uint16_t framesize);
|
||||
|
||||
/**
|
||||
Read an Ethernet frame data
|
||||
readFrameSize() must be called first,
|
||||
its result must be passed into framesize parameter
|
||||
@param buffer a pointer to a buffer to write the frame to
|
||||
@param framesize readFrameSize()'s result
|
||||
@return the length of the received frame
|
||||
or 0 if a problem occurred
|
||||
*/
|
||||
uint16_t readFrameData(uint8_t* frame, uint16_t framesize);
|
||||
|
||||
private:
|
||||
//< SPI interface Read operation in Control Phase
|
||||
static const uint8_t AccessModeRead = (0x00 << 2);
|
||||
|
||||
//< SPI interface Read operation in Control Phase
|
||||
static const uint8_t AccessModeWrite = (0x01 << 2);
|
||||
|
||||
//< Common register block in Control Phase
|
||||
static const uint8_t BlockSelectCReg = (0x00 << 3);
|
||||
|
||||
//< Socket 0 register block in Control Phase
|
||||
static const uint8_t BlockSelectSReg = (0x01 << 3);
|
||||
|
||||
//< Socket 0 Tx buffer address block
|
||||
static const uint8_t BlockSelectTxBuf = (0x02 << 3);
|
||||
|
||||
//< Socket 0 Rx buffer address block
|
||||
static const uint8_t BlockSelectRxBuf = (0x03 << 3);
|
||||
|
||||
SPIClass& _spi;
|
||||
int8_t _cs;
|
||||
int8_t _intr;
|
||||
uint8_t _mac_address[6];
|
||||
|
||||
/**
|
||||
Default function to select chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function
|
||||
or register any functions, null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_select() {
|
||||
digitalWrite(WIZNET_PIO_SPI_CS_PIN, LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to deselect chip.
|
||||
@note This function help not to access wrong address. If you do not describe this function
|
||||
or register any functions, null function is called.
|
||||
*/
|
||||
inline void wizchip_cs_deselect() {
|
||||
//digitalWrite(_cs, HIGH);
|
||||
digitalWrite(WIZNET_PIO_SPI_CS_PIN, HIGH);
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to read in SPI interface.
|
||||
@note This function help not to access wrong address. If you do not describe this function
|
||||
or register any functions, null function is called.
|
||||
*/
|
||||
inline uint8_t wizchip_spi_read_byte() {
|
||||
//return _spi.transfer(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Default function to write in SPI interface.
|
||||
@note This function help not to access wrong address. If you do not describe this function
|
||||
or register any functions, null function is called.
|
||||
*/
|
||||
inline void wizchip_spi_write_byte(uint8_t wb) {
|
||||
//_spi.transfer(wb);
|
||||
}
|
||||
|
||||
/**
|
||||
Read a 1 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint8_t wizchip_read(uint8_t block, uint16_t address);
|
||||
|
||||
/**
|
||||
Reads a 2 byte value from a register.
|
||||
@param address Register address
|
||||
@return The value of register
|
||||
*/
|
||||
uint16_t wizchip_read_word(uint8_t block, uint16_t address);
|
||||
|
||||
/**
|
||||
It reads sequence data from registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to read data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_read_buf(uint8_t block, uint16_t address, uint8_t* pBuf, uint16_t len);
|
||||
|
||||
/**
|
||||
Write a 1 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write(uint8_t block, uint16_t address, uint8_t wb);
|
||||
|
||||
/**
|
||||
Write a 2 byte value to a register.
|
||||
@param address Register address
|
||||
@param wb Write data
|
||||
@return void
|
||||
*/
|
||||
void wizchip_write_word(uint8_t block, uint16_t address, uint16_t word);
|
||||
|
||||
/**
|
||||
It writes sequence data to registers.
|
||||
@param address Register address
|
||||
@param pBuf Pointer buffer to write data
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_write_buf(uint8_t block, uint16_t address, const uint8_t* pBuf, uint16_t len);
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_FSR register
|
||||
@return uint16_t. Value of @ref Sn_TX_FSR.
|
||||
*/
|
||||
uint16_t getSn_TX_FSR();
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RSR register
|
||||
@return uint16_t. Value of @ref Sn_RX_RSR.
|
||||
*/
|
||||
uint16_t getSn_RX_RSR();
|
||||
|
||||
/**
|
||||
Reset WIZCHIP by softly.
|
||||
*/
|
||||
void wizchip_sw_reset();
|
||||
|
||||
/**
|
||||
Get the link status of phy in WIZCHIP
|
||||
*/
|
||||
int8_t wizphy_getphylink();
|
||||
|
||||
/**
|
||||
Get the power mode of PHY in WIZCHIP
|
||||
*/
|
||||
int8_t wizphy_getphypmode();
|
||||
|
||||
/**
|
||||
Reset Phy
|
||||
*/
|
||||
void wizphy_reset();
|
||||
|
||||
/**
|
||||
set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in
|
||||
W5200
|
||||
@param pmode Setting value of power down mode.
|
||||
*/
|
||||
int8_t wizphy_setphypmode(uint8_t pmode);
|
||||
|
||||
/**
|
||||
It copies data to internal TX memory
|
||||
|
||||
@details This function reads the Tx write pointer register and after that,
|
||||
it copies the <i>wizdata(pointer buffer)</i> of the length of <i>len(variable)</i> bytes to
|
||||
internal TX memory and updates the Tx write pointer register. This function is being called
|
||||
by send() and sendto() function also.
|
||||
|
||||
@param wizdata Pointer buffer to write data
|
||||
@param len Data length
|
||||
@sa wizchip_recv_data()
|
||||
*/
|
||||
void wizchip_send_data(const uint8_t* wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It copies data to your buffer from internal RX memory
|
||||
|
||||
@details This function read the Rx read pointer register and after that,
|
||||
it copies the received data from internal RX memory
|
||||
to <i>wizdata(pointer variable)</i> of the length of <i>len(variable)</i> bytes.
|
||||
This function is being called by recv() also.
|
||||
|
||||
@param wizdata Pointer buffer to read data
|
||||
@param len Data length
|
||||
@sa wizchip_send_data()
|
||||
*/
|
||||
void wizchip_recv_data(uint8_t* wizdata, uint16_t len);
|
||||
|
||||
/**
|
||||
It discard the received data in RX memory.
|
||||
@details It discards the data of the length of <i>len(variable)</i> bytes in internal RX
|
||||
memory.
|
||||
@param len Data length
|
||||
*/
|
||||
void wizchip_recv_ignore(uint16_t len);
|
||||
|
||||
/** Common registers */
|
||||
enum {
|
||||
MR = 0x0000, ///< Mode Register address (R/W)
|
||||
SHAR = 0x0009, ///< Source MAC Register address (R/W)
|
||||
INTLEVEL = 0x0013, ///< Set Interrupt low level timer register address (R/W)
|
||||
IR = 0x0015, ///< Interrupt Register (R/W)
|
||||
_IMR_ = 0x0016, ///< Interrupt mask register (R/W)
|
||||
SIR = 0x0017, ///< Socket Interrupt Register (R/W)
|
||||
_SIMR_ = 0x0018, ///< Socket Interrupt Mask Register (R/W)
|
||||
_RTR_ = 0x0019, ///< Timeout register address (1 is 100us) (R/W)
|
||||
_RCR_ = 0x001B, ///< Retry count register (R/W)
|
||||
UIPR = 0x0028, ///< Unreachable IP register address in UDP mode (R)
|
||||
UPORTR = 0x002C, ///< Unreachable Port register address in UDP mode (R)
|
||||
PHYCFGR = 0x002E, ///< PHY Status Register (R/W)
|
||||
VERSIONR = 0x0039, ///< Chip version register address (R)
|
||||
};
|
||||
|
||||
/** Socket registers */
|
||||
enum {
|
||||
Sn_MR = 0x0000, ///< Socket Mode register (R/W)
|
||||
Sn_CR = 0x0001, ///< Socket command register (R/W)
|
||||
Sn_IR = 0x0002, ///< Socket interrupt register (R)
|
||||
Sn_SR = 0x0003, ///< Socket status register (R)
|
||||
Sn_PORT = 0x0004, ///< Source port register (R/W)
|
||||
Sn_DHAR = 0x0006, ///< Peer MAC register address (R/W)
|
||||
Sn_DIPR = 0x000C, ///< Peer IP register address (R/W)
|
||||
Sn_DPORT = 0x0010, ///< Peer port register address (R/W)
|
||||
Sn_MSSR = 0x0012, ///< Maximum Segment Size(Sn_MSSR0) register address (R/W)
|
||||
Sn_TOS = 0x0015, ///< IP Type of Service(TOS) Register (R/W)
|
||||
Sn_TTL = 0x0016, ///< IP Time to live(TTL) Register (R/W)
|
||||
Sn_RXBUF_SIZE = 0x001E, ///< Receive memory size register (R/W)
|
||||
Sn_TXBUF_SIZE = 0x001F, ///< Transmit memory size register (R/W)
|
||||
Sn_TX_FSR = 0x0020, ///< Transmit free memory size register (R)
|
||||
Sn_TX_RD = 0x0022, ///< Transmit memory read pointer register address (R)
|
||||
Sn_TX_WR = 0x0024, ///< Transmit memory write pointer register address (R/W)
|
||||
Sn_RX_RSR = 0x0026, ///< Received data size register (R)
|
||||
Sn_RX_RD = 0x0028, ///< Read point of Receive memory (R/W)
|
||||
Sn_RX_WR = 0x002A, ///< Write point of Receive memory (R)
|
||||
Sn_IMR = 0x002C, ///< Socket interrupt mask register (R)
|
||||
Sn_FRAG = 0x002D, ///< Fragment field value in IP header register (R/W)
|
||||
Sn_KPALVTR = 0x002F, ///< Keep Alive Timer register (R/W)
|
||||
};
|
||||
|
||||
/** Mode register values */
|
||||
enum {
|
||||
MR_RST = 0x80, ///< Reset
|
||||
MR_WOL = 0x20, ///< Wake on LAN
|
||||
MR_PB = 0x10, ///< Ping block
|
||||
MR_PPPOE = 0x08, ///< Enable PPPoE
|
||||
MR_FARP = 0x02, ///< Enable UDP_FORCE_ARP CHECK
|
||||
};
|
||||
|
||||
/* Interrupt Register values */
|
||||
enum {
|
||||
IR_CONFLICT = 0x80, ///< Check IP conflict
|
||||
IR_UNREACH = 0x40, ///< Get the destination unreachable message in UDP sending
|
||||
IR_PPPoE = 0x20, ///< Get the PPPoE close message
|
||||
IR_MP = 0x10, ///< Get the magic packet interrupt
|
||||
};
|
||||
|
||||
/* Interrupt Mask Register values */
|
||||
enum {
|
||||
IM_IR7 = 0x80, ///< IP Conflict Interrupt Mask
|
||||
IM_IR6 = 0x40, ///< Destination unreachable Interrupt Mask
|
||||
IM_IR5 = 0x20, ///< PPPoE Close Interrupt Mask
|
||||
IM_IR4 = 0x10, ///< Magic Packet Interrupt Mask
|
||||
};
|
||||
|
||||
/** Socket Mode Register values @ref Sn_MR */
|
||||
enum {
|
||||
Sn_MR_CLOSE = 0x00, ///< Unused socket
|
||||
Sn_MR_TCP = 0x01, ///< TCP
|
||||
Sn_MR_UDP = 0x02, ///< UDP
|
||||
Sn_MR_MACRAW = 0x04, ///< MAC LAYER RAW SOCK
|
||||
Sn_MR_UCASTB = 0x10, ///< Unicast Block in UDP Multicasting
|
||||
Sn_MR_ND = 0x20, ///< No Delayed Ack(TCP), Multicast flag
|
||||
Sn_MR_BCASTB = 0x40, ///< Broadcast block in UDP Multicasting
|
||||
Sn_MR_MULTI = 0x80, ///< Support UDP Multicasting
|
||||
Sn_MR_MIP6B = 0x10, ///< IPv6 packet Blocking in @ref Sn_MR_MACRAW mode
|
||||
Sn_MR_MMB = 0x20, ///< Multicast Blocking in @ref Sn_MR_MACRAW mode
|
||||
Sn_MR_MFEN = 0x80, ///< MAC filter enable in @ref Sn_MR_MACRAW mode
|
||||
};
|
||||
|
||||
/** Socket Command Register values */
|
||||
enum {
|
||||
Sn_CR_OPEN = 0x01, ///< Initialise or open socket
|
||||
Sn_CR_LISTEN = 0x02, ///< Wait connection request in TCP mode (Server mode)
|
||||
Sn_CR_CONNECT = 0x04, ///< Send connection request in TCP mode (Client mode)
|
||||
Sn_CR_DISCON = 0x08, ///< Send closing request in TCP mode
|
||||
Sn_CR_CLOSE = 0x10, ///< Close socket
|
||||
Sn_CR_SEND = 0x20, ///< Update TX buffer pointer and send data
|
||||
Sn_CR_SEND_MAC = 0x21, ///< Send data with MAC address, so without ARP process
|
||||
Sn_CR_SEND_KEEP = 0x22, ///< Send keep alive message
|
||||
Sn_CR_RECV = 0x40, ///< Update RX buffer pointer and receive data
|
||||
};
|
||||
|
||||
/** Socket Interrupt register values */
|
||||
enum {
|
||||
Sn_IR_CON = 0x01, ///< CON Interrupt
|
||||
Sn_IR_DISCON = 0x02, ///< DISCON Interrupt
|
||||
Sn_IR_RECV = 0x04, ///< RECV Interrupt
|
||||
Sn_IR_TIMEOUT = 0x08, ///< TIMEOUT Interrupt
|
||||
Sn_IR_SENDOK = 0x10, ///< SEND_OK Interrupt
|
||||
};
|
||||
|
||||
/** Socket Status Register values */
|
||||
enum {
|
||||
SOCK_CLOSED = 0x00, ///< Closed
|
||||
SOCK_INIT = 0x13, ///< Initiate state
|
||||
SOCK_LISTEN = 0x14, ///< Listen state
|
||||
SOCK_SYNSENT = 0x15, ///< Connection state
|
||||
SOCK_SYNRECV = 0x16, ///< Connection state
|
||||
SOCK_ESTABLISHED = 0x17, ///< Success to connect
|
||||
SOCK_FIN_WAIT = 0x18, ///< Closing state
|
||||
SOCK_CLOSING = 0x1A, ///< Closing state
|
||||
SOCK_TIME_WAIT = 0x1B, ///< Closing state
|
||||
SOCK_CLOSE_WAIT = 0x1C, ///< Closing state
|
||||
SOCK_LAST_ACK = 0x1D, ///< Closing state
|
||||
SOCK_UDP = 0x22, ///< UDP socket
|
||||
SOCK_MACRAW = 0x42, ///< MAC raw mode socket
|
||||
};
|
||||
|
||||
/* PHYCFGR register value */
|
||||
enum {
|
||||
PHYCFGR_RST = ~(1 << 7), //< For PHY reset, must operate AND mask.
|
||||
PHYCFGR_OPMD = (1 << 6), // Configure PHY with OPMDC value
|
||||
PHYCFGR_OPMDC_ALLA = (7 << 3),
|
||||
PHYCFGR_OPMDC_PDOWN = (6 << 3),
|
||||
PHYCFGR_OPMDC_NA = (5 << 3),
|
||||
PHYCFGR_OPMDC_100FA = (4 << 3),
|
||||
PHYCFGR_OPMDC_100F = (3 << 3),
|
||||
PHYCFGR_OPMDC_100H = (2 << 3),
|
||||
PHYCFGR_OPMDC_10F = (1 << 3),
|
||||
PHYCFGR_OPMDC_10H = (0 << 3),
|
||||
PHYCFGR_DPX_FULL = (1 << 2),
|
||||
PHYCFGR_DPX_HALF = (0 << 2),
|
||||
PHYCFGR_SPD_100 = (1 << 1),
|
||||
PHYCFGR_SPD_10 = (0 << 1),
|
||||
PHYCFGR_LNK_ON = (1 << 0),
|
||||
PHYCFGR_LNK_OFF = (0 << 0),
|
||||
};
|
||||
|
||||
enum {
|
||||
PHY_SPEED_10 = 0, ///< Link Speed 10
|
||||
PHY_SPEED_100 = 1, ///< Link Speed 100
|
||||
PHY_DUPLEX_HALF = 0, ///< Link Half-Duplex
|
||||
PHY_DUPLEX_FULL = 1, ///< Link Full-Duplex
|
||||
PHY_LINK_OFF = 0, ///< Link Off
|
||||
PHY_LINK_ON = 1, ///< Link On
|
||||
PHY_POWER_NORM = 0, ///< PHY power normal mode
|
||||
PHY_POWER_DOWN = 1, ///< PHY power down mode
|
||||
};
|
||||
|
||||
/**
|
||||
Set Mode Register
|
||||
@param (uint8_t)mr The value to be set.
|
||||
@sa getMR()
|
||||
*/
|
||||
inline void setMR(uint8_t mode) {
|
||||
wizchip_write(BlockSelectCReg, MR, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
Get Mode Register
|
||||
@return uint8_t. The value of Mode register.
|
||||
@sa setMR()
|
||||
*/
|
||||
inline uint8_t getMR() {
|
||||
return wizchip_read(BlockSelectCReg, MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to set local MAC address. It should be allocated 6
|
||||
bytes.
|
||||
@sa getSHAR()
|
||||
*/
|
||||
inline void setSHAR(const uint8_t* macaddr) {
|
||||
wizchip_write_buf(BlockSelectCReg, SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Get local MAC address
|
||||
@param (uint8_t*)shar Pointer variable to get local MAC address. It should be allocated 6
|
||||
bytes.
|
||||
@sa setSHAR()
|
||||
*/
|
||||
inline void getSHAR(uint8_t* macaddr) {
|
||||
wizchip_read_buf(BlockSelectCReg, SHAR, macaddr, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref IR register
|
||||
@param (uint8_t)ir Value to set @ref IR register.
|
||||
@sa getIR()
|
||||
*/
|
||||
inline void setIR(uint8_t ir) {
|
||||
wizchip_write(BlockSelectCReg, IR, (ir & 0xF0));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref IR register
|
||||
@return uint8_t. Value of @ref IR register.
|
||||
@sa setIR()
|
||||
*/
|
||||
inline uint8_t getIR() {
|
||||
return wizchip_read(BlockSelectCReg, IR) & 0xF0;
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref SIR register
|
||||
@param (uint8_t)ir Value to set @ref SIR register.
|
||||
@sa getSIR()
|
||||
*/
|
||||
inline void setSIR(uint8_t ir) {
|
||||
wizchip_write(BlockSelectCReg, SIR, ir);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref SIR register
|
||||
@return uint8_t. Value of @ref SIR register.
|
||||
@sa setSIR()
|
||||
*/
|
||||
inline uint8_t getSIR() {
|
||||
return wizchip_read(BlockSelectCReg, SIR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref _IMR_ register
|
||||
@param (uint8_t)imr Value to set @ref _IMR_ register.
|
||||
@sa getIMR()
|
||||
*/
|
||||
inline void setIMR(uint8_t imr) {
|
||||
wizchip_write(BlockSelectCReg, _IMR_, imr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref _IMR_ register
|
||||
@return uint8_t. Value of @ref _IMR_ register.
|
||||
@sa setIMR()
|
||||
*/
|
||||
inline uint8_t getIMR() {
|
||||
return wizchip_read(BlockSelectCReg, _IMR_);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref _SIMR_ register
|
||||
@param (uint8_t)imr Value to set @ref _SIMR_ register.
|
||||
@sa getIMR()
|
||||
*/
|
||||
inline void setSIMR(uint8_t imr) {
|
||||
wizchip_write(BlockSelectCReg, _SIMR_, imr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref _SIMR_ register
|
||||
@return uint8_t. Value of @ref _SIMR_ register.
|
||||
@sa setSIMR()
|
||||
*/
|
||||
inline uint8_t getSIMR() {
|
||||
return wizchip_read(BlockSelectCReg, _SIMR_);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref PHYCFGR register
|
||||
@param (uint8_t)phycfgr Value to set @ref PHYCFGR register.
|
||||
@sa getPHYCFGR()
|
||||
*/
|
||||
inline void setPHYCFGR(uint8_t phycfgr) {
|
||||
wizchip_write(BlockSelectCReg, PHYCFGR, phycfgr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref PHYCFGR register
|
||||
@return uint8_t. Value of @ref PHYCFGR register.
|
||||
@sa setPHYCFGR()
|
||||
*/
|
||||
inline uint8_t getPHYCFGR() {
|
||||
return wizchip_read(BlockSelectCReg, PHYCFGR);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref VERSIONR register
|
||||
@return uint8_t. Value of @ref VERSIONR register.
|
||||
*/
|
||||
inline uint8_t getVERSIONR() {
|
||||
return wizchip_read(BlockSelectCReg, VERSIONR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_MR register
|
||||
@param (uint8_t)mr Value to set @ref Sn_MR
|
||||
@sa getSn_MR()
|
||||
*/
|
||||
inline void setSn_MR(uint8_t mr) {
|
||||
wizchip_write(BlockSelectSReg, Sn_MR, mr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_MR register
|
||||
@return uint8_t. Value of @ref Sn_MR.
|
||||
@sa setSn_MR()
|
||||
*/
|
||||
inline uint8_t getSn_MR() {
|
||||
return wizchip_read(BlockSelectSReg, Sn_MR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_CR register, then wait for the command to execute
|
||||
@param (uint8_t)cr Value to set @ref Sn_CR
|
||||
@sa getSn_CR()
|
||||
*/
|
||||
void setSn_CR(uint8_t cr);
|
||||
|
||||
/**
|
||||
Get @ref Sn_CR register
|
||||
@return uint8_t. Value of @ref Sn_CR.
|
||||
@sa setSn_CR()
|
||||
*/
|
||||
inline uint8_t getSn_CR() {
|
||||
return wizchip_read(BlockSelectSReg, Sn_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_IR register
|
||||
@param (uint8_t)ir Value to set @ref Sn_IR
|
||||
@sa getSn_IR()
|
||||
*/
|
||||
inline void setSn_IR(uint8_t ir) {
|
||||
wizchip_write(BlockSelectSReg, Sn_IR, (ir & 0x1F));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_IR register
|
||||
@return uint8_t. Value of @ref Sn_IR.
|
||||
@sa setSn_IR()
|
||||
*/
|
||||
inline uint8_t getSn_IR() {
|
||||
return (wizchip_read(BlockSelectSReg, Sn_IR) & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_IMR register
|
||||
@param (uint8_t)imr Value to set @ref Sn_IMR
|
||||
@sa getSn_IMR()
|
||||
*/
|
||||
inline void setSn_IMR(uint8_t imr) {
|
||||
wizchip_write(BlockSelectSReg, Sn_IMR, (imr & 0x1F));
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_IMR register
|
||||
@return uint8_t. Value of @ref Sn_IMR.
|
||||
@sa setSn_IMR()
|
||||
*/
|
||||
inline uint8_t getSn_IMR() {
|
||||
return (wizchip_read(BlockSelectSReg, Sn_IMR) & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_SR register
|
||||
@return uint8_t. Value of @ref Sn_SR.
|
||||
*/
|
||||
inline uint8_t getSn_SR() {
|
||||
return wizchip_read(BlockSelectSReg, Sn_SR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_RXBUF_SIZE register
|
||||
@param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE
|
||||
@sa getSn_RXBUF_SIZE()
|
||||
*/
|
||||
inline void setSn_RXBUF_SIZE(uint8_t rxbufsize) {
|
||||
wizchip_write(BlockSelectSReg, Sn_RXBUF_SIZE, rxbufsize);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RXBUF_SIZE register
|
||||
@return uint8_t. Value of @ref Sn_RXBUF_SIZE.
|
||||
@sa setSn_RXBUF_SIZE()
|
||||
*/
|
||||
inline uint8_t getSn_RXBUF_SIZE() {
|
||||
return wizchip_read(BlockSelectSReg, Sn_RXBUF_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_TXBUF_SIZE register
|
||||
@param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE
|
||||
@sa getSn_TXBUF_SIZE()
|
||||
*/
|
||||
inline void setSn_TXBUF_SIZE(uint8_t txbufsize) {
|
||||
wizchip_write(BlockSelectSReg, Sn_TXBUF_SIZE, txbufsize);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TXBUF_SIZE register
|
||||
@return uint8_t. Value of @ref Sn_TXBUF_SIZE.
|
||||
@sa setSn_TXBUF_SIZE()
|
||||
*/
|
||||
inline uint8_t getSn_TXBUF_SIZE() {
|
||||
return wizchip_read(BlockSelectSReg, Sn_TXBUF_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_RD register
|
||||
@return uint16_t. Value of @ref Sn_TX_RD.
|
||||
*/
|
||||
inline uint16_t getSn_TX_RD() {
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_TX_RD);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_TX_WR register
|
||||
@param (uint16_t)txwr Value to set @ref Sn_TX_WR
|
||||
@sa GetSn_TX_WR()
|
||||
*/
|
||||
inline void setSn_TX_WR(uint16_t txwr) {
|
||||
wizchip_write_word(BlockSelectSReg, Sn_TX_WR, txwr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_TX_WR register
|
||||
@return uint16_t. Value of @ref Sn_TX_WR.
|
||||
@sa setSn_TX_WR()
|
||||
*/
|
||||
inline uint16_t getSn_TX_WR() {
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_TX_WR);
|
||||
}
|
||||
|
||||
/**
|
||||
Set @ref Sn_RX_RD register
|
||||
@param (uint16_t)rxrd Value to set @ref Sn_RX_RD
|
||||
@sa getSn_RX_RD()
|
||||
*/
|
||||
inline void setSn_RX_RD(uint16_t rxrd) {
|
||||
wizchip_write_word(BlockSelectSReg, Sn_RX_RD, rxrd);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_RD register
|
||||
@return uint16_t. Value of @ref Sn_RX_RD.
|
||||
@sa setSn_RX_RD()
|
||||
*/
|
||||
inline uint16_t getSn_RX_RD() {
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_RX_RD);
|
||||
}
|
||||
|
||||
/**
|
||||
Get @ref Sn_RX_WR register
|
||||
@return uint16_t. Value of @ref Sn_RX_WR.
|
||||
*/
|
||||
inline uint16_t getSn_RX_WR() {
|
||||
return wizchip_read_word(BlockSelectSReg, Sn_RX_WR);
|
||||
}
|
||||
|
||||
netif *_netif;
|
||||
};
|
||||
|
||||
#endif // W5500_H
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
Copyright (c) 2024, WIZnet Co., Ltd.
|
||||
Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/error.h"
|
||||
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
#include "wiznet_pio_spi.h"
|
||||
#include "wiznet_pio_spi.pio.h"
|
||||
|
||||
#ifndef PIO_SPI_PREFERRED_PIO
|
||||
#define PIO_SPI_PREFERRED_PIO 1
|
||||
#endif
|
||||
|
||||
#define PADS_DRIVE_STRENGTH PADS_BANK0_GPIO0_DRIVE_VALUE_12MA
|
||||
#define IRQ_SAMPLE_DELAY_NS 100
|
||||
|
||||
#define WIZNET_PIO_SPI_PROGRAM_NAME wiznet_pio_spi_write_read
|
||||
#define WIZNET_PIO_SPI_PROGRAM_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program)
|
||||
#define WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program_get_default_config)
|
||||
#define WIZNET_PIO_SPI_OFFSET_WRITE_BITS __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_bits)
|
||||
#define WIZNET_PIO_SPI_OFFSET_WRITE_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_end)
|
||||
#define WIZNET_PIO_SPI_OFFSET_READ_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_read_end)
|
||||
|
||||
// All wiznet spi operations must start with writing a 3 byte header
|
||||
#define WIZNET_PIO_SPI_HEADER_LEN 3
|
||||
|
||||
#ifndef WIZNET_PICO_PIO_SPI_INSTANCE_COUNT
|
||||
#define WIZNET_PICO_PIO_SPI_INSTANCE_COUNT 1
|
||||
#endif
|
||||
|
||||
typedef struct wiznet_pio_spi_state {
|
||||
wiznet_pio_spi_funcs_t *funcs;
|
||||
const wiznet_pio_spi_config_t *spi_config;
|
||||
pio_hw_t *pio;
|
||||
uint8_t pio_func_sel;
|
||||
int8_t pio_offset;
|
||||
int8_t pio_sm;
|
||||
int8_t dma_out;
|
||||
int8_t dma_in;
|
||||
uint8_t spi_header[WIZNET_PIO_SPI_HEADER_LEN];
|
||||
uint8_t spi_header_count;
|
||||
} wiznet_pio_spi_state_t;
|
||||
static wiznet_pio_spi_state_t wiznet_pio_spi_state[WIZNET_PICO_PIO_SPI_INSTANCE_COUNT];
|
||||
static wiznet_pio_spi_state_t *active_state;
|
||||
|
||||
static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void);
|
||||
|
||||
// Initialise our gpios
|
||||
static void wiznet_pio_spi_gpio_setup(wiznet_pio_spi_state_t *state) {
|
||||
|
||||
// Setup MOSI, MISO and IRQ
|
||||
gpio_init(state->spi_config->data_out_pin);
|
||||
gpio_set_dir(state->spi_config->data_out_pin, GPIO_OUT);
|
||||
gpio_put(state->spi_config->data_out_pin, false);
|
||||
|
||||
// Setup CS
|
||||
gpio_init(state->spi_config->cs_pin);
|
||||
gpio_set_dir(state->spi_config->cs_pin, GPIO_OUT);
|
||||
gpio_put(state->spi_config->cs_pin, true);
|
||||
|
||||
// Setup IRQ
|
||||
gpio_init(state->spi_config->irq_pin);
|
||||
gpio_set_dir(state->spi_config->irq_pin, GPIO_IN);
|
||||
gpio_set_pulls(state->spi_config->irq_pin, false, false);
|
||||
}
|
||||
|
||||
wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *wiznet_pio_spi_config) {
|
||||
wiznet_pio_spi_state_t *state;
|
||||
for (unsigned int i = 0; i < count_of(wiznet_pio_spi_state); i++) {
|
||||
if (!wiznet_pio_spi_state[i].funcs) {
|
||||
state = &wiznet_pio_spi_state[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(state);
|
||||
//if (!state) return NULL;
|
||||
state->spi_config = wiznet_pio_spi_config;
|
||||
state->funcs = get_wiznet_pio_spi_impl();
|
||||
|
||||
wiznet_pio_spi_gpio_setup(state);
|
||||
|
||||
pio_hw_t *pios[2] = {pio0, pio1};
|
||||
uint pio_index = PIO_SPI_PREFERRED_PIO;
|
||||
|
||||
if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) {
|
||||
pio_index ^= 1;
|
||||
if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
state->pio = pios[pio_index];
|
||||
state->dma_in = -1;
|
||||
state->dma_out = -1;
|
||||
|
||||
static_assert(GPIO_FUNC_PIO1 == GPIO_FUNC_PIO0 + 1, "");
|
||||
state->pio_func_sel = GPIO_FUNC_PIO0 + pio_index;
|
||||
state->pio_sm = (int8_t)pio_claim_unused_sm(state->pio, false);
|
||||
if (state->pio_sm < 0) {
|
||||
wiznet_pio_spi_close(&state->funcs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->pio_offset = pio_add_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC);
|
||||
|
||||
pio_sm_config sm_config = WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(state->pio_offset);
|
||||
|
||||
sm_config_set_clkdiv_int_frac(&sm_config, state->spi_config->clock_div_major, state->spi_config->clock_div_minor);
|
||||
hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin],
|
||||
(uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB,
|
||||
PADS_BANK0_GPIO0_DRIVE_BITS
|
||||
);
|
||||
hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin],
|
||||
(uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB,
|
||||
PADS_BANK0_GPIO0_SLEWFAST_BITS
|
||||
);
|
||||
|
||||
sm_config_set_out_pins(&sm_config, state->spi_config->data_out_pin, 1);
|
||||
sm_config_set_in_pins(&sm_config, state->spi_config->data_in_pin);
|
||||
sm_config_set_set_pins(&sm_config, state->spi_config->data_out_pin, 1);
|
||||
sm_config_set_sideset(&sm_config, 1, false, false);
|
||||
sm_config_set_sideset_pins(&sm_config, state->spi_config->clock_pin);
|
||||
|
||||
sm_config_set_in_shift(&sm_config, false, true, 8);
|
||||
sm_config_set_out_shift(&sm_config, false, true, 8);
|
||||
hw_set_bits(&state->pio->input_sync_bypass, 1u << state->spi_config->data_in_pin);
|
||||
pio_sm_set_config(state->pio, state->pio_sm, &sm_config);
|
||||
pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->clock_pin, 1, true);
|
||||
gpio_set_function(state->spi_config->data_out_pin, state->pio_func_sel);
|
||||
gpio_set_function(state->spi_config->clock_pin, state->pio_func_sel);
|
||||
|
||||
// Set data pin to pull down and schmitt
|
||||
gpio_set_pulls(state->spi_config->data_in_pin, false, true);
|
||||
gpio_set_input_hysteresis_enabled(state->spi_config->data_in_pin, true);
|
||||
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 1));
|
||||
|
||||
state->dma_out = (int8_t) dma_claim_unused_channel(false); // todo: Should be able to use one dma channel?
|
||||
state->dma_in = (int8_t) dma_claim_unused_channel(false);
|
||||
if (state->dma_out < 0 || state->dma_in < 0) {
|
||||
wiznet_pio_spi_close(&state->funcs);
|
||||
return NULL;
|
||||
}
|
||||
return &state->funcs;
|
||||
}
|
||||
|
||||
void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle) {
|
||||
wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle;
|
||||
if (state) {
|
||||
if (state->pio_sm >= 0) {
|
||||
if (state->pio_offset != -1) {
|
||||
pio_remove_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC, state->pio_offset);
|
||||
}
|
||||
|
||||
pio_sm_unclaim(state->pio, state->pio_sm);
|
||||
}
|
||||
if (state->dma_out >= 0) {
|
||||
dma_channel_unclaim(state->dma_out);
|
||||
state->dma_out = -1;
|
||||
}
|
||||
if (state->dma_in >= 0) {
|
||||
dma_channel_unclaim(state->dma_in);
|
||||
state->dma_in = -1;
|
||||
}
|
||||
state->funcs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void cs_set(wiznet_pio_spi_state_t *state, bool value) {
|
||||
gpio_put(state->spi_config->cs_pin, value);
|
||||
}
|
||||
|
||||
static __noinline void ns_delay(uint32_t ns) {
|
||||
// cycles = ns * clk_sys_hz / 1,000,000,000
|
||||
uint32_t cycles = ns * (clock_get_hz(clk_sys) >> 16u) / (1000000000u >> 16u);
|
||||
busy_wait_at_least_cycles(cycles);
|
||||
}
|
||||
|
||||
static void wiznet_pio_spi_frame_start(void) {
|
||||
assert(active_state);
|
||||
|
||||
gpio_set_function(active_state->spi_config->data_out_pin, active_state->pio_func_sel);
|
||||
gpio_set_function(active_state->spi_config->clock_pin, active_state->pio_func_sel);
|
||||
gpio_pull_down(active_state->spi_config->clock_pin);
|
||||
|
||||
// Pull CS low
|
||||
cs_set(active_state, false);
|
||||
}
|
||||
|
||||
static void wiznet_pio_spi_frame_end(void) {
|
||||
assert(active_state);
|
||||
|
||||
// from this point a positive edge will cause an IRQ to be pending
|
||||
cs_set(active_state, true);
|
||||
|
||||
// we need to wait a bit in case the irq line is incorrectly high
|
||||
#ifdef IRQ_SAMPLE_DELAY_NS
|
||||
ns_delay(IRQ_SAMPLE_DELAY_NS);
|
||||
#endif
|
||||
}
|
||||
|
||||
// send tx then receive rx
|
||||
// rx can be null if you just want to send, but tx and tx_length must be valid
|
||||
bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length) {
|
||||
const wiznet_pio_spi_state_t *state = active_state;
|
||||
if (!state || (tx == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rx != NULL && tx != NULL) {
|
||||
assert(tx && tx_length && rx_length);
|
||||
|
||||
pio_sm_set_enabled(state->pio, state->pio_sm, false); // disable sm
|
||||
pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_READ_END - 1);
|
||||
pio_sm_clear_fifos(state->pio, state->pio_sm); // clear fifos from previous run
|
||||
pio_sm_set_pindirs_with_mask(state->pio, state->pio_sm, 1u << state->spi_config->data_out_pin, 1u << state->spi_config->data_out_pin);
|
||||
pio_sm_restart(state->pio, state->pio_sm);
|
||||
pio_sm_clkdiv_restart(state->pio, state->pio_sm);
|
||||
pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1); // set x
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32));
|
||||
pio_sm_put(state->pio, state->pio_sm, rx_length - 1); // set y
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32));
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset)); // setup pc
|
||||
dma_channel_abort(state->dma_out);
|
||||
dma_channel_abort(state->dma_in);
|
||||
|
||||
dma_channel_config out_config = dma_channel_get_default_config(state->dma_out);
|
||||
channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true));
|
||||
channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8);
|
||||
dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true);
|
||||
|
||||
dma_channel_config in_config = dma_channel_get_default_config(state->dma_in);
|
||||
channel_config_set_dreq(&in_config, pio_get_dreq(state->pio, state->pio_sm, false));
|
||||
channel_config_set_write_increment(&in_config, true);
|
||||
channel_config_set_read_increment(&in_config, false);
|
||||
channel_config_set_transfer_data_size(&in_config, DMA_SIZE_8);
|
||||
dma_channel_configure(state->dma_in, &in_config, rx, &state->pio->rxf[state->pio_sm], rx_length, true);
|
||||
|
||||
pio_sm_set_enabled(state->pio, state->pio_sm, true);
|
||||
__compiler_memory_barrier();
|
||||
|
||||
dma_channel_wait_for_finish_blocking(state->dma_out);
|
||||
dma_channel_wait_for_finish_blocking(state->dma_in);
|
||||
|
||||
__compiler_memory_barrier();
|
||||
} else if (tx != NULL) {
|
||||
assert(tx_length);
|
||||
|
||||
pio_sm_set_enabled(state->pio, state->pio_sm, false);
|
||||
pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_END - 1);
|
||||
pio_sm_clear_fifos(state->pio, state->pio_sm);
|
||||
pio_sm_restart(state->pio, state->pio_sm);
|
||||
pio_sm_clkdiv_restart(state->pio, state->pio_sm);
|
||||
pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1);
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32));
|
||||
pio_sm_put(state->pio, state->pio_sm, tx_length - 1);
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32));
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 0));
|
||||
pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_out_pin, 1, true);
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS));
|
||||
dma_channel_abort(state->dma_out);
|
||||
|
||||
dma_channel_config out_config = dma_channel_get_default_config(state->dma_out);
|
||||
channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true));
|
||||
|
||||
channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8);
|
||||
dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true);
|
||||
|
||||
const uint32_t fDebugTxStall = 1u << (PIO_FDEBUG_TXSTALL_LSB + state->pio_sm);
|
||||
state->pio->fdebug = fDebugTxStall;
|
||||
pio_sm_set_enabled(state->pio, state->pio_sm, true);
|
||||
while (!(state->pio->fdebug & fDebugTxStall)) {
|
||||
tight_loop_contents(); // todo timeout
|
||||
}
|
||||
__compiler_memory_barrier();
|
||||
pio_sm_set_enabled(state->pio, state->pio_sm, false);
|
||||
pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_in_pin, 1, false);
|
||||
} else if (rx != NULL) {
|
||||
panic_unsupported(); // shouldn't be used
|
||||
}
|
||||
pio_sm_exec(state->pio, state->pio_sm, pio_encode_mov(pio_pins, pio_null)); // for next time we turn output on
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// To read a byte we must first have been asked to write a 3 byte spi header
|
||||
static uint8_t wiznet_pio_spi_read_byte(void) {
|
||||
assert(active_state);
|
||||
assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN);
|
||||
uint8_t ret;
|
||||
if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, &ret, 1)) {
|
||||
panic("spi failed read");
|
||||
}
|
||||
active_state->spi_header_count = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This is not used when the burst functions are provided
|
||||
static void wiznet_pio_spi_write_byte(uint8_t wb) {
|
||||
panic_unsupported(); // shouldn't be used
|
||||
}
|
||||
|
||||
// To read a buffer we must first have been asked to write a 3 byte spi header
|
||||
void wiznet_pio_spi_read_buffer(uint8_t* pBuf, uint16_t len) {
|
||||
|
||||
assert(active_state);
|
||||
assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN);
|
||||
if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, pBuf, len)) {
|
||||
panic("spi failed reading buffer");
|
||||
}
|
||||
active_state->spi_header_count = 0;
|
||||
}
|
||||
|
||||
// If we have been asked to write a spi header already, then write it and the rest of the buffer
|
||||
// or else if we've been given enough data for just the spi header, save it until the next call
|
||||
// or we're writing a byte in which case we're given a buffer including the spi header
|
||||
void wiznet_pio_spi_write_buffer(const uint8_t* pBuf, uint16_t len) {
|
||||
assert(active_state);
|
||||
if (len == WIZNET_PIO_SPI_HEADER_LEN && active_state->spi_header_count == 0) {
|
||||
memcpy(active_state->spi_header, pBuf, WIZNET_PIO_SPI_HEADER_LEN); // expect another call
|
||||
active_state->spi_header_count = WIZNET_PIO_SPI_HEADER_LEN;
|
||||
} else {
|
||||
if (active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN) {
|
||||
if (!wiznet_pio_spi_transfer(active_state->spi_header, WIZNET_PIO_SPI_HEADER_LEN, NULL, 0)) {
|
||||
panic("spi failed writing header");
|
||||
}
|
||||
active_state->spi_header_count = 0;
|
||||
}
|
||||
assert(active_state->spi_header_count == 0);
|
||||
if (!wiznet_pio_spi_transfer(pBuf, len, NULL, 0)) {
|
||||
panic("spi failed writing buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wiznet_pio_spi_set_active(wiznet_pio_spi_handle_t handle) {
|
||||
active_state = (wiznet_pio_spi_state_t *)handle;
|
||||
}
|
||||
|
||||
static void wiznet_pio_spi_set_inactive(void) {
|
||||
active_state = NULL;
|
||||
}
|
||||
|
||||
static void wiznet_pio_spi_reset(wiznet_pio_spi_handle_t handle) {
|
||||
wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle;
|
||||
gpio_set_dir(state->spi_config->reset_pin, GPIO_OUT);
|
||||
gpio_put(state->spi_config->reset_pin, 0);
|
||||
sleep_ms(100);
|
||||
gpio_put(state->spi_config->reset_pin, 1);
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void) {
|
||||
static wiznet_pio_spi_funcs_t funcs = {
|
||||
.close = wiznet_pio_spi_close,
|
||||
.set_active = wiznet_pio_spi_set_active,
|
||||
.set_inactive = wiznet_pio_spi_set_inactive,
|
||||
.frame_start = wiznet_pio_spi_frame_start,
|
||||
.frame_end = wiznet_pio_spi_frame_end,
|
||||
.read_byte = wiznet_pio_spi_read_byte,
|
||||
.write_byte = wiznet_pio_spi_write_byte,
|
||||
.read_buffer = wiznet_pio_spi_read_buffer,
|
||||
.write_buffer = wiznet_pio_spi_write_buffer,
|
||||
.reset = wiznet_pio_spi_reset,
|
||||
};
|
||||
return &funcs;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (c) 2024 WIZnet Co., Ltd.
|
||||
Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _WIZNET_PIO_SPI_H_
|
||||
#define _WIZNET_PIO_SPI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct wiznet_pio_spi_config {
|
||||
uint8_t data_in_pin;
|
||||
uint8_t data_out_pin;
|
||||
uint8_t cs_pin;
|
||||
uint8_t clock_pin;
|
||||
uint8_t irq_pin;
|
||||
uint8_t reset_pin;
|
||||
uint16_t clock_div_major;
|
||||
uint8_t clock_div_minor;
|
||||
uint8_t spi_hw_instance;
|
||||
} wiznet_pio_spi_config_t;
|
||||
|
||||
typedef struct wiznet_pio_spi_funcs** wiznet_pio_spi_handle_t;
|
||||
|
||||
typedef struct wiznet_pio_spi_funcs {
|
||||
void (*close)(wiznet_pio_spi_handle_t funcs);
|
||||
void (*set_active)(wiznet_pio_spi_handle_t funcs);
|
||||
void (*set_inactive)(void);
|
||||
void (*frame_start)(void);
|
||||
void (*frame_end)(void);
|
||||
uint8_t (*read_byte)(void);
|
||||
void (*write_byte)(uint8_t tx_data);
|
||||
void (*read_buffer)(uint8_t *pBuf, uint16_t len);
|
||||
void (*write_buffer)(const uint8_t *pBuf, uint16_t len);
|
||||
void (*reset)(wiznet_pio_spi_handle_t funcs);
|
||||
} wiznet_pio_spi_funcs_t;
|
||||
|
||||
wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *pio_spi_config);
|
||||
void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle);
|
||||
bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length);
|
||||
void wiznet_pio_spi_read_buffer(uint8_t* pBuf, uint16_t len);
|
||||
void wiznet_pio_spi_write_buffer(const uint8_t* pBuf, uint16_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
;
|
||||
; Copyright (c) 2024 WIZnet Co., Ltd.
|
||||
; Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program wiznet_pio_spi_write_read
|
||||
.side_set 1
|
||||
|
||||
public write_bits:
|
||||
out pins, 1 side 0
|
||||
jmp x-- write_bits side 1
|
||||
set pins 0 side 0
|
||||
public write_end:
|
||||
read_byte_delay:
|
||||
set pindirs 0 side 0
|
||||
read_byte:
|
||||
set x 6 side 1
|
||||
read_bits:
|
||||
in pins, 1 side 0
|
||||
jmp x-- read_bits side 1
|
||||
in pins, 1 side 0
|
||||
jmp y-- read_byte side 0
|
||||
public read_end:
|
||||
@@ -0,0 +1,50 @@
|
||||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------------------------- //
|
||||
// wiznet_pio_spi_write_read //
|
||||
// ------------------------- //
|
||||
|
||||
#define wiznet_pio_spi_write_read_wrap_target 0
|
||||
#define wiznet_pio_spi_write_read_wrap 8
|
||||
|
||||
#define wiznet_pio_spi_write_read_offset_write_bits 0u
|
||||
#define wiznet_pio_spi_write_read_offset_write_end 3u
|
||||
#define wiznet_pio_spi_write_read_offset_read_end 9u
|
||||
|
||||
static const uint16_t wiznet_pio_spi_write_read_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0x6001, // 0: out pins, 1 side 0
|
||||
0x1040, // 1: jmp x--, 0 side 1
|
||||
0xe000, // 2: set pins, 0 side 0
|
||||
0xe080, // 3: set pindirs, 0 side 0
|
||||
0xf026, // 4: set x, 6 side 1
|
||||
0x4001, // 5: in pins, 1 side 0
|
||||
0x1045, // 6: jmp x--, 5 side 1
|
||||
0x4001, // 7: in pins, 1 side 0
|
||||
0x0084, // 8: jmp y--, 4 side 0
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program wiznet_pio_spi_write_read_program = {
|
||||
.instructions = wiznet_pio_spi_write_read_program_instructions,
|
||||
.length = 9,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config wiznet_pio_spi_write_read_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + wiznet_pio_spi_write_read_wrap_target, offset + wiznet_pio_spi_write_read_wrap);
|
||||
sm_config_set_sideset(&c, 1, false, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// This sketch will cycle thru some possible restart reasons and shall help you understanding the rp2040.getResetReason() function
|
||||
// Author: palmerr23
|
||||
|
||||
#include <EEPROM.h>
|
||||
#define NTESTS 5 // Number of tests, Debug port test not enabled
|
||||
char resetReasonText[][24] = { "Unknown", "Power On / Brownout", "Run pin", "Software", "Watchdog Timer", "Debug reset" };
|
||||
char testText[][128] = { "Run pin\n\tShort Run pin to ground", "Power On / Brownout\n\tDisconnect / reconnect power (i.e. USB)", "Software reBOOT in 5 Secs", "Watchdog Timer in 7 Secs", "Software reSTART in 5 Secs\n\tUSB Serial does not always restart", "Debug port - do something!" };
|
||||
|
||||
// Small function that will send one dot every second over Serial, forever.
|
||||
void delayCount(void) {
|
||||
int t = 1;
|
||||
while (1) {
|
||||
Serial.print(".");
|
||||
if (t % 50 == 0) {
|
||||
Serial.println();
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) {
|
||||
delay(10);
|
||||
}
|
||||
delay(1000);
|
||||
Serial.println("Reset reason:");
|
||||
|
||||
RP2040::resetReason_t rr = rp2040.getResetReason();
|
||||
Serial.printf("RR %i %s\n\n", rr, resetReasonText[rr]);
|
||||
|
||||
EEPROM.begin(512);
|
||||
byte test = EEPROM.read(0);
|
||||
if (test >= NTESTS) { // un-initialised EEPROM read is random
|
||||
test = -1;
|
||||
}
|
||||
test = (test + 1) % NTESTS; // Go to next test, but limit to NTESTS-1
|
||||
Serial.printf("Test %i: %s\n", test, testText[test]);
|
||||
EEPROM.write(0, test);
|
||||
EEPROM.commit();
|
||||
delay(5000);
|
||||
switch (test) {
|
||||
case 0: // Run pin
|
||||
delayCount();
|
||||
break; // Break to avoid compiler warnings
|
||||
case 1: // Power On
|
||||
delayCount();
|
||||
break;
|
||||
case 2: // reboot command
|
||||
rp2040.reboot();
|
||||
delayCount();
|
||||
break;
|
||||
case 3: // watchdog
|
||||
rp2040.wdt_begin(2000);
|
||||
rp2040.wdt_reset();
|
||||
delayCount();
|
||||
break;
|
||||
case 4: // restart command
|
||||
rp2040.restart();
|
||||
delayCount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// never gets here
|
||||
void loop() {
|
||||
delay(100);
|
||||
}
|
||||
+12
-3
@@ -9,12 +9,21 @@ if (${cpu} MATCHES "rp2040")
|
||||
set(PICO_CYW43_SUPPORTED 0)
|
||||
set(OBJARCH armv6-m)
|
||||
set(WRAP -Wl,--wrap=clocks_init)
|
||||
elseif(${cpu} MATCHES "rp2350")
|
||||
set(TUPLE arm-none-eabi)
|
||||
elseif(${cpu} MATCHES "rp2350$")
|
||||
set(PICO_BOARD pico2)
|
||||
set(PICO_PLATFORM rp2350)
|
||||
set(PICO_CYW43_SUPPORTED 0)
|
||||
set(OBJARCH armv8-m)
|
||||
set(WRAP )
|
||||
set(TUPLE arm-none-eabi)
|
||||
elseif(${cpu} MATCHES "rp2350-riscv$")
|
||||
set(PICO_BOARD pico2)
|
||||
set(PICO_PLATFORM rp2350-riscv)
|
||||
set(PICO_CYW43_SUPPORTED 0)
|
||||
set(OBJARCH rv32imac_zicsr_zifencei_zba_zbb_zbs_zbkb)
|
||||
set(WRAP )
|
||||
set(TUPLE riscv32-unknown-elf)
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown CPU, '${cpu}'")
|
||||
endif()
|
||||
@@ -101,7 +110,7 @@ target_link_libraries(ota
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ota POST_BUILD
|
||||
COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-ld -r -A ${OBJARCH} -b binary -o ota.o ota.bin
|
||||
COMMAND ../../system/arm-none-eabi/bin/arm-none-eabi-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o
|
||||
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-ld -r -A ${OBJARCH} -b binary -o ota.o ota.bin
|
||||
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o
|
||||
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user