diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml
index 7b97e1753..b5b4cb6f3 100644
--- a/.github/actions/setup-base/action.yml
+++ b/.github/actions/setup-base/action.yml
@@ -5,37 +5,25 @@ runs:
using: "composite"
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- - name: Install cppcheck
+ - name: Install dependencies
shell: bash
run: |
- sudo apt-get install -y cppcheck
-
- - name: Install libbluetooth
- shell: bash
- run: |
- sudo apt-get install -y libbluetooth-dev
- - name: Install libgpiod
- shell: bash
- run: |
- sudo apt-get install -y libgpiod-dev
- - name: Install libyaml-cpp
- shell: bash
- run: |
- sudo apt-get install -y libyaml-cpp-dev
+ sudo apt-get -y update
+ sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev
- name: Setup Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
diff --git a/.github/workflows/build_esp32.yml b/.github/workflows/build_esp32.yml
index 31f0dd5a0..4cbb4c7a4 100644
--- a/.github/workflows/build_esp32.yml
+++ b/.github/workflows/build_esp32.yml
@@ -11,13 +11,13 @@ jobs:
build-esp32:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
@@ -41,7 +41,7 @@ jobs:
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware.bin
@@ -54,9 +54,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/*.bin
release/*.elf
diff --git a/.github/workflows/build_esp32_c3.yml b/.github/workflows/build_esp32_c3.yml
index a30cf33f1..07727d711 100644
--- a/.github/workflows/build_esp32_c3.yml
+++ b/.github/workflows/build_esp32_c3.yml
@@ -13,13 +13,13 @@ jobs:
build-esp32-c3:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
@@ -41,7 +41,7 @@ jobs:
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-c3.bin
@@ -54,9 +54,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/*.bin
release/*.elf
diff --git a/.github/workflows/build_esp32_s3.yml b/.github/workflows/build_esp32_s3.yml
index f603a6a31..10773833e 100644
--- a/.github/workflows/build_esp32_s3.yml
+++ b/.github/workflows/build_esp32_s3.yml
@@ -11,13 +11,13 @@ jobs:
build-esp32-s3:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
@@ -39,7 +39,7 @@ jobs:
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-s3.bin
@@ -52,9 +52,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/*.bin
release/*.elf
diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml
new file mode 100644
index 000000000..8fe8e6c31
--- /dev/null
+++ b/.github/workflows/build_native.yml
@@ -0,0 +1,85 @@
+name: Build Native
+
+on: workflow_call
+
+permissions:
+ contents: write
+ packages: write
+
+jobs:
+ build-native:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install libbluetooth
+ shell: bash
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+
+ - name: Upgrade python tools
+ shell: bash
+ run: |
+ python -m pip install --upgrade pip
+ pip install -U platformio adafruit-nrfutil
+ pip install -U meshtastic --pre
+
+ - name: Upgrade platformio
+ shell: bash
+ run: |
+ pio upgrade
+
+ - name: Build Native
+ run: bin/build-native.sh
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Store binaries as an artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: firmware-native-${{ steps.version.outputs.version }}.zip
+ overwrite: true
+ path: |
+ release/meshtasticd_linux_x86_64
+ bin/config-dist.yaml
+
+ - name: Docker login
+ if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
+ uses: docker/login-action@v3
+ continue-on-error: true # FIXME: Failing docker login auth
+ with:
+ username: meshtastic
+ password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
+
+ - name: Docker setup
+ if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
+ continue-on-error: true # FIXME: Failing docker login auth
+ uses: docker/setup-buildx-action@v3
+
+ - name: Docker build and push tagged versions
+ if: ${{ github.event_name == 'workflow_dispatch' }}
+ continue-on-error: true # FIXME: Failing docker login auth
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./Dockerfile
+ push: true
+ tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
+
+ - name: Docker build and push
+ if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
+ continue-on-error: true # FIXME: Failing docker login auth
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./Dockerfile
+ push: true
+ tags: meshtastic/device-simulator:latest
diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml
index 33ee4d00c..eb1779963 100644
--- a/.github/workflows/build_nrf52.yml
+++ b/.github/workflows/build_nrf52.yml
@@ -11,7 +11,7 @@ jobs:
build-nrf52:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
@@ -24,9 +24,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/*.uf2
release/*.elf
diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml
index 7a25892bc..697d08727 100644
--- a/.github/workflows/build_raspbian.yml
+++ b/.github/workflows/build_raspbian.yml
@@ -10,8 +10,13 @@ jobs:
build-raspbian:
runs-on: [self-hosted, linux, ARM64]
steps:
+ - name: Install libbluetooth
+ shell: bash
+ run: |
+ apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
+
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
@@ -37,9 +42,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/meshtasticd_linux_aarch64
bin/config-dist.yaml
diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml
new file mode 100644
index 000000000..ee5eb66eb
--- /dev/null
+++ b/.github/workflows/build_raspbian_armv7l.yml
@@ -0,0 +1,51 @@
+name: Build Raspbian Arm
+
+on: workflow_call
+
+permissions:
+ contents: write
+ packages: write
+
+jobs:
+ build-raspbian-armv7l:
+ runs-on: [self-hosted, linux, ARM]
+ steps:
+ - name: Install libbluetooth
+ shell: bash
+ run: |
+ apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+
+ - name: Upgrade python tools
+ shell: bash
+ run: |
+ python -m pip install --upgrade pip
+ pip install -U platformio adafruit-nrfutil
+ pip install -U meshtastic --pre
+
+ - name: Upgrade platformio
+ shell: bash
+ run: |
+ pio upgrade
+
+ - name: Build Raspbian
+ run: bin/build-native.sh
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Store binaries as an artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: firmware-raspbian-armv7l-${{ steps.version.outputs.version }}.zip
+ overwrite: true
+ path: |
+ release/meshtasticd_linux_armv7l
+ bin/config-dist.yaml
diff --git a/.github/workflows/build_rpi2040.yml b/.github/workflows/build_rpi2040.yml
index 76ca2c20e..6e258fe2a 100644
--- a/.github/workflows/build_rpi2040.yml
+++ b/.github/workflows/build_rpi2040.yml
@@ -11,7 +11,7 @@ jobs:
build-rpi2040:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
@@ -24,9 +24,10 @@ jobs:
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: |
release/*.uf2
release/*.elf
diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index 9ca0764b5..89b71acb8 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -8,7 +8,7 @@ on:
branches: [master, develop]
paths-ignore:
- "**.md"
- - "version.properties"
+ - version.properties
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
@@ -20,209 +20,104 @@ on:
workflow_dispatch:
jobs:
- check:
+ setup:
strategy:
fail-fast: false
matrix:
- include:
- - board: rak11200
- - board: tlora-v2-1-1_6
- - board: tbeam
- - board: heltec-v2_1
- - board: meshtastic-diy-v1
- - board: rak4631
- - board: t-echo
- - board: station-g2
- - board: m5stack-coreink
- - board: tbeam-s3-core
- - board: tlora-t3s3-v1
- - board: t-watch-s3
- - board: t-deck
- #- board: rak11310
+ arch: [esp32, esp32s3, esp32c3, nrf52840, rp2040, check]
+ runs-on: ubuntu-latest
+ steps:
+ - id: checkout
+ uses: actions/checkout@v4
+ name: Checkout base
+ - id: jsonStep
+ run: |
+ TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
+ echo "$TARGETS"
+ echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
+ outputs:
+ esp32: ${{ steps.jsonStep.outputs.esp32 }}
+ esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
+ esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
+ nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
+ rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
+ check: ${{ steps.jsonStep.outputs.check }}
+
+ check:
+ needs: setup
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
-
- - name: Trunk Check
- if: ${{ github.event_name != 'workflow_dispatch' }}
- uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
-
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
build-esp32:
+ needs: setup
strategy:
fail-fast: false
- matrix:
- include:
- - board: rak11200
- - board: tlora-v2
- - board: tlora-v1
- - board: tlora_v1_3
- - board: tlora-v2-1-1_6
- - board: tlora-v2-1-1_6-tcxo
- - board: tlora-v2-1-1_8
- - board: tbeam
- - board: heltec-v2_0
- - board: heltec-v2_1
- - board: tbeam0_7
- - board: meshtastic-diy-v1
- - board: hydra
- - board: meshtastic-dr-dev
- - board: nano-g1
- - board: station-g1
- - board: m5stack-core
- - board: m5stack-coreink
- - board: nano-g1-explorer
- - board: chatter2
+ matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
uses: ./.github/workflows/build_esp32.yml
with:
board: ${{ matrix.board }}
build-esp32-s3:
+ needs: setup
strategy:
fail-fast: false
- matrix:
- include:
- - board: heltec-v3
- - board: heltec-wsl-v3
- - board: heltec-wireless-tracker
- - board: heltec-wireless-tracker-V1-0
- - board: heltec-wireless-paper-v1_0
- - board: heltec-wireless-paper #v1.1
- - board: tbeam-s3-core
- - board: tlora-t3s3-v1
- - board: t-watch-s3
- - board: t-deck
- - board: picomputer-s3
- - board: station-g2
- - board: unphone
+ matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
uses: ./.github/workflows/build_esp32_s3.yml
with:
board: ${{ matrix.board }}
build-esp32-c3:
+ needs: setup
strategy:
fail-fast: false
- matrix:
- include:
- - board: heltec-ht62-esp32c3-sx1262
+ matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
uses: ./.github/workflows/build_esp32_c3.yml
with:
board: ${{ matrix.board }}
build-nrf52:
+ needs: setup
strategy:
fail-fast: false
- matrix:
- include:
- - board: rak4631
- - board: rak4631_eink
- - board: monteops_hw1
- - board: t-echo
- - board: canaryone
- - board: pca10059_diy_eink
- - board: feather_diy
- - board: nano-g2-ultra
+ matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
uses: ./.github/workflows/build_nrf52.yml
with:
board: ${{ matrix.board }}
build-rpi2040:
+ needs: setup
strategy:
fail-fast: false
- matrix:
- include:
- - board: pico
- - board: picow
- - board: rak11310
- - board: senselora_rp2040
- - board: rp2040-lora
+ matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
uses: ./.github/workflows/build_rpi2040.yml
with:
board: ${{ matrix.board }}
- build-raspbian:
- strategy:
- fail-fast: false
- max-parallel: 1
- uses: ./.github/workflows/build_raspbian.yml
-
package-raspbian:
uses: ./.github/workflows/package_raspbian.yml
- build-native:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - name: Build base
- id: base
- uses: ./.github/actions/setup-base
+ package-raspbian-armv7l:
+ uses: ./.github/workflows/package_raspbian_armv7l.yml
- # We now run integration test before other build steps (to quickly see runtime failures)
- #- name: Build for native
- # run: platformio run -e native
- #- name: Integration test
- # run: |
- #.pio/build/native/program
- #& sleep 20 # 5 seconds was not enough
- #echo "Simulator started, launching python test..."
- #python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
-
- - name: Build Native
- run: bin/build-native.sh
-
- - name: Get release version string
- run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
- id: version
-
- - name: Store binaries as an artifact
- uses: actions/upload-artifact@v3
- with:
- name: firmware-native-${{ steps.version.outputs.version }}.zip
- path: |
- release/device-*.sh
- release/device-*.bat
-
- - name: Docker login
- if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
- uses: docker/login-action@v2
- with:
- username: meshtastic
- password: ${{ secrets.DOCKER_TOKEN }}
-
- - name: Docker setup
- if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
- uses: docker/setup-buildx-action@v2
-
- - name: Docker build and push tagged versions
- if: ${{ github.event_name == 'workflow_dispatch' }}
- uses: docker/build-push-action@v3
- with:
- context: .
- file: ./Dockerfile
- push: true
- tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
-
- - name: Docker build and push
- if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
- uses: docker/build-push-action@v3
- with:
- context: .
- file: ./Dockerfile
- push: true
- tags: meshtastic/device-simulator:latest
+ package-native:
+ uses: ./.github/workflows/package_amd64.yml
after-checks:
runs-on: ubuntu-latest
needs: [check]
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -238,21 +133,22 @@ jobs:
build-esp32-s3,
build-esp32-c3,
build-nrf52,
- build-raspbian,
- build-native,
build-rpi2040,
package-raspbian,
+ package-raspbian-armv7l,
+ package-native
]
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
path: ./
+ merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
@@ -262,25 +158,30 @@ jobs:
id: version
- name: Move files up
- run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./*esp32c3*/bleota-c3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
+ run: mv -b -t ./ ./release/meshtasticd_linux_* ./bin/config-dist.yaml ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firmware-${{ steps.version.outputs.version }}
+ overwrite: true
path: |
- ./*.bin
- ./*.uf2
+ ./firmware-*.bin
+ ./firmware-*.uf2
./firmware-*-ota.zip
./device-*.sh
./device-*.bat
- ./meshtasticd_linux_arm64
+ ./meshtasticd_linux_*
./config-dist.yaml
+ ./littlefs-*.bin
+ ./bleota*bin
+ ./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 90
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
name: firmware-${{ steps.version.outputs.version }}
+ merge-multiple: true
path: ./output
# For diagnostics
@@ -296,9 +197,10 @@ jobs:
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- name: Repackage in single elfs zip
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
+ overwrite: true
path: ./*.elf
retention-days: 30
@@ -320,10 +222,10 @@ jobs:
needs: [gather-artifacts, after-checks]
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.x
@@ -331,14 +233,17 @@ jobs:
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
name: firmware-${{ steps.version.outputs.version }}
+ merge-multiple: true
path: ./output
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
- name: artifact-deb
+ pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
+ merge-multiple: true
+ path: ./output
- name: Display structure of downloaded files
run: ls -R
@@ -351,9 +256,10 @@ jobs:
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- - uses: actions/download-artifact@v3
+ - uses: actions/download-artifact@v4
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
+ merge-multiple: true
path: ./elfs
- name: Zip Elfs
@@ -396,22 +302,42 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- - name: Add raspbian .deb
+ - name: Add raspbian aarch64 .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
- asset_path: ./meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
+ asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_content_type: application/vnd.debian.binary-package
+ - name: Add raspbian armv7l .deb
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
+ asset_name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
+ asset_content_type: application/vnd.debian.binary-package
+
+ - name: Add raspbian amd64 .deb
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
+ asset_name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
+ asset_content_type: application/vnd.debian.binary-package
+
- name: Bump version.properties
run: >-
bin/bump_version.py
- name: Create version.properties pull request
- uses: peter-evans/create-pull-request@v3
+ uses: peter-evans/create-pull-request@v6
with:
add-paths: |
version.properties
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index da59bc0fd..e249823a7 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Trunk Check
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml
new file mode 100644
index 000000000..ae7bf3242
--- /dev/null
+++ b/.github/workflows/package_amd64.yml
@@ -0,0 +1,78 @@
+name: Package Native
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ packages: write
+
+jobs:
+ build-native:
+ uses: ./.github/workflows/build_native.yml
+
+ package-native:
+ runs-on: ubuntu-latest
+ needs: build-native
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+
+ - name: Pull web ui
+ uses: dsaltares/fetch-gh-release-asset@master
+ with:
+ repo: meshtastic/web
+ file: build.tar
+ target: build.tar
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: firmware-native-${{ steps.version.outputs.version }}.zip
+ merge-multiple: true
+
+ - name: Display structure of downloaded files
+ run: ls -R
+
+ - name: build .debpkg
+ run: |
+ mkdir -p .debpkg/DEBIAN
+ mkdir -p .debpkg/usr/share/doc/meshtasticd/web
+ mkdir -p .debpkg/usr/sbin
+ mkdir -p .debpkg/etc/meshtasticd
+ mkdir -p .debpkg/usr/lib/systemd/system/
+ tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
+ gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
+ cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd
+ cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
+ chmod +x .debpkg/usr/sbin/meshtasticd
+ cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
+ echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
+ chmod +x .debpkg/DEBIAN/conffiles
+
+ - uses: jiro4989/build-deb-action@v3
+ with:
+ package: meshtasticd
+ package_root: .debpkg
+ maintainer: Jonathan Bennett
+ version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
+ arch: amd64
+ depends: libyaml-cpp0.7, openssl, libulfius2.7
+ desc: Native Linux Meshtastic binary.
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
+ overwrite: true
+ path: |
+ ./*.deb
diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml
index 81ff6ee25..5471332c5 100644
--- a/.github/workflows/package_raspbian.yml
+++ b/.github/workflows/package_raspbian.yml
@@ -17,14 +17,14 @@ jobs:
needs: build-raspbian
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Pull web ui
- uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
@@ -36,16 +36,17 @@ jobs:
id: version
- name: Download artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
+ merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: build .debpkg
run: |
- mkdir -p .debpkg/debian
+ mkdir -p .debpkg/DEBIAN
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
@@ -56,7 +57,8 @@ jobs:
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
- echo "etc/meshtasticd/config.yaml" > .debpkg/debian/conffiles
+ echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
+ chmod +x .debpkg/DEBIAN/conffiles
- uses: jiro4989/build-deb-action@v3
with:
@@ -68,8 +70,9 @@ jobs:
depends: libyaml-cpp0.7, openssl, libulfius2.7
desc: Native Linux Meshtastic binary.
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
- name: artifact-deb
+ name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
+ overwrite: true
path: |
./*.deb
diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml
new file mode 100644
index 000000000..5b9c9aa71
--- /dev/null
+++ b/.github/workflows/package_raspbian_armv7l.yml
@@ -0,0 +1,78 @@
+name: Package Raspbian
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ packages: write
+
+jobs:
+ build-raspbian_armv7l:
+ uses: ./.github/workflows/build_raspbian_armv7l.yml
+
+ package-raspbian_armv7l:
+ runs-on: ubuntu-latest
+ needs: build-raspbian_armv7l
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+
+ - name: Pull web ui
+ uses: dsaltares/fetch-gh-release-asset@master
+ with:
+ repo: meshtastic/web
+ file: build.tar
+ target: build.tar
+ token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: firmware-raspbian-armv7l-${{ steps.version.outputs.version }}.zip
+ merge-multiple: true
+
+ - name: Display structure of downloaded files
+ run: ls -R
+
+ - name: build .debpkg
+ run: |
+ mkdir -p .debpkg/DEBIAN
+ mkdir -p .debpkg/usr/share/doc/meshtasticd/web
+ mkdir -p .debpkg/usr/sbin
+ mkdir -p .debpkg/etc/meshtasticd
+ mkdir -p .debpkg/usr/lib/systemd/system/
+ tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
+ gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
+ cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd
+ cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
+ chmod +x .debpkg/usr/sbin/meshtasticd
+ cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
+ echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
+ chmod +x .debpkg/DEBIAN/conffiles
+
+ - uses: jiro4989/build-deb-action@v3
+ with:
+ package: meshtasticd
+ package_root: .debpkg
+ maintainer: Jonathan Bennett
+ version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
+ arch: armhf
+ depends: libyaml-cpp0.7, openssl, libulfius2.7
+ desc: Native Linux Meshtastic binary.
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
+ overwrite: true
+ path: |
+ ./*.deb
diff --git a/.github/workflows/sec_sast_flawfinder.yml b/.github/workflows/sec_sast_flawfinder.yml
index 2c7e751af..99cc72190 100644
--- a/.github/workflows/sec_sast_flawfinder.yml
+++ b/.github/workflows/sec_sast_flawfinder.yml
@@ -16,7 +16,7 @@ jobs:
steps:
# step 1
- name: clone application source code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# step 2
- name: flawfinder_scan
@@ -27,14 +27,15 @@ jobs:
# step 3
- name: save report as pipeline artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: flawfinder_report.sarif
+ overwrite: true
path: flawfinder_report.sarif
# step 4
- name: publish code scanning alerts
- uses: github/codeql-action/upload-sarif@v2
+ uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: flawfinder_report.sarif
category: flawfinder
diff --git a/.github/workflows/sec_sast_semgrep_cron.yml b/.github/workflows/sec_sast_semgrep_cron.yml
index cdd2c3c37..2a0361f5e 100644
--- a/.github/workflows/sec_sast_semgrep_cron.yml
+++ b/.github/workflows/sec_sast_semgrep_cron.yml
@@ -17,7 +17,7 @@ jobs:
steps:
# step 1
- name: clone application source code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# step 2
- name: full scan
@@ -29,14 +29,15 @@ jobs:
# step 3
- name: save report as pipeline artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: report.sarif
+ overwrite: true
path: report.sarif
# step 4
- name: publish code scanning alerts
- uses: github/codeql-action/upload-sarif@v2
+ uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: report.sarif
category: semgrep
diff --git a/.github/workflows/sec_sast_semgrep_pull.yml b/.github/workflows/sec_sast_semgrep_pull.yml
index 1697ffb1b..b6c288494 100644
--- a/.github/workflows/sec_sast_semgrep_pull.yml
+++ b/.github/workflows/sec_sast_semgrep_pull.yml
@@ -11,7 +11,7 @@ jobs:
steps:
# step 1
- name: clone application source code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml
index e35b91cb9..6ed905bc8 100644
--- a/.github/workflows/trunk-check.yml
+++ b/.github/workflows/trunk-check.yml
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Trunk Check
uses: trunk-io/trunk-action@v1
diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml
index 30f9b3578..4402a280e 100644
--- a/.github/workflows/update_protobufs.yml
+++ b/.github/workflows/update_protobufs.yml
@@ -7,7 +7,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
submodules: true
@@ -26,7 +26,7 @@ jobs:
./bin/regen-protos.sh
- name: Create pull request
- uses: peter-evans/create-pull-request@v3
+ uses: peter-evans/create-pull-request@v6
with:
add-paths: |
protobufs
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index 0826b71d9..8a2f18ad5 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -1,32 +1,32 @@
version: 0.1
cli:
- version: 1.20.1
+ version: 1.22.1
plugins:
sources:
- id: trunk
- ref: v1.4.4
+ ref: v1.5.0
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- - trufflehog@3.68.5
+ - trufflehog@3.76.3
- yamllint@1.35.1
- - bandit@1.7.7
- - checkov@3.2.32
+ - bandit@1.7.8
+ - checkov@3.2.95
- terrascan@1.19.1
- - trivy@0.49.1
+ - trivy@0.51.1
#- trufflehog@3.63.2-rc0
- taplo@0.8.1
- - ruff@0.3.1
+ - ruff@0.4.4
- isort@5.13.2
- - markdownlint@0.39.0
- - oxipng@9.0.0
- - svgo@3.2.0
- - actionlint@1.6.27
+ - markdownlint@0.40.0
+ - oxipng@9.1.1
+ - svgo@3.3.2
+ - actionlint@1.7.0
- flake8@7.0.0
- hadolint@2.12.0
- shfmt@3.6.0
- - shellcheck@0.9.0
- - black@24.2.0
+ - shellcheck@0.10.0
+ - black@24.4.2
- git-diff-check
- gitleaks@8.18.2
- clang-format@16.0.3
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 783791f0b..4fc84fa78 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -6,4 +6,4 @@
"platformio.platformio-ide",
"trunk.io"
],
-}
\ No newline at end of file
+}
diff --git a/Dockerfile b/Dockerfile
index fee6c62d4..08cb3925d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -48,6 +48,7 @@ USER mesh
WORKDIR /home/mesh
COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/
+RUN mkdir data
VOLUME /home/mesh/data
CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ]
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index 39935b849..f3eb0cbc0 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -1,7 +1,8 @@
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
-platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch.
+custom_esp32_kind = esp32
+platform = platformio/espressif32@6.7.0
build_src_filter =
${arduino_base.build_src_filter} - - - - -
@@ -15,8 +16,10 @@ board_build.filesystem = littlefs
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
+build_unflags = -fno-lto
build_flags =
${arduino_base.build_flags}
+ -flto
-Wall
-Wextra
-Isrc/platform/esp32
diff --git a/arch/esp32/esp32c3.ini b/arch/esp32/esp32c3.ini
index 619fdb28a..2ba3036d0 100644
--- a/arch/esp32/esp32c3.ini
+++ b/arch/esp32/esp32c3.ini
@@ -1,5 +1,6 @@
[esp32c3_base]
extends = esp32_base
+custom_esp32_kind = esp32c3
monitor_speed = 115200
monitor_filters = esp32_c3_exception_decoder
diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini
index 71b2c1f3b..fe92954a4 100644
--- a/arch/esp32/esp32s2.ini
+++ b/arch/esp32/esp32s2.ini
@@ -1,5 +1,6 @@
[esp32s2_base]
extends = esp32_base
+custom_esp32_kind = esp32s2
build_src_filter =
${esp32_base.build_src_filter} - - -
diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini
index 92382d99f..c53e2f225 100644
--- a/arch/esp32/esp32s3.ini
+++ b/arch/esp32/esp32s3.ini
@@ -1,5 +1,6 @@
[esp32s3_base]
extends = esp32_base
+custom_esp32_kind = esp32s3
monitor_speed = 115200
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index f41ef0edc..1a371e920 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -1,6 +1,6 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
-platform = platformio/nordicnrf52@^10.4.0
+platform = platformio/nordicnrf52@^10.5.0
extends = arduino_base
build_type = debug
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index 63f5576b6..482b1f9c5 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
-platform = https://github.com/meshtastic/platform-native.git#9881bf3721d610cccacf5ae8e3a07839cce75d63
+platform = https://github.com/meshtastic/platform-native.git#ad8112adf82ce1f5b917092cf32be07a077801a0
framework = arduino
build_src_filter =
diff --git a/bin/build-native.sh b/bin/build-native.sh
index 9d31d091a..e8ed61bcf 100755
--- a/bin/build-native.sh
+++ b/bin/build-native.sh
@@ -2,6 +2,17 @@
set -e
+platformioFailed() {
+ [[ $VIRTUAL_ENV != "" ]] && exit 1 # don't hint at virtualenv if it's already in use
+ echo -e "\nThere were issues running platformio and you are not using a virtual environment." \
+ "\nYou may try setting up virtualenv and downloading the latest platformio from pip:" \
+ "\n\tvirtualenv venv" \
+ "\n\tsource venv/bin/activate" \
+ "\n\tpip install platformio" \
+ "\n\t./bin/build-native.sh # retry building"
+ exit 1
+}
+
VERSION=$(bin/buildinfo.py long)
SHORT_VERSION=$(bin/buildinfo.py short)
@@ -13,8 +24,8 @@ mkdir -p $OUTDIR/
rm -r $OUTDIR/* || true
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
-platformio pkg update --environment native
-pio run --environment native
+platformio pkg update --environment native || platformioFailed
+pio run --environment native || platformioFailed
cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(uname -m)"
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR
diff --git a/bin/buildinfo.py b/bin/buildinfo.py
index 6b123c9cf..5aecad1bd 100755
--- a/bin/buildinfo.py
+++ b/bin/buildinfo.py
@@ -1,9 +1,8 @@
#!/usr/bin/env python3
-import configparser
import sys
+
from readprops import readProps
-
-verObj = readProps('version.properties')
+verObj = readProps("version.properties")
propName = sys.argv[1]
print(f"{verObj[propName]}")
diff --git a/bin/generate_ci_matrix.py b/bin/generate_ci_matrix.py
index 2501e83c1..46398dd59 100755
--- a/bin/generate_ci_matrix.py
+++ b/bin/generate_ci_matrix.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-"""Generate the CI matrix"""
+"""Generate the CI matrix."""
import configparser
import json
@@ -34,5 +34,10 @@ for subdir, dirs, files in os.walk(rootdir):
outlist.append(section)
else:
outlist.append(section)
+ if "board_check" in config[config[c].name]:
+ if (config[config[c].name]["board_check"] == "true") & (
+ "check" in options
+ ):
+ outlist.append(section)
print(json.dumps(outlist))
diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py
index e03a35e3a..3202a1e7a 100644
--- a/bin/platformio-custom.py
+++ b/bin/platformio-custom.py
@@ -1,13 +1,14 @@
-import subprocess
-import configparser
-import traceback
+# trunk-ignore-all(ruff/F821)
+# trunk-ignore-all(flake8/F821): For SConstruct imports
import sys
from os.path import join
+
from readprops import readProps
Import("env")
platform = env.PioPlatform()
+
def esp32_create_combined_bin(source, target, env):
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
@@ -20,8 +21,8 @@ def esp32_create_combined_bin(source, target, env):
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
chip = env.get("BOARD_MCU")
flash_size = env.BoardConfig().get("upload.flash_size")
- flash_freq = env.BoardConfig().get("build.f_flash", '40m')
- flash_freq = flash_freq.replace('000000L', 'm')
+ flash_freq = env.BoardConfig().get("build.f_flash", "40m")
+ flash_freq = flash_freq.replace("000000L", "m")
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
if flash_mode == "qio" or flash_mode == "qout":
@@ -51,23 +52,42 @@ def esp32_create_combined_bin(source, target, env):
print(f" - {hex(app_offset)} | {firmware_name}")
cmd += [hex(app_offset), firmware_name]
- print('Using esptool.py arguments: %s' % ' '.join(cmd))
+ print("Using esptool.py arguments: %s" % " ".join(cmd))
esptool.main(cmd)
-if (platform.name == "espressif32"):
+
+if platform.name == "espressif32":
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
import esptool
- env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
+
+ env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
+
+ esp32_kind = env.GetProjectOption("custom_esp32_kind")
+ if esp32_kind == "esp32":
+ # Free up some IRAM by removing auxiliary SPI flash chip drivers.
+ # Wrapped stub symbols are defined in src/platform/esp32/iram-quirk.c.
+ env.Append(
+ LINKFLAGS=[
+ "-Wl,--wrap=esp_flash_chip_gd",
+ "-Wl,--wrap=esp_flash_chip_issi",
+ "-Wl,--wrap=esp_flash_chip_winbond",
+ ]
+ )
+ else:
+ # For newer ESP32 targets, using newlib nano works better.
+ env.Append(LINKFLAGS=["--specs=nano.specs", "-u", "_printf_float"])
Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
verObj = readProps(prefsLoc)
-print("Using meshtastic platformio-custom.py, firmware version " + verObj['long'])
+print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"])
# General options that are passed to the C and C++ compilers
-projenv.Append(CCFLAGS=[
- "-DAPP_VERSION=" + verObj['long'],
- "-DAPP_VERSION_SHORT=" + verObj['short']
-])
+projenv.Append(
+ CCFLAGS=[
+ "-DAPP_VERSION=" + verObj["long"],
+ "-DAPP_VERSION_SHORT=" + verObj["short"],
+ ]
+)
diff --git a/boards/tbeam-s3-core.json b/boards/tbeam-s3-core.json
index 4c82a2789..7bda2e5a0 100644
--- a/boards/tbeam-s3-core.json
+++ b/boards/tbeam-s3-core.json
@@ -7,7 +7,8 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_S3_CORE",
- "-DARDUINO_USB_MODE=1",
+ "-DARDUINO_USB_CDC_ON_BOOT=1",
+ "-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json
new file mode 100644
index 000000000..029c9c085
--- /dev/null
+++ b/boards/wio-sdk-wm1110.json
@@ -0,0 +1,58 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x8029"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"],
+ ["0x239A", "0x802A"]
+ ],
+ "usb_product": "WIO-BOOT",
+ "mcu": "nrf52840",
+ "variant": "Seeed_WIO_WM1110",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "svd_path": "nrf52840.svd"
+ },
+ "frameworks": ["arduino"],
+ "name": "Seeed WIO WM1110",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": [
+ "jlink",
+ "nrfjprog",
+ "nrfutil",
+ "stlink",
+ "cmsis-dap",
+ "blackmagic"
+ ],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ },
+ "url": "https://www.seeedstudio.com/Wio-WM1110-Dev-Kit-p-5677.html",
+ "vendor": "Seeed Studio"
+}
diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json
new file mode 100644
index 000000000..029c9c085
--- /dev/null
+++ b/boards/wio-tracker-wm1110.json
@@ -0,0 +1,58 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "nrf52840_s140_v6.ld"
+ },
+ "core": "nRF5",
+ "cpu": "cortex-m4",
+ "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
+ "f_cpu": "64000000L",
+ "hwids": [
+ ["0x239A", "0x8029"],
+ ["0x239A", "0x0029"],
+ ["0x239A", "0x002A"],
+ ["0x239A", "0x802A"]
+ ],
+ "usb_product": "WIO-BOOT",
+ "mcu": "nrf52840",
+ "variant": "Seeed_WIO_WM1110",
+ "bsp": {
+ "name": "adafruit"
+ },
+ "softdevice": {
+ "sd_flags": "-DS140",
+ "sd_name": "s140",
+ "sd_version": "6.1.1",
+ "sd_fwid": "0x00B6"
+ },
+ "bootloader": {
+ "settings_addr": "0xFF000"
+ }
+ },
+ "connectivity": ["bluetooth"],
+ "debug": {
+ "jlink_device": "nRF52840_xxAA",
+ "svd_path": "nrf52840.svd"
+ },
+ "frameworks": ["arduino"],
+ "name": "Seeed WIO WM1110",
+ "upload": {
+ "maximum_ram_size": 248832,
+ "maximum_size": 815104,
+ "speed": 115200,
+ "protocol": "nrfutil",
+ "protocols": [
+ "jlink",
+ "nrfjprog",
+ "nrfutil",
+ "stlink",
+ "cmsis-dap",
+ "blackmagic"
+ ],
+ "use_1200bps_touch": true,
+ "require_upload_port": true,
+ "wait_for_upload_port": true
+ },
+ "url": "https://www.seeedstudio.com/Wio-WM1110-Dev-Kit-p-5677.html",
+ "vendor": "Seeed Studio"
+}
diff --git a/boards/wiscore_rak11200.json b/boards/wiscore_rak11200.json
index 33d16ba77..54ee9b69e 100644
--- a/boards/wiscore_rak11200.json
+++ b/boards/wiscore_rak11200.json
@@ -4,7 +4,7 @@
"ldscript": "esp32_out.ld"
},
"core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV",
+ "extra_flags": ["-DBOARD_HAS_PSRAM", "-DARDUINO_ESP32_DEV"],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
diff --git a/platformio.ini b/platformio.ini
index 9d7c76fbf..d8d398775 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -31,6 +31,9 @@ default_envs = tbeam
;default_envs = rak4631
;default_envs = rak10701
;default_envs = wio-e5
+;default_envs = radiomaster_900_bandit_nano
+;default_envs = radiomaster_900_bandit_micro
+;default_envs = heltec_capsule_sensor_v3
extra_configs =
arch/*/*.ini
@@ -70,17 +73,18 @@ build_flags = -Wno-missing-field-initializers
-DRADIOLIB_EXCLUDE_FSK4
-DRADIOLIB_EXCLUDE_APRS
-DRADIOLIB_EXCLUDE_LORAWAN
+ -DMESHTASTIC_EXCLUDE_DROPZONE=1
monitor_speed = 115200
lib_deps =
- jgromes/RadioLib@~6.5.0
- https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
+ jgromes/RadioLib@~6.6.0
+ https://github.com/meshtastic/esp8266-oled-ssd1306.git#69ba98fa30e67b12d4577b121f210f3eb7049d6b ; ESP8266_SSD1306
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
- nanopb/Nanopb@^0.4.7
+ nanopb/Nanopb@^0.4.8
erriez/ErriezCRC32@^1.0.1
; Used for the code analysis in PIO Home / Inspect
@@ -118,10 +122,7 @@ lib_deps =
adafruit/Adafruit BMP280 Library@^2.6.8
adafruit/Adafruit BMP085 Library@^1.2.4
adafruit/Adafruit BME280 Library@^2.2.2
- https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
- boschsensortec/BME68x Sensor Library@^1.1.40407
adafruit/Adafruit MCP9808 Library@^2.0.0
- https://github.com/KodinLanewave/INA3221@^1.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit SHTC3 Library@^1.0.0
@@ -130,7 +131,23 @@ lib_deps =
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
adafruit/Adafruit MPU6050@^2.2.4
adafruit/Adafruit LIS3DH@^1.2.4
- https://github.com/lewisxhe/SensorLib#27fd0f721e20cd09e1f81383f0ba58a54fe84a17
+ adafruit/Adafruit AHTX0@^2.0.5
adafruit/Adafruit LSM6DS@^4.7.2
+ adafruit/Adafruit VEML7700 Library@^2.1.6
+ adafruit/Adafruit SHT4x Library@^1.0.4
+ adafruit/Adafruit TSL2591 Library@^1.4.5
+ sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@^1.0.5
+ ClosedCube OPT3001@^1.1.2
+ emotibit/EmotiBit MLX90632@^1.0.8
+ dfrobot/DFRobot_RTU@^1.0.3
+
+
+ https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
+ boschsensortec/BME68x Sensor Library@^1.1.40407
+ https://github.com/KodinLanewave/INA3221@^1.0.0
+ lewisxhe/SensorLib@^0.2.0
mprograms/QMC5883LCompass@^1.2.0
- https://github.com/Sensirion/arduino-i2c-sht4x#1.1.0
+
+
+ https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee
+
diff --git a/protobufs b/protobufs
index 1bfe0354d..dc066c89f 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 1bfe0354d101a6a71ea1354ea158e59193671a0b
+Subproject commit dc066c89f73fce882e5a47648cba18a1967a7f56
diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h
index 66e5624f1..f45511cca 100644
--- a/src/AccelerometerThread.h
+++ b/src/AccelerometerThread.h
@@ -1,3 +1,4 @@
+#pragma once
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
@@ -13,14 +14,15 @@
#include
#include
#include
-
-SensorBMA423 bmaSensor;
-bool BMA_IRQ = false;
+#ifdef RAK_4631
+#include "Fusion/Fusion.h"
+#include
+#endif
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
#define ACCELEROMETER_CLICK_THRESHOLD 40
-int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
+static inline int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
@@ -33,7 +35,7 @@ int readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
return 0; // Pass
}
-int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
+static inline int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
{
Wire.beginTransmission(address);
Wire.write(reg);
@@ -41,8 +43,6 @@ int writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint8_t len)
return (0 != Wire.endTransmission());
}
-namespace concurrency
-{
class AccelerometerThread : public concurrency::OSThread
{
public:
@@ -53,14 +53,122 @@ class AccelerometerThread : public concurrency::OSThread
disable();
return;
}
-
+ acceleremoter_type = type;
+#ifndef RAK_4631
if (!config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) {
LOG_DEBUG("AccelerometerThread disabling due to no interested configurations\n");
disable();
return;
}
+#endif
+ init();
+ }
- acceleremoter_type = type;
+ void start()
+ {
+ init();
+ setIntervalFromNow(0);
+ };
+
+ protected:
+ int32_t runOnce() override
+ {
+ canSleep = true; // Assume we should not keep the board awake
+
+ if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
+ wakeScreen();
+ } else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
+ uint8_t click = lis.getClick();
+ if (!config.device.double_tap_as_button_press) {
+ wakeScreen();
+ }
+
+ if (config.device.double_tap_as_button_press && (click & 0x20)) {
+ buttonPress();
+ return 500;
+ }
+ } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.readIrqStatus() != DEV_WIRE_NONE) {
+ if (bmaSensor.isTilt() || bmaSensor.isDoubleTap()) {
+ wakeScreen();
+ return 500;
+ }
+#ifdef RAK_4631
+ } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160) {
+ sBmx160SensorData_t magAccel;
+ sBmx160SensorData_t gAccel;
+
+ /* Get a new sensor event */
+ bmx160.getAllData(&magAccel, NULL, &gAccel);
+
+ // expirimental calibrate routine. Limited to between 10 and 30 seconds after boot
+ if (millis() > 10 * 1000 && millis() < 30 * 1000) {
+ if (magAccel.x > highestX)
+ highestX = magAccel.x;
+ if (magAccel.x < lowestX)
+ lowestX = magAccel.x;
+ if (magAccel.y > highestY)
+ highestY = magAccel.y;
+ if (magAccel.y < lowestY)
+ lowestY = magAccel.y;
+ if (magAccel.z > highestZ)
+ highestZ = magAccel.z;
+ if (magAccel.z < lowestZ)
+ lowestZ = magAccel.z;
+ }
+
+ int highestRealX = highestX - (highestX + lowestX) / 2;
+
+ magAccel.x -= (highestX + lowestX) / 2;
+ magAccel.y -= (highestY + lowestY) / 2;
+ magAccel.z -= (highestZ + lowestZ) / 2;
+ FusionVector ga, ma;
+ ga.axis.x = -gAccel.x; // default location for the BMX160 is on the rear of the board
+ ga.axis.y = -gAccel.y;
+ ga.axis.z = gAccel.z;
+ ma.axis.x = -magAccel.x;
+ ma.axis.y = -magAccel.y;
+ ma.axis.z = magAccel.z * 3;
+
+ // If we're set to one of the inverted positions
+ if (config.display.compass_orientation > meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270) {
+ ma = FusionAxesSwap(ma, FusionAxesAlignmentNXNYPZ);
+ ga = FusionAxesSwap(ga, FusionAxesAlignmentNXNYPZ);
+ }
+
+ float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma);
+
+ switch (config.display.compass_orientation) {
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED:
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0:
+ break;
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90:
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED:
+ heading += 90;
+ break;
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180:
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED:
+ heading += 180;
+ break;
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270:
+ case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED:
+ heading += 270;
+ break;
+ }
+
+ screen->setHeading(heading);
+
+#endif
+ } else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.shake()) {
+ wakeScreen();
+ return 500;
+ }
+
+ return ACCELEROMETER_CHECK_INTERVAL_MS;
+ }
+
+ private:
+ void init()
+ {
LOG_DEBUG("AccelerometerThread initializing\n");
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
@@ -112,6 +220,11 @@ class AccelerometerThread : public concurrency::OSThread
bmaSensor.enableTiltIRQ();
// It corresponds to isDoubleClick interrupt
bmaSensor.enableWakeupIRQ();
+#ifdef RAK_4631
+ } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160 && bmx160.begin()) {
+ bmx160.ODR_Config(BMX160_ACCEL_ODR_100HZ, BMX160_GYRO_ODR_100HZ); // set output data rate
+
+#endif
} else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.begin_I2C(accelerometer_found.address)) {
LOG_DEBUG("LSM6DS3 initializing\n");
// Default threshold of 2G, less sensitive options are 4, 8 or 16G
@@ -123,38 +236,6 @@ class AccelerometerThread : public concurrency::OSThread
// Duration is number of occurances needed to trigger, higher threshold is less sensitive
}
}
-
- protected:
- int32_t runOnce() override
- {
- canSleep = true; // Assume we should not keep the board awake
-
- if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
- wakeScreen();
- } else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
- uint8_t click = lis.getClick();
- if (!config.device.double_tap_as_button_press) {
- wakeScreen();
- }
-
- if (config.device.double_tap_as_button_press && (click & 0x20)) {
- buttonPress();
- return 500;
- }
- } else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.readIrqStatus() != DEV_WIRE_NONE) {
- if (bmaSensor.isTilt() || bmaSensor.isDoubleTap()) {
- wakeScreen();
- return 500;
- }
- } else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.shake()) {
- wakeScreen();
- return 500;
- }
-
- return ACCELEROMETER_CHECK_INTERVAL_MS;
- }
-
- private:
void wakeScreen()
{
if (powerFSM.getState() == &stateDARK) {
@@ -173,8 +254,12 @@ class AccelerometerThread : public concurrency::OSThread
Adafruit_MPU6050 mpu;
Adafruit_LIS3DH lis;
Adafruit_LSM6DS3TRC lsm;
+ SensorBMA423 bmaSensor;
+#ifdef RAK_4631
+ RAK_BMX160 bmx160;
+ float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0;
+#endif
+ bool BMA_IRQ = false;
};
-} // namespace concurrency
-
#endif
\ No newline at end of file
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index aaead62be..4b3bb3fbc 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -41,7 +41,11 @@ ButtonThread::ButtonThread() : OSThread("Button")
}
#elif defined(BUTTON_PIN)
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
+#if defined(HELTEC_CAPSULE_SENSOR_V3)
+ this->userButton = OneButton(pin, false, false);
+#else
this->userButton = OneButton(pin, true, true);
+#endif
LOG_DEBUG("Using GPIO%02d for button\n", pin);
#endif
@@ -232,10 +236,10 @@ void ButtonThread::attachButtonInterrupts()
attachInterrupt(
config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN,
[]() {
- BaseType_t higherWake = 0;
- mainDelay.interruptFromISR(&higherWake);
ButtonThread::userButton.tick();
runASAP = true;
+ BaseType_t higherWake = 0;
+ mainDelay.interruptFromISR(&higherWake);
},
CHANGE);
#endif
diff --git a/src/Fusion/Fusion.h b/src/Fusion/Fusion.h
new file mode 100644
index 000000000..48f5198c5
--- /dev/null
+++ b/src/Fusion/Fusion.h
@@ -0,0 +1,32 @@
+/**
+ * @file Fusion.h
+ * @author Seb Madgwick
+ * @brief Main header file for the Fusion library. This is the only file that
+ * needs to be included when using the library.
+ */
+
+#ifndef FUSION_H
+#define FUSION_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "FusionAhrs.h"
+#include "FusionAxes.h"
+#include "FusionCalibration.h"
+#include "FusionCompass.h"
+#include "FusionConvention.h"
+#include "FusionMath.h"
+#include "FusionOffset.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionAhrs.c b/src/Fusion/FusionAhrs.c
new file mode 100644
index 000000000..d6c1d0215
--- /dev/null
+++ b/src/Fusion/FusionAhrs.c
@@ -0,0 +1,542 @@
+/**
+ * @file FusionAhrs.c
+ * @author Seb Madgwick
+ * @brief AHRS algorithm to combine gyroscope, accelerometer, and magnetometer
+ * measurements into a single measurement of orientation relative to the Earth.
+ */
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionAhrs.h"
+#include // FLT_MAX
+#include // atan2f, cosf, fabsf, powf, sinf
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief Initial gain used during the initialisation.
+ */
+#define INITIAL_GAIN (10.0f)
+
+/**
+ * @brief Initialisation period in seconds.
+ */
+#define INITIALISATION_PERIOD (3.0f)
+
+//------------------------------------------------------------------------------
+// Function declarations
+
+static inline FusionVector HalfGravity(const FusionAhrs *const ahrs);
+
+static inline FusionVector HalfMagnetic(const FusionAhrs *const ahrs);
+
+static inline FusionVector Feedback(const FusionVector sensor, const FusionVector reference);
+
+static inline int Clamp(const int value, const int min, const int max);
+
+//------------------------------------------------------------------------------
+// Functions
+
+/**
+ * @brief Initialises the AHRS algorithm structure.
+ * @param ahrs AHRS algorithm structure.
+ */
+void FusionAhrsInitialise(FusionAhrs *const ahrs)
+{
+ const FusionAhrsSettings settings = {
+ .convention = FusionConventionNwu,
+ .gain = 0.5f,
+ .gyroscopeRange = 0.0f,
+ .accelerationRejection = 90.0f,
+ .magneticRejection = 90.0f,
+ .recoveryTriggerPeriod = 0,
+ };
+ FusionAhrsSetSettings(ahrs, &settings);
+ FusionAhrsReset(ahrs);
+}
+
+/**
+ * @brief Resets the AHRS algorithm. This is equivalent to reinitialising the
+ * algorithm while maintaining the current settings.
+ * @param ahrs AHRS algorithm structure.
+ */
+void FusionAhrsReset(FusionAhrs *const ahrs)
+{
+ ahrs->quaternion = FUSION_IDENTITY_QUATERNION;
+ ahrs->accelerometer = FUSION_VECTOR_ZERO;
+ ahrs->initialising = true;
+ ahrs->rampedGain = INITIAL_GAIN;
+ ahrs->angularRateRecovery = false;
+ ahrs->halfAccelerometerFeedback = FUSION_VECTOR_ZERO;
+ ahrs->halfMagnetometerFeedback = FUSION_VECTOR_ZERO;
+ ahrs->accelerometerIgnored = false;
+ ahrs->accelerationRecoveryTrigger = 0;
+ ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+ ahrs->magnetometerIgnored = false;
+ ahrs->magneticRecoveryTrigger = 0;
+ ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+}
+
+/**
+ * @brief Sets the AHRS algorithm settings.
+ * @param ahrs AHRS algorithm structure.
+ * @param settings Settings.
+ */
+void FusionAhrsSetSettings(FusionAhrs *const ahrs, const FusionAhrsSettings *const settings)
+{
+ ahrs->settings.convention = settings->convention;
+ ahrs->settings.gain = settings->gain;
+ ahrs->settings.gyroscopeRange = settings->gyroscopeRange == 0.0f ? FLT_MAX : 0.98f * settings->gyroscopeRange;
+ ahrs->settings.accelerationRejection = settings->accelerationRejection == 0.0f
+ ? FLT_MAX
+ : powf(0.5f * sinf(FusionDegreesToRadians(settings->accelerationRejection)), 2);
+ ahrs->settings.magneticRejection =
+ settings->magneticRejection == 0.0f ? FLT_MAX : powf(0.5f * sinf(FusionDegreesToRadians(settings->magneticRejection)), 2);
+ ahrs->settings.recoveryTriggerPeriod = settings->recoveryTriggerPeriod;
+ ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+ ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+ if ((settings->gain == 0.0f) ||
+ (settings->recoveryTriggerPeriod == 0)) { // disable acceleration and magnetic rejection features if gain is zero
+ ahrs->settings.accelerationRejection = FLT_MAX;
+ ahrs->settings.magneticRejection = FLT_MAX;
+ }
+ if (ahrs->initialising == false) {
+ ahrs->rampedGain = ahrs->settings.gain;
+ }
+ ahrs->rampedGainStep = (INITIAL_GAIN - ahrs->settings.gain) / INITIALISATION_PERIOD;
+}
+
+/**
+ * @brief Updates the AHRS algorithm using the gyroscope, accelerometer, and
+ * magnetometer measurements.
+ * @param ahrs AHRS algorithm structure.
+ * @param gyroscope Gyroscope measurement in degrees per second.
+ * @param accelerometer Accelerometer measurement in g.
+ * @param magnetometer Magnetometer measurement in arbitrary units.
+ * @param deltaTime Delta time in seconds.
+ */
+void FusionAhrsUpdate(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const FusionVector magnetometer, const float deltaTime)
+{
+#define Q ahrs->quaternion.element
+
+ // Store accelerometer
+ ahrs->accelerometer = accelerometer;
+
+ // Reinitialise if gyroscope range exceeded
+ if ((fabsf(gyroscope.axis.x) > ahrs->settings.gyroscopeRange) || (fabsf(gyroscope.axis.y) > ahrs->settings.gyroscopeRange) ||
+ (fabsf(gyroscope.axis.z) > ahrs->settings.gyroscopeRange)) {
+ const FusionQuaternion quaternion = ahrs->quaternion;
+ FusionAhrsReset(ahrs);
+ ahrs->quaternion = quaternion;
+ ahrs->angularRateRecovery = true;
+ }
+
+ // Ramp down gain during initialisation
+ if (ahrs->initialising) {
+ ahrs->rampedGain -= ahrs->rampedGainStep * deltaTime;
+ if ((ahrs->rampedGain < ahrs->settings.gain) || (ahrs->settings.gain == 0.0f)) {
+ ahrs->rampedGain = ahrs->settings.gain;
+ ahrs->initialising = false;
+ ahrs->angularRateRecovery = false;
+ }
+ }
+
+ // Calculate direction of gravity indicated by algorithm
+ const FusionVector halfGravity = HalfGravity(ahrs);
+
+ // Calculate accelerometer feedback
+ FusionVector halfAccelerometerFeedback = FUSION_VECTOR_ZERO;
+ ahrs->accelerometerIgnored = true;
+ if (FusionVectorIsZero(accelerometer) == false) {
+
+ // Calculate accelerometer feedback scaled by 0.5
+ ahrs->halfAccelerometerFeedback = Feedback(FusionVectorNormalise(accelerometer), halfGravity);
+
+ // Don't ignore accelerometer if acceleration error below threshold
+ if (ahrs->initialising ||
+ ((FusionVectorMagnitudeSquared(ahrs->halfAccelerometerFeedback) <= ahrs->settings.accelerationRejection))) {
+ ahrs->accelerometerIgnored = false;
+ ahrs->accelerationRecoveryTrigger -= 9;
+ } else {
+ ahrs->accelerationRecoveryTrigger += 1;
+ }
+
+ // Don't ignore accelerometer during acceleration recovery
+ if (ahrs->accelerationRecoveryTrigger > ahrs->accelerationRecoveryTimeout) {
+ ahrs->accelerationRecoveryTimeout = 0;
+ ahrs->accelerometerIgnored = false;
+ } else {
+ ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+ }
+ ahrs->accelerationRecoveryTrigger = Clamp(ahrs->accelerationRecoveryTrigger, 0, ahrs->settings.recoveryTriggerPeriod);
+
+ // Apply accelerometer feedback
+ if (ahrs->accelerometerIgnored == false) {
+ halfAccelerometerFeedback = ahrs->halfAccelerometerFeedback;
+ }
+ }
+
+ // Calculate magnetometer feedback
+ FusionVector halfMagnetometerFeedback = FUSION_VECTOR_ZERO;
+ ahrs->magnetometerIgnored = true;
+ if (FusionVectorIsZero(magnetometer) == false) {
+
+ // Calculate direction of magnetic field indicated by algorithm
+ const FusionVector halfMagnetic = HalfMagnetic(ahrs);
+
+ // Calculate magnetometer feedback scaled by 0.5
+ ahrs->halfMagnetometerFeedback =
+ Feedback(FusionVectorNormalise(FusionVectorCrossProduct(halfGravity, magnetometer)), halfMagnetic);
+
+ // Don't ignore magnetometer if magnetic error below threshold
+ if (ahrs->initialising ||
+ ((FusionVectorMagnitudeSquared(ahrs->halfMagnetometerFeedback) <= ahrs->settings.magneticRejection))) {
+ ahrs->magnetometerIgnored = false;
+ ahrs->magneticRecoveryTrigger -= 9;
+ } else {
+ ahrs->magneticRecoveryTrigger += 1;
+ }
+
+ // Don't ignore magnetometer during magnetic recovery
+ if (ahrs->magneticRecoveryTrigger > ahrs->magneticRecoveryTimeout) {
+ ahrs->magneticRecoveryTimeout = 0;
+ ahrs->magnetometerIgnored = false;
+ } else {
+ ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod;
+ }
+ ahrs->magneticRecoveryTrigger = Clamp(ahrs->magneticRecoveryTrigger, 0, ahrs->settings.recoveryTriggerPeriod);
+
+ // Apply magnetometer feedback
+ if (ahrs->magnetometerIgnored == false) {
+ halfMagnetometerFeedback = ahrs->halfMagnetometerFeedback;
+ }
+ }
+
+ // Convert gyroscope to radians per second scaled by 0.5
+ const FusionVector halfGyroscope = FusionVectorMultiplyScalar(gyroscope, FusionDegreesToRadians(0.5f));
+
+ // Apply feedback to gyroscope
+ const FusionVector adjustedHalfGyroscope = FusionVectorAdd(
+ halfGyroscope,
+ FusionVectorMultiplyScalar(FusionVectorAdd(halfAccelerometerFeedback, halfMagnetometerFeedback), ahrs->rampedGain));
+
+ // Integrate rate of change of quaternion
+ ahrs->quaternion = FusionQuaternionAdd(
+ ahrs->quaternion,
+ FusionQuaternionMultiplyVector(ahrs->quaternion, FusionVectorMultiplyScalar(adjustedHalfGyroscope, deltaTime)));
+
+ // Normalise quaternion
+ ahrs->quaternion = FusionQuaternionNormalise(ahrs->quaternion);
+#undef Q
+}
+
+/**
+ * @brief Returns the direction of gravity scaled by 0.5.
+ * @param ahrs AHRS algorithm structure.
+ * @return Direction of gravity scaled by 0.5.
+ */
+static inline FusionVector HalfGravity(const FusionAhrs *const ahrs)
+{
+#define Q ahrs->quaternion.element
+ switch (ahrs->settings.convention) {
+ case FusionConventionNwu:
+ case FusionConventionEnu: {
+ const FusionVector halfGravity = {.axis = {
+ .x = Q.x * Q.z - Q.w * Q.y,
+ .y = Q.y * Q.z + Q.w * Q.x,
+ .z = Q.w * Q.w - 0.5f + Q.z * Q.z,
+ }}; // third column of transposed rotation matrix scaled by 0.5
+ return halfGravity;
+ }
+ case FusionConventionNed: {
+ const FusionVector halfGravity = {.axis = {
+ .x = Q.w * Q.y - Q.x * Q.z,
+ .y = -1.0f * (Q.y * Q.z + Q.w * Q.x),
+ .z = 0.5f - Q.w * Q.w - Q.z * Q.z,
+ }}; // third column of transposed rotation matrix scaled by -0.5
+ return halfGravity;
+ }
+ }
+ return FUSION_VECTOR_ZERO; // avoid compiler warning
+#undef Q
+}
+
+/**
+ * @brief Returns the direction of the magnetic field scaled by 0.5.
+ * @param ahrs AHRS algorithm structure.
+ * @return Direction of the magnetic field scaled by 0.5.
+ */
+static inline FusionVector HalfMagnetic(const FusionAhrs *const ahrs)
+{
+#define Q ahrs->quaternion.element
+ switch (ahrs->settings.convention) {
+ case FusionConventionNwu: {
+ const FusionVector halfMagnetic = {.axis = {
+ .x = Q.x * Q.y + Q.w * Q.z,
+ .y = Q.w * Q.w - 0.5f + Q.y * Q.y,
+ .z = Q.y * Q.z - Q.w * Q.x,
+ }}; // second column of transposed rotation matrix scaled by 0.5
+ return halfMagnetic;
+ }
+ case FusionConventionEnu: {
+ const FusionVector halfMagnetic = {.axis = {
+ .x = 0.5f - Q.w * Q.w - Q.x * Q.x,
+ .y = Q.w * Q.z - Q.x * Q.y,
+ .z = -1.0f * (Q.x * Q.z + Q.w * Q.y),
+ }}; // first column of transposed rotation matrix scaled by -0.5
+ return halfMagnetic;
+ }
+ case FusionConventionNed: {
+ const FusionVector halfMagnetic = {.axis = {
+ .x = -1.0f * (Q.x * Q.y + Q.w * Q.z),
+ .y = 0.5f - Q.w * Q.w - Q.y * Q.y,
+ .z = Q.w * Q.x - Q.y * Q.z,
+ }}; // second column of transposed rotation matrix scaled by -0.5
+ return halfMagnetic;
+ }
+ }
+ return FUSION_VECTOR_ZERO; // avoid compiler warning
+#undef Q
+}
+
+/**
+ * @brief Returns the feedback.
+ * @param sensor Sensor.
+ * @param reference Reference.
+ * @return Feedback.
+ */
+static inline FusionVector Feedback(const FusionVector sensor, const FusionVector reference)
+{
+ if (FusionVectorDotProduct(sensor, reference) < 0.0f) { // if error is >90 degrees
+ return FusionVectorNormalise(FusionVectorCrossProduct(sensor, reference));
+ }
+ return FusionVectorCrossProduct(sensor, reference);
+}
+
+/**
+ * @brief Returns a value limited to maximum and minimum.
+ * @param value Value.
+ * @param min Minimum value.
+ * @param max Maximum value.
+ * @return Value limited to maximum and minimum.
+ */
+static inline int Clamp(const int value, const int min, const int max)
+{
+ if (value < min) {
+ return min;
+ }
+ if (value > max) {
+ return max;
+ }
+ return value;
+}
+
+/**
+ * @brief Updates the AHRS algorithm using the gyroscope and accelerometer
+ * measurements only.
+ * @param ahrs AHRS algorithm structure.
+ * @param gyroscope Gyroscope measurement in degrees per second.
+ * @param accelerometer Accelerometer measurement in g.
+ * @param deltaTime Delta time in seconds.
+ */
+void FusionAhrsUpdateNoMagnetometer(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const float deltaTime)
+{
+
+ // Update AHRS algorithm
+ FusionAhrsUpdate(ahrs, gyroscope, accelerometer, FUSION_VECTOR_ZERO, deltaTime);
+
+ // Zero heading during initialisation
+ if (ahrs->initialising) {
+ FusionAhrsSetHeading(ahrs, 0.0f);
+ }
+}
+
+/**
+ * @brief Updates the AHRS algorithm using the gyroscope, accelerometer, and
+ * heading measurements.
+ * @param ahrs AHRS algorithm structure.
+ * @param gyroscope Gyroscope measurement in degrees per second.
+ * @param accelerometer Accelerometer measurement in g.
+ * @param heading Heading measurement in degrees.
+ * @param deltaTime Delta time in seconds.
+ */
+void FusionAhrsUpdateExternalHeading(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const float heading, const float deltaTime)
+{
+#define Q ahrs->quaternion.element
+
+ // Calculate roll
+ const float roll = atan2f(Q.w * Q.x + Q.y * Q.z, 0.5f - Q.y * Q.y - Q.x * Q.x);
+
+ // Calculate magnetometer
+ const float headingRadians = FusionDegreesToRadians(heading);
+ const float sinHeadingRadians = sinf(headingRadians);
+ const FusionVector magnetometer = {.axis = {
+ .x = cosf(headingRadians),
+ .y = -1.0f * cosf(roll) * sinHeadingRadians,
+ .z = sinHeadingRadians * sinf(roll),
+ }};
+
+ // Update AHRS algorithm
+ FusionAhrsUpdate(ahrs, gyroscope, accelerometer, magnetometer, deltaTime);
+#undef Q
+}
+
+/**
+ * @brief Returns the quaternion describing the sensor relative to the Earth.
+ * @param ahrs AHRS algorithm structure.
+ * @return Quaternion describing the sensor relative to the Earth.
+ */
+FusionQuaternion FusionAhrsGetQuaternion(const FusionAhrs *const ahrs)
+{
+ return ahrs->quaternion;
+}
+
+/**
+ * @brief Sets the quaternion describing the sensor relative to the Earth.
+ * @param ahrs AHRS algorithm structure.
+ * @param quaternion Quaternion describing the sensor relative to the Earth.
+ */
+void FusionAhrsSetQuaternion(FusionAhrs *const ahrs, const FusionQuaternion quaternion)
+{
+ ahrs->quaternion = quaternion;
+}
+
+/**
+ * @brief Returns the linear acceleration measurement equal to the accelerometer
+ * measurement with the 1 g of gravity removed.
+ * @param ahrs AHRS algorithm structure.
+ * @return Linear acceleration measurement in g.
+ */
+FusionVector FusionAhrsGetLinearAcceleration(const FusionAhrs *const ahrs)
+{
+#define Q ahrs->quaternion.element
+
+ // Calculate gravity in the sensor coordinate frame
+ const FusionVector gravity = {.axis = {
+ .x = 2.0f * (Q.x * Q.z - Q.w * Q.y),
+ .y = 2.0f * (Q.y * Q.z + Q.w * Q.x),
+ .z = 2.0f * (Q.w * Q.w - 0.5f + Q.z * Q.z),
+ }}; // third column of transposed rotation matrix
+
+ // Remove gravity from accelerometer measurement
+ switch (ahrs->settings.convention) {
+ case FusionConventionNwu:
+ case FusionConventionEnu: {
+ return FusionVectorSubtract(ahrs->accelerometer, gravity);
+ }
+ case FusionConventionNed: {
+ return FusionVectorAdd(ahrs->accelerometer, gravity);
+ }
+ }
+ return FUSION_VECTOR_ZERO; // avoid compiler warning
+#undef Q
+}
+
+/**
+ * @brief Returns the Earth acceleration measurement equal to accelerometer
+ * measurement in the Earth coordinate frame with the 1 g of gravity removed.
+ * @param ahrs AHRS algorithm structure.
+ * @return Earth acceleration measurement in g.
+ */
+FusionVector FusionAhrsGetEarthAcceleration(const FusionAhrs *const ahrs)
+{
+#define Q ahrs->quaternion.element
+#define A ahrs->accelerometer.axis
+
+ // Calculate accelerometer measurement in the Earth coordinate frame
+ const float qwqw = Q.w * Q.w; // calculate common terms to avoid repeated operations
+ const float qwqx = Q.w * Q.x;
+ const float qwqy = Q.w * Q.y;
+ const float qwqz = Q.w * Q.z;
+ const float qxqy = Q.x * Q.y;
+ const float qxqz = Q.x * Q.z;
+ const float qyqz = Q.y * Q.z;
+ FusionVector accelerometer = {.axis = {
+ .x = 2.0f * ((qwqw - 0.5f + Q.x * Q.x) * A.x + (qxqy - qwqz) * A.y + (qxqz + qwqy) * A.z),
+ .y = 2.0f * ((qxqy + qwqz) * A.x + (qwqw - 0.5f + Q.y * Q.y) * A.y + (qyqz - qwqx) * A.z),
+ .z = 2.0f * ((qxqz - qwqy) * A.x + (qyqz + qwqx) * A.y + (qwqw - 0.5f + Q.z * Q.z) * A.z),
+ }}; // rotation matrix multiplied with the accelerometer
+
+ // Remove gravity from accelerometer measurement
+ switch (ahrs->settings.convention) {
+ case FusionConventionNwu:
+ case FusionConventionEnu:
+ accelerometer.axis.z -= 1.0f;
+ break;
+ case FusionConventionNed:
+ accelerometer.axis.z += 1.0f;
+ break;
+ }
+ return accelerometer;
+#undef Q
+#undef A
+}
+
+/**
+ * @brief Returns the AHRS algorithm internal states.
+ * @param ahrs AHRS algorithm structure.
+ * @return AHRS algorithm internal states.
+ */
+FusionAhrsInternalStates FusionAhrsGetInternalStates(const FusionAhrs *const ahrs)
+{
+ const FusionAhrsInternalStates internalStates = {
+ .accelerationError = FusionRadiansToDegrees(FusionAsin(2.0f * FusionVectorMagnitude(ahrs->halfAccelerometerFeedback))),
+ .accelerometerIgnored = ahrs->accelerometerIgnored,
+ .accelerationRecoveryTrigger =
+ ahrs->settings.recoveryTriggerPeriod == 0
+ ? 0.0f
+ : (float)ahrs->accelerationRecoveryTrigger / (float)ahrs->settings.recoveryTriggerPeriod,
+ .magneticError = FusionRadiansToDegrees(FusionAsin(2.0f * FusionVectorMagnitude(ahrs->halfMagnetometerFeedback))),
+ .magnetometerIgnored = ahrs->magnetometerIgnored,
+ .magneticRecoveryTrigger = ahrs->settings.recoveryTriggerPeriod == 0
+ ? 0.0f
+ : (float)ahrs->magneticRecoveryTrigger / (float)ahrs->settings.recoveryTriggerPeriod,
+ };
+ return internalStates;
+}
+
+/**
+ * @brief Returns the AHRS algorithm flags.
+ * @param ahrs AHRS algorithm structure.
+ * @return AHRS algorithm flags.
+ */
+FusionAhrsFlags FusionAhrsGetFlags(const FusionAhrs *const ahrs)
+{
+ const FusionAhrsFlags flags = {
+ .initialising = ahrs->initialising,
+ .angularRateRecovery = ahrs->angularRateRecovery,
+ .accelerationRecovery = ahrs->accelerationRecoveryTrigger > ahrs->accelerationRecoveryTimeout,
+ .magneticRecovery = ahrs->magneticRecoveryTrigger > ahrs->magneticRecoveryTimeout,
+ };
+ return flags;
+}
+
+/**
+ * @brief Sets the heading of the orientation measurement provided by the AHRS
+ * algorithm. This function can be used to reset drift in heading when the AHRS
+ * algorithm is being used without a magnetometer.
+ * @param ahrs AHRS algorithm structure.
+ * @param heading Heading angle in degrees.
+ */
+void FusionAhrsSetHeading(FusionAhrs *const ahrs, const float heading)
+{
+#define Q ahrs->quaternion.element
+ const float yaw = atan2f(Q.w * Q.z + Q.x * Q.y, 0.5f - Q.y * Q.y - Q.z * Q.z);
+ const float halfYawMinusHeading = 0.5f * (yaw - FusionDegreesToRadians(heading));
+ const FusionQuaternion rotation = {.element = {
+ .w = cosf(halfYawMinusHeading),
+ .x = 0.0f,
+ .y = 0.0f,
+ .z = -1.0f * sinf(halfYawMinusHeading),
+ }};
+ ahrs->quaternion = FusionQuaternionMultiply(rotation, ahrs->quaternion);
+#undef Q
+}
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionAhrs.h b/src/Fusion/FusionAhrs.h
new file mode 100644
index 000000000..aa2326e43
--- /dev/null
+++ b/src/Fusion/FusionAhrs.h
@@ -0,0 +1,112 @@
+/**
+ * @file FusionAhrs.h
+ * @author Seb Madgwick
+ * @brief AHRS algorithm to combine gyroscope, accelerometer, and magnetometer
+ * measurements into a single measurement of orientation relative to the Earth.
+ */
+
+#ifndef FUSION_AHRS_H
+#define FUSION_AHRS_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionConvention.h"
+#include "FusionMath.h"
+#include
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief AHRS algorithm settings.
+ */
+typedef struct {
+ FusionConvention convention;
+ float gain;
+ float gyroscopeRange;
+ float accelerationRejection;
+ float magneticRejection;
+ unsigned int recoveryTriggerPeriod;
+} FusionAhrsSettings;
+
+/**
+ * @brief AHRS algorithm structure. Structure members are used internally and
+ * must not be accessed by the application.
+ */
+typedef struct {
+ FusionAhrsSettings settings;
+ FusionQuaternion quaternion;
+ FusionVector accelerometer;
+ bool initialising;
+ float rampedGain;
+ float rampedGainStep;
+ bool angularRateRecovery;
+ FusionVector halfAccelerometerFeedback;
+ FusionVector halfMagnetometerFeedback;
+ bool accelerometerIgnored;
+ int accelerationRecoveryTrigger;
+ int accelerationRecoveryTimeout;
+ bool magnetometerIgnored;
+ int magneticRecoveryTrigger;
+ int magneticRecoveryTimeout;
+} FusionAhrs;
+
+/**
+ * @brief AHRS algorithm internal states.
+ */
+typedef struct {
+ float accelerationError;
+ bool accelerometerIgnored;
+ float accelerationRecoveryTrigger;
+ float magneticError;
+ bool magnetometerIgnored;
+ float magneticRecoveryTrigger;
+} FusionAhrsInternalStates;
+
+/**
+ * @brief AHRS algorithm flags.
+ */
+typedef struct {
+ bool initialising;
+ bool angularRateRecovery;
+ bool accelerationRecovery;
+ bool magneticRecovery;
+} FusionAhrsFlags;
+
+//------------------------------------------------------------------------------
+// Function declarations
+
+void FusionAhrsInitialise(FusionAhrs *const ahrs);
+
+void FusionAhrsReset(FusionAhrs *const ahrs);
+
+void FusionAhrsSetSettings(FusionAhrs *const ahrs, const FusionAhrsSettings *const settings);
+
+void FusionAhrsUpdate(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const FusionVector magnetometer, const float deltaTime);
+
+void FusionAhrsUpdateNoMagnetometer(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const float deltaTime);
+
+void FusionAhrsUpdateExternalHeading(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer,
+ const float heading, const float deltaTime);
+
+FusionQuaternion FusionAhrsGetQuaternion(const FusionAhrs *const ahrs);
+
+void FusionAhrsSetQuaternion(FusionAhrs *const ahrs, const FusionQuaternion quaternion);
+
+FusionVector FusionAhrsGetLinearAcceleration(const FusionAhrs *const ahrs);
+
+FusionVector FusionAhrsGetEarthAcceleration(const FusionAhrs *const ahrs);
+
+FusionAhrsInternalStates FusionAhrsGetInternalStates(const FusionAhrs *const ahrs);
+
+FusionAhrsFlags FusionAhrsGetFlags(const FusionAhrs *const ahrs);
+
+void FusionAhrsSetHeading(FusionAhrs *const ahrs, const float heading);
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionAxes.h b/src/Fusion/FusionAxes.h
new file mode 100644
index 000000000..9673c88ff
--- /dev/null
+++ b/src/Fusion/FusionAxes.h
@@ -0,0 +1,188 @@
+/**
+ * @file FusionAxes.h
+ * @author Seb Madgwick
+ * @brief Swaps sensor axes for alignment with the body axes.
+ */
+
+#ifndef FUSION_AXES_H
+#define FUSION_AXES_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionMath.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief Axes alignment describing the sensor axes relative to the body axes.
+ * For example, if the body X axis is aligned with the sensor Y axis and the
+ * body Y axis is aligned with sensor X axis but pointing the opposite direction
+ * then alignment is +Y-X+Z.
+ */
+typedef enum {
+ FusionAxesAlignmentPXPYPZ, /* +X+Y+Z */
+ FusionAxesAlignmentPXNZPY, /* +X-Z+Y */
+ FusionAxesAlignmentPXNYNZ, /* +X-Y-Z */
+ FusionAxesAlignmentPXPZNY, /* +X+Z-Y */
+ FusionAxesAlignmentNXPYNZ, /* -X+Y-Z */
+ FusionAxesAlignmentNXPZPY, /* -X+Z+Y */
+ FusionAxesAlignmentNXNYPZ, /* -X-Y+Z */
+ FusionAxesAlignmentNXNZNY, /* -X-Z-Y */
+ FusionAxesAlignmentPYNXPZ, /* +Y-X+Z */
+ FusionAxesAlignmentPYNZNX, /* +Y-Z-X */
+ FusionAxesAlignmentPYPXNZ, /* +Y+X-Z */
+ FusionAxesAlignmentPYPZPX, /* +Y+Z+X */
+ FusionAxesAlignmentNYPXPZ, /* -Y+X+Z */
+ FusionAxesAlignmentNYNZPX, /* -Y-Z+X */
+ FusionAxesAlignmentNYNXNZ, /* -Y-X-Z */
+ FusionAxesAlignmentNYPZNX, /* -Y+Z-X */
+ FusionAxesAlignmentPZPYNX, /* +Z+Y-X */
+ FusionAxesAlignmentPZPXPY, /* +Z+X+Y */
+ FusionAxesAlignmentPZNYPX, /* +Z-Y+X */
+ FusionAxesAlignmentPZNXNY, /* +Z-X-Y */
+ FusionAxesAlignmentNZPYPX, /* -Z+Y+X */
+ FusionAxesAlignmentNZNXPY, /* -Z-X+Y */
+ FusionAxesAlignmentNZNYNX, /* -Z-Y-X */
+ FusionAxesAlignmentNZPXNY, /* -Z+X-Y */
+} FusionAxesAlignment;
+
+//------------------------------------------------------------------------------
+// Inline functions
+
+/**
+ * @brief Swaps sensor axes for alignment with the body axes.
+ * @param sensor Sensor axes.
+ * @param alignment Axes alignment.
+ * @return Sensor axes aligned with the body axes.
+ */
+static inline FusionVector FusionAxesSwap(const FusionVector sensor, const FusionAxesAlignment alignment)
+{
+ FusionVector result;
+ switch (alignment) {
+ case FusionAxesAlignmentPXPYPZ:
+ break;
+ case FusionAxesAlignmentPXNZPY:
+ result.axis.x = +sensor.axis.x;
+ result.axis.y = -sensor.axis.z;
+ result.axis.z = +sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentPXNYNZ:
+ result.axis.x = +sensor.axis.x;
+ result.axis.y = -sensor.axis.y;
+ result.axis.z = -sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentPXPZNY:
+ result.axis.x = +sensor.axis.x;
+ result.axis.y = +sensor.axis.z;
+ result.axis.z = -sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentNXPYNZ:
+ result.axis.x = -sensor.axis.x;
+ result.axis.y = +sensor.axis.y;
+ result.axis.z = -sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentNXPZPY:
+ result.axis.x = -sensor.axis.x;
+ result.axis.y = +sensor.axis.z;
+ result.axis.z = +sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentNXNYPZ:
+ result.axis.x = -sensor.axis.x;
+ result.axis.y = -sensor.axis.y;
+ result.axis.z = +sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentNXNZNY:
+ result.axis.x = -sensor.axis.x;
+ result.axis.y = -sensor.axis.z;
+ result.axis.z = -sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentPYNXPZ:
+ result.axis.x = +sensor.axis.y;
+ result.axis.y = -sensor.axis.x;
+ result.axis.z = +sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentPYNZNX:
+ result.axis.x = +sensor.axis.y;
+ result.axis.y = -sensor.axis.z;
+ result.axis.z = -sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentPYPXNZ:
+ result.axis.x = +sensor.axis.y;
+ result.axis.y = +sensor.axis.x;
+ result.axis.z = -sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentPYPZPX:
+ result.axis.x = +sensor.axis.y;
+ result.axis.y = +sensor.axis.z;
+ result.axis.z = +sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentNYPXPZ:
+ result.axis.x = -sensor.axis.y;
+ result.axis.y = +sensor.axis.x;
+ result.axis.z = +sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentNYNZPX:
+ result.axis.x = -sensor.axis.y;
+ result.axis.y = -sensor.axis.z;
+ result.axis.z = +sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentNYNXNZ:
+ result.axis.x = -sensor.axis.y;
+ result.axis.y = -sensor.axis.x;
+ result.axis.z = -sensor.axis.z;
+ return result;
+ case FusionAxesAlignmentNYPZNX:
+ result.axis.x = -sensor.axis.y;
+ result.axis.y = +sensor.axis.z;
+ result.axis.z = -sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentPZPYNX:
+ result.axis.x = +sensor.axis.z;
+ result.axis.y = +sensor.axis.y;
+ result.axis.z = -sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentPZPXPY:
+ result.axis.x = +sensor.axis.z;
+ result.axis.y = +sensor.axis.x;
+ result.axis.z = +sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentPZNYPX:
+ result.axis.x = +sensor.axis.z;
+ result.axis.y = -sensor.axis.y;
+ result.axis.z = +sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentPZNXNY:
+ result.axis.x = +sensor.axis.z;
+ result.axis.y = -sensor.axis.x;
+ result.axis.z = -sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentNZPYPX:
+ result.axis.x = -sensor.axis.z;
+ result.axis.y = +sensor.axis.y;
+ result.axis.z = +sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentNZNXPY:
+ result.axis.x = -sensor.axis.z;
+ result.axis.y = -sensor.axis.x;
+ result.axis.z = +sensor.axis.y;
+ return result;
+ case FusionAxesAlignmentNZNYNX:
+ result.axis.x = -sensor.axis.z;
+ result.axis.y = -sensor.axis.y;
+ result.axis.z = -sensor.axis.x;
+ return result;
+ case FusionAxesAlignmentNZPXNY:
+ result.axis.x = -sensor.axis.z;
+ result.axis.y = +sensor.axis.x;
+ result.axis.z = -sensor.axis.y;
+ return result;
+ }
+ return sensor; // avoid compiler warning
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionCalibration.h b/src/Fusion/FusionCalibration.h
new file mode 100644
index 000000000..be7102b73
--- /dev/null
+++ b/src/Fusion/FusionCalibration.h
@@ -0,0 +1,49 @@
+/**
+ * @file FusionCalibration.h
+ * @author Seb Madgwick
+ * @brief Gyroscope, accelerometer, and magnetometer calibration models.
+ */
+
+#ifndef FUSION_CALIBRATION_H
+#define FUSION_CALIBRATION_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionMath.h"
+
+//------------------------------------------------------------------------------
+// Inline functions
+
+/**
+ * @brief Gyroscope and accelerometer calibration model.
+ * @param uncalibrated Uncalibrated measurement.
+ * @param misalignment Misalignment matrix.
+ * @param sensitivity Sensitivity.
+ * @param offset Offset.
+ * @return Calibrated measurement.
+ */
+static inline FusionVector FusionCalibrationInertial(const FusionVector uncalibrated, const FusionMatrix misalignment,
+ const FusionVector sensitivity, const FusionVector offset)
+{
+ return FusionMatrixMultiplyVector(misalignment,
+ FusionVectorHadamardProduct(FusionVectorSubtract(uncalibrated, offset), sensitivity));
+}
+
+/**
+ * @brief Magnetometer calibration model.
+ * @param uncalibrated Uncalibrated measurement.
+ * @param softIronMatrix Soft-iron matrix.
+ * @param hardIronOffset Hard-iron offset.
+ * @return Calibrated measurement.
+ */
+static inline FusionVector FusionCalibrationMagnetic(const FusionVector uncalibrated, const FusionMatrix softIronMatrix,
+ const FusionVector hardIronOffset)
+{
+ return FusionMatrixMultiplyVector(softIronMatrix, FusionVectorSubtract(uncalibrated, hardIronOffset));
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionCompass.c b/src/Fusion/FusionCompass.c
new file mode 100644
index 000000000..6a6f9591a
--- /dev/null
+++ b/src/Fusion/FusionCompass.c
@@ -0,0 +1,51 @@
+/**
+ * @file FusionCompass.c
+ * @author Seb Madgwick
+ * @brief Tilt-compensated compass to calculate the magnetic heading using
+ * accelerometer and magnetometer measurements.
+ */
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionCompass.h"
+#include "FusionAxes.h"
+#include // atan2f
+
+//------------------------------------------------------------------------------
+// Functions
+
+/**
+ * @brief Calculates the magnetic heading.
+ * @param convention Earth axes convention.
+ * @param accelerometer Accelerometer measurement in any calibrated units.
+ * @param magnetometer Magnetometer measurement in any calibrated units.
+ * @return Heading angle in degrees.
+ */
+float FusionCompassCalculateHeading(const FusionConvention convention, const FusionVector accelerometer,
+ const FusionVector magnetometer)
+{
+ switch (convention) {
+ case FusionConventionNwu: {
+ const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(accelerometer, magnetometer));
+ const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, accelerometer));
+ return FusionRadiansToDegrees(atan2f(west.axis.x, north.axis.x));
+ }
+ case FusionConventionEnu: {
+ const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(accelerometer, magnetometer));
+ const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, accelerometer));
+ const FusionVector east = FusionVectorMultiplyScalar(west, -1.0f);
+ return FusionRadiansToDegrees(atan2f(north.axis.x, east.axis.x));
+ }
+ case FusionConventionNed: {
+ const FusionVector up = FusionVectorMultiplyScalar(accelerometer, -1.0f);
+ const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(up, magnetometer));
+ const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, up));
+ return FusionRadiansToDegrees(atan2f(west.axis.x, north.axis.x));
+ }
+ }
+ return 0; // avoid compiler warning
+}
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionCompass.h b/src/Fusion/FusionCompass.h
new file mode 100644
index 000000000..a3d0b466a
--- /dev/null
+++ b/src/Fusion/FusionCompass.h
@@ -0,0 +1,26 @@
+/**
+ * @file FusionCompass.h
+ * @author Seb Madgwick
+ * @brief Tilt-compensated compass to calculate the magnetic heading using
+ * accelerometer and magnetometer measurements.
+ */
+
+#ifndef FUSION_COMPASS_H
+#define FUSION_COMPASS_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionConvention.h"
+#include "FusionMath.h"
+
+//------------------------------------------------------------------------------
+// Function declarations
+
+float FusionCompassCalculateHeading(const FusionConvention convention, const FusionVector accelerometer,
+ const FusionVector magnetometer);
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionConvention.h b/src/Fusion/FusionConvention.h
new file mode 100644
index 000000000..0b0d43adc
--- /dev/null
+++ b/src/Fusion/FusionConvention.h
@@ -0,0 +1,25 @@
+/**
+ * @file FusionConvention.h
+ * @author Seb Madgwick
+ * @brief Earth axes convention.
+ */
+
+#ifndef FUSION_CONVENTION_H
+#define FUSION_CONVENTION_H
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief Earth axes convention.
+ */
+typedef enum {
+ FusionConventionNwu, /* North-West-Up */
+ FusionConventionEnu, /* East-North-Up */
+ FusionConventionNed, /* North-East-Down */
+} FusionConvention;
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionMath.h b/src/Fusion/FusionMath.h
new file mode 100644
index 000000000..c3fc34b2d
--- /dev/null
+++ b/src/Fusion/FusionMath.h
@@ -0,0 +1,503 @@
+/**
+ * @file FusionMath.h
+ * @author Seb Madgwick
+ * @brief Math library.
+ */
+
+#ifndef FUSION_MATH_H
+#define FUSION_MATH_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include // M_PI, sqrtf, atan2f, asinf
+#include
+#include
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief 3D vector.
+ */
+typedef union {
+ float array[3];
+
+ struct {
+ float x;
+ float y;
+ float z;
+ } axis;
+} FusionVector;
+
+/**
+ * @brief Quaternion.
+ */
+typedef union {
+ float array[4];
+
+ struct {
+ float w;
+ float x;
+ float y;
+ float z;
+ } element;
+} FusionQuaternion;
+
+/**
+ * @brief 3x3 matrix in row-major order.
+ * See http://en.wikipedia.org/wiki/Row-major_order
+ */
+typedef union {
+ float array[3][3];
+
+ struct {
+ float xx;
+ float xy;
+ float xz;
+ float yx;
+ float yy;
+ float yz;
+ float zx;
+ float zy;
+ float zz;
+ } element;
+} FusionMatrix;
+
+/**
+ * @brief Euler angles. Roll, pitch, and yaw correspond to rotations around
+ * X, Y, and Z respectively.
+ */
+typedef union {
+ float array[3];
+
+ struct {
+ float roll;
+ float pitch;
+ float yaw;
+ } angle;
+} FusionEuler;
+
+/**
+ * @brief Vector of zeros.
+ */
+#define FUSION_VECTOR_ZERO ((FusionVector){.array = {0.0f, 0.0f, 0.0f}})
+
+/**
+ * @brief Vector of ones.
+ */
+#define FUSION_VECTOR_ONES ((FusionVector){.array = {1.0f, 1.0f, 1.0f}})
+
+/**
+ * @brief Identity quaternion.
+ */
+#define FUSION_IDENTITY_QUATERNION ((FusionQuaternion){.array = {1.0f, 0.0f, 0.0f, 0.0f}})
+
+/**
+ * @brief Identity matrix.
+ */
+#define FUSION_IDENTITY_MATRIX ((FusionMatrix){.array = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}})
+
+/**
+ * @brief Euler angles of zero.
+ */
+#define FUSION_EULER_ZERO ((FusionEuler){.array = {0.0f, 0.0f, 0.0f}})
+
+/**
+ * @brief Pi. May not be defined in math.h.
+ */
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+/**
+ * @brief Include this definition or add as a preprocessor definition to use
+ * normal square root operations.
+ */
+// #define FUSION_USE_NORMAL_SQRT
+
+//------------------------------------------------------------------------------
+// Inline functions - Degrees and radians conversion
+
+/**
+ * @brief Converts degrees to radians.
+ * @param degrees Degrees.
+ * @return Radians.
+ */
+static inline float FusionDegreesToRadians(const float degrees)
+{
+ return degrees * ((float)M_PI / 180.0f);
+}
+
+/**
+ * @brief Converts radians to degrees.
+ * @param radians Radians.
+ * @return Degrees.
+ */
+static inline float FusionRadiansToDegrees(const float radians)
+{
+ return radians * (180.0f / (float)M_PI);
+}
+
+//------------------------------------------------------------------------------
+// Inline functions - Arc sine
+
+/**
+ * @brief Returns the arc sine of the value.
+ * @param value Value.
+ * @return Arc sine of the value.
+ */
+static inline float FusionAsin(const float value)
+{
+ if (value <= -1.0f) {
+ return (float)M_PI / -2.0f;
+ }
+ if (value >= 1.0f) {
+ return (float)M_PI / 2.0f;
+ }
+ return asinf(value);
+}
+
+//------------------------------------------------------------------------------
+// Inline functions - Fast inverse square root
+
+#ifndef FUSION_USE_NORMAL_SQRT
+
+/**
+ * @brief Calculates the reciprocal of the square root.
+ * See https://pizer.wordpress.com/2008/10/12/fast-inverse-square-root/
+ * @param x Operand.
+ * @return Reciprocal of the square root of x.
+ */
+static inline float FusionFastInverseSqrt(const float x)
+{
+
+ typedef union {
+ float f;
+ int32_t i;
+ } Union32;
+
+ Union32 union32 = {.f = x};
+ union32.i = 0x5F1F1412 - (union32.i >> 1);
+ return union32.f * (1.69000231f - 0.714158168f * x * union32.f * union32.f);
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+// Inline functions - Vector operations
+
+/**
+ * @brief Returns true if the vector is zero.
+ * @param vector Vector.
+ * @return True if the vector is zero.
+ */
+static inline bool FusionVectorIsZero(const FusionVector vector)
+{
+ return (vector.axis.x == 0.0f) && (vector.axis.y == 0.0f) && (vector.axis.z == 0.0f);
+}
+
+/**
+ * @brief Returns the sum of two vectors.
+ * @param vectorA Vector A.
+ * @param vectorB Vector B.
+ * @return Sum of two vectors.
+ */
+static inline FusionVector FusionVectorAdd(const FusionVector vectorA, const FusionVector vectorB)
+{
+ const FusionVector result = {.axis = {
+ .x = vectorA.axis.x + vectorB.axis.x,
+ .y = vectorA.axis.y + vectorB.axis.y,
+ .z = vectorA.axis.z + vectorB.axis.z,
+ }};
+ return result;
+}
+
+/**
+ * @brief Returns vector B subtracted from vector A.
+ * @param vectorA Vector A.
+ * @param vectorB Vector B.
+ * @return Vector B subtracted from vector A.
+ */
+static inline FusionVector FusionVectorSubtract(const FusionVector vectorA, const FusionVector vectorB)
+{
+ const FusionVector result = {.axis = {
+ .x = vectorA.axis.x - vectorB.axis.x,
+ .y = vectorA.axis.y - vectorB.axis.y,
+ .z = vectorA.axis.z - vectorB.axis.z,
+ }};
+ return result;
+}
+
+/**
+ * @brief Returns the sum of the elements.
+ * @param vector Vector.
+ * @return Sum of the elements.
+ */
+static inline float FusionVectorSum(const FusionVector vector)
+{
+ return vector.axis.x + vector.axis.y + vector.axis.z;
+}
+
+/**
+ * @brief Returns the multiplication of a vector by a scalar.
+ * @param vector Vector.
+ * @param scalar Scalar.
+ * @return Multiplication of a vector by a scalar.
+ */
+static inline FusionVector FusionVectorMultiplyScalar(const FusionVector vector, const float scalar)
+{
+ const FusionVector result = {.axis = {
+ .x = vector.axis.x * scalar,
+ .y = vector.axis.y * scalar,
+ .z = vector.axis.z * scalar,
+ }};
+ return result;
+}
+
+/**
+ * @brief Calculates the Hadamard product (element-wise multiplication).
+ * @param vectorA Vector A.
+ * @param vectorB Vector B.
+ * @return Hadamard product.
+ */
+static inline FusionVector FusionVectorHadamardProduct(const FusionVector vectorA, const FusionVector vectorB)
+{
+ const FusionVector result = {.axis = {
+ .x = vectorA.axis.x * vectorB.axis.x,
+ .y = vectorA.axis.y * vectorB.axis.y,
+ .z = vectorA.axis.z * vectorB.axis.z,
+ }};
+ return result;
+}
+
+/**
+ * @brief Returns the cross product.
+ * @param vectorA Vector A.
+ * @param vectorB Vector B.
+ * @return Cross product.
+ */
+static inline FusionVector FusionVectorCrossProduct(const FusionVector vectorA, const FusionVector vectorB)
+{
+#define A vectorA.axis
+#define B vectorB.axis
+ const FusionVector result = {.axis = {
+ .x = A.y * B.z - A.z * B.y,
+ .y = A.z * B.x - A.x * B.z,
+ .z = A.x * B.y - A.y * B.x,
+ }};
+ return result;
+#undef A
+#undef B
+}
+
+/**
+ * @brief Returns the dot product.
+ * @param vectorA Vector A.
+ * @param vectorB Vector B.
+ * @return Dot product.
+ */
+static inline float FusionVectorDotProduct(const FusionVector vectorA, const FusionVector vectorB)
+{
+ return FusionVectorSum(FusionVectorHadamardProduct(vectorA, vectorB));
+}
+
+/**
+ * @brief Returns the vector magnitude squared.
+ * @param vector Vector.
+ * @return Vector magnitude squared.
+ */
+static inline float FusionVectorMagnitudeSquared(const FusionVector vector)
+{
+ return FusionVectorSum(FusionVectorHadamardProduct(vector, vector));
+}
+
+/**
+ * @brief Returns the vector magnitude.
+ * @param vector Vector.
+ * @return Vector magnitude.
+ */
+static inline float FusionVectorMagnitude(const FusionVector vector)
+{
+ return sqrtf(FusionVectorMagnitudeSquared(vector));
+}
+
+/**
+ * @brief Returns the normalised vector.
+ * @param vector Vector.
+ * @return Normalised vector.
+ */
+static inline FusionVector FusionVectorNormalise(const FusionVector vector)
+{
+#ifdef FUSION_USE_NORMAL_SQRT
+ const float magnitudeReciprocal = 1.0f / sqrtf(FusionVectorMagnitudeSquared(vector));
+#else
+ const float magnitudeReciprocal = FusionFastInverseSqrt(FusionVectorMagnitudeSquared(vector));
+#endif
+ return FusionVectorMultiplyScalar(vector, magnitudeReciprocal);
+}
+
+//------------------------------------------------------------------------------
+// Inline functions - Quaternion operations
+
+/**
+ * @brief Returns the sum of two quaternions.
+ * @param quaternionA Quaternion A.
+ * @param quaternionB Quaternion B.
+ * @return Sum of two quaternions.
+ */
+static inline FusionQuaternion FusionQuaternionAdd(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB)
+{
+ const FusionQuaternion result = {.element = {
+ .w = quaternionA.element.w + quaternionB.element.w,
+ .x = quaternionA.element.x + quaternionB.element.x,
+ .y = quaternionA.element.y + quaternionB.element.y,
+ .z = quaternionA.element.z + quaternionB.element.z,
+ }};
+ return result;
+}
+
+/**
+ * @brief Returns the multiplication of two quaternions.
+ * @param quaternionA Quaternion A (to be post-multiplied).
+ * @param quaternionB Quaternion B (to be pre-multiplied).
+ * @return Multiplication of two quaternions.
+ */
+static inline FusionQuaternion FusionQuaternionMultiply(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB)
+{
+#define A quaternionA.element
+#define B quaternionB.element
+ const FusionQuaternion result = {.element = {
+ .w = A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z,
+ .x = A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y,
+ .y = A.w * B.y - A.x * B.z + A.y * B.w + A.z * B.x,
+ .z = A.w * B.z + A.x * B.y - A.y * B.x + A.z * B.w,
+ }};
+ return result;
+#undef A
+#undef B
+}
+
+/**
+ * @brief Returns the multiplication of a quaternion with a vector. This is a
+ * normal quaternion multiplication where the vector is treated a
+ * quaternion with a W element value of zero. The quaternion is post-
+ * multiplied by the vector.
+ * @param quaternion Quaternion.
+ * @param vector Vector.
+ * @return Multiplication of a quaternion with a vector.
+ */
+static inline FusionQuaternion FusionQuaternionMultiplyVector(const FusionQuaternion quaternion, const FusionVector vector)
+{
+#define Q quaternion.element
+#define V vector.axis
+ const FusionQuaternion result = {.element = {
+ .w = -Q.x * V.x - Q.y * V.y - Q.z * V.z,
+ .x = Q.w * V.x + Q.y * V.z - Q.z * V.y,
+ .y = Q.w * V.y - Q.x * V.z + Q.z * V.x,
+ .z = Q.w * V.z + Q.x * V.y - Q.y * V.x,
+ }};
+ return result;
+#undef Q
+#undef V
+}
+
+/**
+ * @brief Returns the normalised quaternion.
+ * @param quaternion Quaternion.
+ * @return Normalised quaternion.
+ */
+static inline FusionQuaternion FusionQuaternionNormalise(const FusionQuaternion quaternion)
+{
+#define Q quaternion.element
+#ifdef FUSION_USE_NORMAL_SQRT
+ const float magnitudeReciprocal = 1.0f / sqrtf(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z);
+#else
+ const float magnitudeReciprocal = FusionFastInverseSqrt(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z);
+#endif
+ const FusionQuaternion result = {.element = {
+ .w = Q.w * magnitudeReciprocal,
+ .x = Q.x * magnitudeReciprocal,
+ .y = Q.y * magnitudeReciprocal,
+ .z = Q.z * magnitudeReciprocal,
+ }};
+ return result;
+#undef Q
+}
+
+//------------------------------------------------------------------------------
+// Inline functions - Matrix operations
+
+/**
+ * @brief Returns the multiplication of a matrix with a vector.
+ * @param matrix Matrix.
+ * @param vector Vector.
+ * @return Multiplication of a matrix with a vector.
+ */
+static inline FusionVector FusionMatrixMultiplyVector(const FusionMatrix matrix, const FusionVector vector)
+{
+#define R matrix.element
+ const FusionVector result = {.axis = {
+ .x = R.xx * vector.axis.x + R.xy * vector.axis.y + R.xz * vector.axis.z,
+ .y = R.yx * vector.axis.x + R.yy * vector.axis.y + R.yz * vector.axis.z,
+ .z = R.zx * vector.axis.x + R.zy * vector.axis.y + R.zz * vector.axis.z,
+ }};
+ return result;
+#undef R
+}
+
+//------------------------------------------------------------------------------
+// Inline functions - Conversion operations
+
+/**
+ * @brief Converts a quaternion to a rotation matrix.
+ * @param quaternion Quaternion.
+ * @return Rotation matrix.
+ */
+static inline FusionMatrix FusionQuaternionToMatrix(const FusionQuaternion quaternion)
+{
+#define Q quaternion.element
+ const float qwqw = Q.w * Q.w; // calculate common terms to avoid repeated operations
+ const float qwqx = Q.w * Q.x;
+ const float qwqy = Q.w * Q.y;
+ const float qwqz = Q.w * Q.z;
+ const float qxqy = Q.x * Q.y;
+ const float qxqz = Q.x * Q.z;
+ const float qyqz = Q.y * Q.z;
+ const FusionMatrix matrix = {.element = {
+ .xx = 2.0f * (qwqw - 0.5f + Q.x * Q.x),
+ .xy = 2.0f * (qxqy - qwqz),
+ .xz = 2.0f * (qxqz + qwqy),
+ .yx = 2.0f * (qxqy + qwqz),
+ .yy = 2.0f * (qwqw - 0.5f + Q.y * Q.y),
+ .yz = 2.0f * (qyqz - qwqx),
+ .zx = 2.0f * (qxqz - qwqy),
+ .zy = 2.0f * (qyqz + qwqx),
+ .zz = 2.0f * (qwqw - 0.5f + Q.z * Q.z),
+ }};
+ return matrix;
+#undef Q
+}
+
+/**
+ * @brief Converts a quaternion to ZYX Euler angles in degrees.
+ * @param quaternion Quaternion.
+ * @return Euler angles in degrees.
+ */
+static inline FusionEuler FusionQuaternionToEuler(const FusionQuaternion quaternion)
+{
+#define Q quaternion.element
+ const float halfMinusQySquared = 0.5f - Q.y * Q.y; // calculate common terms to avoid repeated operations
+ const FusionEuler euler = {.angle = {
+ .roll = FusionRadiansToDegrees(atan2f(Q.w * Q.x + Q.y * Q.z, halfMinusQySquared - Q.x * Q.x)),
+ .pitch = FusionRadiansToDegrees(FusionAsin(2.0f * (Q.w * Q.y - Q.z * Q.x))),
+ .yaw = FusionRadiansToDegrees(atan2f(Q.w * Q.z + Q.x * Q.y, halfMinusQySquared - Q.z * Q.z)),
+ }};
+ return euler;
+#undef Q
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionOffset.c b/src/Fusion/FusionOffset.c
new file mode 100644
index 000000000..d4334c874
--- /dev/null
+++ b/src/Fusion/FusionOffset.c
@@ -0,0 +1,80 @@
+/**
+ * @file FusionOffset.c
+ * @author Seb Madgwick
+ * @brief Gyroscope offset correction algorithm for run-time calibration of the
+ * gyroscope offset.
+ */
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionOffset.h"
+#include // fabsf
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief Cutoff frequency in Hz.
+ */
+#define CUTOFF_FREQUENCY (0.02f)
+
+/**
+ * @brief Timeout in seconds.
+ */
+#define TIMEOUT (5)
+
+/**
+ * @brief Threshold in degrees per second.
+ */
+#define THRESHOLD (3.0f)
+
+//------------------------------------------------------------------------------
+// Functions
+
+/**
+ * @brief Initialises the gyroscope offset algorithm.
+ * @param offset Gyroscope offset algorithm structure.
+ * @param sampleRate Sample rate in Hz.
+ */
+void FusionOffsetInitialise(FusionOffset *const offset, const unsigned int sampleRate)
+{
+ offset->filterCoefficient = 2.0f * (float)M_PI * CUTOFF_FREQUENCY * (1.0f / (float)sampleRate);
+ offset->timeout = TIMEOUT * sampleRate;
+ offset->timer = 0;
+ offset->gyroscopeOffset = FUSION_VECTOR_ZERO;
+}
+
+/**
+ * @brief Updates the gyroscope offset algorithm and returns the corrected
+ * gyroscope measurement.
+ * @param offset Gyroscope offset algorithm structure.
+ * @param gyroscope Gyroscope measurement in degrees per second.
+ * @return Corrected gyroscope measurement in degrees per second.
+ */
+FusionVector FusionOffsetUpdate(FusionOffset *const offset, FusionVector gyroscope)
+{
+
+ // Subtract offset from gyroscope measurement
+ gyroscope = FusionVectorSubtract(gyroscope, offset->gyroscopeOffset);
+
+ // Reset timer if gyroscope not stationary
+ if ((fabsf(gyroscope.axis.x) > THRESHOLD) || (fabsf(gyroscope.axis.y) > THRESHOLD) || (fabsf(gyroscope.axis.z) > THRESHOLD)) {
+ offset->timer = 0;
+ return gyroscope;
+ }
+
+ // Increment timer while gyroscope stationary
+ if (offset->timer < offset->timeout) {
+ offset->timer++;
+ return gyroscope;
+ }
+
+ // Adjust offset if timer has elapsed
+ offset->gyroscopeOffset =
+ FusionVectorAdd(offset->gyroscopeOffset, FusionVectorMultiplyScalar(gyroscope, offset->filterCoefficient));
+ return gyroscope;
+}
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Fusion/FusionOffset.h b/src/Fusion/FusionOffset.h
new file mode 100644
index 000000000..51ae4a896
--- /dev/null
+++ b/src/Fusion/FusionOffset.h
@@ -0,0 +1,40 @@
+/**
+ * @file FusionOffset.h
+ * @author Seb Madgwick
+ * @brief Gyroscope offset correction algorithm for run-time calibration of the
+ * gyroscope offset.
+ */
+
+#ifndef FUSION_OFFSET_H
+#define FUSION_OFFSET_H
+
+//------------------------------------------------------------------------------
+// Includes
+
+#include "FusionMath.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+
+/**
+ * @brief Gyroscope offset algorithm structure. Structure members are used
+ * internally and must not be accessed by the application.
+ */
+typedef struct {
+ float filterCoefficient;
+ unsigned int timeout;
+ unsigned int timer;
+ FusionVector gyroscopeOffset;
+} FusionOffset;
+
+//------------------------------------------------------------------------------
+// Function declarations
+
+void FusionOffsetInitialise(FusionOffset *const offset, const unsigned int sampleRate);
+
+FusionVector FusionOffsetUpdate(FusionOffset *const offset, FusionVector gyroscope);
+
+#endif
+
+//------------------------------------------------------------------------------
+// End of file
diff --git a/src/Power.cpp b/src/Power.cpp
index 64e310b68..d80bfd55c 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -50,7 +50,7 @@ RTC_NOINIT_ATTR uint64_t RTC_reg_b;
esp_adc_cal_characteristics_t *adc_characs = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
#ifndef ADC_ATTENUATION
-static const adc_atten_t atten = ADC_ATTEN_DB_11;
+static const adc_atten_t atten = ADC_ATTEN_DB_12;
#else
static const adc_atten_t atten = ADC_ATTENUATION;
#endif
@@ -335,13 +335,20 @@ class AnalogBatteryLevel : public HasBatteryLevel
virtual bool isVbusIn() override
{
#ifdef EXT_PWR_DETECT
- // if external powered that pin will be pulled up
- if (digitalRead(EXT_PWR_DETECT) == HIGH) {
- return true;
- }
- // if it's not HIGH - check the battery
+ #ifdef HELTEC_CAPSULE_SENSOR_V3
+ // if external powered that pin will be pulled down
+ if (digitalRead(EXT_PWR_DETECT) == LOW) {
+ return true;
+ }
+ // if it's not LOW - check the battery
+ #else
+ // if external powered that pin will be pulled up
+ if (digitalRead(EXT_PWR_DETECT) == HIGH) {
+ return true;
+ }
+ // if it's not HIGH - check the battery
+ #endif
#endif
-
return getBattVoltage() > chargingVolt;
}
@@ -421,7 +428,11 @@ Power::Power() : OSThread("Power")
bool Power::analogInit()
{
#ifdef EXT_PWR_DETECT
- pinMode(EXT_PWR_DETECT, INPUT);
+ #ifdef HELTEC_CAPSULE_SENSOR_V3
+ pinMode(EXT_PWR_DETECT, INPUT_PULLUP);
+ #else
+ pinMode(EXT_PWR_DETECT, INPUT);
+ #endif
#endif
#ifdef EXT_CHRG_DETECT
pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode);
@@ -555,14 +566,24 @@ void Power::readPowerStatus()
#ifdef NRF_APM // Section of code detects USB power on the RAK4631 and updates the power states. Takes 20 seconds or so to detect
// changes.
+ static nrfx_power_usb_state_t prev_nrf_usb_state = (nrfx_power_usb_state_t)-1; // -1 so that state detected at boot
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
- if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED) {
- powerFSM.trigger(EVENT_POWER_DISCONNECTED);
- NRF_USB = OptFalse;
- } else {
- powerFSM.trigger(EVENT_POWER_CONNECTED);
- NRF_USB = OptTrue;
+ // If state changed
+ if (nrf_usb_state != prev_nrf_usb_state) {
+ // If changed to DISCONNECTED
+ if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED) {
+ powerFSM.trigger(EVENT_POWER_DISCONNECTED);
+ NRF_USB = OptFalse;
+ }
+ // If changed to CONNECTED / READY
+ else {
+ powerFSM.trigger(EVENT_POWER_CONNECTED);
+ NRF_USB = OptTrue;
+ }
+
+ // Cache the current state
+ prev_nrf_usb_state = nrf_usb_state;
}
#endif
// Notify any status instances that are observing us
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index 4f42b36b5..a7bc18f1a 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -348,12 +348,18 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
- powerFSM.add_timed_transition(&stateON, &stateDARK,
- Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
- "Screen-on timeout");
- powerFSM.add_timed_transition(&statePOWER, &stateDARK,
- Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
- "Screen-on timeout");
+#ifdef USE_EINK
+ // Allow E-Ink devices to suppress the screensaver, if screen timeout set to 0
+ if (config.display.screen_on_secs > 0)
+#endif
+ {
+ powerFSM.add_timed_transition(&stateON, &stateDARK,
+ Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs),
+ NULL, "Screen-on timeout");
+ powerFSM.add_timed_transition(&statePOWER, &stateDARK,
+ Default::getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs),
+ NULL, "Screen-on timeout");
+ }
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32
diff --git a/src/PowerStatus.h b/src/PowerStatus.h
index 56d19b758..592a03328 100644
--- a/src/PowerStatus.h
+++ b/src/PowerStatus.h
@@ -59,9 +59,18 @@ class PowerStatus : public Status
int getBatteryVoltageMv() const { return batteryVoltageMv; }
/**
- * Note: 0% battery means 'unknown/this board doesn't have a battery installed'
+ * Note: for boards with battery pin or PMU, 0% battery means 'unknown/this board doesn't have a battery installed'
*/
+#if defined(HAS_PMU) || defined(BATTERY_PIN)
uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 0; }
+#endif
+
+ /**
+ * Note: for boards without battery pin and PMU, 101% battery means 'the board is using external power'
+ */
+#if !defined(HAS_PMU) && !defined(BATTERY_PIN)
+ uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 101; }
+#endif
bool matches(const PowerStatus *newStatus) const
{
diff --git a/src/configuration.h b/src/configuration.h
index 0d9ee5451..1149f344c 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -128,7 +128,15 @@ along with this program. If not, see .
#define LPS22HB_ADDR_ALT 0x5D
#define SHT31_4x_ADDR 0x44
#define PMSA0031_ADDR 0x12
+#define AHT10_ADDR 0x38
#define RCWL9620_ADDR 0x57
+#define VEML7700_ADDR 0x10
+#define TSL25911_ADDR 0x29
+#define OPT3001_ADDR 0x45
+#define OPT3001_ADDR_ALT 0x44
+#define MLX90632_ADDR 0x3A
+#define DFROBOT_LARK_ADDR 0x42
+#define NAU7802_ADDR 0x2A
// -----------------------------------------------------------------------------
// ACCELEROMETER
@@ -137,6 +145,7 @@ along with this program. If not, see .
#define LIS3DH_ADR 0x18
#define BMA423_ADDR 0x19
#define LSM6DS3_ADDR 0x6A
+#define BMX160_ADDR 0x69
// -----------------------------------------------------------------------------
// LED
diff --git a/src/detect/LoRaRadioType.h b/src/detect/LoRaRadioType.h
index eadd92e64..3975153b5 100644
--- a/src/detect/LoRaRadioType.h
+++ b/src/detect/LoRaRadioType.h
@@ -1,5 +1,16 @@
#pragma once
-enum LoRaRadioType { NO_RADIO, STM32WLx_RADIO, SIM_RADIO, RF95_RADIO, SX1262_RADIO, SX1268_RADIO, LLCC68_RADIO, SX1280_RADIO };
+enum LoRaRadioType {
+ NO_RADIO,
+ STM32WLx_RADIO,
+ SIM_RADIO,
+ RF95_RADIO,
+ SX1262_RADIO,
+ SX1268_RADIO,
+ LLCC68_RADIO,
+ SX1280_RADIO,
+ LR1110_RADIO,
+ LR1120_RADIO
+};
extern LoRaRadioType radioType;
\ No newline at end of file
diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp
index 149bb95f0..3231f7054 100644
--- a/src/detect/ScanI2C.cpp
+++ b/src/detect/ScanI2C.cpp
@@ -36,8 +36,8 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
- ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3};
- return firstOfOrNONE(4, types);
+ ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160};
+ return firstOfOrNONE(5, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index a53df11f3..dcc1f40ae 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -42,8 +42,16 @@ class ScanI2C
BQ24295,
LSM6DS3,
TCA9555,
+ VEML7700,
RCWL9620,
NCP5623,
+ TSL2591,
+ OPT3001,
+ MLX90632,
+ AHT10,
+ BMX160,
+ DFROBOT_LARK,
+ NAU7802
} DeviceType;
// typedef uint8_t DeviceAddress;
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 58d46a58d..6766db014 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -256,7 +256,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
type = BMP_280;
}
break;
-
+#ifndef HAS_NCP5623
+ case AHT10_ADDR:
+ LOG_INFO("AHT10 sensor found at address 0x%x\n", (uint8_t)addr.address);
+ type = AHT10;
+ break;
+#endif
case INA_ADDR:
case INA_ADDR_ALTERNATE:
case INA_ADDR_WAVESHARE_UPS:
@@ -276,8 +281,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
if (registerValue == 0x5449) {
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA3221;
- } else { // Unknown device
- LOG_INFO("No INA3221 found at address 0x%x\n", (uint8_t)addr.address);
+ } else {
+ LOG_INFO("DFRobot Lark weather station found at address 0x%x\n", (uint8_t)addr.address);
+ type = DFROBOT_LARK;
}
break;
case MCP9808_ADDR:
@@ -297,6 +303,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
if (registerValue == 0x11a2) {
type = SHT4X;
LOG_INFO("SHT4X sensor found\n");
+ } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
+ type = OPT3001;
+ LOG_INFO("OPT3001 light sensor found\n");
} else {
type = SHT31;
LOG_INFO("SHT31 sensor found\n");
@@ -333,9 +342,15 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n");
+ SCAN_SIMPLE_CASE(BMX160_ADDR, BMX160, "BMX160 accelerometer found\n");
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x\n", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found\n");
+ SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700 light sensor found\n");
+ SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found\n");
+ SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found\n");
+ SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n");
+ SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n");
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
@@ -368,4 +383,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
-}
+}
\ No newline at end of file
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index eaae049b5..8d46742ba 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -21,6 +21,19 @@
#define GPS_RESET_MODE HIGH
#endif
+// How many minutes of sleep make it worthwhile to power-off the GPS
+// Shorter than this, and GPS will only enter standby
+// Affected by lock-time, and config.position.gps_update_interval
+#ifndef GPS_STANDBY_THRESHOLD_MINUTES
+#define GPS_STANDBY_THRESHOLD_MINUTES 15
+#endif
+
+// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby
+// Shorter than this, and we'll just wait instead
+#ifndef GPS_IDLE_THRESHOLD_SECONDS
+#define GPS_IDLE_THRESHOLD_SECONDS 10
+#endif
+
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
HardwareSerial *GPS::_serial_gps = &Serial1;
#else
@@ -472,6 +485,9 @@ bool GPS::setup()
// Turn off GSV messages, we don't really care about which and where the sats are, maybe someday.
_serial_gps->write("$CFGMSG,0,3,0\r\n");
delay(250);
+ // Turn off GSA messages, TinyGPS++ doesn't use this message.
+ _serial_gps->write("$CFGMSG,0,2,0\r\n");
+ delay(250);
// Turn off NOTICE __TXT messages, these may provide Unicore some info but we don't care.
_serial_gps->write("$CFGMSG,6,0,0\r\n");
delay(250);
@@ -764,7 +780,24 @@ GPS::~GPS()
void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
{
- LOG_INFO("Setting GPS power=%d\n", on);
+ // Record the current powerState
+ if (on)
+ powerState = GPS_ACTIVE;
+ else if (!enabled) // User has disabled with triple press
+ powerState = GPS_OFF;
+ else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL)
+ powerState = GPS_IDLE;
+ else if (standbyOnly)
+ powerState = GPS_STANDBY;
+ else
+ powerState = GPS_OFF;
+
+ LOG_DEBUG("GPS::powerState=%d\n", powerState);
+
+ // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out.
+ if (!on && powerState == GPS_IDLE)
+ return;
+
if (on) {
clearBuffer(); // drop any old data waiting in the buffer before re-enabling
if (en_gpio)
@@ -858,45 +891,72 @@ void GPS::setConnected()
*
* calls sleep/wake
*/
-void GPS::setAwake(bool on)
+void GPS::setAwake(bool wantAwake)
{
- if (isAwake != on) {
- LOG_DEBUG("WANT GPS=%d\n", on);
- isAwake = on;
- if (!enabled) { // short circuit if the user has disabled GPS
- setGPSPower(false, false, 0);
- return;
- }
- if (on) {
+ // If user has disabled GPS, make sure it is off, not just in standby or idle
+ if (!wantAwake && !enabled && powerState != GPS_OFF) {
+ setGPSPower(false, false, 0);
+ return;
+ }
+
+ // If GPS power state needs to change
+ if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) {
+ LOG_DEBUG("WANT GPS=%d\n", wantAwake);
+
+ // Calculate how long it takes to get a GPS lock
+ if (wantAwake) {
+ // Record the time we start looking for a lock
lastWakeStartMsec = millis();
} else {
+ // Record by how much we missed our ideal target postion.gps_update_interval (for logging only)
+ // Need to calculate this before we update lastSleepStartMsec, to make the new prediction
+ int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime();
+
+ // Record the time we finish looking for a lock
lastSleepStartMsec = millis();
- if (GPSCycles == 1) { // Skipping initial lock time, as it will likely be much longer than average
- averageLockTime = lastSleepStartMsec - lastWakeStartMsec;
- } else if (GPSCycles > 1) {
- averageLockTime += ((int32_t)(lastSleepStartMsec - lastWakeStartMsec) - averageLockTime) / (int32_t)GPSCycles;
+
+ // How long did it take to get GPS lock this time?
+ uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec;
+
+ // Update the lock-time prediction
+ // Used pre-emptively, attempting to hit target of gps.position_update_interval
+ switch (GPSCycles) {
+ case 0:
+ LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000);
+ break;
+ case 1:
+ predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value
+ LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000);
+ break;
+ default:
+ // Predict lock-time using exponential smoothing: respond slowly to changes
+ predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction
+ LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000,
+ (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000);
}
GPSCycles++;
- LOG_DEBUG("GPS Lock took %d, average %d\n", (lastSleepStartMsec - lastWakeStartMsec) / 1000, averageLockTime / 1000);
}
- if ((int32_t)getSleepTime() - averageLockTime >
- 15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it.
- setGPSPower(on, false, getSleepTime() - averageLockTime);
- return;
- } else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby
+
+ // How long to wait before attempting next GPS update
+ // Aims to hit position.gps_update_interval by using the lock-time prediction
+ uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0;
+
+ // If long interval between updates: power off between updates
+ if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) {
+ setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime);
+ }
+
+ // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time
+ // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due
+ // Will decide which inside setGPSPower method
+ else {
#ifdef GPS_UC6580
- setGPSPower(on, false, getSleepTime() - averageLockTime);
+ setGPSPower(wantAwake, false, compensatedSleepTime);
#else
- setGPSPower(on, true, getSleepTime() - averageLockTime);
+ setGPSPower(wantAwake, true, compensatedSleepTime);
#endif
- return;
}
- if (averageLockTime > 20000) {
- averageLockTime -= 1000; // eventually want to sleep again.
- }
- if (on)
- setGPSPower(true, true, 0); // make sure we don't have a fallthrough where GPS is stuck off
}
}
@@ -1002,14 +1062,14 @@ int32_t GPS::runOnce()
uint32_t timeAsleep = now - lastSleepStartMsec;
auto sleepTime = getSleepTime();
- if (!isAwake && (sleepTime != UINT32_MAX) &&
- ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - averageLockTime)))) {
+ if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) &&
+ ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) {
// We now want to be awake - so wake up the GPS
setAwake(true);
}
// While we are awake
- if (isAwake) {
+ if (powerState == GPS_ACTIVE) {
// LOG_DEBUG("looking for location\n");
// If we've already set time from the GPS, no need to ask the GPS
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
@@ -1055,7 +1115,7 @@ int32_t GPS::runOnce()
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
- return isAwake ? GPS_THREAD_INTERVAL : 5000;
+ return (powerState == GPS_ACTIVE) ? GPS_THREAD_INTERVAL : 5000;
}
// clear the GPS rx buffer as quickly as possible
@@ -1586,9 +1646,9 @@ bool GPS::whileIdle()
{
unsigned int charsInBuf = 0;
bool isValid = false;
- if (!isAwake) {
+ if (powerState != GPS_ACTIVE) {
clearBuffer();
- return isAwake;
+ return (powerState == GPS_ACTIVE);
}
#ifdef SERIAL_BUFFER_SIZE
if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) {
@@ -1619,6 +1679,10 @@ bool GPS::whileIdle()
}
void GPS::enable()
{
+ // Clear the old lock-time prediction
+ GPSCycles = 0;
+ predictedLockTime = 0;
+
enabled = true;
setInterval(GPS_THREAD_INTERVAL);
setAwake(true);
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 77c6c0269..55bd42d0f 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -38,6 +38,13 @@ typedef enum {
GNSS_RESPONSE_OK,
} GPS_RESPONSE;
+enum GPSPowerState : uint8_t {
+ GPS_OFF = 0, // Physically powered off
+ GPS_ACTIVE = 1, // Awake and want a position
+ GPS_STANDBY = 2, // Physically powered on, but soft-sleeping
+ GPS_IDLE = 3, // Awake, but not wanting another position yet
+};
+
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
@@ -66,7 +73,7 @@ class GPS : private concurrency::OSThread
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
uint32_t en_gpio = 0;
- int32_t averageLockTime = 0;
+ uint32_t predictedLockTime = 0;
uint32_t GPSCycles = 0;
int speedSelect = 0;
@@ -78,8 +85,6 @@ class GPS : private concurrency::OSThread
*/
bool hasValidLocation = false; // default to false, until we complete our first read
- bool isAwake = false; // true if we want a location right now
-
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
@@ -89,6 +94,8 @@ class GPS : private concurrency::OSThread
bool GPSInitFinished = false; // Init thread finished?
bool GPSInitStarted = false; // Init thread finished?
+ GPSPowerState powerState = GPS_OFF; // GPS_ACTIVE if we want a location right now
+
uint8_t numSatellites = 0;
CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep);
diff --git a/src/gps/GeoCoord.cpp b/src/gps/GeoCoord.cpp
index cb4e69ff2..2224bd281 100644
--- a/src/gps/GeoCoord.cpp
+++ b/src/gps/GeoCoord.cpp
@@ -486,3 +486,91 @@ std::shared_ptr GeoCoord::pointAtDistance(double bearing, double range
return std::make_shared(double(lat), double(lon), this->getAltitude());
}
+
+/**
+ * Convert bearing to degrees
+ * @param bearing
+ * The bearing in string format
+ * @return Bearing in degrees
+ */
+uint GeoCoord::bearingToDegrees(const char *bearing)
+{
+ if (strcmp(bearing, "N") == 0)
+ return 0;
+ else if (strcmp(bearing, "NNE") == 0)
+ return 22;
+ else if (strcmp(bearing, "NE") == 0)
+ return 45;
+ else if (strcmp(bearing, "ENE") == 0)
+ return 67;
+ else if (strcmp(bearing, "E") == 0)
+ return 90;
+ else if (strcmp(bearing, "ESE") == 0)
+ return 112;
+ else if (strcmp(bearing, "SE") == 0)
+ return 135;
+ else if (strcmp(bearing, "SSE") == 0)
+ return 157;
+ else if (strcmp(bearing, "S") == 0)
+ return 180;
+ else if (strcmp(bearing, "SSW") == 0)
+ return 202;
+ else if (strcmp(bearing, "SW") == 0)
+ return 225;
+ else if (strcmp(bearing, "WSW") == 0)
+ return 247;
+ else if (strcmp(bearing, "W") == 0)
+ return 270;
+ else if (strcmp(bearing, "WNW") == 0)
+ return 292;
+ else if (strcmp(bearing, "NW") == 0)
+ return 315;
+ else if (strcmp(bearing, "NNW") == 0)
+ return 337;
+ else
+ return 0;
+}
+
+/**
+ * Convert bearing to string
+ * @param degrees
+ * The bearing in degrees
+ * @return Bearing in string format
+ */
+const char *GeoCoord::degreesToBearing(uint degrees)
+{
+ if (degrees >= 348 || degrees < 11)
+ return "N";
+ else if (degrees >= 11 && degrees < 34)
+ return "NNE";
+ else if (degrees >= 34 && degrees < 56)
+ return "NE";
+ else if (degrees >= 56 && degrees < 79)
+ return "ENE";
+ else if (degrees >= 79 && degrees < 101)
+ return "E";
+ else if (degrees >= 101 && degrees < 124)
+ return "ESE";
+ else if (degrees >= 124 && degrees < 146)
+ return "SE";
+ else if (degrees >= 146 && degrees < 169)
+ return "SSE";
+ else if (degrees >= 169 && degrees < 191)
+ return "S";
+ else if (degrees >= 191 && degrees < 214)
+ return "SSW";
+ else if (degrees >= 214 && degrees < 236)
+ return "SW";
+ else if (degrees >= 236 && degrees < 259)
+ return "WSW";
+ else if (degrees >= 259 && degrees < 281)
+ return "W";
+ else if (degrees >= 281 && degrees < 304)
+ return "WNW";
+ else if (degrees >= 304 && degrees < 326)
+ return "NW";
+ else if (degrees >= 326 && degrees < 348)
+ return "NNW";
+ else
+ return "N";
+}
diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h
index e811035db..b02d12afb 100644
--- a/src/gps/GeoCoord.h
+++ b/src/gps/GeoCoord.h
@@ -117,6 +117,8 @@ class GeoCoord
static float bearing(double lat1, double lon1, double lat2, double lon2);
static float rangeRadiansToMeters(double range_radians);
static float rangeMetersToRadians(double range_meters);
+ static uint bearingToDegrees(const char *bearing);
+ static const char *degreesToBearing(uint degrees);
// Point to point conversions
int32_t distanceTo(const GeoCoord &pointB);
diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp
index a2cdb5b30..d60e3825c 100644
--- a/src/gps/RTC.cpp
+++ b/src/gps/RTC.cpp
@@ -96,13 +96,17 @@ void readFromRTC()
*
* If we haven't yet set our RTC this boot, set it from a GPS derived time
*/
-bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
+bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
{
static uint32_t lastSetMsec = 0;
uint32_t now = millis();
bool shouldSet;
- if (q > currentQuality) {
+ if (forceUpdate) {
+ shouldSet = true;
+ LOG_DEBUG("Overriding current RTC quality (%s) with incoming time of RTC quality of %s\n", RtcName(currentQuality),
+ RtcName(q));
+ } else if (q > currentQuality) {
shouldSet = true;
LOG_DEBUG("Upgrading time to quality %s\n", RtcName(q));
} else if (q >= RTCQualityNTP && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
@@ -218,9 +222,8 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
*/
int32_t getTZOffset()
{
- time_t now;
+ time_t now = getTime(false);
struct tm *gmt;
- now = time(NULL);
gmt = gmtime(&now);
gmt->tm_isdst = -1;
return (int32_t)difftime(now, mktime(gmt));
@@ -261,4 +264,4 @@ time_t gm_mktime(struct tm *tm)
setenv("TZ", "UTC0", 1);
}
return res;
-}
+}
\ No newline at end of file
diff --git a/src/gps/RTC.h b/src/gps/RTC.h
index 1d609f136..4b065b376 100644
--- a/src/gps/RTC.h
+++ b/src/gps/RTC.h
@@ -25,7 +25,7 @@ enum RTCQuality {
RTCQuality getRTCQuality();
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
-bool perhapsSetRTC(RTCQuality q, const struct timeval *tv);
+bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate = false);
bool perhapsSetRTC(RTCQuality q, struct tm &t);
/// Return a string name for the quality
diff --git a/src/gps/ubx.h b/src/gps/ubx.h
index 5b2cb24ce..0852c331d 100644
--- a/src/gps/ubx.h
+++ b/src/gps/ubx.h
@@ -206,14 +206,14 @@ const uint8_t GPS::_message_GLL[] = {
0x00 // Reserved
};
-// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
+// Disable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
const uint8_t GPS::_message_GSA[] = {
0xF0, 0x02, // NMEA ID for GSA
0x00, // Rate for DDC
- 0x01, // Rate for UART1
+ 0x00, // Rate for UART1
0x00, // Rate for UART2
- 0x01, // Rate for USB usefull for native linux
+ 0x00, // Rate for USB usefull for native linux
0x00, // Rate for SPI
0x00 // Reserved
};
@@ -319,6 +319,8 @@ const uint8_t GPS::_message_SAVE[] = {
// As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR.
// BBR will survive a restart, and power off for a while, but modules with small backup
// batteries or super caps will not retain the config for a long power off time.
+// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after
+// sleep
// VALSET Commands for M10
// Please refer to the M10 Protocol Specification:
@@ -327,40 +329,42 @@ const uint8_t GPS::_message_SAVE[] = {
// and:
// https://content.u-blox.com/sites/default/files/u-blox-M10-ROM-5.10_ReleaseNotes_UBX-22001426.pdf
// for interesting insights.
+//
+// Integration manual:
+// https://content.u-blox.com/sites/default/files/documents/SAM-M10Q_IntegrationManual_UBX-22020019.pdf
+// has details on low-power modes
+
/*
CFG-PM2 has been replaced by many CFG-PM commands
-OPERATEMODE E1 2 (0 | 1 | 2)
-POSUPDATEPERIOD U4 1000ms for M10 must be >= 5s try 5
-ACQPERIOD U4 10 seems ok for M10 def ok
-GRIDOFFSET U4 0 seems ok for M10 def ok
-ONTIME U2 1 will try 1
-MINACQTIME U1 0 will try 0 def ok
-MAXACQTIME U1 stick with default of 0 def ok
-DONOTENTEROFF L 1 stay at 1
-WAITTIMEFIX L 1 stay with 1
-UPDATEEPH L 1 changed to 1 for gps rework default is 1
-EXTINTWAKE L 0 no ext ints
-EXTINTBACKUP L 0 no ext ints
-EXTINTINACTIVE L 0 no ext ints
-EXTINTACTIVITY U4 0 no ext ints
-LIMITPEAKCURRENT L 1 stay with 1
-*/
-// CFG-PMS has been removed
+CFG-PMS has been removed
+
+CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s
+(PSMCT) CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby
+mode" by legacy UBX-RXM-PMREQ request CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby
+mode" by legacy UBX-RXM-PMREQ request CFG-PM-ONTIME U4 -> 0ms, optional I guess CFG-PM-EXTINTBACKUP L -> 1, force receiver into
+BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low"
+
+This is required because the receiver never enters low power mode if microcontroller is in deep-sleep.
+Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled)
+the receivcer remains in aquisition state -> potentially a bug
+
+Workaround: Control the EXTINT pin by the GPS_EN_PIN signal
+
+As mentioned in the M10 operational issues down below, power save won't allow the use of BDS B1C.
+CFG-SIGNAL-BDS_B1C_ENA L -> 0
// Ram layer config message:
-// b5 62 06 8a 26 00 00 01 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
-// 10 01 8b de
+// 01 01 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
// BBR layer config message:
-// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
-// 10 01 8c 03
-
-const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
- 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
- 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
-const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
- 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
- 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
+// 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01
+*/
+const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
+ 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
+const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01,
+ 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01};
/*
CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR
@@ -402,23 +406,28 @@ const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00,
// BBR layer config message:
// b5 62 06 8a 09 00 00 02 00 00 07 00 92 20 06 5a 58
-// Turn NMEA GSA, GGA, RMC messages on:
-// Ram layer config message:
-// b5 62 06 8a 13 00 00 01 00 00 c0 00 91 20 01 bb 00 91 20 01 ac 00 91 20 01 e1 3b
-
-// BBR layer config message:
-// b5 62 06 8a 13 00 00 02 00 00 c0 00 91 20 01 bb 00 91 20 01 ac 00 91 20 01 e2 4d
+// Turn NMEA GGA, RMC messages on:
+// Layer config messages:
+// RAM:
+// b5 62 06 8a 0e 00 00 01 00 00 bb 00 91 20 01 ac 00 91 20 01 6a 8f
+// BBR:
+// b5 62 06 8a 0e 00 00 02 00 00 bb 00 91 20 01 ac 00 91 20 01 6b 9c
+// FLASH:
+// b5 62 06 8a 0e 00 00 04 00 00 bb 00 91 20 01 ac 00 91 20 01 6d b6
+// Doing this for the FLASH layer isn't really required since we save the config to flash later
const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
-const uint8_t GPS::_message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x91, 0x20, 0x01, 0xbb,
- 0x00, 0x91, 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
-const uint8_t GPS::_message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xc0, 0x00, 0x91, 0x20, 0x01, 0xbb,
- 0x00, 0x91, 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
+
+const uint8_t GPS::_message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91,
+ 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
+const uint8_t GPS::_message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91,
+ 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
const uint8_t GPS::_message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
const uint8_t GPS::_message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
+
/*
Operational issues with the M10:
diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp
index 04915fe07..bbc12521a 100644
--- a/src/graphics/EInkDisplay2.cpp
+++ b/src/graphics/EInkDisplay2.cpp
@@ -62,12 +62,19 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
return false;
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
+ const bool flipped = config.display.flip_screen;
for (uint32_t y = 0; y < displayHeight; y++) {
for (uint32_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7));
- adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
+
+ // Handle flip here, rather than with setRotation(),
+ // Avoids issues when display width is not a multiple of 8
+ if (flipped)
+ adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
+ else
+ adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
}
}
diff --git a/src/graphics/EInkDynamicDisplay.h b/src/graphics/EInkDynamicDisplay.h
index 8f3ce205a..9e131dca7 100644
--- a/src/graphics/EInkDynamicDisplay.h
+++ b/src/graphics/EInkDynamicDisplay.h
@@ -109,6 +109,7 @@ class EInkDynamicDisplay : public EInkDisplay, protected concurrency::NotifiedWo
refreshTypes currentConfig = FULL; // Which refresh type is GxEPD2 currently configured for
// Optional - track ghosting, pixel by pixel
+ // May 2024: no longer used by any display. Kept for possible future use.
#ifdef EINK_LIMIT_GHOSTING_PX
void countGhostPixels(); // Count any pixels which have moved from black to white since last full-refresh
void checkExcessiveGhosting(); // Check if ghosting exceeds defined limit
diff --git a/src/graphics/PointStruct.h b/src/graphics/PointStruct.h
new file mode 100644
index 000000000..218731978
--- /dev/null
+++ b/src/graphics/PointStruct.h
@@ -0,0 +1,4 @@
+struct PointStruct {
+ int x;
+ int y;
+};
\ No newline at end of file
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 0899335e6..60168cffc 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -277,6 +277,30 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
}
}
+/// Check if the display can render a string (detect special chars; emoji)
+static bool haveGlyphs(const char *str)
+{
+#if defined(OLED_UA) || defined(OLED_RU)
+ // Don't want to make any assumptions about custom language support
+ return true;
+#endif
+
+ // Check each character with the lookup function for the OLED library
+ // We're not really meant to use this directly..
+ bool have = true;
+ for (uint16_t i = 0; i < strlen(str); i++) {
+ uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]);
+ // If font doesn't support a character, it is substituted for ¿
+ if (result == 191 && (uint8_t)str[i] != 191) {
+ have = false;
+ break;
+ }
+ }
+
+ LOG_DEBUG("haveGlyphs=%d\n", have);
+ return have;
+}
+
#ifdef USE_EINK
/// Used on eink displays while in deep sleep
static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
@@ -301,14 +325,15 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *pauseText = "Screen Paused";
const char *idText = owner.short_name;
+ const bool useId = haveGlyphs(idText); // This bool is used to hide the idText box if we can't render the short name
constexpr uint16_t padding = 5;
constexpr uint8_t dividerGap = 1;
constexpr uint8_t imprecision = 5; // How far the box origins can drift from center. Combat burn-in.
// Dimensions
- const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText));
+ const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText), true); // "true": handle utf8 chars
const uint16_t pauseTextWidth = display->getStringWidth(pauseText, strlen(pauseText));
- const uint16_t boxWidth = padding + idTextWidth + padding + padding + pauseTextWidth + padding;
+ const uint16_t boxWidth = padding + (useId ? idTextWidth + padding + padding : 0) + pauseTextWidth + padding;
const uint16_t boxHeight = padding + FONT_HEIGHT_SMALL + padding;
// Position
@@ -318,7 +343,7 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta
const int16_t boxBottom = boxTop + boxHeight - 1;
const int16_t idTextLeft = boxLeft + padding;
const int16_t idTextTop = boxTop + padding;
- const int16_t pauseTextLeft = boxLeft + padding + idTextWidth + padding + padding;
+ const int16_t pauseTextLeft = boxLeft + (useId ? padding + idTextWidth + padding : 0) + padding;
const int16_t pauseTextTop = boxTop + padding;
const int16_t dividerX = boxLeft + padding + idTextWidth + padding;
const int16_t dividerTop = boxTop + 1 + dividerGap;
@@ -331,12 +356,14 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight);
// Draw: Text
- display->drawString(idTextLeft, idTextTop, idText);
+ if (useId)
+ display->drawString(idTextLeft, idTextTop, idText);
display->drawString(pauseTextLeft, pauseTextTop, pauseText);
display->drawString(pauseTextLeft + 1, pauseTextTop, pauseText); // Faux bold
// Draw: divider
- display->drawLine(dividerX, dividerTop, dividerX, dividerBottom);
+ if (useId)
+ display->drawLine(dividerX, dividerTop, dividerX, dividerBottom);
}
#endif
@@ -419,6 +446,536 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
return packet->from != 0 && !moduleConfig.store_forward.enabled;
}
+// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
+static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
+{
+ static const uint8_t powerBar[3] = {0x81, 0xBD, 0xBD};
+ static const uint8_t lightning[8] = {0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85};
+ // Clear the bar area on the battery image
+ for (int i = 1; i < 14; i++) {
+ imgBuffer[i] = 0x81;
+ }
+ // If charging, draw a charging indicator
+ if (powerStatus->getIsCharging()) {
+ memcpy(imgBuffer + 3, lightning, 8);
+ // If not charging, Draw power bars
+ } else {
+ for (int i = 0; i < 4; i++) {
+ if (powerStatus->getBatteryChargePercent() >= 25 * i)
+ memcpy(imgBuffer + 1 + (i * 3), powerBar, 3);
+ }
+ }
+ display->drawFastImage(x, y, 16, 8, imgBuffer);
+}
+
+#ifdef T_WATCH_S3
+
+void Screen::drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode, float scale)
+{
+ uint16_t segmentWidth = SEGMENT_WIDTH * scale;
+ uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
+
+ if (digitalMode) {
+ uint16_t radius = (segmentWidth + (segmentHeight * 2) + 4) / 2;
+ uint16_t centerX = (x + segmentHeight + 2) + (radius / 2);
+ uint16_t centerY = (y + segmentHeight + 2) + (radius / 2);
+
+ display->drawCircle(centerX, centerY, radius);
+ display->drawCircle(centerX, centerY, radius + 1);
+ display->drawLine(centerX, centerY, centerX, centerY - radius + 3);
+ display->drawLine(centerX, centerY, centerX + radius - 3, centerY);
+ } else {
+ uint16_t segmentOneX = x + segmentHeight + 2;
+ uint16_t segmentOneY = y;
+
+ uint16_t segmentTwoX = segmentOneX + segmentWidth + 2;
+ uint16_t segmentTwoY = segmentOneY + segmentHeight + 2;
+
+ uint16_t segmentThreeX = segmentOneX;
+ uint16_t segmentThreeY = segmentTwoY + segmentWidth + 2;
+
+ uint16_t segmentFourX = x;
+ uint16_t segmentFourY = y + segmentHeight + 2;
+
+ drawHorizontalSegment(display, segmentOneX, segmentOneY, segmentWidth, segmentHeight);
+ drawVerticalSegment(display, segmentTwoX, segmentTwoY, segmentWidth, segmentHeight);
+ drawHorizontalSegment(display, segmentThreeX, segmentThreeY, segmentWidth, segmentHeight);
+ drawVerticalSegment(display, segmentFourX, segmentFourY, segmentWidth, segmentHeight);
+ }
+}
+
+// Draw a digital clock
+void Screen::drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+
+ drawBattery(display, x, y + 7, imgBattery, powerStatus);
+
+ if (powerStatus->getHasBattery()) {
+ String batteryPercent = String(powerStatus->getBatteryChargePercent()) + "%";
+
+ display->setFont(FONT_SMALL);
+
+ display->drawString(x + 20, y + 2, batteryPercent);
+ }
+
+ if (nimbleBluetooth->isConnected()) {
+ drawBluetoothConnectedIcon(display, display->getWidth() - 18, y + 2);
+ }
+
+ drawWatchFaceToggleButton(display, display->getWidth() - 36, display->getHeight() - 36, screen->digitalWatchFace, 1);
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+
+ uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
+ if (rtc_sec > 0) {
+ long hms = rtc_sec % SEC_PER_DAY;
+ hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
+
+ int hour = hms / SEC_PER_HOUR;
+ int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
+ int second = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
+
+ hour = hour > 12 ? hour - 12 : hour;
+
+ if (hour == 0) {
+ hour = 12;
+ }
+
+ // hours string
+ String hourString = String(hour);
+
+ // minutes string
+ String minuteString = minute < 10 ? "0" + String(minute) : String(minute);
+
+ String timeString = hourString + ":" + minuteString;
+
+ // seconds string
+ String secondString = second < 10 ? "0" + String(second) : String(second);
+
+ float scale = 1.5;
+
+ uint16_t segmentWidth = SEGMENT_WIDTH * scale;
+ uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
+
+ // calculate hours:minutes string width
+ uint16_t timeStringWidth = timeString.length() * 5;
+
+ for (uint8_t i = 0; i < timeString.length(); i++) {
+ String character = String(timeString[i]);
+
+ if (character == ":") {
+ timeStringWidth += segmentHeight;
+ } else {
+ timeStringWidth += segmentWidth + (segmentHeight * 2) + 4;
+ }
+ }
+
+ // calculate seconds string width
+ uint16_t secondStringWidth = (secondString.length() * 12) + 4;
+
+ // sum these to get total string width
+ uint16_t totalWidth = timeStringWidth + secondStringWidth;
+
+ uint16_t hourMinuteTextX = (display->getWidth() / 2) - (totalWidth / 2);
+
+ uint16_t startingHourMinuteTextX = hourMinuteTextX;
+
+ uint16_t hourMinuteTextY = (display->getHeight() / 2) - (((segmentWidth * 2) + (segmentHeight * 3) + 8) / 2);
+
+ // iterate over characters in hours:minutes string and draw segmented characters
+ for (uint8_t i = 0; i < timeString.length(); i++) {
+ String character = String(timeString[i]);
+
+ if (character == ":") {
+ drawSegmentedDisplayColon(display, hourMinuteTextX, hourMinuteTextY, scale);
+
+ hourMinuteTextX += segmentHeight + 6;
+ } else {
+ drawSegmentedDisplayCharacter(display, hourMinuteTextX, hourMinuteTextY, character.toInt(), scale);
+
+ hourMinuteTextX += segmentWidth + (segmentHeight * 2) + 4;
+ }
+
+ hourMinuteTextX += 5;
+ }
+
+ // draw seconds string
+ display->setFont(FONT_MEDIUM);
+ display->drawString(startingHourMinuteTextX + timeStringWidth + 4,
+ (display->getHeight() - hourMinuteTextY) - FONT_HEIGHT_MEDIUM + 6, secondString);
+ }
+}
+
+void Screen::drawSegmentedDisplayColon(OLEDDisplay *display, int x, int y, float scale)
+{
+ uint16_t segmentWidth = SEGMENT_WIDTH * scale;
+ uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
+
+ uint16_t cellHeight = (segmentWidth * 2) + (segmentHeight * 3) + 8;
+
+ uint16_t topAndBottomX = x + (4 * scale);
+
+ uint16_t quarterCellHeight = cellHeight / 4;
+
+ uint16_t topY = y + quarterCellHeight;
+ uint16_t bottomY = y + (quarterCellHeight * 3);
+
+ display->fillRect(topAndBottomX, topY, segmentHeight, segmentHeight);
+ display->fillRect(topAndBottomX, bottomY, segmentHeight, segmentHeight);
+}
+
+void Screen::drawSegmentedDisplayCharacter(OLEDDisplay *display, int x, int y, uint8_t number, float scale)
+{
+ // the numbers 0-9, each expressed as an array of seven boolean (0|1) values encoding the on/off state of
+ // segment {innerIndex + 1}
+ // e.g., to display the numeral '0', segments 1-6 are on, and segment 7 is off.
+ uint8_t numbers[10][7] = {
+ {1, 1, 1, 1, 1, 1, 0}, // 0 Display segment key
+ {0, 1, 1, 0, 0, 0, 0}, // 1 1
+ {1, 1, 0, 1, 1, 0, 1}, // 2 ___
+ {1, 1, 1, 1, 0, 0, 1}, // 3 6 | | 2
+ {0, 1, 1, 0, 0, 1, 1}, // 4 |_7̲_|
+ {1, 0, 1, 1, 0, 1, 1}, // 5 5 | | 3
+ {1, 0, 1, 1, 1, 1, 1}, // 6 |___|
+ {1, 1, 1, 0, 0, 1, 0}, // 7
+ {1, 1, 1, 1, 1, 1, 1}, // 8 4
+ {1, 1, 1, 1, 0, 1, 1}, // 9
+ };
+
+ // the width and height of each segment's central rectangle:
+ // _____________________
+ // ⋰| (only this part, |⋱
+ // ⋰ | not including | ⋱
+ // ⋱ | the triangles | ⋰
+ // ⋱| on the ends) |⋰
+ // ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+
+ uint16_t segmentWidth = SEGMENT_WIDTH * scale;
+ uint16_t segmentHeight = SEGMENT_HEIGHT * scale;
+
+ // segment x and y coordinates
+ uint16_t segmentOneX = x + segmentHeight + 2;
+ uint16_t segmentOneY = y;
+
+ uint16_t segmentTwoX = segmentOneX + segmentWidth + 2;
+ uint16_t segmentTwoY = segmentOneY + segmentHeight + 2;
+
+ uint16_t segmentThreeX = segmentTwoX;
+ uint16_t segmentThreeY = segmentTwoY + segmentWidth + 2 + segmentHeight + 2;
+
+ uint16_t segmentFourX = segmentOneX;
+ uint16_t segmentFourY = segmentThreeY + segmentWidth + 2;
+
+ uint16_t segmentFiveX = x;
+ uint16_t segmentFiveY = segmentThreeY;
+
+ uint16_t segmentSixX = x;
+ uint16_t segmentSixY = segmentTwoY;
+
+ uint16_t segmentSevenX = segmentOneX;
+ uint16_t segmentSevenY = segmentTwoY + segmentWidth + 2;
+
+ if (numbers[number][0]) {
+ drawHorizontalSegment(display, segmentOneX, segmentOneY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][1]) {
+ drawVerticalSegment(display, segmentTwoX, segmentTwoY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][2]) {
+ drawVerticalSegment(display, segmentThreeX, segmentThreeY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][3]) {
+ drawHorizontalSegment(display, segmentFourX, segmentFourY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][4]) {
+ drawVerticalSegment(display, segmentFiveX, segmentFiveY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][5]) {
+ drawVerticalSegment(display, segmentSixX, segmentSixY, segmentWidth, segmentHeight);
+ }
+
+ if (numbers[number][6]) {
+ drawHorizontalSegment(display, segmentSevenX, segmentSevenY, segmentWidth, segmentHeight);
+ }
+}
+
+void Screen::drawHorizontalSegment(OLEDDisplay *display, int x, int y, int width, int height)
+{
+ int halfHeight = height / 2;
+
+ // draw central rectangle
+ display->fillRect(x, y, width, height);
+
+ // draw end triangles
+ display->fillTriangle(x, y, x, y + height - 1, x - halfHeight, y + halfHeight);
+
+ display->fillTriangle(x + width, y, x + width + halfHeight, y + halfHeight, x + width, y + height - 1);
+}
+
+void Screen::drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int height)
+{
+ int halfHeight = height / 2;
+
+ // draw central rectangle
+ display->fillRect(x, y, height, width);
+
+ // draw end triangles
+ display->fillTriangle(x + halfHeight, y - halfHeight, x + height - 1, y, x, y);
+
+ display->fillTriangle(x, y + width, x + height - 1, y + width, x + halfHeight, y + width + halfHeight);
+}
+
+void Screen::drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y)
+{
+ display->drawFastImage(x, y, 18, 14, bluetoothConnectedIcon);
+}
+
+// Draw an analog clock
+void Screen::drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+
+ drawBattery(display, x, y + 7, imgBattery, powerStatus);
+
+ if (powerStatus->getHasBattery()) {
+ String batteryPercent = String(powerStatus->getBatteryChargePercent()) + "%";
+
+ display->setFont(FONT_SMALL);
+
+ display->drawString(x + 20, y + 2, batteryPercent);
+ }
+
+ if (nimbleBluetooth->isConnected()) {
+ drawBluetoothConnectedIcon(display, display->getWidth() - 18, y + 2);
+ }
+
+ drawWatchFaceToggleButton(display, display->getWidth() - 36, display->getHeight() - 36, screen->digitalWatchFace, 1);
+
+ // clock face center coordinates
+ int16_t centerX = display->getWidth() / 2;
+ int16_t centerY = display->getHeight() / 2;
+
+ // clock face radius
+ int16_t radius = (display->getWidth() / 2) * 0.8;
+
+ // noon (0 deg) coordinates (outermost circle)
+ int16_t noonX = centerX;
+ int16_t noonY = centerY - radius;
+
+ // second hand radius and y coordinate (outermost circle)
+ int16_t secondHandNoonY = noonY + 1;
+
+ // tick mark outer y coordinate; (first nested circle)
+ int16_t tickMarkOuterNoonY = secondHandNoonY;
+
+ // seconds tick mark inner y coordinate; (second nested circle)
+ double secondsTickMarkInnerNoonY = (double)noonY + 8;
+
+ // hours tick mark inner y coordinate; (third nested circle)
+ double hoursTickMarkInnerNoonY = (double)noonY + 16;
+
+ // minute hand y coordinate
+ int16_t minuteHandNoonY = secondsTickMarkInnerNoonY + 4;
+
+ // hour string y coordinate
+ int16_t hourStringNoonY = minuteHandNoonY + 18;
+
+ // hour hand radius and y coordinate
+ int16_t hourHandRadius = radius * 0.55;
+ int16_t hourHandNoonY = centerY - hourHandRadius;
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+ display->drawCircle(centerX, centerY, radius);
+
+ uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
+ if (rtc_sec > 0) {
+ long hms = rtc_sec % SEC_PER_DAY;
+ hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
+
+ // Tear apart hms into h:m:s
+ int hour = hms / SEC_PER_HOUR;
+ int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
+ int second = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
+
+ hour = hour > 12 ? hour - 12 : hour;
+
+ int16_t degreesPerHour = 30;
+ int16_t degreesPerMinuteOrSecond = 6;
+
+ double hourBaseAngle = hour * degreesPerHour;
+ double hourAngleOffset = ((double)minute / 60) * degreesPerHour;
+ double hourAngle = radians(hourBaseAngle + hourAngleOffset);
+
+ double minuteBaseAngle = minute * degreesPerMinuteOrSecond;
+ double minuteAngleOffset = ((double)second / 60) * degreesPerMinuteOrSecond;
+ double minuteAngle = radians(minuteBaseAngle + minuteAngleOffset);
+
+ double secondAngle = radians(second * degreesPerMinuteOrSecond);
+
+ double hourX = sin(-hourAngle) * (hourHandNoonY - centerY) + noonX;
+ double hourY = cos(-hourAngle) * (hourHandNoonY - centerY) + centerY;
+
+ double minuteX = sin(-minuteAngle) * (minuteHandNoonY - centerY) + noonX;
+ double minuteY = cos(-minuteAngle) * (minuteHandNoonY - centerY) + centerY;
+
+ double secondX = sin(-secondAngle) * (secondHandNoonY - centerY) + noonX;
+ double secondY = cos(-secondAngle) * (secondHandNoonY - centerY) + centerY;
+
+ display->setFont(FONT_MEDIUM);
+
+ // draw minute and hour tick marks and hour numbers
+ for (uint16_t angle = 0; angle < 360; angle += 6) {
+ double angleInRadians = radians(angle);
+
+ double sineAngleInRadians = sin(-angleInRadians);
+ double cosineAngleInRadians = cos(-angleInRadians);
+
+ double endX = sineAngleInRadians * (tickMarkOuterNoonY - centerY) + noonX;
+ double endY = cosineAngleInRadians * (tickMarkOuterNoonY - centerY) + centerY;
+
+ if (angle % degreesPerHour == 0) {
+ double startX = sineAngleInRadians * (hoursTickMarkInnerNoonY - centerY) + noonX;
+ double startY = cosineAngleInRadians * (hoursTickMarkInnerNoonY - centerY) + centerY;
+
+ // draw hour tick mark
+ display->drawLine(startX, startY, endX, endY);
+
+ static char buffer[2];
+
+ uint8_t hourInt = (angle / 30);
+
+ if (hourInt == 0) {
+ hourInt = 12;
+ }
+
+ // hour number x offset needs to be adjusted for some cases
+ int8_t hourStringXOffset;
+ int8_t hourStringYOffset = 13;
+
+ switch (hourInt) {
+ case 3:
+ hourStringXOffset = 5;
+ break;
+ case 9:
+ hourStringXOffset = 7;
+ break;
+ case 10:
+ case 11:
+ hourStringXOffset = 8;
+ break;
+ case 12:
+ hourStringXOffset = 13;
+ break;
+ default:
+ hourStringXOffset = 6;
+ break;
+ }
+
+ double hourStringX = (sineAngleInRadians * (hourStringNoonY - centerY) + noonX) - hourStringXOffset;
+ double hourStringY = (cosineAngleInRadians * (hourStringNoonY - centerY) + centerY) - hourStringYOffset;
+
+ // draw hour number
+ display->drawStringf(hourStringX, hourStringY, buffer, "%d", hourInt);
+ }
+
+ if (angle % degreesPerMinuteOrSecond == 0) {
+ double startX = sineAngleInRadians * (secondsTickMarkInnerNoonY - centerY) + noonX;
+ double startY = cosineAngleInRadians * (secondsTickMarkInnerNoonY - centerY) + centerY;
+
+ // draw minute tick mark
+ display->drawLine(startX, startY, endX, endY);
+ }
+ }
+
+ // draw hour hand
+ display->drawLine(centerX, centerY, hourX, hourY);
+
+ // draw minute hand
+ display->drawLine(centerX, centerY, minuteX, minuteY);
+
+ // draw second hand
+ display->drawLine(centerX, centerY, secondX, secondY);
+ }
+}
+
+#endif
+
+// Get an absolute time from "seconds ago" info. Returns false if no valid timestamp possible
+bool deltaToTimestamp(uint32_t secondsAgo, uint8_t *hours, uint8_t *minutes, int32_t *daysAgo)
+{
+ // Cache the result - avoid frequent recalculation
+ static uint8_t hoursCached = 0, minutesCached = 0;
+ static uint32_t daysAgoCached = 0;
+ static uint32_t secondsAgoCached = 0;
+ static bool validCached = false;
+
+ // Abort: if timezone not set
+ if (strlen(config.device.tzdef) == 0) {
+ validCached = false;
+ return validCached;
+ }
+
+ // Abort: if invalid pointers passed
+ if (hours == nullptr || minutes == nullptr || daysAgo == nullptr) {
+ validCached = false;
+ return validCached;
+ }
+
+ // Abort: if time seems invalid.. (> 6 months ago, probably seen before RTC set)
+ if (secondsAgo > SEC_PER_DAY * 30UL * 6) {
+ validCached = false;
+ return validCached;
+ }
+
+ // If repeated request, don't bother recalculating
+ if (secondsAgo - secondsAgoCached < 60 && secondsAgoCached != 0) {
+ if (validCached) {
+ *hours = hoursCached;
+ *minutes = minutesCached;
+ *daysAgo = daysAgoCached;
+ }
+ return validCached;
+ }
+
+ // Get local time
+ uint32_t secondsRTC = getValidTime(RTCQuality::RTCQualityDevice, true); // Get local time
+
+ // Abort: if RTC not set
+ if (!secondsRTC) {
+ validCached = false;
+ return validCached;
+ }
+
+ // Get absolute time when last seen
+ uint32_t secondsSeenAt = secondsRTC - secondsAgo;
+
+ // Calculate daysAgo
+ *daysAgo = (secondsRTC / SEC_PER_DAY) - (secondsSeenAt / SEC_PER_DAY); // How many "midnights" have passed
+
+ // Get seconds since midnight
+ uint32_t hms = (secondsRTC - secondsAgo) % SEC_PER_DAY;
+ hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
+
+ // Tear apart hms into hours and minutes
+ *hours = hms / SEC_PER_HOUR;
+ *minutes = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
+
+ // Cache the result
+ daysAgoCached = *daysAgo;
+ hoursCached = *hours;
+ minutesCached = *minutes;
+ secondsAgoCached = secondsAgo;
+
+ validCached = true;
+ return validCached;
+}
+
/// Draw the last text message we received
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -440,22 +997,98 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->setColor(BLACK);
}
+ // For time delta
uint32_t seconds = sinceReceived(&mp);
uint32_t minutes = seconds / 60;
uint32_t hours = minutes / 60;
uint32_t days = hours / 24;
- if (config.display.heading_bold) {
- display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s",
- screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
- (node && node->has_user) ? node->user.short_name : "???");
+ // For timestamp
+ uint8_t timestampHours, timestampMinutes;
+ int32_t daysAgo;
+ bool useTimestamp = deltaToTimestamp(seconds, ×tampHours, ×tampMinutes, &daysAgo);
+
+ // If bold, draw twice, shifting right by one pixel
+ for (uint8_t xOff = 0; xOff <= (config.display.heading_bold ? 1 : 0); xOff++) {
+ // Show a timestamp if received today, but longer than 15 minutes ago
+ if (useTimestamp && minutes >= 15 && daysAgo == 0) {
+ display->drawStringf(xOff + x, 0 + y, tempBuf, "At %02hu:%02hu from %s", timestampHours, timestampMinutes,
+ (node && node->has_user) ? node->user.short_name : "???");
+ }
+ // Timestamp yesterday (if display is wide enough)
+ else if (useTimestamp && daysAgo == 1 && display->width() >= 200) {
+ display->drawStringf(xOff + x, 0 + y, tempBuf, "Yesterday %02hu:%02hu from %s", timestampHours, timestampMinutes,
+ (node && node->has_user) ? node->user.short_name : "???");
+ }
+ // Otherwise, show a time delta
+ else {
+ display->drawStringf(xOff + x, 0 + y, tempBuf, "%s ago from %s",
+ screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
+ (node && node->has_user) ? node->user.short_name : "???");
+ }
}
- display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(),
- (node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE);
+#ifndef EXCLUDE_EMOJI
+ if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F44D") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
+ thumbup);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F44E") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
+ thumbdown);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"❓") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height,
+ question);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"‼️") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - bang_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - bang_height) / 2 + 2 + 5,
+ bang_width, bang_height, bang);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F4A9") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - poo_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - poo_height) / 2 + 2 + 5,
+ poo_width, poo_height, poo);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\xf0\x9f\xa4\xa3") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - haha_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - haha_height) / 2 + 2 + 5,
+ haha_width, haha_height, haha);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F44B") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - wave_icon_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - wave_icon_height) / 2 + 2 + 5, wave_icon_width,
+ wave_icon_height, wave_icon);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F920") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - cowboy_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cowboy_height) / 2 + 2 + 5, cowboy_width, cowboy_height,
+ cowboy);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\U0001F42D") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - deadmau5_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - deadmau5_height) / 2 + 2 + 5, deadmau5_width, deadmau5_height,
+ deadmau5);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\xE2\x98\x80\xEF\xB8\x8F") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - sun_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - sun_height) / 2 + 2 + 5,
+ sun_width, sun_height, sun);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\u2614") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - rain_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - rain_height) / 2 + 2 + 10,
+ rain_width, rain_height, rain);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"☁️") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - cloud_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cloud_height) / 2 + 2 + 5, cloud_width, cloud_height, cloud);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"🌫️") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - fog_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - fog_height) / 2 + 2 + 5,
+ fog_width, fog_height, fog);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"\xf0\x9f\x98\x88") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - devil_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil);
+ } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), u8"♥️") == 0) {
+ display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2,
+ y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart);
+ } else {
+ snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
+ display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
+ }
+#else
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
+#endif
}
/// Draw the last waypoint we received
@@ -518,28 +1151,6 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
}
}
-// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
-static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
-{
- static const uint8_t powerBar[3] = {0x81, 0xBD, 0xBD};
- static const uint8_t lightning[8] = {0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85};
- // Clear the bar area on the battery image
- for (int i = 1; i < 14; i++) {
- imgBuffer[i] = 0x81;
- }
- // If charging, draw a charging indicator
- if (powerStatus->getIsCharging()) {
- memcpy(imgBuffer + 3, lightning, 8);
- // If not charging, Draw power bars
- } else {
- for (int i = 0; i < 4; i++) {
- if (powerStatus->getBatteryChargePercent() >= 25 * i)
- memcpy(imgBuffer + 1 + (i * 3), powerBar, 3);
- }
- }
- display->drawFastImage(x, y, 16, 8, imgBuffer);
-}
-
// Draw nodes status
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const NodeStatus *nodeStatus)
{
@@ -875,23 +1486,42 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *username = node->has_user ? node->user.long_name : "Unknown Name";
static char signalStr[20];
- snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100));
+
+ // section here to choose whether to display hops away rather than signal strength if more than 0 hops away.
+ if (node->hops_away > 0) {
+ snprintf(signalStr, sizeof(signalStr), "Hops Away: %d", node->hops_away);
+ } else {
+ snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100));
+ }
uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20];
+
+ // Use an absolute timestamp in some cases.
+ // Particularly useful with E-Ink displays. Static UI, fewer refreshes.
+ uint8_t timestampHours, timestampMinutes;
+ int32_t daysAgo;
+ bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo);
+
if (agoSecs < 120) // last 2 mins?
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
+ // -- if suitable for timestamp --
+ else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes
+ snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE);
+ else if (useTimestamp && daysAgo == 0) // Today
+ snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes);
+ else if (useTimestamp && daysAgo == 1) // Yesterday
+ snprintf(lastStr, sizeof(lastStr), "Seen yesterday");
+ else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method)
+ snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo);
+ // -- if using time delta instead --
else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
- else {
- // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad
- // data.
- if ((agoSecs / 60 / 60) < (hours_in_month * 6)) {
- snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
- } else {
- snprintf(lastStr, sizeof(lastStr), "unknown age");
- }
- }
+ // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data.
+ else if ((agoSecs / 60 / 60) < (hours_in_month * 6))
+ snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
+ else
+ snprintf(lastStr, sizeof(lastStr), "unknown age");
static char distStr[20];
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
@@ -900,7 +1530,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
strncpy(distStr, "? km", sizeof(distStr));
}
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
- const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
+ const char *fields[] = {username, lastStr, signalStr, distStr, NULL};
int16_t compassX = 0, compassY = 0;
// coordinates for the center of the compass/circle
@@ -913,9 +1543,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
}
bool hasNodeHeading = false;
- if (ourNode && hasValidPosition(ourNode)) {
+ if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) {
const meshtastic_PositionLite &op = ourNode->position;
- float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
+ float myHeading;
+ if (screen->hasHeading())
+ myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians
+ else
+ myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
drawCompassNorth(display, compassX, compassY, myHeading);
if (hasValidPosition(node)) {
@@ -1218,6 +1852,10 @@ int32_t Screen::runOnce()
return RUN_SAME;
}
+ if (displayHeight == 0) {
+ displayHeight = dispdev->getHeight();
+ }
+
// Show boot screen for first logo_timeout seconds, then switch to normal operation.
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
static bool showingBootScreen = true;
@@ -1448,6 +2086,15 @@ void Screen::setFrames()
LOG_DEBUG("showing standard frames\n");
showingNormalScreen = true;
+#ifdef USE_EINK
+ // If user has disabled the screensaver, warn them after boot
+ static bool warnedScreensaverDisabled = false;
+ if (config.display.screen_on_secs == 0 && !warnedScreensaverDisabled) {
+ screen->print("Screensaver disabled\n");
+ warnedScreensaverDisabled = true;
+ }
+#endif
+
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
#ifdef DEBUG_PORT
@@ -1455,7 +2102,7 @@ void Screen::setFrames()
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
#endif
- // We don't show the node info our our node (if we have it yet - we should)
+ // We don't show the node info of our node (if we have it yet - we should)
size_t numMeshNodes = nodeDB->getNumMeshNodes();
if (numMeshNodes > 0)
numMeshNodes--;
@@ -1478,6 +2125,10 @@ void Screen::setFrames()
if (error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
+#ifdef T_WATCH_S3
+ normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame;
+#endif
+
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
normalFrames[numframes++] = drawTextMessageFrame;
@@ -2058,6 +2709,21 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
int Screen::handleInputEvent(const InputEvent *event)
{
+
+#ifdef T_WATCH_S3
+ // For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button
+ uint8_t watchFaceFrame = error_code ? 1 : 0;
+
+ if (this->ui->getUiState()->currentFrame == watchFaceFrame && event->touchX >= 204 && event->touchX <= 240 &&
+ event->touchY >= 204 && event->touchY <= 240) {
+ screen->digitalWatchFace = !screen->digitalWatchFace;
+
+ setFrames();
+
+ return 0;
+ }
+#endif
+
if (showingNormalScreen && moduleFrames.size() == 0) {
// LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index cfb08c0f4..f4d719715 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -48,6 +48,7 @@ class Screen
#include "EInkDisplay2.h"
#include "EInkDynamicDisplay.h"
+#include "PointStruct.h"
#include "TFTDisplay.h"
#include "TypedQueue.h"
#include "commands.h"
@@ -77,6 +78,10 @@ class Screen
#define EINK_BLACK OLEDDISPLAY_COLOR::WHITE
#define EINK_WHITE OLEDDISPLAY_COLOR::BLACK
+// Base segment dimensions for T-Watch segmented display
+#define SEGMENT_WIDTH 16
+#define SEGMENT_HEIGHT 4
+
namespace graphics
{
@@ -199,6 +204,17 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
+ // Function to allow the AccelerometerThread to set the heading if a sensor provides it
+ // Mutex needed?
+ void setHeading(long _heading)
+ {
+ hasCompass = true;
+ compassHeading = _heading;
+ }
+
+ bool hasHeading() { return hasCompass; }
+
+ long getHeading() { return compassHeading; }
// functions for display brightness
void increaseBrightness();
void decreaseBrightness();
@@ -355,7 +371,7 @@ class Screen : public concurrency::OSThread
bool enqueueCmd(const ScreenCmd &cmd)
{
if (!useDisplay)
- return true; // claim success if our display is not in use
+ return false; // not enqueued if our display is not in use
else {
bool success = cmdQueue.enqueue(cmd, 0);
enabled = true; // handle ASAP (we are the registered reader for cmdQueue, but might have been disabled)
@@ -389,6 +405,27 @@ class Screen : public concurrency::OSThread
static void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+#ifdef T_WATCH_S3
+ static void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+
+ static void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
+
+ static void drawSegmentedDisplayCharacter(OLEDDisplay *display, int x, int y, uint8_t number, float scale = 1);
+
+ static void drawHorizontalSegment(OLEDDisplay *display, int x, int y, int width, int height);
+
+ static void drawVerticalSegment(OLEDDisplay *display, int x, int y, int width, int height);
+
+ static void drawSegmentedDisplayColon(OLEDDisplay *display, int x, int y, float scale = 1);
+
+ static void drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode = true, float scale = 1);
+
+ static void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y);
+
+ // Whether we are showing the digital watch face or the analog one
+ bool digitalWatchFace = true;
+#endif
+
/// Queue of commands to execute in doTask.
TypedQueue cmdQueue;
/// Whether we are using a display
@@ -402,6 +439,8 @@ class Screen : public concurrency::OSThread
// Implementation to Adjust Brightness
uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103
+ bool hasCompass = false;
+ float compassHeading;
/// Holds state for debug information
DebugInfo debugInfo;
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index b19e402b8..8ea90c523 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -117,8 +117,16 @@ class LGFX : public lgfx::LGFX_Device
static LGFX *tft = nullptr;
#elif defined(RAK14014)
+#include
#include
TFT_eSPI *tft = nullptr;
+FT6336U ft6336u;
+
+static uint8_t _rak14014_touch_int = false; // TP interrupt generation flag.
+static void rak14014_tpIntHandle(void)
+{
+ _rak14014_touch_int = true;
+}
#elif defined(ST7789_CS)
#include // Graphics and font library for ST7735 driver chip
@@ -642,8 +650,12 @@ void TFTDisplay::sendCommand(uint8_t com)
void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
{
+#ifdef RAK14014
+ // todo
+#else
tft->setBrightness(_brightness);
LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
+#endif
}
void TFTDisplay::flipScreenVertically()
@@ -657,6 +669,7 @@ void TFTDisplay::flipScreenVertically()
bool TFTDisplay::hasTouch(void)
{
#ifdef RAK14014
+ return true;
#elif !defined(M5STACK)
return tft->touch() != nullptr;
#else
@@ -667,6 +680,15 @@ bool TFTDisplay::hasTouch(void)
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{
#ifdef RAK14014
+ if (_rak14014_touch_int) {
+ _rak14014_touch_int = false;
+ /* The X and Y axes have to be switched */
+ *y = ft6336u.read_touch1_x();
+ *x = TFT_HEIGHT - ft6336u.read_touch1_y();
+ return true;
+ } else {
+ return false;
+ }
#elif !defined(M5STACK)
return tft->getTouch(x, y);
#else
@@ -716,7 +738,10 @@ bool TFTDisplay::connect()
#elif defined(RAK14014)
tft->setRotation(1);
tft->setSwapBytes(true);
-// tft->fillScreen(TFT_BLACK);
+ // tft->fillScreen(TFT_BLACK);
+ ft6336u.begin();
+ pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP);
+ attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING);
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
tft->setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3)
diff --git a/src/graphics/images.h b/src/graphics/images.h
index 5c6fb4275..d4c738610 100644
--- a/src/graphics/images.h
+++ b/src/graphics/images.h
@@ -14,6 +14,12 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
+#ifdef T_WATCH_S3
+const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0xe3, 0x1f,
+ 0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33,
+ 0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
+#endif
+
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || defined(HX8357_CS) || \
ARCH_PORTDUINO) && \
!defined(DISPLAY_FORCE_SMALL_FONTS)
@@ -31,4 +37,171 @@ const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1,
const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
#endif
+#ifndef EXCLUDE_EMOJI
+#define thumbs_height 25
+#define thumbs_width 25
+static unsigned char thumbup[] PROGMEM = {
+ 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00,
+ 0xC0, 0x08, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00,
+ 0x0C, 0xCE, 0x7F, 0x00, 0x04, 0x20, 0x80, 0x00, 0x02, 0x20, 0x80, 0x00, 0x02, 0x60, 0xC0, 0x00, 0x01, 0xF8, 0xFF, 0x01,
+ 0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0x18, 0x80, 0x00,
+ 0x02, 0x30, 0xC0, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x38, 0x20, 0x10, 0x00, 0xE0, 0xCF, 0x1F, 0x00,
+};
+
+static unsigned char thumbdown[] PROGMEM = {
+ 0xE0, 0xCF, 0x1F, 0x00, 0x38, 0x20, 0x10, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x02, 0x30, 0xC0, 0x00,
+ 0x01, 0x18, 0x80, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01,
+ 0x01, 0xF8, 0xFF, 0x01, 0x02, 0x60, 0xC0, 0x00, 0x02, 0x20, 0x80, 0x00, 0x04, 0x20, 0x80, 0x00, 0x0C, 0xCE, 0x7F, 0x00,
+ 0x18, 0x02, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
+ 0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
+};
+
+#define question_height 25
+#define question_width 25
+static unsigned char question[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00,
+ 0xE0, 0xC3, 0x0F, 0x00, 0xF0, 0x81, 0x0F, 0x00, 0xF0, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x0F, 0x00,
+ 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00,
+ 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define bang_height 30
+#define bang_width 30
+static unsigned char bang[] PROGMEM = {
+ 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x07, 0xF8, 0x3F, 0xFF, 0x07, 0xF8, 0x3F,
+ 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F,
+ 0xFE, 0x03, 0xF0, 0x1F, 0xFE, 0x03, 0xF0, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F,
+ 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0xFC, 0x03, 0xF0, 0x0F, 0xFE, 0x03, 0xF0, 0x1F,
+ 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xF8, 0x01, 0xE0, 0x07,
+};
+
+#define haha_height 30
+#define haha_width 30
+static unsigned char haha[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00,
+ 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x1F, 0x3E, 0x00, 0x80, 0x03, 0x70, 0x00, 0xC0, 0x01, 0xE0, 0x00, 0xC0, 0x00, 0xC2, 0x00,
+ 0x60, 0x00, 0x03, 0x00, 0x60, 0x00, 0xC1, 0x1F, 0x60, 0x80, 0x8F, 0x31, 0x30, 0x0E, 0x80, 0x31, 0x30, 0x10, 0x30, 0x1F,
+ 0x30, 0x08, 0x58, 0x00, 0x30, 0x04, 0x6C, 0x03, 0x60, 0x00, 0xF3, 0x01, 0x60, 0xC0, 0xFC, 0x01, 0x80, 0x38, 0xBF, 0x01,
+ 0xE0, 0xC5, 0xDF, 0x00, 0xB0, 0xF9, 0xEF, 0x00, 0x30, 0xF1, 0x73, 0x00, 0xB0, 0x1D, 0x3E, 0x00, 0xF0, 0xFD, 0x0F, 0x00,
+ 0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define wave_icon_height 30
+#define wave_icon_width 30
+static unsigned char wave_icon[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xC0, 0x00,
+ 0x00, 0x0C, 0x9C, 0x01, 0x80, 0x17, 0x20, 0x01, 0x80, 0x26, 0x46, 0x02, 0x80, 0x44, 0x88, 0x02, 0xC0, 0x89, 0x8A, 0x02,
+ 0x40, 0x93, 0x8B, 0x02, 0x40, 0x26, 0x13, 0x00, 0x80, 0x44, 0x16, 0x00, 0xC0, 0x89, 0x24, 0x00, 0x40, 0x93, 0x60, 0x00,
+ 0x40, 0x26, 0x40, 0x00, 0x80, 0x0C, 0x80, 0x00, 0x00, 0x09, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, 0x06, 0x80, 0x00,
+ 0x50, 0x0C, 0x80, 0x00, 0x50, 0x08, 0x40, 0x00, 0x90, 0x10, 0x20, 0x00, 0xB0, 0x21, 0x10, 0x00, 0x20, 0x47, 0x18, 0x00,
+ 0x40, 0x80, 0x0F, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define cowboy_height 30
+#define cowboy_width 30
+static unsigned char cowboy[] PROGMEM = {
+ 0x00, 0xF0, 0x03, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x3C, 0xFE, 0x1F, 0x0F,
+ 0xFE, 0xFE, 0xDF, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F,
+ 0x3E, 0xC0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x0E, 0x1C, 0x04, 0x00, 0x0E, 0x1C, 0x00,
+ 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x0E, 0x1C, 0x08, 0x04, 0x04, 0x08, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x08,
+ 0x8C, 0x07, 0x70, 0x0C, 0x88, 0xFC, 0x4F, 0x04, 0x88, 0x01, 0x40, 0x04, 0x90, 0xFF, 0x7F, 0x02, 0x30, 0x03, 0x30, 0x03,
+ 0x60, 0x0E, 0x9C, 0x01, 0xC0, 0xF8, 0xC7, 0x00, 0x80, 0x01, 0x60, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0xF8, 0x07, 0x00,
+};
+
+#define deadmau5_height 30
+#define deadmau5_width 60
+static unsigned char deadmau5[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
+ 0x00, 0xFC, 0x03, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0x00,
+ 0xE0, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0x7F, 0x00, 0xF0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x07,
+ 0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x00,
+ 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0xFC,
+ 0x0F, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x1F, 0xF8, 0x0F, 0xFC, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0xF8, 0x1F, 0xFC, 0x1F, 0x00,
+ 0x00, 0xFF, 0x0F, 0xFC, 0x3F, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x01, 0x00, 0x00, 0x00, 0xFC, 0xFF,
+ 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x07, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define sun_width 30
+#define sun_height 30
+static unsigned char sun[] PROGMEM = {
+ 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x30, 0xC0, 0x00, 0x03,
+ 0x70, 0x00, 0x80, 0x03, 0xF0, 0x00, 0xC0, 0x03, 0xF0, 0xF8, 0xC7, 0x03, 0xE0, 0xFC, 0xCF, 0x01, 0x00, 0xFE, 0x1F, 0x00,
+ 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x8E, 0xFF, 0x7F, 0x1C, 0x9F, 0xFF, 0x7F, 0x3E,
+ 0x9F, 0xFF, 0x7F, 0x3E, 0x8E, 0xFF, 0x7F, 0x1C, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00,
+ 0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0xC0, 0xF9, 0xE7, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xE0, 0x03,
+ 0xF0, 0xC0, 0xC0, 0x03, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00,
+};
+
+#define rain_width 30
+#define rain_height 30
+static unsigned char rain[] PROGMEM = {
+ 0xC0, 0x0F, 0xC0, 0x00, 0x40, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x03, 0x38, 0x00,
+ 0x00, 0x0E, 0x0C, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x20,
+ 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x30, 0x02, 0x00,
+ 0x00, 0x10, 0x06, 0x00, 0x00, 0x08, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x01, 0x80, 0x00, 0x01, 0x00,
+ 0xC0, 0xC0, 0x81, 0x03, 0xA0, 0x60, 0xC1, 0x03, 0x90, 0x20, 0x41, 0x01, 0xF0, 0xE0, 0xC0, 0x01, 0x60, 0x4C,
+ 0x98, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x00, 0x09, 0x1A, 0x00, 0x00, 0x06, 0x0E, 0x00,
+};
+
+#define cloud_height 30
+#define cloud_width 30
+static unsigned char cloud[] PROGMEM = {
+ 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x10, 0x60, 0x00, 0x80, 0x1F, 0x40, 0x00,
+ 0xC0, 0x0F, 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x60, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x01,
+ 0x20, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10,
+ 0x02, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
+ 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x10,
+ 0x02, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x0C, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03,
+};
+
+#define fog_height 25
+#define fog_width 25
+static unsigned char fog[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x3C, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01,
+ 0x00, 0x38, 0x00, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0xFF, 0x83, 0xFF, 0x01, 0x03, 0xFF, 0x81, 0x01, 0x00, 0x7C, 0x00, 0x00,
+ 0xF8, 0x00, 0x3E, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01, 0x00, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define devil_height 30
+#define devil_width 30
+static unsigned char devil[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x03, 0xC0, 0x01, 0x38, 0x07, 0x7C, 0x0F, 0x38, 0x1F, 0x03, 0x30, 0x1E,
+ 0xFE, 0x01, 0xE0, 0x1F, 0x7E, 0x00, 0x80, 0x1F, 0x3C, 0x00, 0x00, 0x0F, 0x1C, 0x00, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x06,
+ 0x08, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x0E, 0x1C, 0x0C,
+ 0x0C, 0x18, 0x06, 0x0C, 0x0C, 0x1C, 0x06, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x1C, 0x0E, 0x0C, 0x0C, 0x0C, 0x06, 0x0C,
+ 0x08, 0x00, 0x00, 0x06, 0x18, 0x02, 0x10, 0x06, 0x10, 0x0C, 0x0C, 0x03, 0x30, 0xF8, 0x07, 0x03, 0x60, 0xE0, 0x80, 0x01,
+ 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x01, 0x70, 0x00, 0x00, 0x06, 0x1C, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define heart_height 30
+#define heart_width 30
+static unsigned char heart[] PROGMEM = {
+ 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18,
+ 0xFE, 0xFF, 0x7F, 0x10, 0xFF, 0xFF, 0xFF, 0x31, 0xFF, 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0xFF, 0x37, 0xFF, 0xFF, 0xFF, 0x37,
+ 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x1F,
+ 0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x03,
+ 0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0xFE, 0x1F, 0x00,
+ 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+};
+
+#define poo_width 30
+#define poo_height 30
+static unsigned char poo[] PROGMEM = {
+ 0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xEC, 0x01, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, 0x0C, 0x06, 0x00,
+ 0x00, 0x24, 0x0C, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x1F, 0x08, 0x00, 0xC0, 0x0F, 0x08, 0x00, 0xC0, 0x00, 0x3C, 0x00,
+ 0x60, 0x00, 0x7C, 0x00, 0x60, 0x00, 0xC6, 0x00, 0x20, 0x00, 0xCB, 0x00, 0xA0, 0xC7, 0xFF, 0x00, 0xE0, 0x7F, 0xF7, 0x00,
+ 0xF0, 0x18, 0xE3, 0x03, 0x78, 0x18, 0x41, 0x03, 0x6C, 0x9B, 0x5D, 0x06, 0x64, 0x9B, 0x5D, 0x04, 0x44, 0x1A, 0x41, 0x04,
+ 0x4C, 0xD8, 0x63, 0x06, 0xF8, 0xFC, 0x36, 0x06, 0xFE, 0x0F, 0x9C, 0x1F, 0x07, 0x03, 0xC0, 0x30, 0x03, 0x00, 0x78, 0x20,
+ 0x01, 0x00, 0x1F, 0x20, 0x03, 0xE0, 0x03, 0x20, 0x07, 0x7E, 0x04, 0x30, 0xFE, 0x0F, 0xFC, 0x1F, 0xF0, 0x00, 0xF0, 0x0F,
+};
+#endif
+
#include "img/icon.xbm"
diff --git a/src/input/InputBroker.h b/src/input/InputBroker.h
index d73e6657a..57c25af4b 100644
--- a/src/input/InputBroker.h
+++ b/src/input/InputBroker.h
@@ -8,6 +8,8 @@ typedef struct _InputEvent {
const char *source;
char inputEvent;
char kbchar;
+ uint16_t touchX;
+ uint16_t touchY;
} InputEvent;
class InputBroker : public Observable
{
diff --git a/src/input/LinuxInput.cpp b/src/input/LinuxInput.cpp
index 1ace2044c..6194195ed 100644
--- a/src/input/LinuxInput.cpp
+++ b/src/input/LinuxInput.cpp
@@ -155,6 +155,9 @@ int32_t LinuxInput::runOnce()
case KEY_ENTER: // Enter
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
break;
+ case KEY_POWER:
+ system("poweroff");
+ break;
default: // all other keys
if (keymap[code]) {
e.inputEvent = ANYKEY;
diff --git a/src/input/TouchScreenImpl1.cpp b/src/input/TouchScreenImpl1.cpp
index c863ead69..20196278d 100644
--- a/src/input/TouchScreenImpl1.cpp
+++ b/src/input/TouchScreenImpl1.cpp
@@ -49,6 +49,10 @@ void TouchScreenImpl1::onEvent(const TouchEvent &event)
{
InputEvent e;
e.source = event.source;
+
+ e.touchX = event.x;
+ e.touchY = event.y;
+
switch (event.touchEvent) {
case TOUCH_ACTION_LEFT: {
e.inputEvent = static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
diff --git a/src/main.cpp b/src/main.cpp
index 93c6ef38f..6797c8375 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -65,6 +65,8 @@ NRF52Bluetooth *nrf52Bluetooth;
#endif
#include "LLCC68Interface.h"
+#include "LR1110Interface.h"
+#include "LR1120Interface.h"
#include "RF95Interface.h"
#include "SX1262Interface.h"
#include "SX1268Interface.h"
@@ -94,9 +96,10 @@ NRF52Bluetooth *nrf52Bluetooth;
#include "PowerFSMThread.h"
-#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
+#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "AccelerometerThread.h"
#include "AmbientLightingThread.h"
+AccelerometerThread *accelerometerThread;
#endif
#ifdef HAS_I2S
@@ -197,9 +200,6 @@ uint32_t timeLastPowered = 0;
static Periodic *ledPeriodic;
static OSThread *powerFSMthread;
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
-static OSThread *accelerometerThread;
-#endif
static OSThread *ambientLightingThread;
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
@@ -362,18 +362,11 @@ void setup()
delay(1);
#endif
-#ifdef RAK4630
-#ifdef PIN_3V3_EN
- // We need to enable 3.3V periphery in order to scan it
- pinMode(PIN_3V3_EN, OUTPUT);
- digitalWrite(PIN_3V3_EN, HIGH);
-#endif
#ifdef AQ_SET_PIN
// RAK-12039 set pin for Air quality sensor
pinMode(AQ_SET_PIN, OUTPUT);
digitalWrite(AQ_SET_PIN, HIGH);
#endif
-#endif
#ifdef T_DECK
// enable keyboard
@@ -541,7 +534,13 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK)
i2cScanner.reset();
@@ -549,10 +548,6 @@ void setup()
setupSDCard();
#endif
-#ifdef RAK4630
- // scanEInkDevice();
-#endif
-
// LED init
#ifdef LED_PIN
@@ -890,6 +885,32 @@ void setup()
}
#endif
+#if defined(USE_LR1110)
+ if (!rIf) {
+ rIf = new LR1110Interface(RadioLibHAL, LR1110_SPI_NSS_PIN, LR1110_IRQ_PIN, LR1110_NRESER_PIN, LR1110_BUSY_PIN);
+ if (!rIf->init()) {
+ LOG_WARN("Failed to find LR1110 radio\n");
+ delete rIf;
+ rIf = NULL;
+ } else {
+ LOG_INFO("LR1110 Radio init succeeded, using LR1110 radio\n");
+ }
+ }
+#endif
+
+#if defined(USE_LR1120)
+ if (!rIf) {
+ rIf = new LR1120Interface(RadioLibHAL, LR1120_SPI_NSS_PIN, LR1120_IRQ_PIN, LR1120_NRESER_PIN, LR1120_BUSY_PIN);
+ if (!rIf->init()) {
+ LOG_WARN("Failed to find LR1120 radio\n");
+ delete rIf;
+ rIf = NULL;
+ } else {
+ LOG_INFO("LR1120 Radio init succeeded, using LR1120 radio\n");
+ }
+ }
+#endif
+
#if defined(USE_SX1280)
if (!rIf) {
rIf = new SX1280Interface(RadioLibHAL, SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY);
diff --git a/src/main.h b/src/main.h
index bb812b7b6..2ef7edb3a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -53,13 +53,18 @@ extern Adafruit_DRV2605 drv;
extern AudioThread *audioThread;
#endif
+// Global Screen singleton.
+extern graphics::Screen *screen;
+
+#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+#include "AccelerometerThread.h"
+extern AccelerometerThread *accelerometerThread;
+#endif
+
extern bool isVibrating;
extern int TCPPort; // set by Portduino
-// Global Screen singleton.
-extern graphics::Screen *screen;
-
// extern Observable newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class
// extern meshtastic::PowerStatus *powerStatus;
diff --git a/src/memGet.cpp b/src/memGet.cpp
index 0575da279..e982ef7ee 100644
--- a/src/memGet.cpp
+++ b/src/memGet.cpp
@@ -22,6 +22,8 @@ uint32_t MemGet::getFreeHeap()
return ESP.getFreeHeap();
#elif defined(ARCH_NRF52)
return dbgHeapFree();
+#elif defined(ARCH_RP2040)
+ return rp2040.getFreeHeap();
#else
// this platform does not have heap management function implemented
return UINT32_MAX;
@@ -38,6 +40,8 @@ uint32_t MemGet::getHeapSize()
return ESP.getHeapSize();
#elif defined(ARCH_NRF52)
return dbgHeapTotal();
+#elif defined(ARCH_RP2040)
+ return rp2040.getTotalHeap();
#else
// this platform does not have heap management function implemented
return UINT32_MAX;
diff --git a/src/mesh/InterfacesTemplates.cpp b/src/mesh/InterfacesTemplates.cpp
index c732829e9..f2cac8028 100644
--- a/src/mesh/InterfacesTemplates.cpp
+++ b/src/mesh/InterfacesTemplates.cpp
@@ -1,3 +1,5 @@
+#include "LR11x0Interface.cpp"
+#include "LR11x0Interface.h"
#include "SX126xInterface.cpp"
#include "SX126xInterface.h"
#include "SX128xInterface.cpp"
@@ -10,6 +12,8 @@ template class SX126xInterface;
template class SX126xInterface;
template class SX126xInterface;
template class SX128xInterface;
+template class LR11x0Interface;
+template class LR11x0Interface;
#ifdef ARCH_STM32WL
template class SX126xInterface;
#endif
diff --git a/src/mesh/LR1110Interface.cpp b/src/mesh/LR1110Interface.cpp
new file mode 100644
index 000000000..c000bd838
--- /dev/null
+++ b/src/mesh/LR1110Interface.cpp
@@ -0,0 +1,9 @@
+#include "LR1110Interface.h"
+#include "configuration.h"
+#include "error.h"
+
+LR1110Interface::LR1110Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy)
+ : LR11x0Interface(hal, cs, irq, rst, busy)
+{
+}
\ No newline at end of file
diff --git a/src/mesh/LR1110Interface.h b/src/mesh/LR1110Interface.h
new file mode 100644
index 000000000..79e7c36ca
--- /dev/null
+++ b/src/mesh/LR1110Interface.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "LR11x0Interface.h"
+
+/**
+ * Our adapter for LR1110 radios
+ */
+class LR1110Interface : public LR11x0Interface
+{
+ public:
+ LR1110Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy);
+};
\ No newline at end of file
diff --git a/src/mesh/LR1120Interface.cpp b/src/mesh/LR1120Interface.cpp
new file mode 100644
index 000000000..94f3568f7
--- /dev/null
+++ b/src/mesh/LR1120Interface.cpp
@@ -0,0 +1,9 @@
+#include "LR1120Interface.h"
+#include "configuration.h"
+#include "error.h"
+
+LR1120Interface::LR1120Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy)
+ : LR11x0Interface(hal, cs, irq, rst, busy)
+{
+}
\ No newline at end of file
diff --git a/src/mesh/LR1120Interface.h b/src/mesh/LR1120Interface.h
new file mode 100644
index 000000000..fc59293ec
--- /dev/null
+++ b/src/mesh/LR1120Interface.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "LR11x0Interface.h"
+
+/**
+ * Our adapter for LR1120 wideband radios
+ */
+class LR1120Interface : public LR11x0Interface
+{
+ public:
+ LR1120Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy);
+};
\ No newline at end of file
diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp
new file mode 100644
index 000000000..bffca0c44
--- /dev/null
+++ b/src/mesh/LR11x0Interface.cpp
@@ -0,0 +1,299 @@
+#include "LR11x0Interface.h"
+#include "configuration.h"
+#include "error.h"
+#include "mesh/NodeDB.h"
+#ifdef ARCH_PORTDUINO
+#include "PortduinoGlue.h"
+#endif
+
+// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
+// specified (may be dangerous if using external PA and LR11x0 power config forgotten)
+#ifndef LR11X0_MAX_POWER
+#define LR11X0_MAX_POWER 22
+#endif
+
+template
+LR11x0Interface::LR11x0Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy)
+ : RadioLibInterface(hal, cs, irq, rst, busy, &lora), lora(&module)
+{
+ LOG_WARN("LR11x0Interface(cs=%d, irq=%d, rst=%d, busy=%d)\n", cs, irq, rst, busy);
+}
+
+/// Initialise the Driver transport hardware and software.
+/// Make sure the Driver is properly configured before calling init().
+/// \return true if initialisation succeeded.
+template bool LR11x0Interface::init()
+{
+#ifdef LR11X0_POWER_EN
+ pinMode(LR11X0_POWER_EN, OUTPUT);
+ digitalWrite(LR11X0_POWER_EN, HIGH);
+#endif
+
+// FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE
+#if !defined(LR11X0_DIO3_TCXO_VOLTAGE)
+ float tcxoVoltage =
+ 0; // "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per
+ // https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/LR11x0/LR11x0.h#L471C26-L471C104
+ // (DIO3 is free to be used as an IRQ)
+ LOG_DEBUG("LR11X0_DIO3_TCXO_VOLTAGE not defined, not using DIO3 as TCXO reference voltage\n");
+#else
+ float tcxoVoltage = LR11X0_DIO3_TCXO_VOLTAGE;
+ LOG_DEBUG("LR11X0_DIO3_TCXO_VOLTAGE defined, using DIO3 as TCXO reference voltage at %f V\n", LR11X0_DIO3_TCXO_VOLTAGE);
+ // (DIO3 is not free to be used as an IRQ)
+#endif
+
+ RadioLibInterface::init();
+
+ if (power > LR11X0_MAX_POWER) // Clamp power to maximum defined level
+ power = LR11X0_MAX_POWER;
+
+ limitPower();
+
+ // set RF switch configuration for Wio WM1110
+ // Wio WM1110 uses DIO5 and DIO6 for RF switching
+ // NOTE: other boards may be different. If you are
+ // using a different board, you may need to wrap
+ // this in a conditional.
+
+ static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, RADIOLIB_NC,
+ RADIOLIB_NC};
+
+ static const Module::RfSwitchMode_t rfswitch_table[] = {
+ // mode DIO5 DIO6
+ {LR11x0::MODE_STBY, {LOW, LOW}}, {LR11x0::MODE_RX, {HIGH, LOW}},
+ {LR11x0::MODE_TX, {HIGH, HIGH}}, {LR11x0::MODE_TX_HP, {LOW, HIGH}},
+ {LR11x0::MODE_TX_HF, {LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW}},
+ {LR11x0::MODE_WIFI, {LOW, LOW}}, END_OF_MODE_TABLE,
+ };
+
+// We need to do this before begin() call
+#ifdef LR11X0_DIO_AS_RF_SWITCH
+ LOG_DEBUG("Setting DIO RF switch\n");
+ bool dioAsRfSwitch = true;
+#elif defined(ARCH_PORTDUINO)
+ bool dioAsRfSwitch = false;
+ if (settingsMap[dio2_as_rf_switch]) {
+ LOG_DEBUG("Setting DIO RF switch\n");
+ dioAsRfSwitch = true;
+ }
+#else
+ bool dioAsRfSwitch = false;
+#endif
+
+ if (dioAsRfSwitch)
+ lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
+
+ int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
+ // \todo Display actual typename of the adapter, not just `LR11x0`
+ LOG_INFO("LR11x0 init result %d\n", res);
+ if (res == RADIOLIB_ERR_CHIP_NOT_FOUND)
+ return false;
+
+ LOG_INFO("Frequency set to %f\n", getFreq());
+ LOG_INFO("Bandwidth set to %f\n", bw);
+ LOG_INFO("Power output set to %d\n", power);
+
+ if (res == RADIOLIB_ERR_NONE)
+ res = lora.setCRC(2);
+
+ // FIXME: May want to set depending on a definition, currently all LR1110 variant files use the DC-DC regulator option
+ if (res == RADIOLIB_ERR_NONE)
+ res = lora.setRegulatorDCDC();
+
+ if (res == RADIOLIB_ERR_NONE) {
+ if (config.lora.sx126x_rx_boosted_gain) { // the name is unfortunate but historically accurate
+ res = lora.setRxBoostedGainMode(true);
+ LOG_INFO("Set RX gain to boosted mode; result: %d\n", res);
+ } else {
+ res = lora.setRxBoostedGainMode(false);
+ LOG_INFO("Set RX gain to power saving mode (boosted mode off); result: %d\n", res);
+ }
+ }
+
+ if (res == RADIOLIB_ERR_NONE)
+ startReceive(); // start receiving
+
+ return res == RADIOLIB_ERR_NONE;
+}
+
+template bool LR11x0Interface::reconfigure()
+{
+ RadioLibInterface::reconfigure();
+
+ // set mode to standby
+ setStandby();
+
+ // configure publicly accessible settings
+ int err = lora.setSpreadingFactor(sf);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ err = lora.setBandwidth(bw);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ err = lora.setCodingRate(cr);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ // Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
+ // TODO: Confirm gain registers are okay now
+ // err = lora.setRxGain(true);
+ // assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setSyncWord(syncWord);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setPreambleLength(preambleLength);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setFrequency(getFreq());
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ if (power > LR11X0_MAX_POWER) // This chip has lower power limits than some
+ power = LR11X0_MAX_POWER;
+
+ err = lora.setOutputPower(power);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ startReceive(); // restart receiving
+
+ return RADIOLIB_ERR_NONE;
+}
+
+template void INTERRUPT_ATTR LR11x0Interface::disableInterrupt()
+{
+ lora.clearIrqAction();
+}
+
+template void LR11x0Interface::setStandby()
+{
+ checkNotification(); // handle any pending interrupts before we force standby
+
+ int err = lora.standby();
+
+ if (err != RADIOLIB_ERR_NONE) {
+ LOG_DEBUG("LR11x0 standby failed with error %d\n", err);
+ }
+
+ assert(err == RADIOLIB_ERR_NONE);
+
+ isReceiving = false; // If we were receiving, not any more
+ activeReceiveStart = 0;
+ disableInterrupt();
+ completeSending(); // If we were sending, not anymore
+}
+
+/**
+ * Add SNR data to received messages
+ */
+template void LR11x0Interface::addReceiveMetadata(meshtastic_MeshPacket *mp)
+{
+ // LOG_DEBUG("PacketStatus %x\n", lora.getPacketStatus());
+ mp->rx_snr = lora.getSNR();
+ mp->rx_rssi = lround(lora.getRSSI());
+}
+
+/** We override to turn on transmitter power as needed.
+ */
+template void LR11x0Interface::configHardwareForSend()
+{
+ RadioLibInterface::configHardwareForSend();
+}
+
+// For power draw measurements, helpful to force radio to stay sleeping
+// #define SLEEP_ONLY
+
+template void LR11x0Interface::startReceive()
+{
+#ifdef SLEEP_ONLY
+ sleep();
+#else
+
+ setStandby();
+
+ lora.setPreambleLength(preambleLength); // Solve RX ack fail after direct message sent. Not sure why this is needed.
+
+ // We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
+ // Furthermore, we need the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving
+ int err = lora.startReceive(
+ RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE,
+ 0); // only RX_DONE IRQ is needed, we'll check for PREAMBLE_DETECTED and HEADER_VALID in isActivelyReceiving
+ assert(err == RADIOLIB_ERR_NONE);
+
+ isReceiving = true;
+
+ // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
+ enableInterrupt(isrRxLevel0);
+#endif
+}
+
+/** Is the channel currently active? */
+template bool LR11x0Interface::isChannelActive()
+{
+ // check if we can detect a LoRa preamble on the current channel
+ int16_t result;
+
+ setStandby();
+ result = lora.scanChannel();
+ if (result == RADIOLIB_LORA_DETECTED)
+ return true;
+
+ assert(result != RADIOLIB_ERR_WRONG_MODEM);
+
+ return false;
+}
+
+/** Could we send right now (i.e. either not actively receiving or transmitting)? */
+template bool LR11x0Interface::isActivelyReceiving()
+{
+ // The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
+ // received and handled the interrupt for reading the packet/handling errors.
+
+ uint16_t irq = lora.getIrqStatus();
+ bool detected = (irq & (RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID | RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED));
+ // Handle false detections
+ if (detected) {
+ uint32_t now = millis();
+ if (!activeReceiveStart) {
+ activeReceiveStart = now;
+ } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID)) {
+ // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag
+ activeReceiveStart = 0;
+ LOG_DEBUG("Ignore false preamble detection.\n");
+ return false;
+ } else if (now - activeReceiveStart > maxPacketTimeMsec) {
+ // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag
+ activeReceiveStart = 0;
+ LOG_DEBUG("Ignore false header detection.\n");
+ return false;
+ }
+ }
+
+ // if (detected) LOG_DEBUG("rx detected\n");
+ return detected;
+}
+
+template bool LR11x0Interface::sleep()
+{
+ // Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
+ // \todo Display actual typename of the adapter, not just `LR11x0`
+ LOG_DEBUG("LR11x0 entering sleep mode (FIXME, don't keep config)\n");
+ setStandby(); // Stop any pending operations
+
+ // turn off TCXO if it was powered
+ // FIXME - this isn't correct
+ // lora.setTCXO(0);
+
+ // put chipset into sleep mode (we've already disabled interrupts by now)
+ bool keepConfig = true;
+ lora.sleep(keepConfig, 0); // Note: we do not keep the config, full reinit will be needed
+
+#ifdef LR11X0_POWER_EN
+ digitalWrite(LR11X0_POWER_EN, LOW);
+#endif
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/mesh/LR11x0Interface.h b/src/mesh/LR11x0Interface.h
new file mode 100644
index 000000000..11a389d25
--- /dev/null
+++ b/src/mesh/LR11x0Interface.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "RadioLibInterface.h"
+
+/**
+ * \brief Adapter for LR11x0 radio family. Implements common logic for child classes.
+ * \tparam T RadioLib module type for LR11x0: SX1262, SX1268.
+ */
+template class LR11x0Interface : public RadioLibInterface
+{
+ public:
+ LR11x0Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
+ RADIOLIB_PIN_TYPE busy);
+
+ /// Initialise the Driver transport hardware and software.
+ /// Make sure the Driver is properly configured before calling init().
+ /// \return true if initialisation succeeded.
+ virtual bool init() override;
+
+ /// Apply any radio provisioning changes
+ /// Make sure the Driver is properly configured before calling init().
+ /// \return true if initialisation succeeded.
+ virtual bool reconfigure() override;
+
+ /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
+ virtual bool sleep() override;
+
+ bool isIRQPending() override { return lora.getIrqStatus() != 0; }
+
+ protected:
+ /**
+ * Specific module instance
+ */
+ T lora;
+
+ /**
+ * Glue functions called from ISR land
+ */
+ virtual void disableInterrupt() override;
+
+ /**
+ * Enable a particular ISR callback glue function
+ */
+ virtual void enableInterrupt(void (*callback)()) { lora.setIrqAction(callback); }
+
+ /** can we detect a LoRa preamble on the current channel? */
+ virtual bool isChannelActive() override;
+
+ /** are we actively receiving a packet (only called during receiving state) */
+ virtual bool isActivelyReceiving() override;
+
+ /**
+ * Start waiting to receive a message
+ */
+ virtual void startReceive() override;
+
+ /**
+ * We override to turn on transmitter power as needed.
+ */
+ virtual void configHardwareForSend() override;
+
+ /**
+ * Add SNR data to received messages
+ */
+ virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) override;
+
+ virtual void setStandby() override;
+
+ private:
+ uint32_t activeReceiveStart = 0;
+};
diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp
index 2ef46e4db..04fa250bf 100644
--- a/src/mesh/MeshModule.cpp
+++ b/src/mesh/MeshModule.cpp
@@ -62,7 +62,10 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p)
{
- auto r = allocAckNak(err, getFrom(p), p->id, p->channel);
+ // If the original packet couldn't be decoded, use the primary channel
+ uint8_t channelIndex =
+ p->which_payload_variant == meshtastic_MeshPacket_decoded_tag ? p->channel : channels.getPrimaryIndex();
+ auto r = allocAckNak(err, getFrom(p), p->id, channelIndex);
setReplyTo(r, *p);
@@ -114,13 +117,13 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and
/// it needs to to be able to fetch the initial admin packets without yet knowing any channels.
- bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcasecmp(ch->settings.name, pi.boundChannel) == 0);
+ bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (ch && strcasecmp(ch->settings.name, pi.boundChannel) == 0);
if (!rxChannelOk) {
// no one should have already replied!
assert(!currentReply);
- if (mp.decoded.want_response) {
+ if (isDecoded && mp.decoded.want_response) {
printPacket("packet on wrong channel, returning error", &mp);
currentReply = pi.allocErrorResponse(meshtastic_Routing_Error_NOT_AUTHORIZED, &mp);
} else
@@ -138,7 +141,8 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// because currently when the phone sends things, it sends things using the local node ID as the from address. A
// better solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like
// any other node.
- if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
+ if (isDecoded && mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) &&
+ !currentReply) {
pi.sendResponse(mp);
ignoreRequest = ignoreRequest || pi.ignoreRequest; // If at least one module asks it, we may ignore a request
LOG_INFO("Asked module '%s' to send a response\n", pi.name);
@@ -163,7 +167,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
pi.currentRequest = NULL;
}
- if (mp.decoded.want_response && toUs) {
+ if (isDecoded && mp.decoded.want_response && toUs) {
if (currentReply) {
printPacket("Sending response", currentReply);
service.sendToMesh(currentReply);
@@ -183,7 +187,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
}
}
- if (!moduleFound) {
+ if (!moduleFound && isDecoded) {
LOG_DEBUG("No modules interested in portnum=%d, src=%s\n", mp.decoded.portnum,
(src == RX_SRC_LOCAL) ? "LOCAL" : "REMOTE");
}
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index b79911a3e..cf576e94f 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -292,6 +292,9 @@ void NodeDB::installDefaultConfig()
meshtastic_Config_PositionConfig_PositionFlags_SPEED | meshtastic_Config_PositionConfig_PositionFlags_HEADING |
meshtastic_Config_PositionConfig_PositionFlags_DOP | meshtastic_Config_PositionConfig_PositionFlags_SATINVIEW);
+#ifdef RADIOMASTER_900_BANDIT_NANO
+ config.display.flip_screen = true;
+#endif
#ifdef T_WATCH_S3
config.display.screen_on_secs = 30;
config.display.wake_on_tap_or_motion = true;
@@ -441,9 +444,9 @@ void NodeDB::installDefaultChannels()
void NodeDB::resetNodes()
{
+ clearLocalPosition();
numMeshNodes = 1;
std::fill(devicestate.node_db_lite.begin() + 1, devicestate.node_db_lite.end(), meshtastic_NodeInfoLite());
- clearLocalPosition();
saveDeviceStateToDisk();
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
neighborInfoModule->resetNeighbors();
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 2a69d6d56..26d0d9525 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -140,16 +140,18 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
*
* We assume buf is at least FromRadio_size bytes long.
*
- * Our sending states progress in the following sequence (the client app ASSUMES THIS SEQUENCE, DO NOT CHANGE IT):
- * STATE_SEND_MY_INFO, // send our my info record
- * STATE_SEND_CHANNELS
- * STATE_SEND_NODEINFO, // states progress in this order as the device sends to the client
- STATE_SEND_CONFIG,
- STATE_SEND_MODULE_CONFIG,
- STATE_SEND_METADATA,
- STATE_SEND_COMPLETE_ID,
- STATE_SEND_PACKETS // send packets or debug strings
+ * Our sending states progress in the following sequence (the client apps ASSUME THIS SEQUENCE, DO NOT CHANGE IT):
+ STATE_SEND_MY_INFO, // send our my info record
+ STATE_SEND_OWN_NODEINFO,
+ STATE_SEND_METADATA,
+ STATE_SEND_CHANNELS
+ STATE_SEND_CONFIG,
+ STATE_SEND_MODULE_CONFIG,
+ STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to the client
+ STATE_SEND_COMPLETE_ID,
+ STATE_SEND_PACKETS // send packets or debug strings
*/
+
size_t PhoneAPI::getFromRadio(uint8_t *buf)
{
if (!available()) {
@@ -171,37 +173,32 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// app not to send locations on our behalf.
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
- state = STATE_SEND_METADATA;
+ state = STATE_SEND_OWN_NODEINFO;
service.refreshLocalMeshNode(); // Update my NodeInfo because the client will be asking for it soon.
break;
+ case STATE_SEND_OWN_NODEINFO: {
+ LOG_INFO("getFromRadio=STATE_SEND_OWN_NODEINFO\n");
+ auto us = nodeDB->readNextMeshNode(readIndex);
+ if (us) {
+ nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(us);
+ fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
+ fromRadioScratch.node_info = nodeInfoForPhone;
+ // Should allow us to resume sending NodeInfo in STATE_SEND_OTHER_NODEINFOS
+ nodeInfoForPhone.num = 0;
+ }
+ state = STATE_SEND_METADATA;
+ break;
+ }
+
case STATE_SEND_METADATA:
LOG_INFO("getFromRadio=STATE_SEND_METADATA\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_metadata_tag;
fromRadioScratch.metadata = getDeviceMetadata();
- state = STATE_SEND_NODEINFO;
+ state = STATE_SEND_CHANNELS;
break;
- case STATE_SEND_NODEINFO: {
- LOG_INFO("getFromRadio=STATE_SEND_NODEINFO\n");
-
- if (nodeInfoForPhone.num != 0) {
- LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
- nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
- fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
- fromRadioScratch.node_info = nodeInfoForPhone;
- // Stay in current state until done sending nodeinfos
- nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time
- } else {
- LOG_INFO("Done sending nodeinfos\n");
- state = STATE_SEND_CHANNELS;
- // Go ahead and send that ID right now
- return getFromRadio(buf);
- }
- break;
- }
-
case STATE_SEND_CHANNELS:
LOG_INFO("getFromRadio=STATE_SEND_CHANNELS\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_channel_tag;
@@ -325,11 +322,30 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
config_state++;
// Advance when we have sent all of our ModuleConfig objects
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
- state = STATE_SEND_COMPLETE_ID;
+ // Clients sending special nonce don't want to see other nodeinfos
+ state = config_nonce == SPECIAL_NONCE ? STATE_SEND_COMPLETE_ID : STATE_SEND_OTHER_NODEINFOS;
config_state = 0;
}
break;
+ case STATE_SEND_OTHER_NODEINFOS: {
+ LOG_INFO("getFromRadio=STATE_SEND_OTHER_NODEINFOS\n");
+ if (nodeInfoForPhone.num != 0) {
+ LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
+ nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
+ fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
+ fromRadioScratch.node_info = nodeInfoForPhone;
+ // Stay in current state until done sending nodeinfos
+ nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time
+ } else {
+ LOG_INFO("Done sending nodeinfos\n");
+ state = STATE_SEND_COMPLETE_ID;
+ // Go ahead and send that ID right now
+ return getFromRadio(buf);
+ }
+ break;
+ }
+
case STATE_SEND_COMPLETE_ID:
LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n");
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
@@ -422,10 +438,11 @@ bool PhoneAPI::available()
case STATE_SEND_CONFIG:
case STATE_SEND_MODULECONFIG:
case STATE_SEND_METADATA:
+ case STATE_SEND_OWN_NODEINFO:
case STATE_SEND_COMPLETE_ID:
return true;
- case STATE_SEND_NODEINFO:
+ case STATE_SEND_OTHER_NODEINFOS:
if (nodeInfoForPhone.num == 0) {
auto nextNode = nodeDB->readNextMeshNode(readIndex);
if (nextNode) {
diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h
index 450649d7b..49bf0e292 100644
--- a/src/mesh/PhoneAPI.h
+++ b/src/mesh/PhoneAPI.h
@@ -6,6 +6,7 @@
// Make sure that we never let our packets grow too large for one BLE packet
#define MAX_TO_FROM_RADIO_SIZE 512
+#define SPECIAL_NONCE 69420
/**
* Provides our protobuf based API which phone/PC clients can use to talk to our device
@@ -20,13 +21,14 @@ class PhoneAPI
: public Observer // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
{
enum State {
- STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
- STATE_SEND_MY_INFO, // send our my info record
- STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
- STATE_SEND_CHANNELS, // Send all channels
- STATE_SEND_CONFIG, // Replacement for the old Radioconfig
- STATE_SEND_MODULECONFIG, // Send Module specific config
+ STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
+ STATE_SEND_MY_INFO, // send our my info record
+ STATE_SEND_OWN_NODEINFO,
STATE_SEND_METADATA,
+ STATE_SEND_CHANNELS, // Send all channels
+ STATE_SEND_CONFIG, // Replacement for the old Radioconfig
+ STATE_SEND_MODULECONFIG, // Send Module specific config
+ STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to to the client
STATE_SEND_COMPLETE_ID,
STATE_SEND_PACKETS // send packets or debug strings
};
diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp
index 8c6c349fd..c5356ad3b 100644
--- a/src/mesh/RF95Interface.cpp
+++ b/src/mesh/RF95Interface.cpp
@@ -8,12 +8,57 @@
#include "PortduinoGlue.h"
#endif
-#define MAX_POWER 20
+#ifndef RF95_MAX_POWER
+#define RF95_MAX_POWER 20
+#endif
+
// if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17
// In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING
// if you set power to something higher than 17 or 20 you might fry your board.
#define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level
+#ifdef RADIOMASTER_900_BANDIT_NANO
+// Structure to hold DAC and DB values
+typedef struct {
+ uint8_t dac;
+ uint8_t db;
+} DACDB;
+
+// Interpolation function
+DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) {
+ DACDB result;
+ double fraction = (double)(dbm - dbm1) / (dbm2 - dbm1);
+ result.dac = (uint8_t)(val1.dac + fraction * (val2.dac - val1.dac));
+ result.db = (uint8_t)(val1.db + fraction * (val2.db - val1.db));
+ return result;
+}
+
+// Function to find the correct DAC and DB values based on dBm using interpolation
+DACDB getDACandDB(uint8_t dbm) {
+ // Predefined values
+ static const struct {
+ uint8_t dbm;
+ DACDB values;
+ } dbmToDACDB[] = {
+ {20, {168, 2}}, // 100mW
+ {24, {148, 6}}, // 250mW
+ {27, {128, 9}}, // 500mW
+ {30, {90, 12}} // 1000mW
+ };
+ const int numValues = sizeof(dbmToDACDB) / sizeof(dbmToDACDB[0]);
+
+ // Find the interval dbm falls within and interpolate
+ for (int i = 0; i < numValues - 1; i++) {
+ if (dbm >= dbmToDACDB[i].dbm && dbm <= dbmToDACDB[i + 1].dbm) {
+ return interpolate(dbm, dbmToDACDB[i].dbm, dbmToDACDB[i + 1].dbm, dbmToDACDB[i].values, dbmToDACDB[i + 1].values);
+ }
+ }
+
+ // Return a default value if no match is found and default to 100mW
+ DACDB defaultValue = {168, 2};
+ return defaultValue;
+}
+#endif
RF95Interface::RF95Interface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
RADIOLIB_PIN_TYPE busy)
@@ -49,9 +94,16 @@ bool RF95Interface::init()
{
RadioLibInterface::init();
- if (power > MAX_POWER) // This chip has lower power limits than some
- power = MAX_POWER;
+#ifdef RADIOMASTER_900_BANDIT_NANO
+ // DAC and DB values based on dBm using interpolation
+ DACDB dacDbValues = getDACandDB(power);
+ int8_t powerDAC = dacDbValues.dac;
+ power = dacDbValues.db;
+#endif
+ if (power > RF95_MAX_POWER) // This chip has lower power limits than some
+ power = RF95_MAX_POWER;
+
limitPower();
iface = lora = new RadioLibRF95(&module);
@@ -61,6 +113,19 @@ bool RF95Interface::init()
digitalWrite(RF95_TCXO, 1);
#endif
+ // enable PA
+#ifdef RF95_PA_EN
+#if defined(RF95_PA_DAC_EN)
+ #ifdef RADIOMASTER_900_BANDIT_NANO
+ // Use calculated DAC value
+ dacWrite(RF95_PA_EN, powerDAC);
+ #else
+ // Use Value set in /*/variant.h
+ dacWrite(RF95_PA_EN, RF95_PA_LEVEL);
+ #endif
+#endif
+#endif
+
/*
#define RF95_TXEN (22) // If defined, this pin should be set high prior to transmit (controls an external analog switch)
#define RF95_RXEN (23) // If defined, this pin should be set high prior to receive (controls an external analog switch)
@@ -71,6 +136,11 @@ bool RF95Interface::init()
digitalWrite(RF95_TXEN, 0);
#endif
+#ifdef RF95_FAN_EN
+ pinMode(RF95_FAN_EN, OUTPUT);
+ digitalWrite(RF95_FAN_EN, 1);
+#endif
+
#ifdef RF95_RXEN
pinMode(RF95_RXEN, OUTPUT);
digitalWrite(RF95_RXEN, 1);
@@ -92,6 +162,9 @@ bool RF95Interface::init()
LOG_INFO("Frequency set to %f\n", getFreq());
LOG_INFO("Bandwidth set to %f\n", bw);
LOG_INFO("Power output set to %d\n", power);
+#ifdef RADIOMASTER_900_BANDIT_NANO
+ LOG_INFO("DAC output set to %d\n", powerDAC);
+#endif
if (res == RADIOLIB_ERR_NONE)
res = lora->setCRC(RADIOLIB_SX126X_LORA_CRC_ON);
@@ -146,10 +219,14 @@ bool RF95Interface::reconfigure()
if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
- if (power > MAX_POWER) // This chip has lower power limits than some
- power = MAX_POWER;
+ if (power > RF95_MAX_POWER) // This chip has lower power limits than some
+ power = RF95_MAX_POWER;
+#ifdef USE_RF95_RFO
+ err = lora->setOutputPower(power, true);
+#else
err = lora->setOutputPower(power);
+#endif
if (err != RADIOLIB_ERR_NONE)
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
@@ -235,5 +312,9 @@ bool RF95Interface::sleep()
setStandby(); // First cancel any active receiving/sending
lora->sleep();
+#ifdef RF95_FAN_EN
+ digitalWrite(RF95_FAN_EN, 0);
+#endif
+
return true;
-}
\ No newline at end of file
+}
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index cc6ccca07..eb86f4267 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -31,18 +31,18 @@ const RegionInfo regions[] = {
RDEF(EU_433, 433.0f, 434.0f, 10, 0, 12, true, false, false),
/*
- https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
- https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
- https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
+ https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
+ https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
+ https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
- audio_permitted = false per regulation
+ audio_permitted = false per regulation
- Special Note:
- The link above describes LoRaWAN's band plan, stating a power limit of 16 dBm. This is their own suggested specification,
- we do not need to follow it. The European Union regulations clearly state that the power limit for this frequency range is
- 500 mW, or 27 dBm. It also states that we can use interference avoidance and spectrum access techniques to avoid a duty
- cycle. (Please refer to section 4.21 in the following document)
- https://ec.europa.eu/growth/tools-databases/tris/index.cfm/ro/search/?trisaction=search.detail&year=2021&num=528&dLang=EN
+ Special Note:
+ The link above describes LoRaWAN's band plan, stating a power limit of 16 dBm. This is their own suggested specification,
+ we do not need to follow it. The European Union regulations clearly state that the power limit for this frequency range is
+ 500 mW, or 27 dBm. It also states that we can use interference avoidance and spectrum access techniques (such as LBT +
+ AFA) to avoid a duty cycle. (Please refer to line P page 22 of this document.)
+ https://www.etsi.org/deliver/etsi_en/300200_300299/30022002/03.01.01_60/en_30022002v030101p.pdf
*/
RDEF(EU_868, 869.4f, 869.65f, 10, 0, 27, false, false, false),
diff --git a/src/mesh/RadioLibRF95.cpp b/src/mesh/RadioLibRF95.cpp
index 1fe7869a3..a202d4f4d 100644
--- a/src/mesh/RadioLibRF95.cpp
+++ b/src/mesh/RadioLibRF95.cpp
@@ -42,7 +42,11 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
state = setCodingRate(cr);
RADIOLIB_ASSERT(state);
+#ifdef USE_RF95_RFO
+ state = setOutputPower(power, true);
+#else
state = setOutputPower(power);
+#endif
RADIOLIB_ASSERT(state);
state = setGain(gain);
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 4189bca66..3141d986b 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -311,7 +311,10 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
if (channels.decryptForHash(chIndex, p->channel)) {
// Try to decrypt the packet if we can
size_t rawSize = p->encrypted.size;
- assert(rawSize <= sizeof(bytes));
+ if (rawSize > sizeof(bytes)) {
+ LOG_ERROR("Packet too large to attempt decription! (rawSize=%d > 256)\n", rawSize);
+ return false;
+ }
memcpy(bytes, p->encrypted.bytes,
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
crypto->decrypt(p->from, p->id, rawSize, bytes);
diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h
index d692a3f30..d0e643dff 100644
--- a/src/mesh/generated/meshtastic/admin.pb.h
+++ b/src/mesh/generated/meshtastic/admin.pb.h
@@ -75,7 +75,7 @@ typedef struct _meshtastic_HamParameters {
Ensure your radio is capable of operating of the selected frequency before setting this. */
float frequency;
/* Optional short name of user */
- char short_name[6];
+ char short_name[5];
} meshtastic_HamParameters;
/* Response envelope for node_remote_hardware_pins */
@@ -135,6 +135,8 @@ typedef struct _meshtastic_AdminMessage {
bool enter_dfu_mode_request;
/* Delete the file by the specified path from the device */
char delete_file_request[201];
+ /* Set zero and offset for scale chips */
+ uint32_t set_scale;
/* Set the owner for this node */
meshtastic_User set_owner;
/* Set channels (using the new API).
@@ -238,6 +240,7 @@ extern "C" {
#define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20
#define meshtastic_AdminMessage_enter_dfu_mode_request_tag 21
#define meshtastic_AdminMessage_delete_file_request_tag 22
+#define meshtastic_AdminMessage_set_scale_tag 23
#define meshtastic_AdminMessage_set_owner_tag 32
#define meshtastic_AdminMessage_set_channel_tag 33
#define meshtastic_AdminMessage_set_config_tag 34
@@ -281,6 +284,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pin
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,enter_dfu_mode_request,enter_dfu_mode_request), 21) \
X(a, STATIC, ONEOF, STRING, (payload_variant,delete_file_request,delete_file_request), 22) \
+X(a, STATIC, ONEOF, UINT32, (payload_variant,set_scale,set_scale), 23) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \
@@ -342,7 +346,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size
#define meshtastic_AdminMessage_size 500
-#define meshtastic_HamParameters_size 32
+#define meshtastic_HamParameters_size 31
#define meshtastic_NodeRemoteHardwarePinsResponse_size 496
#ifdef __cplusplus
diff --git a/src/mesh/generated/meshtastic/atak.pb.h b/src/mesh/generated/meshtastic/atak.pb.h
index c094727ed..5fd18f963 100644
--- a/src/mesh/generated/meshtastic/atak.pb.h
+++ b/src/mesh/generated/meshtastic/atak.pb.h
@@ -73,6 +73,9 @@ typedef struct _meshtastic_GeoChat {
/* Uid recipient of the message */
bool has_to;
char to[120];
+ /* Callsign of the recipient for the message */
+ bool has_to_callsign;
+ char to_callsign[120];
} meshtastic_GeoChat;
/* ATAK Group
@@ -164,13 +167,13 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_TAKPacket_init_default {0, false, meshtastic_Contact_init_default, false, meshtastic_Group_init_default, false, meshtastic_Status_init_default, 0, {meshtastic_PLI_init_default}}
-#define meshtastic_GeoChat_init_default {"", false, ""}
+#define meshtastic_GeoChat_init_default {"", false, "", false, ""}
#define meshtastic_Group_init_default {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN}
#define meshtastic_Status_init_default {0}
#define meshtastic_Contact_init_default {"", ""}
#define meshtastic_PLI_init_default {0, 0, 0, 0, 0}
#define meshtastic_TAKPacket_init_zero {0, false, meshtastic_Contact_init_zero, false, meshtastic_Group_init_zero, false, meshtastic_Status_init_zero, 0, {meshtastic_PLI_init_zero}}
-#define meshtastic_GeoChat_init_zero {"", false, ""}
+#define meshtastic_GeoChat_init_zero {"", false, "", false, ""}
#define meshtastic_Group_init_zero {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN}
#define meshtastic_Status_init_zero {0}
#define meshtastic_Contact_init_zero {"", ""}
@@ -179,6 +182,7 @@ extern "C" {
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_GeoChat_message_tag 1
#define meshtastic_GeoChat_to_tag 2
+#define meshtastic_GeoChat_to_callsign_tag 3
#define meshtastic_Group_role_tag 1
#define meshtastic_Group_team_tag 2
#define meshtastic_Status_battery_tag 1
@@ -214,7 +218,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,chat,payload_variant.chat),
#define meshtastic_GeoChat_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, message, 1) \
-X(a, STATIC, OPTIONAL, STRING, to, 2)
+X(a, STATIC, OPTIONAL, STRING, to, 2) \
+X(a, STATIC, OPTIONAL, STRING, to_callsign, 3)
#define meshtastic_GeoChat_CALLBACK NULL
#define meshtastic_GeoChat_DEFAULT NULL
@@ -262,11 +267,11 @@ extern const pb_msgdesc_t meshtastic_PLI_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_TAKPacket_size
#define meshtastic_Contact_size 242
-#define meshtastic_GeoChat_size 323
+#define meshtastic_GeoChat_size 444
#define meshtastic_Group_size 4
#define meshtastic_PLI_size 31
#define meshtastic_Status_size 3
-#define meshtastic_TAKPacket_size 584
+#define meshtastic_TAKPacket_size 705
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/config.pb.cpp b/src/mesh/generated/meshtastic/config.pb.cpp
index f05e47573..bb82198c0 100644
--- a/src/mesh/generated/meshtastic/config.pb.cpp
+++ b/src/mesh/generated/meshtastic/config.pb.cpp
@@ -46,3 +46,4 @@ PB_BIND(meshtastic_Config_BluetoothConfig, meshtastic_Config_BluetoothConfig, AU
+
diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h
index 0830ed851..781538d11 100644
--- a/src/mesh/generated/meshtastic/config.pb.h
+++ b/src/mesh/generated/meshtastic/config.pb.h
@@ -182,6 +182,25 @@ typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
meshtastic_Config_DisplayConfig_DisplayMode_COLOR = 3
} meshtastic_Config_DisplayConfig_DisplayMode;
+typedef enum _meshtastic_Config_DisplayConfig_CompassOrientation {
+ /* The compass and the display are in the same orientation. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0 = 0,
+ /* Rotate the compass by 90 degrees. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90 = 1,
+ /* Rotate the compass by 180 degrees. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180 = 2,
+ /* Rotate the compass by 270 degrees. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270 = 3,
+ /* Don't rotate the compass, but invert the result. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED = 4,
+ /* Rotate the compass by 90 degrees and invert. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED = 5,
+ /* Rotate the compass by 180 degrees and invert. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED = 6,
+ /* Rotate the compass by 270 degrees and invert. */
+ meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED = 7
+} meshtastic_Config_DisplayConfig_CompassOrientation;
+
typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
/* Region is not set */
meshtastic_Config_LoRaConfig_RegionCode_UNSET = 0,
@@ -413,6 +432,8 @@ typedef struct _meshtastic_Config_DisplayConfig {
bool heading_bold;
/* Should we wake the screen up on accelerometer detected motion or tap */
bool wake_on_tap_or_motion;
+ /* Indicates how to rotate or invert the compass output to accurate display on the display. */
+ meshtastic_Config_DisplayConfig_CompassOrientation compass_orientation;
} meshtastic_Config_DisplayConfig;
/* Lora Config */
@@ -547,6 +568,10 @@ extern "C" {
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
#define _meshtastic_Config_DisplayConfig_DisplayMode_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayMode)(meshtastic_Config_DisplayConfig_DisplayMode_COLOR+1))
+#define _meshtastic_Config_DisplayConfig_CompassOrientation_MIN meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0
+#define _meshtastic_Config_DisplayConfig_CompassOrientation_MAX meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED
+#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1))
+
#define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET
#define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_SG_923
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_SG_923+1))
@@ -573,6 +598,7 @@ extern "C" {
#define meshtastic_Config_DisplayConfig_units_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayUnits
#define meshtastic_Config_DisplayConfig_oled_ENUMTYPE meshtastic_Config_DisplayConfig_OledType
#define meshtastic_Config_DisplayConfig_displaymode_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayMode
+#define meshtastic_Config_DisplayConfig_compass_orientation_ENUMTYPE meshtastic_Config_DisplayConfig_CompassOrientation
#define meshtastic_Config_LoRaConfig_modem_preset_ENUMTYPE meshtastic_Config_LoRaConfig_ModemPreset
#define meshtastic_Config_LoRaConfig_region_ENUMTYPE meshtastic_Config_LoRaConfig_RegionCode
@@ -587,7 +613,7 @@ extern "C" {
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
-#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
+#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN}
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0}
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
@@ -596,7 +622,7 @@ extern "C" {
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
-#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
+#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN}
#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0}
#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
@@ -656,6 +682,7 @@ extern "C" {
#define meshtastic_Config_DisplayConfig_displaymode_tag 8
#define meshtastic_Config_DisplayConfig_heading_bold_tag 9
#define meshtastic_Config_DisplayConfig_wake_on_tap_or_motion_tag 10
+#define meshtastic_Config_DisplayConfig_compass_orientation_tag 11
#define meshtastic_Config_LoRaConfig_use_preset_tag 1
#define meshtastic_Config_LoRaConfig_modem_preset_tag 2
#define meshtastic_Config_LoRaConfig_bandwidth_tag 3
@@ -778,7 +805,8 @@ X(a, STATIC, SINGULAR, UENUM, units, 6) \
X(a, STATIC, SINGULAR, UENUM, oled, 7) \
X(a, STATIC, SINGULAR, UENUM, displaymode, 8) \
X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) \
-X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10)
+X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) \
+X(a, STATIC, SINGULAR, UENUM, compass_orientation, 11)
#define meshtastic_Config_DisplayConfig_CALLBACK NULL
#define meshtastic_Config_DisplayConfig_DEFAULT NULL
@@ -834,7 +862,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
#define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size
#define meshtastic_Config_BluetoothConfig_size 10
#define meshtastic_Config_DeviceConfig_size 100
-#define meshtastic_Config_DisplayConfig_size 28
+#define meshtastic_Config_DisplayConfig_size 30
#define meshtastic_Config_LoRaConfig_size 80
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
#define meshtastic_Config_NetworkConfig_size 196
diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h
index b8cc80633..0e3e28ba1 100644
--- a/src/mesh/generated/meshtastic/deviceonly.pb.h
+++ b/src/mesh/generated/meshtastic/deviceonly.pb.h
@@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size
#define meshtastic_ChannelFile_size 718
#define meshtastic_NodeInfoLite_size 166
-#define meshtastic_OEMStore_size 3346
+#define meshtastic_OEMStore_size 3370
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus
diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h
index 1799f49da..160202d9b 100644
--- a/src/mesh/generated/meshtastic/localonly.pb.h
+++ b/src/mesh/generated/meshtastic/localonly.pb.h
@@ -181,8 +181,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size
-#define meshtastic_LocalConfig_size 537
-#define meshtastic_LocalModuleConfig_size 663
+#define meshtastic_LocalConfig_size 539
+#define meshtastic_LocalModuleConfig_size 685
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp
index 4907affc6..46d59d609 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.cpp
+++ b/src/mesh/generated/meshtastic/mesh.pb.cpp
@@ -66,6 +66,15 @@ PB_BIND(meshtastic_Heartbeat, meshtastic_Heartbeat, AUTO)
PB_BIND(meshtastic_NodeRemoteHardwarePin, meshtastic_NodeRemoteHardwarePin, AUTO)
+PB_BIND(meshtastic_ChunkedPayload, meshtastic_ChunkedPayload, AUTO)
+
+
+PB_BIND(meshtastic_resend_chunks, meshtastic_resend_chunks, AUTO)
+
+
+PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AUTO)
+
+
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index ffc18c30b..0e9e6a28d 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -65,6 +65,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_LORA_TYPE = 19,
/* wiphone https://www.wiphone.io/ */
meshtastic_HardwareModel_WIPHONE = 20,
+ /* WIO Tracker WM1110 family from Seeed Studio. Includes wio-1110-tracker and wio-1110-sdk */
+ meshtastic_HardwareModel_WIO_WM1110 = 21,
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
meshtastic_HardwareModel_STATION_G1 = 25,
/* RAK11310 (RP2040 + SX1262) */
@@ -156,6 +158,11 @@ typedef enum _meshtastic_HardwareModel {
/* NRF52_PROMICRO_DIY
Promicro NRF52840 with SX1262/LLCC68, SSD1306 OLED and NEO6M GPS */
meshtastic_HardwareModel_NRF52_PROMICRO_DIY = 63,
+ /* RadioMaster 900 Bandit Nano, https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module
+ ESP32-D0WDQ6 With SX1276/SKY66122, SSD1306 OLED and No GPS */
+ meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64,
+ /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */
+ meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -850,6 +857,38 @@ typedef struct _meshtastic_NodeRemoteHardwarePin {
meshtastic_RemoteHardwarePin pin;
} meshtastic_NodeRemoteHardwarePin;
+typedef PB_BYTES_ARRAY_T(228) meshtastic_ChunkedPayload_payload_chunk_t;
+typedef struct _meshtastic_ChunkedPayload {
+ /* The ID of the entire payload */
+ uint32_t payload_id;
+ /* The total number of chunks in the payload */
+ uint16_t chunk_count;
+ /* The current chunk index in the total */
+ uint16_t chunk_index;
+ /* The binary data of the current chunk */
+ meshtastic_ChunkedPayload_payload_chunk_t payload_chunk;
+} meshtastic_ChunkedPayload;
+
+/* Wrapper message for broken repeated oneof support */
+typedef struct _meshtastic_resend_chunks {
+ pb_callback_t chunks;
+} meshtastic_resend_chunks;
+
+/* Responses to a ChunkedPayload request */
+typedef struct _meshtastic_ChunkedPayloadResponse {
+ /* The ID of the entire payload */
+ uint32_t payload_id;
+ pb_size_t which_payload_variant;
+ union {
+ /* Request to transfer chunked payload */
+ bool request_transfer;
+ /* Accept the transfer chunked payload */
+ bool accept_transfer;
+ /* Request missing indexes in the chunked payload */
+ meshtastic_resend_chunks resend_chunks;
+ } payload_variant;
+} meshtastic_ChunkedPayloadResponse;
+
#ifdef __cplusplus
extern "C" {
@@ -925,6 +964,9 @@ extern "C" {
+
+
+
/* Initializer values for message structs */
#define meshtastic_Position_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
@@ -946,6 +988,9 @@ extern "C" {
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_Heartbeat_init_default {0}
#define meshtastic_NodeRemoteHardwarePin_init_default {0, false, meshtastic_RemoteHardwarePin_init_default}
+#define meshtastic_ChunkedPayload_init_default {0, 0, 0, {0, {0}}}
+#define meshtastic_resend_chunks_init_default {{{NULL}, NULL}}
+#define meshtastic_ChunkedPayloadResponse_init_default {0, 0, {0}}
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN}
#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
@@ -966,6 +1011,9 @@ extern "C" {
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN, 0}
#define meshtastic_Heartbeat_init_zero {0}
#define meshtastic_NodeRemoteHardwarePin_init_zero {0, false, meshtastic_RemoteHardwarePin_init_zero}
+#define meshtastic_ChunkedPayload_init_zero {0, 0, 0, {0, {0}}}
+#define meshtastic_resend_chunks_init_zero {{{NULL}, NULL}}
+#define meshtastic_ChunkedPayloadResponse_init_zero {0, 0, {0}}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_Position_latitude_i_tag 1
@@ -1100,6 +1148,15 @@ extern "C" {
#define meshtastic_ToRadio_heartbeat_tag 7
#define meshtastic_NodeRemoteHardwarePin_node_num_tag 1
#define meshtastic_NodeRemoteHardwarePin_pin_tag 2
+#define meshtastic_ChunkedPayload_payload_id_tag 1
+#define meshtastic_ChunkedPayload_chunk_count_tag 2
+#define meshtastic_ChunkedPayload_chunk_index_tag 3
+#define meshtastic_ChunkedPayload_payload_chunk_tag 4
+#define meshtastic_resend_chunks_chunks_tag 1
+#define meshtastic_ChunkedPayloadResponse_payload_id_tag 1
+#define meshtastic_ChunkedPayloadResponse_request_transfer_tag 2
+#define meshtastic_ChunkedPayloadResponse_accept_transfer_tag 3
+#define meshtastic_ChunkedPayloadResponse_resend_chunks_tag 4
/* Struct field encoding specification for nanopb */
#define meshtastic_Position_FIELDLIST(X, a) \
@@ -1338,6 +1395,28 @@ X(a, STATIC, OPTIONAL, MESSAGE, pin, 2)
#define meshtastic_NodeRemoteHardwarePin_DEFAULT NULL
#define meshtastic_NodeRemoteHardwarePin_pin_MSGTYPE meshtastic_RemoteHardwarePin
+#define meshtastic_ChunkedPayload_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, UINT32, payload_id, 1) \
+X(a, STATIC, SINGULAR, UINT32, chunk_count, 2) \
+X(a, STATIC, SINGULAR, UINT32, chunk_index, 3) \
+X(a, STATIC, SINGULAR, BYTES, payload_chunk, 4)
+#define meshtastic_ChunkedPayload_CALLBACK NULL
+#define meshtastic_ChunkedPayload_DEFAULT NULL
+
+#define meshtastic_resend_chunks_FIELDLIST(X, a) \
+X(a, CALLBACK, REPEATED, UINT32, chunks, 1)
+#define meshtastic_resend_chunks_CALLBACK pb_default_field_callback
+#define meshtastic_resend_chunks_DEFAULT NULL
+
+#define meshtastic_ChunkedPayloadResponse_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, UINT32, payload_id, 1) \
+X(a, STATIC, ONEOF, BOOL, (payload_variant,request_transfer,payload_variant.request_transfer), 2) \
+X(a, STATIC, ONEOF, BOOL, (payload_variant,accept_transfer,payload_variant.accept_transfer), 3) \
+X(a, STATIC, ONEOF, MESSAGE, (payload_variant,resend_chunks,payload_variant.resend_chunks), 4)
+#define meshtastic_ChunkedPayloadResponse_CALLBACK NULL
+#define meshtastic_ChunkedPayloadResponse_DEFAULT NULL
+#define meshtastic_ChunkedPayloadResponse_payload_variant_resend_chunks_MSGTYPE meshtastic_resend_chunks
+
extern const pb_msgdesc_t meshtastic_Position_msg;
extern const pb_msgdesc_t meshtastic_User_msg;
extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
@@ -1358,6 +1437,9 @@ extern const pb_msgdesc_t meshtastic_Neighbor_msg;
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
extern const pb_msgdesc_t meshtastic_Heartbeat_msg;
extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
+extern const pb_msgdesc_t meshtastic_ChunkedPayload_msg;
+extern const pb_msgdesc_t meshtastic_resend_chunks_msg;
+extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_Position_fields &meshtastic_Position_msg
@@ -1380,9 +1462,15 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
#define meshtastic_Heartbeat_fields &meshtastic_Heartbeat_msg
#define meshtastic_NodeRemoteHardwarePin_fields &meshtastic_NodeRemoteHardwarePin_msg
+#define meshtastic_ChunkedPayload_fields &meshtastic_ChunkedPayload_msg
+#define meshtastic_resend_chunks_fields &meshtastic_resend_chunks_msg
+#define meshtastic_ChunkedPayloadResponse_fields &meshtastic_ChunkedPayloadResponse_msg
/* Maximum encoded size of messages (where known) */
+/* meshtastic_resend_chunks_size depends on runtime parameters */
+/* meshtastic_ChunkedPayloadResponse_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_MESH_PB_H_MAX_SIZE meshtastic_FromRadio_size
+#define meshtastic_ChunkedPayload_size 245
#define meshtastic_Compressed_size 243
#define meshtastic_Data_size 270
#define meshtastic_DeviceMetadata_size 46
diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h
index ffda48704..f3c48ee6d 100644
--- a/src/mesh/generated/meshtastic/module_config.pb.h
+++ b/src/mesh/generated/meshtastic/module_config.pb.h
@@ -188,6 +188,10 @@ typedef struct _meshtastic_ModuleConfig_PaxcounterConfig {
/* Enable the Paxcounter Module */
bool enabled;
uint32_t paxcounter_update_interval;
+ /* WiFi RSSI threshold. Defaults to -80 */
+ int32_t wifi_threshold;
+ /* BLE RSSI threshold. Defaults to -80 */
+ int32_t ble_threshold;
} meshtastic_ModuleConfig_PaxcounterConfig;
/* Serial Config */
@@ -467,7 +471,7 @@ extern "C" {
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_default {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
-#define meshtastic_ModuleConfig_PaxcounterConfig_init_default {0, 0}
+#define meshtastic_ModuleConfig_PaxcounterConfig_init_default {0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
@@ -483,7 +487,7 @@ extern "C" {
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
#define meshtastic_ModuleConfig_DetectionSensorConfig_init_zero {0, 0, 0, 0, "", 0, 0, 0}
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
-#define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {0, 0}
+#define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
@@ -526,6 +530,8 @@ extern "C" {
#define meshtastic_ModuleConfig_AudioConfig_i2s_sck_tag 7
#define meshtastic_ModuleConfig_PaxcounterConfig_enabled_tag 1
#define meshtastic_ModuleConfig_PaxcounterConfig_paxcounter_update_interval_tag 2
+#define meshtastic_ModuleConfig_PaxcounterConfig_wifi_threshold_tag 3
+#define meshtastic_ModuleConfig_PaxcounterConfig_ble_threshold_tag 4
#define meshtastic_ModuleConfig_SerialConfig_enabled_tag 1
#define meshtastic_ModuleConfig_SerialConfig_echo_tag 2
#define meshtastic_ModuleConfig_SerialConfig_rxd_tag 3
@@ -695,7 +701,9 @@ X(a, STATIC, SINGULAR, UINT32, i2s_sck, 7)
#define meshtastic_ModuleConfig_PaxcounterConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
-X(a, STATIC, SINGULAR, UINT32, paxcounter_update_interval, 2)
+X(a, STATIC, SINGULAR, UINT32, paxcounter_update_interval, 2) \
+X(a, STATIC, SINGULAR, INT32, wifi_threshold, 3) \
+X(a, STATIC, SINGULAR, INT32, ble_threshold, 4)
#define meshtastic_ModuleConfig_PaxcounterConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_PaxcounterConfig_DEFAULT NULL
@@ -836,7 +844,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_MQTTConfig_size 254
#define meshtastic_ModuleConfig_MapReportSettings_size 12
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
-#define meshtastic_ModuleConfig_PaxcounterConfig_size 8
+#define meshtastic_ModuleConfig_PaxcounterConfig_size 30
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.cpp b/src/mesh/generated/meshtastic/telemetry.pb.cpp
index 6388e37a0..c93483a15 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.cpp
+++ b/src/mesh/generated/meshtastic/telemetry.pb.cpp
@@ -21,5 +21,8 @@ PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO)
PB_BIND(meshtastic_Telemetry, meshtastic_Telemetry, AUTO)
+PB_BIND(meshtastic_Nau7802Config, meshtastic_Nau7802Config, AUTO)
+
+
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h
index b6b08f2e7..28d368754 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.h
+++ b/src/mesh/generated/meshtastic/telemetry.pb.h
@@ -47,7 +47,23 @@ typedef enum _meshtastic_TelemetrySensorType {
/* RCWL-9620 Doppler Radar Distance Sensor, used for water level detection */
meshtastic_TelemetrySensorType_RCWL9620 = 16,
/* Sensirion High accuracy temperature and humidity */
- meshtastic_TelemetrySensorType_SHT4X = 17
+ meshtastic_TelemetrySensorType_SHT4X = 17,
+ /* VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. */
+ meshtastic_TelemetrySensorType_VEML7700 = 18,
+ /* MLX90632 non-contact IR temperature sensor. */
+ meshtastic_TelemetrySensorType_MLX90632 = 19,
+ /* TI OPT3001 Ambient Light Sensor */
+ meshtastic_TelemetrySensorType_OPT3001 = 20,
+ /* Lite On LTR-390UV-01 UV Light Sensor */
+ meshtastic_TelemetrySensorType_LTR390UV = 21,
+ /* AMS TSL25911FN RGB Light Sensor */
+ meshtastic_TelemetrySensorType_TSL25911FN = 22,
+ /* AHT10 Integrated temperature and humidity sensor */
+ meshtastic_TelemetrySensorType_AHT10 = 23,
+ /* DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) */
+ meshtastic_TelemetrySensorType_DFROBOT_LARK = 24,
+ /* NAU7802 Scale Chip or compatible */
+ meshtastic_TelemetrySensorType_NAU7802 = 25
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -84,6 +100,21 @@ typedef struct _meshtastic_EnvironmentMetrics {
uint16_t iaq;
/* RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. */
float distance;
+ /* VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. */
+ float lux;
+ /* VEML7700 high accuracy white light(irradiance) not calibrated digital 16-bit resolution sensor. */
+ float white_lux;
+ /* Infrared lux */
+ float ir_lux;
+ /* Ultraviolet lux */
+ float uv_lux;
+ /* Wind direction in degrees
+ 0 degrees = North, 90 = East, etc... */
+ uint16_t wind_direction;
+ /* Wind speed in m/s */
+ float wind_speed;
+ /* Weight in KG */
+ float weight;
} meshtastic_EnvironmentMetrics;
/* Power Metrics (voltage / current / etc) */
@@ -147,6 +178,14 @@ typedef struct _meshtastic_Telemetry {
} variant;
} meshtastic_Telemetry;
+/* NAU7802 Telemetry configuration, for saving to flash */
+typedef struct _meshtastic_Nau7802Config {
+ /* The offset setting for the NAU7802 */
+ int32_t zeroOffset;
+ /* The calibration factor for the NAU7802 */
+ float calibrationFactor;
+} meshtastic_Nau7802Config;
+
#ifdef __cplusplus
extern "C" {
@@ -154,8 +193,9 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
-#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SHT4X
-#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SHT4X+1))
+#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_NAU7802
+#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_NAU7802+1))
+
@@ -165,15 +205,17 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0}
-#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
+#define meshtastic_Nau7802Config_init_default {0, 0}
#define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0}
-#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
+#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
+#define meshtastic_Nau7802Config_init_zero {0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_DeviceMetrics_battery_level_tag 1
@@ -189,6 +231,13 @@ extern "C" {
#define meshtastic_EnvironmentMetrics_current_tag 6
#define meshtastic_EnvironmentMetrics_iaq_tag 7
#define meshtastic_EnvironmentMetrics_distance_tag 8
+#define meshtastic_EnvironmentMetrics_lux_tag 9
+#define meshtastic_EnvironmentMetrics_white_lux_tag 10
+#define meshtastic_EnvironmentMetrics_ir_lux_tag 11
+#define meshtastic_EnvironmentMetrics_uv_lux_tag 12
+#define meshtastic_EnvironmentMetrics_wind_direction_tag 13
+#define meshtastic_EnvironmentMetrics_wind_speed_tag 14
+#define meshtastic_EnvironmentMetrics_weight_tag 15
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
#define meshtastic_PowerMetrics_ch1_current_tag 2
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
@@ -212,6 +261,8 @@ extern "C" {
#define meshtastic_Telemetry_environment_metrics_tag 3
#define meshtastic_Telemetry_air_quality_metrics_tag 4
#define meshtastic_Telemetry_power_metrics_tag 5
+#define meshtastic_Nau7802Config_zeroOffset_tag 1
+#define meshtastic_Nau7802Config_calibrationFactor_tag 2
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceMetrics_FIELDLIST(X, a) \
@@ -231,7 +282,14 @@ X(a, STATIC, SINGULAR, FLOAT, gas_resistance, 4) \
X(a, STATIC, SINGULAR, FLOAT, voltage, 5) \
X(a, STATIC, SINGULAR, FLOAT, current, 6) \
X(a, STATIC, SINGULAR, UINT32, iaq, 7) \
-X(a, STATIC, SINGULAR, FLOAT, distance, 8)
+X(a, STATIC, SINGULAR, FLOAT, distance, 8) \
+X(a, STATIC, SINGULAR, FLOAT, lux, 9) \
+X(a, STATIC, SINGULAR, FLOAT, white_lux, 10) \
+X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \
+X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \
+X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \
+X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \
+X(a, STATIC, SINGULAR, FLOAT, weight, 15)
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
@@ -274,11 +332,18 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,power_metrics,variant.power_metrics)
#define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics
#define meshtastic_Telemetry_variant_power_metrics_MSGTYPE meshtastic_PowerMetrics
+#define meshtastic_Nau7802Config_FIELDLIST(X, a) \
+X(a, STATIC, SINGULAR, INT32, zeroOffset, 1) \
+X(a, STATIC, SINGULAR, FLOAT, calibrationFactor, 2)
+#define meshtastic_Nau7802Config_CALLBACK NULL
+#define meshtastic_Nau7802Config_DEFAULT NULL
+
extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg;
extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_msg;
extern const pb_msgdesc_t meshtastic_PowerMetrics_msg;
extern const pb_msgdesc_t meshtastic_AirQualityMetrics_msg;
extern const pb_msgdesc_t meshtastic_Telemetry_msg;
+extern const pb_msgdesc_t meshtastic_Nau7802Config_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg
@@ -286,14 +351,16 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg;
#define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg
#define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg
#define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg
+#define meshtastic_Nau7802Config_fields &meshtastic_Nau7802Config_msg
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
#define meshtastic_AirQualityMetrics_size 72
#define meshtastic_DeviceMetrics_size 27
-#define meshtastic_EnvironmentMetrics_size 39
+#define meshtastic_EnvironmentMetrics_size 73
+#define meshtastic_Nau7802Config_size 16
#define meshtastic_PowerMetrics_size 30
-#define meshtastic_Telemetry_size 79
+#define meshtastic_Telemetry_size 80
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp
index 1de4d7669..ffb16bd3e 100644
--- a/src/mesh/wifi/WiFiAPClient.cpp
+++ b/src/mesh/wifi/WiFiAPClient.cpp
@@ -108,8 +108,10 @@ static void onNetworkConnected()
}
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
+#ifndef MESHTASTIC_EXCLUDE_MQTT
if (mqtt)
mqtt->reconnect();
+#endif
}
static int32_t reconnectWiFi()
@@ -225,10 +227,16 @@ bool initWifi()
WiFi.mode(WIFI_STA);
WiFi.setHostname(ourHost);
+
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC &&
config.network.ipv4_config.ip != 0) {
+#ifndef ARCH_RP2040
WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet,
config.network.ipv4_config.dns);
+#else
+ WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.gateway,
+ config.network.ipv4_config.subnet);
+#endif
}
#ifndef ARCH_RP2040
WiFi.onEvent(WiFiEvent);
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index adf5620ba..091586462 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -27,6 +27,14 @@
#include "GPS.h"
#endif
+#if MESHTASTIC_EXCLUDE_GPS
+#include "modules/PositionModule.h"
+#endif
+
+#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+#include "AccelerometerThread.h"
+#endif
+
AdminModule *adminModule;
bool hasOpenEditTransaction;
@@ -221,12 +229,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
nodeDB->setLocalPosition(r->set_fixed_position);
config.position.fixed_position = true;
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_CONFIG, false);
- // Send our new fixed position to the mesh for good measure
- positionModule->sendOurPosition();
#if !MESHTASTIC_EXCLUDE_GPS
if (gps != nullptr)
gps->enable();
#endif
+ // Send our new fixed position to the mesh for good measure
+ positionModule->sendOurPosition();
}
break;
}
@@ -352,6 +360,26 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
case meshtastic_Config_device_tag:
LOG_INFO("Setting config: Device\n");
config.has_device = true;
+#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+ if (config.device.double_tap_as_button_press == false && c.payload_variant.device.double_tap_as_button_press == true) {
+ accelerometerThread->start();
+ }
+#endif
+#ifdef LED_PIN
+ // Turn LED off if heartbeat by config
+ if (c.payload_variant.device.led_heartbeat_disabled) {
+ digitalWrite(LED_PIN, LOW ^ LED_INVERTED);
+ }
+#endif
+ if (config.device.button_gpio == c.payload_variant.device.button_gpio &&
+ config.device.buzzer_gpio == c.payload_variant.device.buzzer_gpio &&
+ config.device.debug_log_enabled == c.payload_variant.device.debug_log_enabled &&
+ config.device.serial_enabled == c.payload_variant.device.serial_enabled &&
+ config.device.role == c.payload_variant.device.role &&
+ config.device.disable_triple_click == c.payload_variant.device.disable_triple_click &&
+ config.device.rebroadcast_mode == c.payload_variant.device.rebroadcast_mode) {
+ requiresReboot = false;
+ }
config.device = c.payload_variant.device;
// If we're setting router role for the first time, install its intervals
if (existingRole != c.payload_variant.device.role)
@@ -371,6 +399,16 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
case meshtastic_Config_power_tag:
LOG_INFO("Setting config: Power\n");
config.has_power = true;
+ // Really just the adc override is the only thing that can change without a reboot
+ if (config.power.device_battery_ina_address == c.payload_variant.power.device_battery_ina_address &&
+ config.power.is_power_saving == c.payload_variant.power.is_power_saving &&
+ config.power.ls_secs == c.payload_variant.power.ls_secs &&
+ config.power.min_wake_secs == c.payload_variant.power.min_wake_secs &&
+ config.power.on_battery_shutdown_after_secs == c.payload_variant.power.on_battery_shutdown_after_secs &&
+ config.power.sds_secs == c.payload_variant.power.sds_secs &&
+ config.power.wait_bluetooth_secs == c.payload_variant.power.wait_bluetooth_secs) {
+ requiresReboot = false;
+ }
config.power = c.payload_variant.power;
break;
case meshtastic_Config_network_tag:
@@ -381,6 +419,16 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
case meshtastic_Config_display_tag:
LOG_INFO("Setting config: Display\n");
config.has_display = true;
+ if (config.display.screen_on_secs == c.payload_variant.display.screen_on_secs &&
+ config.display.flip_screen == c.payload_variant.display.flip_screen &&
+ config.display.oled == c.payload_variant.display.oled) {
+ requiresReboot = false;
+ }
+#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+ if (config.display.wake_on_tap_or_motion == false && c.payload_variant.display.wake_on_tap_or_motion == true) {
+ accelerometerThread->start();
+ }
+#endif
config.display = c.payload_variant.display;
break;
case meshtastic_Config_lora_tag:
@@ -708,7 +756,9 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
if (conn.wifi.status.is_connected) {
conn.wifi.rssi = WiFi.RSSI();
conn.wifi.status.ip_address = WiFi.localIP();
+#ifndef MESHTASTIC_EXCLUDE_MQTT
conn.wifi.status.is_mqtt_connected = mqtt && mqtt->isConnectedDirectly();
+#endif
conn.wifi.status.is_syslog_connected = false; // FIXME wire this up
}
#endif
diff --git a/src/modules/AtakPluginModule.cpp b/src/modules/AtakPluginModule.cpp
index 64a85e2bf..59263415c 100644
--- a/src/modules/AtakPluginModule.cpp
+++ b/src/modules/AtakPluginModule.cpp
@@ -64,40 +64,41 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast
{
// From Phone (EUD)
if (mp.from == 0) {
- LOG_DEBUG("Received uncompressed TAK payload from phone with %d bytes\n", mp.decoded.payload.size);
+ LOG_DEBUG("Received uncompressed TAK payload from phone: %d bytes\n", mp.decoded.payload.size);
// Compress for LoRA transport
auto compressed = cloneTAKPacketData(t);
compressed.is_compressed = true;
if (t->has_contact) {
auto length = unishox2_compress_simple(t->contact.callsign, strlen(t->contact.callsign), compressed.contact.callsign);
- LOG_DEBUG("Uncompressed callsign '%s' - %d bytes\n", t->contact.callsign, strlen(t->contact.callsign));
- LOG_DEBUG("Compressed callsign '%s' - %d bytes\n", t->contact.callsign, length);
+ LOG_DEBUG("Compressed callsign: %d bytes\n", length);
length = unishox2_compress_simple(t->contact.device_callsign, strlen(t->contact.device_callsign),
compressed.contact.device_callsign);
- LOG_DEBUG("Uncompressed device_callsign '%s' - %d bytes\n", t->contact.device_callsign,
- strlen(t->contact.device_callsign));
- LOG_DEBUG("Compressed device_callsign '%s' - %d bytes\n", compressed.contact.device_callsign, length);
+ LOG_DEBUG("Compressed device_callsign: %d bytes\n", length);
}
if (t->which_payload_variant == meshtastic_TAKPacket_chat_tag) {
auto length = unishox2_compress_simple(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message),
compressed.payload_variant.chat.message);
- LOG_DEBUG("Uncompressed chat message '%s' - %d bytes\n", t->payload_variant.chat.message,
- strlen(t->payload_variant.chat.message));
- LOG_DEBUG("Compressed chat message '%s' - %d bytes\n", compressed.payload_variant.chat.message, length);
+ LOG_DEBUG("Compressed chat message: %d bytes\n", length);
if (t->payload_variant.chat.has_to) {
compressed.payload_variant.chat.has_to = true;
length = unishox2_compress_simple(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to),
compressed.payload_variant.chat.to);
- LOG_DEBUG("Uncompressed chat to '%s' - %d bytes\n", t->payload_variant.chat.to,
- strlen(t->payload_variant.chat.to));
- LOG_DEBUG("Compressed chat to '%s' - %d bytes\n", compressed.payload_variant.chat.to, length);
+ LOG_DEBUG("Compressed chat to: %d bytes\n", length);
+ }
+
+ if (t->payload_variant.chat.has_to_callsign) {
+ compressed.payload_variant.chat.has_to_callsign = true;
+ length =
+ unishox2_compress_simple(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign),
+ compressed.payload_variant.chat.to_callsign);
+ LOG_DEBUG("Compressed chat to_callsign: %d bytes\n", length);
}
}
mp.decoded.payload.size = pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes),
meshtastic_TAKPacket_fields, &compressed);
- LOG_DEBUG("Final payload size of %d bytes\n", mp.decoded.payload.size);
+ LOG_DEBUG("Final payload: %d bytes\n", mp.decoded.payload.size);
} else {
if (!t->is_compressed) {
// Not compressed. Something is wrong
@@ -113,27 +114,31 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast
auto length =
unishox2_decompress_simple(t->contact.callsign, strlen(t->contact.callsign), uncompressed.contact.callsign);
- LOG_DEBUG("Compressed callsign: %d bytes\n", strlen(t->contact.callsign));
- LOG_DEBUG("Decompressed callsign: '%s' @ %d bytes\n", uncompressed.contact.callsign, length);
+ LOG_DEBUG("Decompressed callsign: %d bytes\n", length);
length = unishox2_decompress_simple(t->contact.device_callsign, strlen(t->contact.device_callsign),
uncompressed.contact.device_callsign);
- LOG_DEBUG("Compressed device_callsign: %d bytes\n", strlen(t->contact.device_callsign));
- LOG_DEBUG("Decompressed device_callsign: '%s' @ %d bytes\n", uncompressed.contact.device_callsign, length);
+ LOG_DEBUG("Decompressed device_callsign: %d bytes\n", length);
}
if (uncompressed.which_payload_variant == meshtastic_TAKPacket_chat_tag) {
auto length = unishox2_decompress_simple(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message),
uncompressed.payload_variant.chat.message);
- LOG_DEBUG("Compressed chat message: %d bytes\n", strlen(t->payload_variant.chat.message));
- LOG_DEBUG("Decompressed chat message: '%s' @ %d bytes\n", uncompressed.payload_variant.chat.message, length);
+ LOG_DEBUG("Decompressed chat message: %d bytes\n", length);
if (t->payload_variant.chat.has_to) {
uncompressed.payload_variant.chat.has_to = true;
length = unishox2_decompress_simple(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to),
uncompressed.payload_variant.chat.to);
- LOG_DEBUG("Compressed chat to: %d bytes\n", strlen(t->payload_variant.chat.to));
- LOG_DEBUG("Decompressed chat to: '%s' @ %d bytes\n", uncompressed.payload_variant.chat.to, length);
+ LOG_DEBUG("Decompressed chat to: %d bytes\n", length);
+ }
+
+ if (t->payload_variant.chat.has_to_callsign) {
+ uncompressed.payload_variant.chat.has_to_callsign = true;
+ length =
+ unishox2_decompress_simple(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign),
+ uncompressed.payload_variant.chat.to_callsign);
+ LOG_DEBUG("Decompressed chat to_callsign: %d bytes\n", length);
}
}
decompressedCopy->decoded.payload.size =
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 0f17c268b..f513e045f 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -47,6 +47,12 @@ CannedMessageModule::CannedMessageModule()
disable();
} else {
LOG_INFO("CannedMessageModule is enabled\n");
+
+ // T-Watch interface currently has no way to select destination type, so default to 'node'
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
+#endif
+
this->inputObserver.observe(inputBroker);
}
} else {
@@ -67,8 +73,16 @@ int CannedMessageModule::splitConfiguredMessages()
int messageIndex = 0;
int i = 0;
+ String messages = cannedMessageModuleConfig.messages;
+
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ String separator = messages.length() ? "|" : "";
+
+ messages = "[---- Free Text ----]" + separator + messages;
+#endif
+
// collect all the message parts
- strncpy(this->messageStore, cannedMessageModuleConfig.messages, sizeof(this->messageStore));
+ strncpy(this->messageStore, messages.c_str(), sizeof(this->messageStore));
// The first message points to the beginning of the store.
this->messages[messageIndex++] = this->messageStore;
@@ -78,7 +92,6 @@ int CannedMessageModule::splitConfiguredMessages()
if (this->messageStore[i] == '|') {
// Message ending found, replace it with string-end character.
this->messageStore[i] = '\0';
- LOG_DEBUG("CannedMessage %d is: '%s'\n", messageIndex - 1, this->messages[messageIndex - 1]);
// hit our max messages, bail
if (messageIndex >= CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT) {
@@ -119,20 +132,30 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
bool validEvent = false;
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP)) {
if (this->messagesCount > 0) {
- // LOG_DEBUG("Canned message event UP\n");
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_UP;
validEvent = true;
}
}
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN)) {
if (this->messagesCount > 0) {
- // LOG_DEBUG("Canned message event DOWN\n");
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_DOWN;
validEvent = true;
}
}
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
- LOG_DEBUG("Canned message event Select\n");
+
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ if (this->currentMessageIndex == 0) {
+ this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
+
+ UIFrameEvent e = {false, true};
+ e.frameChanged = true;
+ this->notifyObservers(&e);
+
+ return 0;
+ }
+#endif
+
// when inactive, call the onebutton shortpress instead. Activate Module only on up/down
if ((this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
powerFSM.trigger(EVENT_PRESS);
@@ -143,38 +166,47 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
}
}
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
- LOG_DEBUG("Canned message event Cancel\n");
UIFrameEvent e = {false, true};
e.frameChanged = true;
this->currentMessageIndex = -1;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->freetext = ""; // clear freetext
this->cursor = 0;
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
this->notifyObservers(&e);
}
if ((event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
(event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
(event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
- // LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
+
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
+ this->payload = 0xb4;
+ } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
+ this->payload = 0xb7;
+ }
+#else
// tweak for left/right events generated via trackball/touch with empty kbchar
if (!event->kbchar) {
if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
this->payload = 0xb4;
- // this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
} else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
this->payload = 0xb7;
- // this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
}
} else {
// pass the pressed key
this->payload = event->kbchar;
}
+#endif
+
this->lastTouchMillis = millis();
validEvent = true;
}
if (event->inputEvent == static_cast(ANYKEY)) {
- LOG_DEBUG("Canned message event any key pressed\n");
// when inactive, this will switch to the freetext mode
if ((this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
@@ -250,8 +282,68 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
screen->removeFunctionSymbal("Fn"); // remove modifier (function) symbal
}
}
+
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
+ String keyTapped = keyForCoordinates(event->touchX, event->touchY);
+
+ if (keyTapped == "⇧") {
+ this->highlight = -1;
+
+ this->payload = 0x00;
+
+ validEvent = true;
+
+ this->shift = !this->shift;
+ } else if (keyTapped == "⌫") {
+ this->highlight = keyTapped[0];
+
+ this->payload = 0x08;
+
+ validEvent = true;
+
+ this->shift = false;
+ } else if (keyTapped == "123" || keyTapped == "ABC") {
+ this->highlight = -1;
+
+ this->payload = 0x00;
+
+ this->charSet = this->charSet == 0 ? 1 : 0;
+
+ validEvent = true;
+ } else if (keyTapped == " ") {
+ this->highlight = keyTapped[0];
+
+ this->payload = keyTapped[0];
+
+ validEvent = true;
+
+ this->shift = false;
+ } else if (keyTapped == "↵") {
+ this->highlight = 0x00;
+
+ this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
+
+ this->payload = CANNED_MESSAGE_RUN_STATE_FREETEXT;
+
+ this->currentMessageIndex = event->kbchar - 1;
+
+ validEvent = true;
+
+ this->shift = false;
+ } else if (keyTapped != "") {
+ this->highlight = keyTapped[0];
+
+ this->payload = this->shift ? keyTapped[0] : std::tolower(keyTapped[0]);
+
+ validEvent = true;
+
+ this->shift = false;
+ }
+ }
+#endif
+
if (event->inputEvent == static_cast(MATRIXKEY)) {
- LOG_DEBUG("Canned message event Matrix key pressed\n");
// this will send the text immediately on matrix press
this->runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
this->payload = MATRIXKEY;
@@ -311,17 +403,24 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->notifyObservers(&e);
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) &&
((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
// Reset module
- LOG_DEBUG("Reset due to lack of activity.\n");
e.frameChanged = true;
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
this->notifyObservers(&e);
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
@@ -330,7 +429,6 @@ int32_t CannedMessageModule::runOnce()
sendText(this->dest, indexChannels[this->channel], this->freetext.c_str(), true);
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
} else {
- LOG_DEBUG("Reset message is empty.\n");
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
}
} else {
@@ -339,11 +437,15 @@ int32_t CannedMessageModule::runOnce()
powerFSM.trigger(EVENT_PRESS);
return INT32_MAX;
} else {
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true);
+#else
sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true);
+#endif
}
this->runState = CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE;
} else {
- LOG_DEBUG("Reset message is empty.\n");
+ // LOG_DEBUG("Reset message is empty.\n");
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
}
}
@@ -351,7 +453,11 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->notifyObservers(&e);
return 2000;
} else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) {
@@ -364,7 +470,11 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = getPrevIndex();
this->freetext = ""; // clear freetext
this->cursor = 0;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
LOG_DEBUG("MOVE UP (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
}
@@ -373,7 +483,11 @@ int32_t CannedMessageModule::runOnce()
this->currentMessageIndex = this->getNextIndex();
this->freetext = ""; // clear freetext
this->cursor = 0;
+
+#if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
+#endif
+
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
}
@@ -457,7 +571,7 @@ int32_t CannedMessageModule::runOnce()
switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the
// display back to the default window
case 0x08: // backspace
- if (this->freetext.length() > 0) {
+ if (this->freetext.length() > 0 && this->highlight == 0x00) {
if (this->cursor == this->freetext.length()) {
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
} else {
@@ -495,13 +609,19 @@ int32_t CannedMessageModule::runOnce()
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
break;
default:
+ if (this->highlight != 0x00) {
+ break;
+ }
+
if (this->cursor == this->freetext.length()) {
this->freetext += this->payload;
} else {
this->freetext =
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
}
+
this->cursor += 1;
+
uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0);
if (this->freetext.length() > maxChars) {
this->cursor = maxChars;
@@ -594,6 +714,201 @@ void CannedMessageModule::showTemporaryMessage(const String &message)
setIntervalFromNow(2000);
}
+#if defined(T_WATCH_S3) || defined(RAK14014)
+
+String CannedMessageModule::keyForCoordinates(uint x, uint y)
+{
+ int outerSize = *(&this->keyboard[this->charSet] + 1) - this->keyboard[this->charSet];
+
+ for (int8_t outerIndex = 0; outerIndex < outerSize; outerIndex++) {
+ int innerSize = *(&this->keyboard[this->charSet][outerIndex] + 1) - this->keyboard[this->charSet][outerIndex];
+
+ for (int8_t innerIndex = 0; innerIndex < innerSize; innerIndex++) {
+ Letter letter = this->keyboard[this->charSet][outerIndex][innerIndex];
+
+ if (x > letter.rectX && x < (letter.rectX + letter.rectWidth) && y > letter.rectY &&
+ y < (letter.rectY + letter.rectHeight)) {
+ return letter.character;
+ }
+ }
+ }
+
+ return "";
+}
+
+void CannedMessageModule::drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+ int outerSize = *(&this->keyboard[this->charSet] + 1) - this->keyboard[this->charSet];
+
+ int xOffset = 0;
+
+ int yOffset = 56;
+
+ display->setTextAlignment(TEXT_ALIGN_LEFT);
+
+ display->setFont(FONT_SMALL);
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+
+ display->drawStringMaxWidth(0, 0, display->getWidth(),
+ cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
+
+ display->setFont(FONT_MEDIUM);
+
+ int cellHeight = round((display->height() - 64) / outerSize);
+
+ int yCorrection = 8;
+
+ for (int8_t outerIndex = 0; outerIndex < outerSize; outerIndex++) {
+ yOffset += outerIndex > 0 ? cellHeight : 0;
+
+ int innerSizeBound = *(&this->keyboard[this->charSet][outerIndex] + 1) - this->keyboard[this->charSet][outerIndex];
+
+ int innerSize = 0;
+
+ for (int8_t innerIndex = 0; innerIndex < innerSizeBound; innerIndex++) {
+ if (this->keyboard[this->charSet][outerIndex][innerIndex].character != "") {
+ innerSize++;
+ }
+ }
+
+ int cellWidth = display->width() / innerSize;
+
+ for (int8_t innerIndex = 0; innerIndex < innerSize; innerIndex++) {
+ xOffset += innerIndex > 0 ? cellWidth : 0;
+
+ Letter letter = this->keyboard[this->charSet][outerIndex][innerIndex];
+
+ Letter updatedLetter = {letter.character, letter.width, xOffset, yOffset, cellWidth, cellHeight};
+
+ this->keyboard[this->charSet][outerIndex][innerIndex] = updatedLetter;
+
+ float characterOffset = ((cellWidth / 2) - (letter.width / 2));
+
+ if (letter.character == "⇧") {
+ if (this->shift) {
+ display->fillRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ display->setColor(OLEDDISPLAY_COLOR::BLACK);
+
+ drawShiftIcon(display, xOffset + characterOffset, yOffset + yCorrection + 5, 1.2);
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+ } else {
+ display->drawRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ drawShiftIcon(display, xOffset + characterOffset, yOffset + yCorrection + 5, 1.2);
+ }
+ } else if (letter.character == "⌫") {
+ if (this->highlight == letter.character[0]) {
+ display->fillRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ display->setColor(OLEDDISPLAY_COLOR::BLACK);
+
+ drawBackspaceIcon(display, xOffset + characterOffset, yOffset + yCorrection + 5, 1.2);
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+
+ setIntervalFromNow(0);
+ } else {
+ display->drawRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ drawBackspaceIcon(display, xOffset + characterOffset, yOffset + yCorrection + 5, 1.2);
+ }
+ } else if (letter.character == "↵") {
+ display->drawRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ drawEnterIcon(display, xOffset + characterOffset, yOffset + yCorrection + 5, 1.7);
+ } else {
+ if (this->highlight == letter.character[0]) {
+ display->fillRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ display->setColor(OLEDDISPLAY_COLOR::BLACK);
+
+ display->drawString(xOffset + characterOffset, yOffset + yCorrection,
+ letter.character == " " ? "space" : letter.character);
+
+ display->setColor(OLEDDISPLAY_COLOR::WHITE);
+
+ setIntervalFromNow(0);
+ } else {
+ display->drawRect(xOffset, yOffset, cellWidth, cellHeight);
+
+ display->drawString(xOffset + characterOffset, yOffset + yCorrection,
+ letter.character == " " ? "space" : letter.character);
+ }
+ }
+ }
+
+ xOffset = 0;
+ }
+
+ this->highlight = 0x00;
+}
+
+void CannedMessageModule::drawShiftIcon(OLEDDisplay *display, int x, int y, float scale)
+{
+ PointStruct shiftIcon[10] = {{8, 0}, {15, 7}, {15, 8}, {12, 8}, {12, 12}, {4, 12}, {4, 8}, {1, 8}, {1, 7}, {8, 0}};
+
+ int size = 10;
+
+ for (int i = 0; i < size - 1; i++) {
+ int x0 = x + (shiftIcon[i].x * scale);
+ int y0 = y + (shiftIcon[i].y * scale);
+ int x1 = x + (shiftIcon[i + 1].x * scale);
+ int y1 = y + (shiftIcon[i + 1].y * scale);
+
+ display->drawLine(x0, y0, x1, y1);
+ }
+}
+
+void CannedMessageModule::drawBackspaceIcon(OLEDDisplay *display, int x, int y, float scale)
+{
+ PointStruct backspaceIcon[6] = {{0, 7}, {5, 2}, {15, 2}, {15, 12}, {5, 12}, {0, 7}};
+
+ int size = 6;
+
+ for (int i = 0; i < size - 1; i++) {
+ int x0 = x + (backspaceIcon[i].x * scale);
+ int y0 = y + (backspaceIcon[i].y * scale);
+ int x1 = x + (backspaceIcon[i + 1].x * scale);
+ int y1 = y + (backspaceIcon[i + 1].y * scale);
+
+ display->drawLine(x0, y0, x1, y1);
+ }
+
+ PointStruct backspaceIconX[4] = {{7, 4}, {13, 10}, {7, 10}, {13, 4}};
+
+ size = 4;
+
+ for (int i = 0; i < size - 1; i++) {
+ int x0 = x + (backspaceIconX[i].x * scale);
+ int y0 = y + (backspaceIconX[i].y * scale);
+ int x1 = x + (backspaceIconX[i + 1].x * scale);
+ int y1 = y + (backspaceIconX[i + 1].y * scale);
+
+ display->drawLine(x0, y0, x1, y1);
+ }
+}
+
+void CannedMessageModule::drawEnterIcon(OLEDDisplay *display, int x, int y, float scale)
+{
+ PointStruct enterIcon[6] = {{0, 7}, {4, 3}, {4, 11}, {0, 7}, {15, 7}, {15, 0}};
+
+ int size = 6;
+
+ for (int i = 0; i < size - 1; i++) {
+ int x0 = x + (enterIcon[i].x * scale);
+ int y0 = y + (enterIcon[i].y * scale);
+ int x1 = x + (enterIcon[i + 1].x * scale);
+ int y1 = y + (enterIcon[i + 1].y * scale);
+
+ display->drawLine(x0, y0, x1, y1);
+ }
+}
+
+#endif
+
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
@@ -614,6 +929,16 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
}
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, displayString,
cannedMessageModule->getNodeName(this->incoming));
+
+ display->setFont(FONT_SMALL);
+
+ String snrString = "Last Rx SNR: %f";
+ String rssiString = "Last Rx RSSI: %d";
+
+ if (this->ack) {
+ display->drawStringf(display->getWidth() / 2 + x, y + 100, buffer, snrString, this->lastRxSnr);
+ display->drawStringf(display->getWidth() / 2 + x, y + 130, buffer, rssiString, this->lastRxRssi);
+ }
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
@@ -623,6 +948,11 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->setFont(FONT_SMALL);
display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled.");
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
+
+#if defined(T_WATCH_S3) || defined(RAK14014)
+ drawKeyboard(display, state, 0, 0);
+#else
+
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
if (this->destSelect != CANNED_MESSAGE_DESTINATION_TYPE_NONE) {
@@ -663,6 +993,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->drawStringMaxWidth(
0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(),
cannedMessageModule->drawWithCursor(cannedMessageModule->freetext, cannedMessageModule->cursor));
+#endif
} else {
if (this->messagesCount > 0) {
display->setTextAlignment(TEXT_ALIGN_LEFT);
diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h
index faf1d80f3..00e8c2bf9 100644
--- a/src/modules/CannedMessageModule.h
+++ b/src/modules/CannedMessageModule.h
@@ -22,6 +22,17 @@ enum cannedMessageDestinationType {
CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL
};
+enum CannedMessageModuleIconType { shift, backspace, space, enter };
+
+struct Letter {
+ String character;
+ float width;
+ int rectX;
+ int rectY;
+ int rectWidth;
+ int rectHeight;
+};
+
#define CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT 50
/**
* Sum of CannedMessageModuleConfig part sizes.
@@ -61,6 +72,14 @@ class CannedMessageModule : public SinglePortModule, public Observablerx_rssi != 0) {
+ this->lastRxRssi = p->rx_rssi;
+ }
+
+ if (p->rx_snr > 0) {
+ this->lastRxSnr = p->rx_snr;
+ }
+
switch (p->decoded.portnum) {
case meshtastic_PortNum_TEXT_MESSAGE_APP:
case meshtastic_PortNum_ROUTING_APP:
@@ -79,6 +98,18 @@ class CannedMessageModule : public SinglePortModule, public ObservableshouldDraw(); }
virtual Observable *getUIFrameObservable() override { return this; }
@@ -110,12 +141,84 @@ class CannedMessageModule : public SinglePortModule, public Observable
+
+#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h"
+#include "modules/Telemetry/UnitConversions.h"
+
+#include
+
+DropzoneModule *dropzoneModule;
+
+int32_t DropzoneModule::runOnce()
+{
+ // Send on a 5 second delay from receiving the matching request
+ if (startSendConditions != 0 && (startSendConditions + 5000U) < millis()) {
+ service.sendToMesh(sendConditions(), RX_SRC_LOCAL);
+ startSendConditions = 0;
+ }
+ // Run every second to check if we need to send conditions
+ return 1000;
+}
+
+ProcessMessage DropzoneModule::handleReceived(const meshtastic_MeshPacket &mp)
+{
+ auto &p = mp.decoded;
+ char matchCompare[54];
+ auto incomingMessage = reinterpret_cast(p.payload.bytes);
+ sprintf(matchCompare, "%s conditions", owner.short_name);
+ if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) {
+ LOG_DEBUG("Received dropzone conditions request\n");
+ startSendConditions = millis();
+ }
+
+ sprintf(matchCompare, "%s conditions", owner.long_name);
+ if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) {
+ LOG_DEBUG("Received dropzone conditions request\n");
+ startSendConditions = millis();
+ }
+ return ProcessMessage::CONTINUE;
+}
+
+meshtastic_MeshPacket *DropzoneModule::sendConditions()
+{
+ char replyStr[200];
+ /*
+ CLOSED @ {HH:MM:SS}z
+ Wind 2 kts @ 125°
+ 29.25 inHg 72°C
+ */
+ uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
+ int hour = 0, min = 0, sec = 0;
+ if (rtc_sec > 0) {
+ long hms = rtc_sec % SEC_PER_DAY;
+ hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
+
+ hour = hms / SEC_PER_HOUR;
+ min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
+ sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN;
+ }
+
+ // Check if the dropzone is open or closed by reading the analog pin
+ // If pin is connected to GND (below 100 should be lower than floating voltage),
+ // the dropzone is open
+ auto dropzoneStatus = analogRead(A1) < 100 ? "OPEN" : "CLOSED";
+ auto reply = allocDataPacket();
+
+ auto node = nodeDB->getMeshNode(nodeDB->getNodeNum());
+ if (sensor.hasSensor()) {
+ meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero;
+ sensor.getMetrics(&telemetry);
+ auto windSpeed = UnitConversions::MetersPerSecondToKnots(telemetry.variant.environment_metrics.wind_speed);
+ auto windDirection = telemetry.variant.environment_metrics.wind_direction;
+ auto temp = telemetry.variant.environment_metrics.temperature;
+ auto baro = UnitConversions::HectoPascalToInchesOfMercury(telemetry.variant.environment_metrics.barometric_pressure);
+ sprintf(replyStr, "%s @ %02d:%02d:%02dz\nWind %.2f kts @ %d°\nBaro %.2f inHg %.2f°C", dropzoneStatus, hour, min, sec,
+ windSpeed, windDirection, baro, temp);
+ } else {
+ LOG_ERROR("No sensor found\n");
+ sprintf(replyStr, "%s @ %02d:%02d:%02d\nNo sensor found", dropzoneStatus, hour, min, sec);
+ }
+ LOG_DEBUG("Conditions reply: %s\n", replyStr);
+ reply->decoded.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply
+ memcpy(reply->decoded.payload.bytes, replyStr, reply->decoded.payload.size);
+
+ return reply;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/DropzoneModule.h b/src/modules/DropzoneModule.h
new file mode 100644
index 000000000..28f54ee0f
--- /dev/null
+++ b/src/modules/DropzoneModule.h
@@ -0,0 +1,37 @@
+#pragma once
+#if !MESHTASTIC_EXCLUDE_DROPZONE
+#include "SinglePortModule.h"
+#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h"
+
+/**
+ * An example module that replies to a message with the current conditions
+ * and status at the dropzone when it receives a text message mentioning it's name followed by "conditions"
+ */
+class DropzoneModule : public SinglePortModule, private concurrency::OSThread
+{
+ DFRobotLarkSensor sensor;
+
+ public:
+ /** Constructor
+ * name is for debugging output
+ */
+ DropzoneModule() : SinglePortModule("dropzone", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("DropzoneModule")
+ {
+ // Set up the analog pin for reading the dropzone status
+ pinMode(PIN_A1, INPUT);
+ }
+
+ virtual int32_t runOnce() override;
+
+ protected:
+ /** Called to handle a particular incoming message
+ */
+ virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
+
+ private:
+ meshtastic_MeshPacket *sendConditions();
+ uint32_t startSendConditions = 0;
+};
+
+extern DropzoneModule *dropzoneModule;
+#endif
\ No newline at end of file
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 5f7ab3975..1c027f981 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -72,6 +72,11 @@
#include "modules/SerialModule.h"
#endif
#endif
+
+#if !MESHTASTIC_EXCLUDE_DROPZONE
+#include "modules/DropzoneModule.h"
+#endif
+
/**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/
@@ -102,6 +107,10 @@ void setupModules()
#if !MESHTASTIC_EXCLUDE_ATAK
atakPluginModule = new AtakPluginModule();
#endif
+
+#if !MESHTASTIC_EXCLUDE_DROPZONE
+ dropzoneModule = new DropzoneModule();
+#endif
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable.
diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp
index f77026708..78af7099a 100644
--- a/src/modules/NodeInfoModule.cpp
+++ b/src/modules/NodeInfoModule.cpp
@@ -58,10 +58,15 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *NodeInfoModule::allocReply()
{
+ if (!airTime->isTxAllowedChannelUtil(false)) {
+ ignoreRequest = true; // Mark it as ignored for MeshModule
+ LOG_DEBUG("Skip sending NodeInfo due to > 40 percent channel util.\n");
+ return NULL;
+ }
uint32_t now = millis();
// If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway.
if (lastSentToMesh && (now - lastSentToMesh) < (5 * 60 * 1000)) {
- LOG_DEBUG("Sending NodeInfo will be ignored since we just sent it.\n");
+ LOG_DEBUG("Skip sending NodeInfo since we just sent it less than 5 minutes ago.\n");
ignoreRequest = true; // Mark it as ignored for MeshModule
return NULL;
} else {
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index 9986f860d..49f2b808b 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -55,6 +55,15 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
isLocal = true;
if (config.position.fixed_position) {
LOG_DEBUG("Ignore incoming position update from myself except for time, because position.fixed_position is true\n");
+
+#ifdef T_WATCH_S3
+ // Since we return early if position.fixed_position is true, set the T-Watch's RTC to the time received from the
+ // client device here
+ if (p.time && channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
+ trySetRtc(p, isLocal, true);
+ }
+#endif
+
nodeDB->setLocalPosition(p, true);
return false;
} else {
@@ -71,8 +80,17 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
p.time);
if (p.time && channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
+ bool force = false;
+
+#ifdef T_WATCH_S3
+ // The T-Watch appears to "pause" its RTC when shut down, such that the time it reads upon powering on is the same as when
+ // it was shut down. So we need to force the update here, since otherwise RTC::perhapsSetRTC will ignore it because it
+ // will always be an equivalent or lesser RTCQuality (RTCQualityNTP or RTCQualityNet).
+ force = true;
+#endif
+
// Set from phone RTC Quality to RTCQualityNTP since it should be approximately so
- trySetRtc(p, isLocal);
+ trySetRtc(p, isLocal, force);
}
nodeDB->updatePosition(getFrom(&mp), p);
@@ -104,14 +122,14 @@ void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic
}
}
-void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal)
+void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal, bool forceUpdate)
{
struct timeval tv;
uint32_t secs = p.time;
tv.tv_sec = secs;
tv.tv_usec = 0;
- perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv);
+ perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv, forceUpdate);
}
meshtastic_MeshPacket *PositionModule::allocReply()
@@ -191,13 +209,13 @@ meshtastic_MeshPacket *PositionModule::allocReply()
p.ground_speed = localPosition.ground_speed;
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
- // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
- // devices can get time.
- if (getRTCQuality() < RTCQualityDevice) {
+ // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS or NTP to include the time, so that devices
+ // without can get time.
+ if (getRTCQuality() < RTCQualityNTP) {
LOG_INFO("Stripping time %u from position send\n", p.time);
p.time = 0;
} else {
- p.time = getValidTime(RTCQualityDevice);
+ p.time = getValidTime(RTCQualityNTP);
LOG_INFO("Providing time to mesh %u\n", p.time);
}
@@ -436,4 +454,4 @@ void PositionModule::handleNewPosition()
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h
index 1161159f7..763b51e5c 100644
--- a/src/modules/PositionModule.h
+++ b/src/modules/PositionModule.h
@@ -54,7 +54,7 @@ class PositionModule : public ProtobufModule, private concu
private:
struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition);
meshtastic_MeshPacket *allocAtakPli();
- void trySetRtc(meshtastic_Position p, bool isLocal);
+ void trySetRtc(meshtastic_Position p, bool isLocal, bool forceUpdate = false);
uint32_t precision;
void sendLostAndFoundText();
diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp
index e4f31ff9f..4f5fbcd13 100644
--- a/src/modules/Telemetry/AirQualityTelemetry.cpp
+++ b/src/modules/Telemetry/AirQualityTelemetry.cpp
@@ -92,7 +92,7 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
return false;
}
- meshtastic_Telemetry m;
+ meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
m.time = getTime();
m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
m.variant.air_quality_metrics.pm10_standard = data.pm10_standard;
diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp
index 3529267cb..b64e8d113 100644
--- a/src/modules/Telemetry/DeviceTelemetry.cpp
+++ b/src/modules/Telemetry/DeviceTelemetry.cpp
@@ -64,13 +64,17 @@ meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry()
{
- meshtastic_Telemetry t;
+ meshtastic_Telemetry t = meshtastic_Telemetry_init_zero;
t.time = getTime();
t.which_variant = meshtastic_Telemetry_device_metrics_tag;
t.variant.device_metrics.air_util_tx = airTime->utilizationTXPercent();
+#if ARCH_PORTDUINO
+ t.variant.device_metrics.battery_level = MAGIC_USB_BATTERY_LEVEL;
+#else
t.variant.device_metrics.battery_level =
powerStatus->getIsCharging() ? MAGIC_USB_BATTERY_LEVEL : powerStatus->getBatteryChargePercent();
+#endif
t.variant.device_metrics.channel_utilization = airTime->channelUtilizationPercent();
t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0;
t.variant.device_metrics.uptime_seconds = getUptimeSeconds();
@@ -100,4 +104,4 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
service.sendToMesh(p, RX_SRC_LOCAL, true);
}
return true;
-}
\ No newline at end of file
+}
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 62adc9a8c..ff3202067 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -18,16 +18,23 @@
#include
// Sensors
+#include "Sensor/AHT10.h"
#include "Sensor/BME280Sensor.h"
#include "Sensor/BME680Sensor.h"
#include "Sensor/BMP085Sensor.h"
#include "Sensor/BMP280Sensor.h"
+#include "Sensor/DFRobotLarkSensor.h"
#include "Sensor/LPS22HBSensor.h"
#include "Sensor/MCP9808Sensor.h"
+#include "Sensor/MLX90632Sensor.h"
+#include "Sensor/NAU7802Sensor.h"
+#include "Sensor/OPT3001Sensor.h"
#include "Sensor/RCWL9620Sensor.h"
#include "Sensor/SHT31Sensor.h"
#include "Sensor/SHT4XSensor.h"
#include "Sensor/SHTC3Sensor.h"
+#include "Sensor/TSL2591Sensor.h"
+#include "Sensor/VEML7700Sensor.h"
BMP085Sensor bmp085Sensor;
BMP280Sensor bmp280Sensor;
@@ -37,8 +44,15 @@ MCP9808Sensor mcp9808Sensor;
SHTC3Sensor shtc3Sensor;
LPS22HBSensor lps22hbSensor;
SHT31Sensor sht31Sensor;
+VEML7700Sensor veml7700Sensor;
+TSL2591Sensor tsl2591Sensor;
+OPT3001Sensor opt3001Sensor;
SHT4XSensor sht4xSensor;
RCWL9620Sensor rcwl9620Sensor;
+AHT10Sensor aht10Sensor;
+MLX90632Sensor mlx90632Sensor;
+DFRobotLarkSensor dfRobotLarkSensor;
+NAU7802Sensor nau7802Sensor;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
@@ -61,8 +75,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
*/
// moduleConfig.telemetry.environment_measurement_enabled = 1;
- // moduleConfig.telemetry.environment_screen_enabled = 1;
- // moduleConfig.telemetry.environment_update_interval = 45;
+ // moduleConfig.telemetry.environment_screen_enabled = 1;
+ // moduleConfig.telemetry.environment_update_interval = 15;
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
// If this module is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
@@ -77,6 +91,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
LOG_INFO("Environment Telemetry: Initializing\n");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
+ if (dfRobotLarkSensor.hasSensor())
+ result = dfRobotLarkSensor.runOnce();
if (bmp085Sensor.hasSensor())
result = bmp085Sensor.runOnce();
if (bmp280Sensor.hasSensor())
@@ -99,8 +115,20 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = ina219Sensor.runOnce();
if (ina260Sensor.hasSensor())
result = ina260Sensor.runOnce();
+ if (veml7700Sensor.hasSensor())
+ result = veml7700Sensor.runOnce();
+ if (tsl2591Sensor.hasSensor())
+ result = tsl2591Sensor.runOnce();
+ if (opt3001Sensor.hasSensor())
+ result = opt3001Sensor.runOnce();
if (rcwl9620Sensor.hasSensor())
result = rcwl9620Sensor.runOnce();
+ if (aht10Sensor.hasSensor())
+ result = aht10Sensor.runOnce();
+ if (mlx90632Sensor.hasSensor())
+ result = mlx90632Sensor.runOnce();
+ if (nau7802Sensor.hasSensor())
+ result = nau7802Sensor.runOnce();
}
return result;
} else {
@@ -199,12 +227,18 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
"Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA");
}
+
if (lastMeasurement.variant.environment_metrics.iaq != 0) {
display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq));
}
+
if (lastMeasurement.variant.environment_metrics.distance != 0)
display->drawString(x, y += fontHeight(FONT_SMALL),
"Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm");
+
+ if (lastMeasurement.variant.environment_metrics.weight != 0)
+ display->drawString(x, y += fontHeight(FONT_SMALL),
+ "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
}
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
@@ -218,8 +252,12 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
sender, t->variant.environment_metrics.barometric_pressure, t->variant.environment_metrics.current,
t->variant.environment_metrics.gas_resistance, t->variant.environment_metrics.relative_humidity,
t->variant.environment_metrics.temperature);
- LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f\n", sender, t->variant.environment_metrics.voltage,
- t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance);
+ LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", sender, t->variant.environment_metrics.voltage,
+ t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux);
+
+ LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", sender,
+ t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
+ t->variant.environment_metrics.weight);
#endif
// release previous packet before occupying a new spot
@@ -234,52 +272,105 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
{
- meshtastic_Telemetry m;
- bool valid = false;
+ meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
+ bool valid = true;
+ bool hasSensor = false;
m.time = getTime();
m.which_variant = meshtastic_Telemetry_environment_metrics_tag;
- m.variant.environment_metrics.barometric_pressure = 0;
- m.variant.environment_metrics.current = 0;
- m.variant.environment_metrics.gas_resistance = 0;
- m.variant.environment_metrics.relative_humidity = 0;
- m.variant.environment_metrics.temperature = 0;
- m.variant.environment_metrics.voltage = 0;
- m.variant.environment_metrics.iaq = 0;
- m.variant.environment_metrics.distance = 0;
+ if (dfRobotLarkSensor.hasSensor()) {
+ valid = valid && dfRobotLarkSensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (sht31Sensor.hasSensor()) {
+ valid = valid && sht31Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (lps22hbSensor.hasSensor()) {
+ valid = valid && lps22hbSensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (shtc3Sensor.hasSensor()) {
+ valid = valid && shtc3Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (bmp085Sensor.hasSensor()) {
+ valid = valid && bmp085Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (bmp280Sensor.hasSensor()) {
+ valid = valid && bmp280Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (bme280Sensor.hasSensor()) {
+ valid = valid && bme280Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (bme680Sensor.hasSensor()) {
+ valid = valid && bme680Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (mcp9808Sensor.hasSensor()) {
+ valid = valid && mcp9808Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (ina219Sensor.hasSensor()) {
+ valid = valid && ina219Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (ina260Sensor.hasSensor()) {
+ valid = valid && ina260Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (veml7700Sensor.hasSensor()) {
+ valid = valid && veml7700Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (tsl2591Sensor.hasSensor()) {
+ valid = valid && tsl2591Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (opt3001Sensor.hasSensor()) {
+ valid = valid && opt3001Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (mlx90632Sensor.hasSensor()) {
+ valid = valid && mlx90632Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (rcwl9620Sensor.hasSensor()) {
+ valid = valid && rcwl9620Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (nau7802Sensor.hasSensor()) {
+ valid = valid && nau7802Sensor.getMetrics(&m);
+ hasSensor = true;
+ }
+ if (aht10Sensor.hasSensor()) {
+ if (!bmp280Sensor.hasSensor()) {
+ valid = valid && aht10Sensor.getMetrics(&m);
+ hasSensor = true;
+ } else {
+ // prefer bmp280 temp if both sensors are present, fetch only humidity
+ meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero;
+ LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0\n");
+ aht10Sensor.getMetrics(&m_ahtx);
+ m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
+ }
+ }
- if (sht31Sensor.hasSensor())
- valid = sht31Sensor.getMetrics(&m);
- if (sht4xSensor.hasSensor())
- valid = sht4xSensor.getMetrics(&m);
- if (lps22hbSensor.hasSensor())
- valid = lps22hbSensor.getMetrics(&m);
- if (shtc3Sensor.hasSensor())
- valid = shtc3Sensor.getMetrics(&m);
- if (bmp085Sensor.hasSensor())
- valid = bmp085Sensor.getMetrics(&m);
- if (bmp280Sensor.hasSensor())
- valid = bmp280Sensor.getMetrics(&m);
- if (bme280Sensor.hasSensor())
- valid = bme280Sensor.getMetrics(&m);
- if (bme680Sensor.hasSensor())
- valid = bme680Sensor.getMetrics(&m);
- if (mcp9808Sensor.hasSensor())
- valid = mcp9808Sensor.getMetrics(&m);
- if (ina219Sensor.hasSensor())
- valid = ina219Sensor.getMetrics(&m);
- if (ina260Sensor.hasSensor())
- valid = ina260Sensor.getMetrics(&m);
- if (rcwl9620Sensor.hasSensor())
- valid = rcwl9620Sensor.getMetrics(&m);
+ valid = valid && hasSensor;
if (valid) {
LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n",
m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current,
m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity,
m.variant.environment_metrics.temperature);
- LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f\n", m.variant.environment_metrics.voltage,
- m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance);
+ LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", m.variant.environment_metrics.voltage,
+ m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance, m.variant.environment_metrics.lux);
+
+ LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", m.variant.environment_metrics.wind_speed,
+ m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight);
sensor_read_error_count = 0;
@@ -312,4 +403,102 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
return valid;
}
+AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
+ meshtastic_AdminMessage *request,
+ meshtastic_AdminMessage *response)
+{
+ AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED;
+ if (dfRobotLarkSensor.hasSensor()) {
+ result = dfRobotLarkSensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (sht31Sensor.hasSensor()) {
+ result = sht31Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (lps22hbSensor.hasSensor()) {
+ result = lps22hbSensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (shtc3Sensor.hasSensor()) {
+ result = shtc3Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (bmp085Sensor.hasSensor()) {
+ result = bmp085Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (bmp280Sensor.hasSensor()) {
+ result = bmp280Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (bme280Sensor.hasSensor()) {
+ result = bme280Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (bme680Sensor.hasSensor()) {
+ result = bme680Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (mcp9808Sensor.hasSensor()) {
+ result = mcp9808Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (ina219Sensor.hasSensor()) {
+ result = ina219Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (ina260Sensor.hasSensor()) {
+ result = ina260Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (veml7700Sensor.hasSensor()) {
+ result = veml7700Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (tsl2591Sensor.hasSensor()) {
+ result = tsl2591Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (opt3001Sensor.hasSensor()) {
+ result = opt3001Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (mlx90632Sensor.hasSensor()) {
+ result = mlx90632Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (rcwl9620Sensor.hasSensor()) {
+ result = rcwl9620Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (nau7802Sensor.hasSensor()) {
+ result = nau7802Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ if (aht10Sensor.hasSensor()) {
+ result = aht10Sensor.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
+ return result;
+}
+
#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h
index cdd9491d4..ca150347e 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.h
+++ b/src/modules/Telemetry/EnvironmentTelemetry.h
@@ -37,6 +37,10 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
*/
bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
+ virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
+ meshtastic_AdminMessage *request,
+ meshtastic_AdminMessage *response) override;
+
private:
float CelsiusToFahrenheit(float c);
bool firstTime = 1;
diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp
index e61a4e629..826de8a4a 100644
--- a/src/modules/Telemetry/PowerTelemetry.cpp
+++ b/src/modules/Telemetry/PowerTelemetry.cpp
@@ -165,7 +165,7 @@ bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &m
bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
{
- meshtastic_Telemetry m;
+ meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
bool valid = false;
m.time = getTime();
m.which_variant = meshtastic_Telemetry_power_metrics_tag;
diff --git a/src/modules/Telemetry/Sensor/AHT10.cpp b/src/modules/Telemetry/Sensor/AHT10.cpp
new file mode 100644
index 000000000..a5212b39b
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/AHT10.cpp
@@ -0,0 +1,41 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "AHT10.h"
+#include "TelemetrySensor.h"
+
+#include
+#include
+
+AHT10Sensor::AHT10Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_AHT10, "AHT10") {}
+
+int32_t AHT10Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ aht10 = Adafruit_AHTX0();
+ status = aht10.begin(nodeTelemetrySensorsMap[sensorType].second, 0, nodeTelemetrySensorsMap[sensorType].first);
+
+ return initI2CSensor();
+}
+
+void AHT10Sensor::setup() {}
+
+bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ LOG_DEBUG("AHT10Sensor::getMetrics\n");
+
+ sensors_event_t humidity, temp;
+ aht10.getEvent(&humidity, &temp);
+
+ measurement->variant.environment_metrics.temperature = temp.temperature;
+ measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/AHT10.h b/src/modules/Telemetry/Sensor/AHT10.h
new file mode 100644
index 000000000..d9a133402
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/AHT10.h
@@ -0,0 +1,23 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class AHT10Sensor : public TelemetrySensor
+{
+ private:
+ Adafruit_AHTX0 aht10;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ AHT10Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
index f2c3804f4..411cbbf69 100644
--- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
@@ -28,7 +28,7 @@ int32_t BME680Sensor::runOnce()
if (bme680.status == BSEC_OK) {
status = 1;
- if (!bme680.setConfig(bsec_config_iaq)) {
+ if (!bme680.setConfig(bsec_config)) {
checkStatus("setConfig");
status = 0;
}
@@ -57,7 +57,7 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
measurement->variant.environment_metrics.temperature = bme680.getData(BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE).signal;
measurement->variant.environment_metrics.relative_humidity =
bme680.getData(BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY).signal;
- measurement->variant.environment_metrics.barometric_pressure = bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal / 100.0F;
+ measurement->variant.environment_metrics.barometric_pressure = bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal;
measurement->variant.environment_metrics.gas_resistance = bme680.getData(BSEC_OUTPUT_RAW_GAS).signal / 1000.0;
// Check if we need to save state to filesystem (every STATE_SAVE_PERIOD ms)
measurement->variant.environment_metrics.iaq = bme680.getData(BSEC_OUTPUT_IAQ).signal;
diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h
index 351db50ab..a5d2b5a48 100644
--- a/src/modules/Telemetry/Sensor/BME680Sensor.h
+++ b/src/modules/Telemetry/Sensor/BME680Sensor.h
@@ -8,7 +8,9 @@
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
-#include "bme680_iaq_33v_3s_4d/bsec_iaq.h"
+const uint8_t bsec_config[] = {
+#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
+};
class BME680Sensor : public TelemetrySensor
{
diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp
new file mode 100644
index 000000000..830552023
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.cpp
@@ -0,0 +1,53 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "DFRobotLarkSensor.h"
+#include "TelemetrySensor.h"
+#include "gps/GeoCoord.h"
+#include
+#include
+
+DFRobotLarkSensor::DFRobotLarkSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_LARK, "DFROBOT_LARK") {}
+
+int32_t DFRobotLarkSensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+
+ lark = DFRobot_LarkWeatherStation_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
+
+ if (lark.begin() == 0) // DFRobotLarkSensor init
+ {
+ LOG_DEBUG("DFRobotLarkSensor Init Succeed\n");
+ status = true;
+ } else {
+ LOG_ERROR("DFRobotLarkSensor Init Failed\n");
+ status = false;
+ }
+ return initI2CSensor();
+}
+
+void DFRobotLarkSensor::setup() {}
+
+bool DFRobotLarkSensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ measurement->variant.environment_metrics.temperature = lark.getValue("Temp").toFloat();
+ measurement->variant.environment_metrics.relative_humidity = lark.getValue("Humi").toFloat();
+ measurement->variant.environment_metrics.wind_speed = lark.getValue("Speed").toFloat();
+ measurement->variant.environment_metrics.wind_direction = GeoCoord::bearingToDegrees(lark.getValue("Dir").c_str());
+ measurement->variant.environment_metrics.barometric_pressure = lark.getValue("Pressure").toFloat();
+
+ LOG_INFO("Temperature: %f\n", measurement->variant.environment_metrics.temperature);
+ LOG_INFO("Humidity: %f\n", measurement->variant.environment_metrics.relative_humidity);
+ LOG_INFO("Wind Speed: %f\n", measurement->variant.environment_metrics.wind_speed);
+ LOG_INFO("Wind Direction: %d\n", measurement->variant.environment_metrics.wind_direction);
+ LOG_INFO("Barometric Pressure: %f\n", measurement->variant.environment_metrics.barometric_pressure);
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h
new file mode 100644
index 000000000..7a988e84a
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#ifndef _MT_DFROBOTLARKSENSOR_H
+#define _MT_DFROBOTLARKSENSOR_H
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+#include
+
+class DFRobotLarkSensor : public TelemetrySensor
+{
+ private:
+ DFRobot_LarkWeatherStation_I2C lark = DFRobot_LarkWeatherStation_I2C();
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ DFRobotLarkSensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp b/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp
new file mode 100644
index 000000000..4c459c365
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/MLX90632Sensor.cpp
@@ -0,0 +1,40 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "MLX90632Sensor.h"
+#include "TelemetrySensor.h"
+
+MLX90632Sensor::MLX90632Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MLX90632, "MLX90632") {}
+
+int32_t MLX90632Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+
+ MLX90632::status returnError;
+ if (mlx.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second, returnError) ==
+ true) // MLX90632 init
+ {
+ LOG_DEBUG("MLX90632 Init Succeed\n");
+ status = true;
+ } else {
+ LOG_ERROR("MLX90632 Init Failed\n");
+ status = false;
+ }
+ return initI2CSensor();
+}
+
+void MLX90632Sensor::setup() {}
+
+bool MLX90632Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ measurement->variant.environment_metrics.temperature = mlx.getObjectTemp(); // Get the object temperature in Fahrenheit
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/MLX90632Sensor.h b/src/modules/Telemetry/Sensor/MLX90632Sensor.h
new file mode 100644
index 000000000..7b36c44cd
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/MLX90632Sensor.h
@@ -0,0 +1,23 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class MLX90632Sensor : public TelemetrySensor
+{
+ private:
+ MLX90632 mlx = MLX90632();
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ MLX90632Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
new file mode 100644
index 000000000..39ac4b08b
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
@@ -0,0 +1,143 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "FSCommon.h"
+#include "NAU7802Sensor.h"
+#include "TelemetrySensor.h"
+#include
+#include
+
+meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero;
+
+NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {}
+
+int32_t NAU7802Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second);
+ nau7802.setSampleRate(NAU7802_SPS_320);
+ if (!loadCalibrationData()) {
+ LOG_ERROR("Failed to load calibration data\n");
+ }
+ nau7802.calibrateAFE();
+ LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
+ return initI2CSensor();
+}
+
+void NAU7802Sensor::setup() {}
+
+bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ LOG_DEBUG("NAU7802Sensor::getMetrics\n");
+ nau7802.powerUp();
+ // Wait for the sensor to become ready for one second max
+ uint32_t start = millis();
+ while (!nau7802.available()) {
+ delay(100);
+ if (millis() - start > 1000) {
+ nau7802.powerDown();
+ return false;
+ }
+ }
+ // Check if we have correct calibration values after powerup
+ LOG_DEBUG("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
+ measurement->variant.environment_metrics.weight = nau7802.getWeight() / 1000; // sample is in kg
+ nau7802.powerDown();
+ return true;
+}
+
+void NAU7802Sensor::calibrate(float weight)
+{
+ nau7802.calculateCalibrationFactor(weight * 1000, 64); // internal sample is in grams
+ if (!saveCalibrationData()) {
+ LOG_WARN("Failed to save calibration data\n");
+ }
+ LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
+}
+
+AdminMessageHandleResult NAU7802Sensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
+ meshtastic_AdminMessage *response)
+{
+ AdminMessageHandleResult result;
+
+ switch (request->which_payload_variant) {
+ case meshtastic_AdminMessage_set_scale_tag:
+ if (request->set_scale == 0) {
+ this->tare();
+ LOG_DEBUG("Client requested to tare scale\n");
+ } else {
+ this->calibrate(request->set_scale);
+ LOG_DEBUG("Client requested to calibrate to %d kg\n", request->set_scale);
+ }
+ result = AdminMessageHandleResult::HANDLED;
+ break;
+
+ default:
+ result = AdminMessageHandleResult::NOT_HANDLED;
+ }
+
+ return result;
+}
+
+void NAU7802Sensor::tare()
+{
+ nau7802.calculateZeroOffset(64);
+ if (!saveCalibrationData()) {
+ LOG_WARN("Failed to save calibration data\n");
+ }
+ LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
+}
+
+bool NAU7802Sensor::saveCalibrationData()
+{
+ if (FSCom.exists(nau7802ConfigFileName) && !FSCom.remove(nau7802ConfigFileName)) {
+ LOG_WARN("Can't remove old state file\n");
+ }
+ auto file = FSCom.open(nau7802ConfigFileName, FILE_O_WRITE);
+ nau7802config.zeroOffset = nau7802.getZeroOffset();
+ nau7802config.calibrationFactor = nau7802.getCalibrationFactor();
+ bool okay = false;
+ if (file) {
+ LOG_INFO("%s state write to %s.\n", sensorName, nau7802ConfigFileName);
+ pb_ostream_t stream = {&writecb, &file, meshtastic_Nau7802Config_size};
+
+ if (!pb_encode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) {
+ LOG_ERROR("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
+ } else {
+ okay = true;
+ }
+ file.flush();
+ file.close();
+ } else {
+ LOG_INFO("Can't write %s state (File: %s).\n", sensorName, nau7802ConfigFileName);
+ }
+ return okay;
+}
+
+bool NAU7802Sensor::loadCalibrationData()
+{
+ auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
+ bool okay = false;
+ if (file) {
+ LOG_INFO("%s state read from %s.\n", sensorName, nau7802ConfigFileName);
+ pb_istream_t stream = {&readcb, &file, meshtastic_Nau7802Config_size};
+ if (!pb_decode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) {
+ LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
+ } else {
+ nau7802.setZeroOffset(nau7802config.zeroOffset);
+ nau7802.setCalibrationFactor(nau7802config.calibrationFactor);
+ okay = true;
+ }
+ file.close();
+ } else {
+ LOG_INFO("No %s state found (File: %s).\n", sensorName, nau7802ConfigFileName);
+ }
+ return okay;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.h b/src/modules/Telemetry/Sensor/NAU7802Sensor.h
new file mode 100644
index 000000000..c53a3b31a
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.h
@@ -0,0 +1,31 @@
+#include "MeshModule.h"
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class NAU7802Sensor : public TelemetrySensor
+{
+ private:
+ NAU7802 nau7802;
+
+ protected:
+ virtual void setup() override;
+ const char *nau7802ConfigFileName = "/prefs/nau7802.dat";
+ bool saveCalibrationData();
+ bool loadCalibrationData();
+
+ public:
+ NAU7802Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+ void tare();
+ void calibrate(float weight);
+ AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
+ meshtastic_AdminMessage *response) override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp
new file mode 100644
index 000000000..0d76e2897
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp
@@ -0,0 +1,44 @@
+#include "OPT3001Sensor.h"
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include "configuration.h"
+#include
+
+OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {}
+
+int32_t OPT3001Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ auto errorCode = opt3001.begin(nodeTelemetrySensorsMap[sensorType].first);
+ status = errorCode == NO_ERROR;
+
+ return initI2CSensor();
+}
+
+void OPT3001Sensor::setup()
+{
+ OPT3001_Config newConfig;
+
+ newConfig.RangeNumber = B1100;
+ newConfig.ConvertionTime = B0;
+ newConfig.Latch = B1;
+ newConfig.ModeOfConversionOperation = B11;
+
+ OPT3001_ErrorCode errorConfig = opt3001.writeConfig(newConfig);
+ if (errorConfig != NO_ERROR) {
+ LOG_ERROR("OPT3001 configuration error #%d", errorConfig);
+ }
+}
+
+bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ OPT3001 result = opt3001.readResult();
+
+ measurement->variant.environment_metrics.lux = result.lux;
+ LOG_INFO("Lux: %f\n", measurement->variant.environment_metrics.lux);
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.h b/src/modules/Telemetry/Sensor/OPT3001Sensor.h
new file mode 100644
index 000000000..4a8deef21
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.h
@@ -0,0 +1,17 @@
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class OPT3001Sensor : public TelemetrySensor
+{
+ private:
+ ClosedCube_OPT3001 opt3001;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ OPT3001Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp
index d324b7fd6..7f37327c6 100644
--- a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp
+++ b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp
@@ -5,17 +5,7 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "SHT4XSensor.h"
#include "TelemetrySensor.h"
-#include
-
-// macro definitions
-// make sure that we use the proper definition of NO_ERROR
-#ifdef NO_ERROR
-#undef NO_ERROR
-#endif
-#define NO_ERROR 0
-
-static char errorMessage[64];
-static int16_t error;
+#include
SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {}
@@ -28,17 +18,15 @@ int32_t SHT4XSensor::runOnce()
uint32_t serialNumber = 0;
- sht4x.begin(*nodeTelemetrySensorsMap[sensorType].second, 0x44);
+ sht4x.begin(nodeTelemetrySensorsMap[sensorType].second);
- error = sht4x.serialNumber(serialNumber);
- LOG_DEBUG("serialNumber : %x\n", serialNumber);
- if (error != NO_ERROR) {
- LOG_DEBUG("Error trying to execute serialNumber(): ");
- errorToString(error, errorMessage, sizeof errorMessage);
- LOG_DEBUG(errorMessage);
- status = 0;
- } else {
+ serialNumber = sht4x.readSerial();
+ if (serialNumber != 0) {
+ LOG_DEBUG("serialNumber : %x\n", serialNumber);
status = 1;
+ } else {
+ LOG_DEBUG("Error trying to execute readSerial(): ");
+ status = 0;
}
return initI2CSensor();
@@ -51,12 +39,10 @@ void SHT4XSensor::setup()
bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement)
{
- float aTemperature = 0.0;
- float aHumidity = 0.0;
- sht4x.measureLowestPrecision(aTemperature, aHumidity);
- measurement->variant.environment_metrics.temperature = aTemperature;
- measurement->variant.environment_metrics.relative_humidity = aHumidity;
-
+ sensors_event_t humidity, temp;
+ sht4x.getEvent(&humidity, &temp);
+ measurement->variant.environment_metrics.temperature = temp.temperature;
+ measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
return true;
}
diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.h b/src/modules/Telemetry/Sensor/SHT4XSensor.h
index 67045eb2a..62a5cefeb 100644
--- a/src/modules/Telemetry/Sensor/SHT4XSensor.h
+++ b/src/modules/Telemetry/Sensor/SHT4XSensor.h
@@ -4,12 +4,12 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
-#include
+#include
class SHT4XSensor : public TelemetrySensor
{
private:
- SensirionI2cSht4x sht4x;
+ Adafruit_SHT4x sht4x = Adafruit_SHT4x();
protected:
virtual void setup() override;
diff --git a/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp
new file mode 100644
index 000000000..d20e48dce
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/TSL2591Sensor.cpp
@@ -0,0 +1,43 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TSL2591Sensor.h"
+#include "TelemetrySensor.h"
+#include
+#include
+
+TSL2591Sensor::TSL2591Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_TSL25911FN, "TSL2591") {}
+
+int32_t TSL2591Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ status = tsl.begin(nodeTelemetrySensorsMap[sensorType].second);
+
+ return initI2CSensor();
+}
+
+void TSL2591Sensor::setup()
+{
+ tsl.setGain(TSL2591_GAIN_MED); // 25x gain
+ tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
+}
+
+bool TSL2591Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ uint32_t lum = tsl.getFullLuminosity();
+ uint16_t ir, full;
+ ir = lum >> 16;
+ full = lum & 0xFFFF;
+
+ measurement->variant.environment_metrics.lux = tsl.calculateLux(full, ir);
+ LOG_INFO("Lux: %f\n", measurement->variant.environment_metrics.lux);
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/TSL2591Sensor.h b/src/modules/Telemetry/Sensor/TSL2591Sensor.h
new file mode 100644
index 000000000..27bebdfe5
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/TSL2591Sensor.h
@@ -0,0 +1,22 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class TSL2591Sensor : public TelemetrySensor
+{
+ private:
+ Adafruit_TSL2591 tsl;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ TSL2591Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h
index 35cb7965d..da376ad31 100644
--- a/src/modules/Telemetry/Sensor/TelemetrySensor.h
+++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h
@@ -4,6 +4,7 @@
#pragma once
#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "MeshModule.h"
#include "NodeDB.h"
#include
@@ -42,6 +43,12 @@ class TelemetrySensor
virtual void setup();
public:
+ virtual AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
+ meshtastic_AdminMessage *response)
+ {
+ return AdminMessageHandleResult::NOT_HANDLED;
+ }
+
bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }
virtual int32_t runOnce() = 0;
diff --git a/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp b/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp
new file mode 100644
index 000000000..cbeaf4c2e
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/VEML7700Sensor.cpp
@@ -0,0 +1,65 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include "VEML7700Sensor.h"
+
+#include
+#include
+
+VEML7700Sensor::VEML7700Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_VEML7700, "VEML7700") {}
+
+int32_t VEML7700Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ status = veml7700.begin(nodeTelemetrySensorsMap[sensorType].second);
+
+ veml7700.setLowThreshold(10000);
+ veml7700.setHighThreshold(20000);
+ veml7700.interruptEnable(true);
+
+ return initI2CSensor();
+}
+
+void VEML7700Sensor::setup() {}
+
+/*!
+ * @brief Copmute lux from ALS reading.
+ * @param rawALS raw ALS register value
+ * @param corrected if true, apply non-linear correction
+ * @return lux value
+ */
+float VEML7700Sensor::computeLux(uint16_t rawALS, bool corrected)
+{
+ float lux = getResolution() * rawALS;
+ if (corrected)
+ lux = (((6.0135e-13 * lux - 9.3924e-9) * lux + 8.1488e-5) * lux + 1.0023) * lux;
+ return lux;
+}
+
+/*!
+ * @brief Determines resolution for current gain and integration time
+ * settings.
+ */
+float VEML7700Sensor::getResolution(void)
+{
+ return MAX_RES * (IT_MAX / veml7700.getIntegrationTimeValue()) * (GAIN_MAX / veml7700.getGainValue());
+}
+
+bool VEML7700Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ int16_t white;
+ measurement->variant.environment_metrics.lux = veml7700.readLux(VEML_LUX_AUTO);
+ white = veml7700.readWhite(true);
+ measurement->variant.environment_metrics.white_lux = computeLux(white, white > 100);
+ LOG_INFO("white lux %f, als lux %f\n", measurement->variant.environment_metrics.white_lux,
+ measurement->variant.environment_metrics.lux);
+
+ return true;
+}
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/VEML7700Sensor.h b/src/modules/Telemetry/Sensor/VEML7700Sensor.h
new file mode 100644
index 000000000..97e57334c
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/VEML7700Sensor.h
@@ -0,0 +1,27 @@
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class VEML7700Sensor : public TelemetrySensor
+{
+ private:
+ const float MAX_RES = 0.0036;
+ const float GAIN_MAX = 2;
+ const float IT_MAX = 800;
+ Adafruit_VEML7700 veml7700;
+ float computeLux(uint16_t rawALS, bool corrected);
+ float getResolution(void);
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ VEML7700Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.c b/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.c
deleted file mode 100644
index 0b5328306..000000000
--- a/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
-
-#include "bsec_iaq.h"
-
-const uint8_t bsec_config_iaq[1974] = {
- 0, 0, 4, 2, 189, 1, 0, 0, 0, 0, 0, 0, 158, 7, 0, 0, 176, 0, 1, 0, 0, 192, 168, 71, 64,
- 49, 119, 76, 0, 0, 97, 69, 0, 0, 97, 69, 137, 65, 0, 191, 205, 204, 204, 190, 0, 0, 64, 191, 225, 122,
- 148, 190, 10, 0, 3, 0, 0, 0, 96, 64, 23, 183, 209, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 205, 204, 204, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 128, 63,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 128, 63, 82, 73, 157, 188, 95, 41, 203, 61, 118, 224,
- 108, 63, 155, 230, 125, 63, 191, 14, 124, 63, 0, 0, 160, 65, 0, 0, 32, 66, 0, 0, 160, 65, 0, 0, 32,
- 66, 0, 0, 32, 66, 0, 0, 160, 65, 0, 0, 32, 66, 0, 0, 160, 65, 8, 0, 2, 0, 236, 81, 133, 66,
- 16, 0, 3, 0, 10, 215, 163, 60, 10, 215, 35, 59, 10, 215, 35, 59, 13, 0, 5, 0, 0, 0, 0, 0, 100,
- 35, 41, 29, 86, 88, 0, 9, 0, 229, 208, 34, 62, 0, 0, 0, 0, 0, 0, 0, 0, 218, 27, 156, 62, 225,
- 11, 67, 64, 0, 0, 160, 64, 0, 0, 0, 0, 0, 0, 0, 0, 94, 75, 72, 189, 93, 254, 159, 64, 66, 62,
- 160, 191, 0, 0, 0, 0, 0, 0, 0, 0, 33, 31, 180, 190, 138, 176, 97, 64, 65, 241, 99, 190, 0, 0, 0,
- 0, 0, 0, 0, 0, 167, 121, 71, 61, 165, 189, 41, 192, 184, 30, 189, 64, 12, 0, 10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 13, 5, 11, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0,
- 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128,
- 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 10, 10, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 128, 63,
- 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0,
- 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 128, 63, 0, 0, 0, 88, 1, 254,
- 0, 2, 1, 5, 48, 117, 100, 0, 44, 1, 112, 23, 151, 7, 132, 3, 197, 0, 92, 4, 144, 1, 64, 1, 64,
- 1, 144, 1, 48, 117, 48, 117, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117, 48, 117, 100, 0,
- 100, 0, 48, 117, 48, 117, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 100, 0, 100, 0, 100, 0, 100, 0, 48,
- 117, 48, 117, 48, 117, 100, 0, 100, 0, 100, 0, 48, 117, 48, 117, 100, 0, 100, 0, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44,
- 1, 44, 1, 44, 1, 44, 1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 112, 23, 112, 23, 112, 23, 112, 23,
- 8, 7, 8, 7, 8, 7, 8, 7, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 112, 23, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 112, 23, 112, 23, 112, 23, 112, 23, 255, 255, 255, 255,
- 220, 5, 220, 5, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 220, 5, 220, 5, 220, 5, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 1, 0, 5, 10, 5,
- 0, 2, 0, 10, 0, 30, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 64, 1, 100, 0, 100, 0,
- 100, 0, 200, 0, 200, 0, 200, 0, 64, 1, 64, 1, 64, 1, 10, 0, 0, 0, 0, 0, 21, 122, 0, 0};
-
-#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.h b/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.h
deleted file mode 100644
index d693f1e6a..000000000
--- a/src/modules/Telemetry/Sensor/bme680_iaq_33v_3s_4d/bsec_iaq.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
-
-#include
-
-extern const uint8_t bsec_config_iaq[1974];
-
-#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/UnitConversions.cpp b/src/modules/Telemetry/UnitConversions.cpp
new file mode 100644
index 000000000..9f40de40f
--- /dev/null
+++ b/src/modules/Telemetry/UnitConversions.cpp
@@ -0,0 +1,21 @@
+#include "UnitConversions.h"
+
+float UnitConversions::CelsiusToFahrenheit(float celcius)
+{
+ return (celcius * 9) / 5 + 32;
+}
+
+float UnitConversions::MetersPerSecondToKnots(float metersPerSecond)
+{
+ return metersPerSecond * 1.94384;
+}
+
+float UnitConversions::MetersPerSecondToMilesPerHour(float metersPerSecond)
+{
+ return metersPerSecond * 2.23694;
+}
+
+float UnitConversions::HectoPascalToInchesOfMercury(float hectoPascal)
+{
+ return hectoPascal * 0.029529983071445;
+}
diff --git a/src/modules/Telemetry/UnitConversions.h b/src/modules/Telemetry/UnitConversions.h
new file mode 100644
index 000000000..60f9b664a
--- /dev/null
+++ b/src/modules/Telemetry/UnitConversions.h
@@ -0,0 +1,10 @@
+#pragma once
+
+class UnitConversions
+{
+ public:
+ static float CelsiusToFahrenheit(float celcius);
+ static float MetersPerSecondToKnots(float metersPerSecond);
+ static float MetersPerSecondToMilesPerHour(float metersPerSecond);
+ static float HectoPascalToInchesOfMercury(float hectoPascal);
+};
diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp
index aa0b6a1eb..f390aafcd 100644
--- a/src/modules/TraceRouteModule.cpp
+++ b/src/modules/TraceRouteModule.cpp
@@ -16,17 +16,37 @@ bool TraceRouteModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, m
void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r)
{
auto &incoming = p.decoded;
- // Only append an ID for the request (one way) and if we are not the destination (the reply will have our NodeNum already)
- if (!incoming.request_id && p.to != nodeDB->getNodeNum()) {
- appendMyID(r);
- printRoute(r, p.from, NODENUM_BROADCAST);
+ // Only append IDs for the request (one way)
+ if (!incoming.request_id) {
+ // Insert unknown hops if necessary
+ insertUnknownHops(p, r);
+ // Don't add ourselves if we are the destination (the reply will have our NodeNum already)
+ if (p.to != nodeDB->getNodeNum()) {
+ appendMyID(r);
+ printRoute(r, p.from, NODENUM_BROADCAST);
+ }
// Set updated route to the payload of the to be flooded packet
p.decoded.payload.size =
pb_encode_to_bytes(p.decoded.payload.bytes, sizeof(p.decoded.payload.bytes), &meshtastic_RouteDiscovery_msg, r);
}
}
+void TraceRouteModule::insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r)
+{
+ // Only insert unknown hops if hop_start is valid
+ if (p.hop_start != 0 && p.hop_limit <= p.hop_start) {
+ uint8_t hopsTaken = p.hop_start - p.hop_limit;
+ int8_t diff = hopsTaken - r->route_count;
+ for (uint8_t i = 0; i < diff; i++) {
+ if (r->route_count < sizeof(r->route) / sizeof(r->route[0])) {
+ r->route[r->route_count] = NODENUM_BROADCAST; // This will represent an unknown hop
+ r->route_count += 1;
+ }
+ }
+ }
+}
+
void TraceRouteModule::appendMyID(meshtastic_RouteDiscovery *updated)
{
// Length of route array can normally not be exceeded due to the max. hop_limit of 7
diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h
index 15e01debd..18a5ac0cb 100644
--- a/src/modules/TraceRouteModule.h
+++ b/src/modules/TraceRouteModule.h
@@ -19,6 +19,9 @@ class TraceRouteModule : public ProtobufModule
void alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r) override;
private:
+ // Call to add unknown hops (e.g. when a node couldn't decrypt it) to the route based on hopStart and current hopLimit
+ void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r);
+
// Call to add your ID to the route array of a RouteDiscovery message
void appendMyID(meshtastic_RouteDiscovery *r);
diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp
index b9fdfcb63..e6712871d 100644
--- a/src/modules/esp32/PaxcounterModule.cpp
+++ b/src/modules/esp32/PaxcounterModule.cpp
@@ -93,8 +93,8 @@ int32_t PaxcounterModule::runOnce()
configuration.wificounter = 1;
configuration.wifi_channel_map = WIFI_CHANNEL_ALL;
configuration.wifi_channel_switch_interval = 50;
- configuration.wifi_rssi_threshold = -80;
- configuration.ble_rssi_threshold = -80;
+ configuration.wifi_rssi_threshold = Default::getConfiguredOrDefault(moduleConfig.paxcounter.wifi_threshold, -80);
+ configuration.ble_rssi_threshold = Default::getConfiguredOrDefault(moduleConfig.paxcounter.ble_threshold, -80);
libpax_update_config(&configuration);
// internal processing initialization
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 95b2daa99..9f9ac5c24 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -396,6 +396,7 @@ bool MQTT::wantsLink() const
int32_t MQTT::runOnce()
{
+#ifdef HAS_NETWORKING
if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled()))
return disable();
@@ -408,7 +409,7 @@ int32_t MQTT::runOnce()
publishQueuedMessages();
return 200;
}
-#ifdef HAS_NETWORKING
+
else if (!pubSub.loop()) {
if (!wantConnection)
return 5000; // If we don't want connection now, check again in 5 secs
@@ -671,6 +672,11 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
+ msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
+ msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
+ msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
+ msgPayload["wind_speed"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_speed);
+ msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
@@ -894,8 +900,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
- if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start)
+ if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
+ jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
+ }
// serialize and write it to the stream
JSONValue *value = new JSONValue(jsonObj);
diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp
index 8f7e00461..68aa9b465 100644
--- a/src/nimble/NimbleBluetooth.cpp
+++ b/src/nimble/NimbleBluetooth.cpp
@@ -157,7 +157,9 @@ void NimbleBluetooth::setup()
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) {
- NimBLEDevice::setSecurityAuth(true, true, true);
+ NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM | BLE_SM_PAIR_AUTHREQ_SC);
+ NimBLEDevice::setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
+ NimBLEDevice::setSecurityRespKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
}
bleServer = NimBLEDevice::createServer();
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index 45d533a76..c979d016c 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -145,6 +145,10 @@
#define HW_VENDOR meshtastic_HardwareModel_UNPHONE
#elif defined(WIPHONE)
#define HW_VENDOR meshtastic_HardwareModel_WIPHONE
+#elif defined(RADIOMASTER_900_BANDIT_NANO)
+#define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO
+#elif defined(HELTEC_CAPSULE_SENSOR_V3)
+#define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3
#endif
// -----------------------------------------------------------------------------
diff --git a/src/platform/esp32/iram-quirk.c b/src/platform/esp32/iram-quirk.c
new file mode 100644
index 000000000..813842138
--- /dev/null
+++ b/src/platform/esp32/iram-quirk.c
@@ -0,0 +1,23 @@
+// Free up some precious space in the iram0_0_seg memory segment
+
+#include
+
+#include
+#include
+#include
+
+#define IRAM_SECTION section(".iram1.stub")
+
+IRAM_ATTR esp_err_t stub_probe(esp_flash_t *chip, uint32_t flash_id)
+{
+ return ESP_ERR_NOT_FOUND;
+}
+
+const spi_flash_chip_t stub_flash_chip __attribute__((IRAM_SECTION)) = {
+ .name = "stub",
+ .probe = stub_probe,
+};
+
+extern const spi_flash_chip_t __wrap_esp_flash_chip_gd __attribute__((IRAM_SECTION, alias("stub_flash_chip")));
+extern const spi_flash_chip_t __wrap_esp_flash_chip_issi __attribute__((IRAM_SECTION, alias("stub_flash_chip")));
+extern const spi_flash_chip_t __wrap_esp_flash_chip_winbond __attribute__((IRAM_SECTION, alias("stub_flash_chip")));
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index 2894a49fc..1dd7a389a 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -24,17 +24,23 @@
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH
void setBluetoothEnable(bool enable)
{
- if (!isWifiAvailable() && config.bluetooth.enabled == true) {
- if (!nimbleBluetooth) {
- nimbleBluetooth = new NimbleBluetooth();
+#ifndef MESHTASTIC_EXCLUDE_WIFI
+ if (!isWifiAvailable() && config.bluetooth.enabled == true)
+#endif
+#ifdef MESHTASTIC_EXCLUDE_WIFI
+ if (config.bluetooth.enabled == true)
+#endif
+ {
+ if (!nimbleBluetooth) {
+ nimbleBluetooth = new NimbleBluetooth();
+ }
+ if (enable && !nimbleBluetooth->isActive()) {
+ nimbleBluetooth->setup();
+ }
+ // For ESP32, no way to recover from bluetooth shutdown without reboot
+ // BLE advertising automatically stops when MCU enters light-sleep(?)
+ // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse
}
- if (enable && !nimbleBluetooth->isActive()) {
- nimbleBluetooth->setup();
- }
- // For ESP32, no way to recover from bluetooth shutdown without reboot
- // BLE advertising automatically stops when MCU enters light-sleep(?)
- // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse
- }
}
#else
void setBluetoothEnable(bool enable) {}
@@ -214,11 +220,16 @@ void cpuDeepSleep(uint32_t msecToWake)
#endif
// Not needed because both of the current boards have external pullups
- // FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of
- // just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
+ // FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead
+ // of just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#if SOC_PM_SUPPORT_EXT_WAKEUP
+#ifdef CONFIG_IDF_TARGET_ESP32
+ // ESP_EXT1_WAKEUP_ALL_LOW has been deprecated since esp-idf v5.4 for any other target.
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
+#else
+ esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ANY_LOW);
+#endif
#endif
#endif
diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp
index 39898ab25..4c25f38ea 100644
--- a/src/platform/nrf52/NRF52Bluetooth.cpp
+++ b/src/platform/nrf52/NRF52Bluetooth.cpp
@@ -215,6 +215,18 @@ void NRF52Bluetooth::shutdown()
Bluefruit.Advertising.stop();
}
+void NRF52Bluetooth::startDisabled()
+{
+ // Setup Bluetooth
+ nrf52Bluetooth->setup();
+
+ // Shutdown bluetooth for minimum power draw
+ Bluefruit.Advertising.stop();
+ Bluefruit.setTxPower(-40); // Minimum power
+
+ LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n");
+}
+
bool NRF52Bluetooth::isConnected()
{
return Bluefruit.connected(connectionHandle);
diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h
index 11e18c127..450af47f9 100644
--- a/src/platform/nrf52/NRF52Bluetooth.h
+++ b/src/platform/nrf52/NRF52Bluetooth.h
@@ -8,6 +8,7 @@ class NRF52Bluetooth : BluetoothApi
public:
void setup();
void shutdown();
+ void startDisabled();
void resumeAdvertising();
void clearBonds();
bool isConnected();
diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h
index 68bd87801..18a4d75f5 100644
--- a/src/platform/nrf52/architecture.h
+++ b/src/platform/nrf52/architecture.h
@@ -56,6 +56,8 @@
#define HW_VENDOR meshtastic_HardwareModel_TWC_MESH_V4
#elif defined(NRF52_PROMICRO_DIY)
#define HW_VENDOR meshtastic_HardwareModel_NRF52_PROMICRO_DIY
+#elif defined(WIO_WM1110)
+#define HW_VENDOR meshtastic_HardwareModel_WIO_WM1110
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#else
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index 9cc52a7de..1f2c6867d 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -68,28 +68,47 @@ static const bool useSoftDevice = true; // Set to false for easier debugging
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
void setBluetoothEnable(bool enable)
{
- if (enable && config.bluetooth.enabled) {
- if (!useSoftDevice) {
+ // For debugging use: don't use bluetooth
+ if (!useSoftDevice) {
+ if (enable)
LOG_INFO("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
- } else {
- if (!nrf52Bluetooth) {
- LOG_DEBUG("Initializing NRF52 Bluetooth\n");
- nrf52Bluetooth = new NRF52Bluetooth();
- nrf52Bluetooth->setup();
-
- // We delay brownout init until after BLE because BLE starts soft device
- initBrownout();
- } else {
- nrf52Bluetooth->resumeAdvertising();
- }
- }
- } else {
- if (nrf52Bluetooth) {
- nrf52Bluetooth->shutdown();
- }
+ return;
}
+
+ // If user disabled bluetooth: init then disable advertising & reduce power
+ // Workaround. Avoid issue where device hangs several days after boot..
+ // Allegedly, no significant increase in power consumption
+ if (!config.bluetooth.enabled) {
+ static bool initialized = false;
+ if (!initialized) {
+ nrf52Bluetooth = new NRF52Bluetooth();
+ nrf52Bluetooth->startDisabled();
+ initBrownout();
+ initialized = true;
+ }
+ return;
+ }
+
+ if (enable) {
+ // If not yet set-up
+ if (!nrf52Bluetooth) {
+ LOG_DEBUG("Initializing NRF52 Bluetooth\n");
+ nrf52Bluetooth = new NRF52Bluetooth();
+ nrf52Bluetooth->setup();
+
+ // We delay brownout init until after BLE because BLE starts soft device
+ initBrownout();
+ }
+ // Already setup, apparently
+ else
+ nrf52Bluetooth->resumeAdvertising();
+ }
+ // Disable (if previously set-up)
+ else if (nrf52Bluetooth)
+ nrf52Bluetooth->shutdown();
}
#else
+#warning NRF52 "Bluetooth disable" workaround does not apply to builds with MESHTASTIC_EXCLUDE_BLUETOOTH
void setBluetoothEnable(bool enable) {}
#endif
/**
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 4077a27bc..89ac806dd 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -283,7 +283,7 @@ void portduinoSetup()
}
for (configNames i : GPIO_lines) {
- if (settingsMap[i] > max_GPIO)
+ if (settingsMap.count(i) && settingsMap[i] > max_GPIO)
max_GPIO = settingsMap[i];
}
@@ -342,6 +342,7 @@ void portduinoSetup()
if (settingsMap[touchscreenIRQ] > 0)
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
}
+
if (settingsStrings[spidev] != "") {
SPI.begin(settingsStrings[spidev].c_str());
}
@@ -350,6 +351,7 @@ void portduinoSetup()
int initGPIOPin(int pinNum, const std::string gpioChipName)
{
+#ifdef PORTDUINO_LINUX_HARDWARE
std::string gpio_name = "GPIO" + std::to_string(pinNum);
try {
GPIOPin *csPin;
@@ -362,4 +364,7 @@ int initGPIOPin(int pinNum, const std::string gpioChipName)
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
return ERRNO_DISABLED;
}
+#else
+ return ERRNO_OK;
+#endif
}
\ No newline at end of file
diff --git a/src/shutdown.h b/src/shutdown.h
index 21abba07e..54fb3071b 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -28,6 +28,7 @@ void powerCommandsCheck()
Serial1.end();
if (screen)
delete screen;
+ LOG_DEBUG("final reboot!\n");
reboot();
#else
rebootAtMsec = -1;
diff --git a/src/sleep.cpp b/src/sleep.cpp
index fe73a755c..590610e6c 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -264,7 +264,11 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
#ifdef BUTTON_PIN
// Avoid leakage through button pin
if (GPIO_IS_VALID_OUTPUT_GPIO(BUTTON_PIN)) {
+#ifdef BUTTON_NEED_PULLUP
+ pinMode(BUTTON_PIN, INPUT_PULLUP);
+#else
pinMode(BUTTON_PIN, INPUT);
+#endif
gpio_hold_en((gpio_num_t)BUTTON_PIN);
}
#endif
diff --git a/variants/CDEBYTE_EoRa-S3/pins_arduino.h b/variants/CDEBYTE_EoRa-S3/pins_arduino.h
index 38a9103f0..46415d30f 100644
--- a/variants/CDEBYTE_EoRa-S3/pins_arduino.h
+++ b/variants/CDEBYTE_EoRa-S3/pins_arduino.h
@@ -11,15 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) \
- (((p) < 48) ? (p) : -1) // Maybe it should be <= 48 but this is from a trustworthy source so it is likely correct
-#define digitalPinHasPWM(p) (p < 46)
-
// Serial
static const uint8_t TX = UART_TX;
static const uint8_t RX = UART_RX;
diff --git a/variants/CDEBYTE_EoRa-S3/platformio.ini b/variants/CDEBYTE_EoRa-S3/platformio.ini
index 1ff54de88..a1642ff97 100644
--- a/variants/CDEBYTE_EoRa-S3/platformio.ini
+++ b/variants/CDEBYTE_EoRa-S3/platformio.ini
@@ -5,4 +5,4 @@ build_flags =
${esp32s3_base.build_flags}
-D CDEBYTE_EORA_S3
-I variants/CDEBYTE_EoRa-S3
- -D GPS_POWER_TOGGLE
+ -D GPS_POWER_TOGGLE
\ No newline at end of file
diff --git a/variants/Dongle_nRF52840-pca10059-v1/platformio.ini b/variants/Dongle_nRF52840-pca10059-v1/platformio.ini
index b1608770e..c87f83d39 100644
--- a/variants/Dongle_nRF52840-pca10059-v1/platformio.ini
+++ b/variants/Dongle_nRF52840-pca10059-v1/platformio.ini
@@ -1,9 +1,8 @@
[env:pca10059_diy_eink]
extends = nrf52840_base
board = nordic_pca10059
-board_level = extra
build_flags = ${nrf52840_base.build_flags} -Ivariants/Dongle_nRF52840-pca10059-v1 -D NORDIC_PCA10059
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_420_M01
-DEINK_WIDTH=300
-DEINK_HEIGHT=400
@@ -11,4 +10,4 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/Dongle_nRF52840-
lib_deps =
${nrf52840_base.lib_deps}
zinggjm/GxEPD2@^1.4.9
-debug_tool = jlink
+debug_tool = jlink
\ No newline at end of file
diff --git a/variants/EBYTE_ESP32-S3/pins_arduino.h b/variants/EBYTE_ESP32-S3/pins_arduino.h
index 38a9103f0..46415d30f 100644
--- a/variants/EBYTE_ESP32-S3/pins_arduino.h
+++ b/variants/EBYTE_ESP32-S3/pins_arduino.h
@@ -11,15 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) \
- (((p) < 48) ? (p) : -1) // Maybe it should be <= 48 but this is from a trustworthy source so it is likely correct
-#define digitalPinHasPWM(p) (p < 46)
-
// Serial
static const uint8_t TX = UART_TX;
static const uint8_t RX = UART_RX;
diff --git a/variants/MakePython_nRF52840_eink/platformio.ini b/variants/MakePython_nRF52840_eink/platformio.ini
index f421466ec..b11b54c7d 100644
--- a/variants/MakePython_nRF52840_eink/platformio.ini
+++ b/variants/MakePython_nRF52840_eink/platformio.ini
@@ -3,7 +3,7 @@ board_level = extra
extends = nrf52840_base
board = nordic_pca10059
build_flags = ${nrf52840_base.build_flags} -Ivariants/MakePython_nRF52840_eink -D PRIVATE_HW
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-D PIN_EINK_EN
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/MakePython_nRF52840_eink>
lib_deps =
diff --git a/variants/MakePython_nRF52840_oled/platformio.ini b/variants/MakePython_nRF52840_oled/platformio.ini
index e0ddb1377..0146385e0 100644
--- a/variants/MakePython_nRF52840_oled/platformio.ini
+++ b/variants/MakePython_nRF52840_oled/platformio.ini
@@ -3,7 +3,7 @@ board_level = extra
extends = nrf52840_base
board = nordic_pca10059
build_flags = ${nrf52840_base.build_flags} -Ivariants/MakePython_nRF52840_oled -D PRIVATE_HW
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/MakePython_nRF52840_oled>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/TWC_mesh_v4/platformio.ini b/variants/TWC_mesh_v4/platformio.ini
index 481682143..4fb382334 100644
--- a/variants/TWC_mesh_v4/platformio.ini
+++ b/variants/TWC_mesh_v4/platformio.ini
@@ -2,7 +2,7 @@
extends = nrf52840_base
board = nordic_pca10059
board_level = extra
-build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\BSEC2 Software Library\src\cortex-m4\fpv4-sp-d16-hard"
+build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\bsec2\src\cortex-m4\fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/TWC_mesh_v4>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/betafpv_900_tx_nano/platformio.ini b/variants/betafpv_900_tx_nano/platformio.ini
index 68e1a469b..3bea16f6b 100644
--- a/variants/betafpv_900_tx_nano/platformio.ini
+++ b/variants/betafpv_900_tx_nano/platformio.ini
@@ -1,6 +1,7 @@
[env:betafpv_900_tx_nano]
extends = esp32_base
board = esp32doit-devkit-v1
+board_level = extra
build_flags =
${esp32_base.build_flags}
-D BETAFPV_900_TX_NANO
@@ -13,4 +14,4 @@ upload_protocol = esptool
;upload_port = /dev/ttyUSB0
upload_speed = 460800
lib_deps =
- ${esp32_base.lib_deps}
+ ${esp32_base.lib_deps}
\ No newline at end of file
diff --git a/variants/bpi_picow_esp32_s3/pins_arduino.h b/variants/bpi_picow_esp32_s3/pins_arduino.h
index af03bf28a..dd7b3c518 100644
--- a/variants/bpi_picow_esp32_s3/pins_arduino.h
+++ b/variants/bpi_picow_esp32_s3/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/canaryone/platformio.ini b/variants/canaryone/platformio.ini
index 4917f52c7..5e01c3763 100644
--- a/variants/canaryone/platformio.ini
+++ b/variants/canaryone/platformio.ini
@@ -6,7 +6,7 @@ debug_tool = jlink
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags} -Ivariants/canaryone
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/canaryone>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/chatter2/platformio.ini b/variants/chatter2/platformio.ini
index 0856debfc..1f086cf07 100644
--- a/variants/chatter2/platformio.ini
+++ b/variants/chatter2/platformio.ini
@@ -2,7 +2,6 @@
[env:chatter2]
extends = esp32_base
board = esp32doit-devkit-v1
-board_level = extra
build_flags =
${esp32_base.build_flags}
-D CHATTER_2
diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini
index 5fb0f6421..adc10de44 100644
--- a/variants/diy/platformio.ini
+++ b/variants/diy/platformio.ini
@@ -2,7 +2,7 @@
[env:meshtastic-diy-v1]
extends = esp32_base
board = esp32doit-devkit-v1
-board_level = extra
+board_check = true
build_flags =
${esp32_base.build_flags}
-D DIY_V1
@@ -26,7 +26,6 @@ build_flags =
[env:meshtastic-dr-dev]
extends = esp32_base
board = esp32doit-devkit-v1
-board_level = extra
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480
build_flags =
@@ -39,7 +38,6 @@ build_flags =
[env:hydra]
extends = esp32_base
board = esp32doit-devkit-v1
-board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
@@ -55,7 +53,7 @@ build_flags = ${nrf52840_base.build_flags}
-I variants/diy/nrf52_promicro_diy_xtal
-D NRF52_PROMICRO_DIY
-D OLED_RU
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/nrf52_promicro_diy_xtal>
lib_deps =
${nrf52840_base.lib_deps}
@@ -71,7 +69,7 @@ build_flags = ${nrf52840_base.build_flags}
-I variants/diy/nrf52_promicro_diy_tcxo
-D NRF52_PROMICRO_DIY
-D OLED_RU
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/diy/nrf52_promicro_diy_tcxo>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/esp32-s3-pico/pins_arduino.h b/variants/esp32-s3-pico/pins_arduino.h
index d24d98a2e..57a66fea2 100644
--- a/variants/esp32-s3-pico/pins_arduino.h
+++ b/variants/esp32-s3-pico/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
// The default Wire will be mapped to PMU and RTC
static const uint8_t SDA = 15;
static const uint8_t SCL = 16;
diff --git a/variants/feather_diy/platformio.ini b/variants/feather_diy/platformio.ini
index 924f9098d..82dbb317c 100644
--- a/variants/feather_diy/platformio.ini
+++ b/variants/feather_diy/platformio.ini
@@ -2,9 +2,8 @@
[env:feather_diy]
extends = nrf52840_base
board = adafruit_feather_nrf52840
-board_level = extra
build_flags = ${nrf52840_base.build_flags} -Ivariants/feather_diy -Dfeather_diy
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/feather_diy>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini
new file mode 100644
index 000000000..f1aef925d
--- /dev/null
+++ b/variants/heltec_capsule_sensor_v3/platformio.ini
@@ -0,0 +1,11 @@
+[env:heltec_capsule_sensor_v3]
+extends = esp32s3_base
+board = heltec_wifi_lora_32_V3
+board_check = true
+
+build_flags =
+ ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3
+ -D HELTEC_CAPSULE_SENSOR_V3
+ -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+ ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output
+
diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h
new file mode 100644
index 000000000..0d5ab73cf
--- /dev/null
+++ b/variants/heltec_capsule_sensor_v3/variant.h
@@ -0,0 +1,42 @@
+#define LED_PIN 33
+#define LED_PIN2 34
+#define EXT_PWR_DETECT 35
+
+#define BUTTON_PIN 18
+
+#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+#define ADC_CHANNEL ADC1_GPIO7_CHANNEL
+#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
+#define ADC_MULTIPLIER (4.9 * 1.045)
+#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1
+#define ADC_CTRL_ENABLED HIGH
+
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+#define GPS_RX_PIN 5
+#define GPS_TX_PIN 4
+#define PIN_GPS_RESET 3
+#define GPS_RESET_MODE LOW
+#define PIN_GPS_PPS 1
+#define PIN_GPS_EN 21
+#define GPS_EN_ACTIVE HIGH
+
+#define USE_SX1262
+#define LORA_DIO0 -1 // a No connect on the SX1262 module
+#define LORA_RESET 12
+#define LORA_DIO1 14 // SX1262 IRQ
+#define LORA_DIO2 13 // SX1262 BUSY
+#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
+
+#define LORA_SCK 9
+#define LORA_MISO 11
+#define LORA_MOSI 10
+#define LORA_CS 8
+
+#define SX126X_CS LORA_CS
+#define SX126X_DIO1 LORA_DIO1
+#define SX126X_BUSY LORA_DIO2
+#define SX126X_RESET LORA_RESET
+
+#define SX126X_DIO2_AS_RF_SWITCH
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8
diff --git a/variants/heltec_esp32c3/pins_arduino.h b/variants/heltec_esp32c3/pins_arduino.h
index db30a2f30..a717a3706 100644
--- a/variants/heltec_esp32c3/pins_arduino.h
+++ b/variants/heltec_esp32c3/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 22
-#define NUM_DIGITAL_PINS 22
-#define NUM_ANALOG_INPUTS 6
-
-#define analogInputToDigitalPin(p) (((p) < NUM_ANALOG_INPUTS) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < NUM_DIGITAL_PINS) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < EXTERNAL_NUM_INTERRUPTS)
-
static const uint8_t TX = 21;
static const uint8_t RX = 20;
diff --git a/variants/heltec_esp32c3/platformio.ini b/variants/heltec_esp32c3/platformio.ini
index d6143c194..61aa94b6a 100644
--- a/variants/heltec_esp32c3/platformio.ini
+++ b/variants/heltec_esp32c3/platformio.ini
@@ -1,7 +1,6 @@
[env:heltec-ht62-esp32c3-sx1262]
extends = esp32c3_base
board = esp32-c3-devkitm-1
-board_level = extra
build_flags =
${esp32c3_base.build_flags}
-D HELTEC_HT62
diff --git a/variants/heltec_v2.1/platformio.ini b/variants/heltec_v2.1/platformio.ini
index 7d4daecc9..5aa04fc58 100644
--- a/variants/heltec_v2.1/platformio.ini
+++ b/variants/heltec_v2.1/platformio.ini
@@ -2,7 +2,6 @@
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
-board_level = extra
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_1 -I variants/heltec_v2.1
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
\ No newline at end of file
diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini
index 3289f4e68..cee1537d0 100644
--- a/variants/heltec_v2/platformio.ini
+++ b/variants/heltec_v2/platformio.ini
@@ -2,6 +2,5 @@
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32_base
board = heltec_wifi_lora_32_V2
-board_level = extra
build_flags =
${esp32_base.build_flags} -D HELTEC_V2_0 -I variants/heltec_v2
\ No newline at end of file
diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini
index 58ee0b5ba..e8f73e1ef 100644
--- a/variants/heltec_v3/platformio.ini
+++ b/variants/heltec_v3/platformio.ini
@@ -1,6 +1,7 @@
[env:heltec-v3]
extends = esp32s3_base
board = heltec_wifi_lora_32_V3
+board_check = true
# Temporary until espressif creates a release with this new target
build_flags =
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3
diff --git a/variants/heltec_v3/variant.h b/variants/heltec_v3/variant.h
index 70b122f58..2417b873d 100644
--- a/variants/heltec_v3/variant.h
+++ b/variants/heltec_v3/variant.h
@@ -16,7 +16,7 @@
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
-#define ADC_MULTIPLIER 4.9
+#define ADC_MULTIPLIER 4.9 * 1.045
#define USE_SX1262
diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h
index 66d091691..9e1d8a9a0 100644
--- a/variants/heltec_wireless_paper/pins_arduino.h
+++ b/variants/heltec_wireless_paper/pins_arduino.h
@@ -7,14 +7,6 @@
#define DISPLAY_HEIGHT 64
#define DISPLAY_WIDTH 128
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 40
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
static const uint8_t LED_BUILTIN = 35;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
diff --git a/variants/heltec_wireless_paper/platformio.ini b/variants/heltec_wireless_paper/platformio.ini
index d7aac5e22..afbbd8be9 100644
--- a/variants/heltec_wireless_paper/platformio.ini
+++ b/variants/heltec_wireless_paper/platformio.ini
@@ -12,12 +12,12 @@ build_flags =
-D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted
-D EINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates
-D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates
- -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated
+; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated
-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached.
-D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
-D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight
lib_deps =
${esp32s3_base.lib_deps}
- https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a
+ https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d
lewisxhe/PCF8563_Library@^1.0.1
upload_speed = 115200
\ No newline at end of file
diff --git a/variants/heltec_wireless_paper_v1/pins_arduino.h b/variants/heltec_wireless_paper_v1/pins_arduino.h
index 66d091691..9e1d8a9a0 100644
--- a/variants/heltec_wireless_paper_v1/pins_arduino.h
+++ b/variants/heltec_wireless_paper_v1/pins_arduino.h
@@ -7,14 +7,6 @@
#define DISPLAY_HEIGHT 64
#define DISPLAY_WIDTH 128
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 40
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
static const uint8_t LED_BUILTIN = 35;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
diff --git a/variants/heltec_wireless_tracker/pins_arduino.h b/variants/heltec_wireless_tracker/pins_arduino.h
index 5c0b529b0..1052af961 100644
--- a/variants/heltec_wireless_tracker/pins_arduino.h
+++ b/variants/heltec_wireless_tracker/pins_arduino.h
@@ -11,18 +11,10 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h
index 167345e1a..f0ee0631d 100644
--- a/variants/heltec_wireless_tracker/variant.h
+++ b/variants/heltec_wireless_tracker/variant.h
@@ -27,13 +27,17 @@
#define SCREEN_TRANSITION_FRAMERATE 3 // fps
#define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE_V05 3 // active HIGH, powers the lora antenna boost
+// pin 3 is Vext on v1.1 - HIGH enables LDO for Vext rail which goes to:
+// GPS UC6580: GPS V_DET(8), VDD_IO(7), DCDC_IN(21), pulls up RESETN(17), D_SEL(33) and BOOT_MODE(34) through 10kR
+// GPS LNA SW7125DE: VCC(4), pulls up SHDN(5) through 10kR
+// LED: VDD, LEDA (through diode)
+#define VEXT_ENABLE_V05 3 // active HIGH - powers the GPS, GPS LNA and OLED VDD/anode
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
-#define ADC_MULTIPLIER 4.9
+#define ADC_MULTIPLIER 4.9 * 1.045
#define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1
#define ADC_CTRL_ENABLED HIGH
@@ -43,6 +47,8 @@
#define GPS_TX_PIN 34
#define PIN_GPS_RESET 35
#define PIN_GPS_PPS 36
+// #define PIN_GPS_EN 3 // Uncomment to power off the GPS with triple-click on Tracker v1.1, though we'll also lose the
+// display.
#define GPS_RESET_MODE LOW
#define GPS_UC6580
diff --git a/variants/heltec_wireless_tracker_V1_0/pins_arduino.h b/variants/heltec_wireless_tracker_V1_0/pins_arduino.h
index f72c7661a..28b982012 100644
--- a/variants/heltec_wireless_tracker_V1_0/pins_arduino.h
+++ b/variants/heltec_wireless_tracker_V1_0/pins_arduino.h
@@ -11,18 +11,10 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/heltec_wireless_tracker_V1_0/variant.h b/variants/heltec_wireless_tracker_V1_0/variant.h
index 84e77a6b9..1b4751a57 100644
--- a/variants/heltec_wireless_tracker_V1_0/variant.h
+++ b/variants/heltec_wireless_tracker_V1_0/variant.h
@@ -34,7 +34,7 @@
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
-#define ADC_MULTIPLIER 4.9
+#define ADC_MULTIPLIER 4.9 * 1.045
#undef GPS_RX_PIN
#undef GPS_TX_PIN
diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h
index d3a009ade..75cea538d 100644
--- a/variants/heltec_wsl_v3/variant.h
+++ b/variants/heltec_wsl_v3/variant.h
@@ -3,8 +3,6 @@
#define LED_PIN LED
-#define HAS_SCREEN 0
-
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
#define BUTTON_PIN 0
@@ -13,7 +11,7 @@
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
-#define ADC_MULTIPLIER 4.9
+#define ADC_MULTIPLIER 4.9 * 1.045
#define USE_SX1262
diff --git a/variants/lora_relay_v1/platformio.ini b/variants/lora_relay_v1/platformio.ini
index 8660bf64a..435d256c5 100644
--- a/variants/lora_relay_v1/platformio.ini
+++ b/variants/lora_relay_v1/platformio.ini
@@ -15,7 +15,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v1
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v1>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/lora_relay_v2/platformio.ini b/variants/lora_relay_v2/platformio.ini
index cd2109f00..3598466d5 100644
--- a/variants/lora_relay_v2/platformio.ini
+++ b/variants/lora_relay_v2/platformio.ini
@@ -17,7 +17,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/lora_relay_v2
-DSPI_FREQUENCY=27000000
-DTFT_WR=ST7735_SDA
-DTFT_SCLK=ST7735_SCK
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v2>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/m5stack-stamp-c3/pins_arduino.h b/variants/m5stack-stamp-c3/pins_arduino.h
index 38ef9934e..22d2af51d 100644
--- a/variants/m5stack-stamp-c3/pins_arduino.h
+++ b/variants/m5stack-stamp-c3/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 22
-#define NUM_DIGITAL_PINS 22
-#define NUM_ANALOG_INPUTS 6
-
-#define analogInputToDigitalPin(p) (((p) < NUM_ANALOG_INPUTS) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < NUM_DIGITAL_PINS) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < EXTERNAL_NUM_INTERRUPTS)
-
static const uint8_t TX = -1; // 21;
static const uint8_t RX = -1; // 20;
diff --git a/variants/m5stack_core/pins_arduino.h b/variants/m5stack_core/pins_arduino.h
index 8f2a0041e..cf807aab4 100644
--- a/variants/m5stack_core/pins_arduino.h
+++ b/variants/m5stack_core/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 20
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
static const uint8_t TX = 1;
static const uint8_t RX = 3;
diff --git a/variants/m5stack_core/platformio.ini b/variants/m5stack_core/platformio.ini
index 84fb9f251..95f5aea9f 100644
--- a/variants/m5stack_core/platformio.ini
+++ b/variants/m5stack_core/platformio.ini
@@ -1,7 +1,6 @@
[env:m5stack-core]
extends = esp32_base
board = m5stack-core-esp32
-board_level = extra
monitor_filters = esp32_exception_decoder
build_src_filter =
${esp32_base.build_src_filter}
@@ -26,4 +25,4 @@ lib_ignore =
m5stack-core
lib_deps =
${esp32_base.lib_deps}
- lovyan03/LovyanGFX@^1.1.8
+ lovyan03/LovyanGFX@^1.1.8
\ No newline at end of file
diff --git a/variants/m5stack_coreink/pins_arduino.h b/variants/m5stack_coreink/pins_arduino.h
index 7f9a14785..c75283ab2 100644
--- a/variants/m5stack_coreink/pins_arduino.h
+++ b/variants/m5stack_coreink/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 40
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
#define TX2 -1
#define RX2 -1
diff --git a/variants/m5stack_coreink/platformio.ini b/variants/m5stack_coreink/platformio.ini
index dfb078a0a..c0c8bd30e 100644
--- a/variants/m5stack_coreink/platformio.ini
+++ b/variants/m5stack_coreink/platformio.ini
@@ -1,7 +1,7 @@
[env:m5stack-coreink]
extends = esp32_base
board = m5stack-coreink
-board_level = extra
+board_check = true
build_src_filter =
${esp32_base.build_src_filter}
build_flags =
@@ -24,4 +24,4 @@ lib_ignore =
monitor_filters = esp32_exception_decoder
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyACM0
+upload_port = /dev/ttyACM0
\ No newline at end of file
diff --git a/variants/monteops_hw1/platformio.ini b/variants/monteops_hw1/platformio.ini
index f9d260e74..551419abc 100644
--- a/variants/monteops_hw1/platformio.ini
+++ b/variants/monteops_hw1/platformio.ini
@@ -3,7 +3,7 @@
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/monteops_hw1 -D MONTEOPS_HW1
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/monteops_hw1> + + +
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/my_esp32s3_diy_eink/pins_arduino.h b/variants/my_esp32s3_diy_eink/pins_arduino.h
index 39e316624..b37a258c3 100644
--- a/variants/my_esp32s3_diy_eink/pins_arduino.h
+++ b/variants/my_esp32s3_diy_eink/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
// The default Wire will be mapped to PMU and RTC
static const uint8_t SDA = 18;
static const uint8_t SCL = 17;
diff --git a/variants/my_esp32s3_diy_oled/pins_arduino.h b/variants/my_esp32s3_diy_oled/pins_arduino.h
index 39e316624..b37a258c3 100644
--- a/variants/my_esp32s3_diy_oled/pins_arduino.h
+++ b/variants/my_esp32s3_diy_oled/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
// The default Wire will be mapped to PMU and RTC
static const uint8_t SDA = 18;
static const uint8_t SCL = 17;
diff --git a/variants/nano-g2-ultra/platformio.ini b/variants/nano-g2-ultra/platformio.ini
index 2b011e032..913b38e3f 100644
--- a/variants/nano-g2-ultra/platformio.ini
+++ b/variants/nano-g2-ultra/platformio.ini
@@ -5,7 +5,7 @@ board = nano-g2-ultra
debug_tool = jlink
build_flags = ${nrf52840_base.build_flags} -Ivariants/nano-g2-ultra -D NANO_G2_ULTRA
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nano-g2-ultra>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/pca10056-rc-clock/platformio.ini b/variants/pca10056-rc-clock/platformio.ini
index 0467b1417..f8cff4d73 100644
--- a/variants/pca10056-rc-clock/platformio.ini
+++ b/variants/pca10056-rc-clock/platformio.ini
@@ -5,5 +5,5 @@ extends = nrf52840_base
board = nrf52840_dk_modified
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/pca10056-rc-clock
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/pca10056-rc-clock>
\ No newline at end of file
diff --git a/variants/picomputer-s3/pins_arduino.h b/variants/picomputer-s3/pins_arduino.h
index c84601b1e..a3d40018c 100644
--- a/variants/picomputer-s3/pins_arduino.h
+++ b/variants/picomputer-s3/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/radiomaster_900_bandit_micro/platformio.ini b/variants/radiomaster_900_bandit_micro/platformio.ini
new file mode 100644
index 000000000..9e54f5859
--- /dev/null
+++ b/variants/radiomaster_900_bandit_micro/platformio.ini
@@ -0,0 +1,19 @@
+;
+; This uses the same code and settings as the Radio Master Bandit Nano (https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module)
+;
+; Link to the unit : https://www.radiomasterrc.com/products/bandit-micro-expresslrs-rf-module
+;
+[env:radiomaster_900_bandit_micro]
+extends = esp32_base
+board = esp32doit-devkit-v1
+build_flags =
+ ${esp32_base.build_flags}
+ -DRADIOMASTER_900_BANDIT_NANO
+ -DVTABLES_IN_FLASH=1
+ -DCONFIG_DISABLE_HAL_LOCKS=1
+ -O2
+ -Ivariants/radiomaster_900_bandit_nano
+board_build.f_cpu = 240000000L
+upload_protocol = esptool
+lib_deps =
+ ${esp32_base.lib_deps}
\ No newline at end of file
diff --git a/variants/radiomaster_900_bandit_nano/platformio.ini b/variants/radiomaster_900_bandit_nano/platformio.ini
new file mode 100644
index 000000000..0d43b8665
--- /dev/null
+++ b/variants/radiomaster_900_bandit_nano/platformio.ini
@@ -0,0 +1,14 @@
+[env:radiomaster_900_bandit_nano]
+extends = esp32_base
+board = esp32doit-devkit-v1
+build_flags =
+ ${esp32_base.build_flags}
+ -DRADIOMASTER_900_BANDIT_NANO
+ -DVTABLES_IN_FLASH=1
+ -DCONFIG_DISABLE_HAL_LOCKS=1
+ -O2
+ -Ivariants/radiomaster_900_bandit_nano
+board_build.f_cpu = 240000000L
+upload_protocol = esptool
+lib_deps =
+ ${esp32_base.lib_deps}
\ No newline at end of file
diff --git a/variants/radiomaster_900_bandit_nano/variant.h b/variants/radiomaster_900_bandit_nano/variant.h
new file mode 100644
index 000000000..bd6687733
--- /dev/null
+++ b/variants/radiomaster_900_bandit_nano/variant.h
@@ -0,0 +1,84 @@
+/*
+ Initial settings and work by https://github.com/uberhalit and re-work by https://github.com/gjelsoe
+ Unit provided by Radio Master RC
+ https://radiomasterrc.com/products/bandit-nano-expresslrs-rf-module with 0.96" OLED display
+*/
+
+/*
+ I2C SDA and SCL.
+*/
+#define I2C_SDA 14
+#define I2C_SCL 12
+
+/*
+ No GPS - but free solder pads are available inside the case.
+*/
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+
+/*
+ Pin connections from ESP32-D0WDQ6 to SX1276.
+*/
+#define LORA_DIO0 22
+#define LORA_DIO1 21
+#define LORA_SCK 18
+#define LORA_MISO 19
+#define LORA_MOSI 23
+#define LORA_CS 4
+#define LORA_RESET 5
+#define LORA_TXEN 33
+
+/*
+ This unit has a FAN built-in.
+ FAN is active at 250mW on it's ExpressLRS Firmware.
+*/
+#define RF95_FAN_EN 2
+
+/*
+ LED PIN setup.
+*/
+#define LED_PIN 15
+
+/*
+ Five way button when using ADC.
+ 2.632V, 2.177V, 1.598V, 1.055V, 0V
+
+ Possible ADC Values:
+ { UP, DOWN, LEFT, RIGHT, ENTER, IDLE }
+ 3227, 0 ,1961, 2668, 1290, 4095
+*/
+#define BUTTON_PIN 39
+#define BUTTON_NEED_PULLUP
+
+#define SCREEN_ROTATE
+
+/*
+ No External notification.
+*/
+#undef EXT_NOTIFY_OUT
+
+/*
+ Remapping PIN Names.
+ Note, that this unit uses RFO
+*/
+#define USE_RF95
+#define USE_RF95_RFO
+#define RF95_CS LORA_CS
+#define RF95_DIO1 LORA_DIO1
+#define RF95_TXEN LORA_TXEN
+#define RF95_RESET LORA_RESET
+#define RF95_MAX_POWER 12
+
+/*
+ This module has Skyworks SKY66122 controlled by dacWrite
+ power rangeing from 100mW to 1000mW.
+
+ Mapping of PA_LEVEL to Power output: GPIO26/dacWrite
+ 168 -> 100mW -> 2.11v
+ 148 -> 250mW -> 1.87v
+ 128 -> 500mW -> 1.63v
+ 90 -> 1000mW -> 1.16v
+*/
+#define RF95_PA_EN 26
+#define RF95_PA_DAC_EN
+#define RF95_PA_LEVEL 90
\ No newline at end of file
diff --git a/variants/rak10701/platformio.ini b/variants/rak10701/platformio.ini
index 37f785e84..4c9bf3b20 100644
--- a/variants/rak10701/platformio.ini
+++ b/variants/rak10701/platformio.ini
@@ -1,9 +1,10 @@
; The very slick RAK wireless RAK10701 Field Tester device. Note you will have to flash to Arduino bootloader to use this firmware. Be aware touch is not currently working.
[env:rak10701]
extends = nrf52840_base
+board_level = extra
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak10701 -D RAK_4631
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
@@ -16,6 +17,8 @@ lib_deps =
https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
bodmer/TFT_eSPI
+ beegee-tokyo/RAKwireless RAK12034@^1.0.0
+ beegee-tokyo/RAK14014-FT6336U @ 1.0.1
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/rak10701/variant.cpp b/variants/rak10701/variant.cpp
index 2b4bd39a6..5a3587982 100644
--- a/variants/rak10701/variant.cpp
+++ b/variants/rak10701/variant.cpp
@@ -38,4 +38,8 @@ void initVariant()
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
}
\ No newline at end of file
diff --git a/variants/rak10701/variant.h b/variants/rak10701/variant.h
index 076504c16..c263796ee 100644
--- a/variants/rak10701/variant.h
+++ b/variants/rak10701/variant.h
@@ -307,10 +307,10 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
#define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5
-#define HAS_TOUCHSCREEN 0
-#define SCREEN_TOUCH_INT 10 // From tp.h on the tracker open source code.
-#define TOUCH_I2C_PORT 0
-#define TOUCH_SLAVE_ADDRESS 0x5D // GT911
+#define HAS_TOUCHSCREEN 1
+#define SCREEN_TOUCH_INT WB_IO6
+
+#define CANNED_MESSAGE_MODULE_ENABLE 1
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
diff --git a/variants/rak11200/pins_arduino.h b/variants/rak11200/pins_arduino.h
index 2dfe02614..f383d54a7 100644
--- a/variants/rak11200/pins_arduino.h
+++ b/variants/rak11200/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 40
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
#define LED_GREEN 12
#define LED_BLUE 2
diff --git a/variants/rak11200/platformio.ini b/variants/rak11200/platformio.ini
index f653adeb2..eddc3458e 100644
--- a/variants/rak11200/platformio.ini
+++ b/variants/rak11200/platformio.ini
@@ -1,7 +1,7 @@
[env:rak11200]
extends = esp32_base
-board_level = extra
board = wiscore_rak11200
+board_check = true
build_flags =
${esp32_base.build_flags} -D RAK_11200 -I variants/rak11200
-upload_speed = 115200
+upload_speed = 115200
\ No newline at end of file
diff --git a/variants/rak11200/variant.h b/variants/rak11200/variant.h
index 3399594e5..3cd601254 100644
--- a/variants/rak11200/variant.h
+++ b/variants/rak11200/variant.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 40
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
#define LED_GREEN 12
#define LED_BLUE 2
diff --git a/variants/rak11310/platformio.ini b/variants/rak11310/platformio.ini
index 6495278bf..e1bd2b1b0 100644
--- a/variants/rak11310/platformio.ini
+++ b/variants/rak11310/platformio.ini
@@ -8,7 +8,7 @@ build_flags = ${rp2040_base.build_flags}
-DRAK11310
-Ivariants/rak11310
-DDEBUG_RP2040_PORT=Serial
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini
index b1bc2d9b5..4870d4b68 100644
--- a/variants/rak4631/platformio.ini
+++ b/variants/rak4631/platformio.ini
@@ -2,8 +2,9 @@
[env:rak4631]
extends = nrf52840_base
board = wiscore_rak4631
+board_check = true
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
@@ -15,6 +16,7 @@ lib_deps =
melopero/Melopero RV3028@^1.1.0
https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
+ https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
-;upload_protocol = jlink
+;upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/rak4631/variant.cpp b/variants/rak4631/variant.cpp
index 75cca1dc3..e84b60b3b 100644
--- a/variants/rak4631/variant.cpp
+++ b/variants/rak4631/variant.cpp
@@ -38,4 +38,8 @@ void initVariant()
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
}
diff --git a/variants/rak4631_epaper/platformio.ini b/variants/rak4631_epaper/platformio.ini
index ced732d94..08342dcf7 100644
--- a/variants/rak4631_epaper/platformio.ini
+++ b/variants/rak4631_epaper/platformio.ini
@@ -3,7 +3,7 @@
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
@@ -13,6 +13,7 @@ lib_deps =
zinggjm/GxEPD2@^1.4.9
melopero/Melopero RV3028@^1.1.0
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
+ beegee-tokyo/RAKwireless RAK12034@^1.0.0
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/rak4631_epaper/variant.cpp b/variants/rak4631_epaper/variant.cpp
index 75cca1dc3..e84b60b3b 100644
--- a/variants/rak4631_epaper/variant.cpp
+++ b/variants/rak4631_epaper/variant.cpp
@@ -38,4 +38,8 @@ void initVariant()
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
}
diff --git a/variants/rak4631_epaper_onrxtx/platformio.ini b/variants/rak4631_epaper_onrxtx/platformio.ini
index c4a13ec82..f7035a1b1 100644
--- a/variants/rak4631_epaper_onrxtx/platformio.ini
+++ b/variants/rak4631_epaper_onrxtx/platformio.ini
@@ -4,7 +4,7 @@ board_level = extra
extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-D PIN_EINK_EN=34
-D EINK_DISPLAY_MODEL=GxEPD2_213_BN
-D EINK_WIDTH=250
@@ -15,7 +15,8 @@ lib_deps =
zinggjm/GxEPD2@^1.5.1
melopero/Melopero RV3028@^1.1.0
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
+ beegee-tokyo/RAKwireless RAK12034@^1.0.0
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
-;upload_port = /dev/ttyACM3
+;upload_port = /dev/ttyACM3
\ No newline at end of file
diff --git a/variants/rak4631_epaper_onrxtx/variant.cpp b/variants/rak4631_epaper_onrxtx/variant.cpp
index 75cca1dc3..e84b60b3b 100644
--- a/variants/rak4631_epaper_onrxtx/variant.cpp
+++ b/variants/rak4631_epaper_onrxtx/variant.cpp
@@ -38,4 +38,8 @@ void initVariant()
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
}
diff --git a/variants/rp2040-lora/platformio.ini b/variants/rp2040-lora/platformio.ini
index a1d6bea9d..8499f6f3c 100644
--- a/variants/rp2040-lora/platformio.ini
+++ b/variants/rp2040-lora/platformio.ini
@@ -9,7 +9,7 @@ build_flags = ${rp2040_base.build_flags}
-Ivariants/rp2040-lora
-DDEBUG_RP2040_PORT=Serial
-DHW_SPI1_DEVICE
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
diff --git a/variants/rpipico-slowclock/platformio.ini b/variants/rpipico-slowclock/platformio.ini
index eec76ca0f..c21994249 100644
--- a/variants/rpipico-slowclock/platformio.ini
+++ b/variants/rpipico-slowclock/platformio.ini
@@ -1,6 +1,7 @@
[env:pico_slowclock]
extends = rp2040_base
board = rpipico
+board_level = extra
upload_protocol = jlink
# debug settings for external openocd with RP2040 support (custom build)
debug_tool = custom
@@ -18,11 +19,11 @@ build_flags = ${rp2040_base.build_flags}
-Ivariants/rpipico-slowclock
-DDEBUG_RP2040_PORT=Serial2
-DHW_SPI1_DEVICE
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
-g
-DNO_USB
lib_deps =
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
-g
- -DNO_USB
+ -DNO_USB
\ No newline at end of file
diff --git a/variants/rpipico/platformio.ini b/variants/rpipico/platformio.ini
index 9537694ec..e4b9e479f 100644
--- a/variants/rpipico/platformio.ini
+++ b/variants/rpipico/platformio.ini
@@ -9,7 +9,7 @@ build_flags = ${rp2040_base.build_flags}
-Ivariants/rpipico
-DDEBUG_RP2040_PORT=Serial
-DHW_SPI1_DEVICE
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
diff --git a/variants/rpipico/variant.h b/variants/rpipico/variant.h
index ad6d0b211..7efaeaf7a 100644
--- a/variants/rpipico/variant.h
+++ b/variants/rpipico/variant.h
@@ -4,8 +4,6 @@
#define ARDUINO_ARCH_AVR
-#define USE_SH1106 1
-
// default I2C pins:
// SDA = 4
// SCL = 5
diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini
index 29b5c8bcb..2600b4b38 100644
--- a/variants/rpipicow/platformio.ini
+++ b/variants/rpipicow/platformio.ini
@@ -1,7 +1,6 @@
[env:picow]
extends = rp2040_base
board = rpipicow
-board_level = extra
upload_protocol = picotool
# add our variants files to the include and src paths
@@ -9,7 +8,7 @@ build_flags = ${rp2040_base.build_flags}
-DRPI_PICO
-Ivariants/rpipicow
-DHW_SPI1_DEVICE
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
-fexceptions # for exception handling in MQTT
build_src_filter = ${rp2040_base.build_src_filter} +
lib_deps =
diff --git a/variants/rpipicow/variant.h b/variants/rpipicow/variant.h
index a17f05ee0..24da8f932 100644
--- a/variants/rpipicow/variant.h
+++ b/variants/rpipicow/variant.h
@@ -8,8 +8,6 @@
#define HAS_WIFI 1
#endif
-#define USE_SH1106 1
-
// default I2C pins:
// SDA = 4
// SCL = 5
diff --git a/variants/senselora_rp2040/platformio.ini b/variants/senselora_rp2040/platformio.ini
index 3b3253ee8..c719bd261 100644
--- a/variants/senselora_rp2040/platformio.ini
+++ b/variants/senselora_rp2040/platformio.ini
@@ -8,6 +8,6 @@ build_flags = ${rp2040_base.build_flags}
-DSENSELORA_RP2040
-Ivariants/senselora_rp2040
-DDEBUG_RP2040_PORT=Serial
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
\ No newline at end of file
diff --git a/variants/station-g2/pins_arduino.h b/variants/station-g2/pins_arduino.h
index 98cbd46d3..6a803008d 100755
--- a/variants/station-g2/pins_arduino.h
+++ b/variants/station-g2/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) <= 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
// GPIO48 Reference: https://github.com/espressif/arduino-esp32/pull/8600
// The default Wire will be mapped to Screen and Sensors
diff --git a/variants/station-g2/platformio.ini b/variants/station-g2/platformio.ini
index b39136684..b674c8bae 100755
--- a/variants/station-g2/platformio.ini
+++ b/variants/station-g2/platformio.ini
@@ -1,13 +1,16 @@
[env:station-g2]
extends = esp32s3_base
board = station-g2
+board_check = true
board_build.mcu = esp32s3
upload_protocol = esptool
;upload_port = /dev/ttyACM0
upload_speed = 921600
lib_deps =
${esp32s3_base.lib_deps}
-build_unflags = -DARDUINO_USB_MODE=1
+build_unflags =
+ ${esp32s3_base.build_unflags}
+ -DARDUINO_USB_MODE=1
build_flags =
${esp32s3_base.build_flags} -D STATION_G2 -I variants/station-g2
-DBOARD_HAS_PSRAM
diff --git a/variants/station-g2/variant.h b/variants/station-g2/variant.h
index f781ceb24..8f0b4b220 100755
--- a/variants/station-g2/variant.h
+++ b/variants/station-g2/variant.h
@@ -40,6 +40,7 @@ Board Information: https://wiki.uniteng.com/en/meshtastic/station-g2
#define SX126X_MAX_POWER 19
#endif
+/*
#define BATTERY_PIN 4 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
#define ADC_MULTIPLIER 4
@@ -50,3 +51,4 @@ Board Information: https://wiki.uniteng.com/en/meshtastic/station-g2
#define BAT_NOBATVOLT 4460
#define CELL_TYPE_LION // same curve for liion/lipo
#define NUM_CELLS 2
+*/
diff --git a/variants/t-deck/pins_arduino.h b/variants/t-deck/pins_arduino.h
index 0150935ed..cb429d776 100644
--- a/variants/t-deck/pins_arduino.h
+++ b/variants/t-deck/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < NUM_ANALOG_INPUTS) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < NUM_DIGITAL_PINS) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < EXTERNAL_NUM_INTERRUPTS)
-
// static const uint8_t LED_BUILTIN = -1;
static const uint8_t TX = 43;
diff --git a/variants/t-deck/platformio.ini b/variants/t-deck/platformio.ini
index 593fdae5e..a63ff57a7 100644
--- a/variants/t-deck/platformio.ini
+++ b/variants/t-deck/platformio.ini
@@ -2,6 +2,7 @@
[env:t-deck]
extends = esp32s3_base
board = t-deck
+board_check = true
upload_protocol = esptool
#upload_port = COM29
diff --git a/variants/t-echo/platformio.ini b/variants/t-echo/platformio.ini
index 5bd56598b..5b295c96a 100644
--- a/variants/t-echo/platformio.ini
+++ b/variants/t-echo/platformio.ini
@@ -2,12 +2,13 @@
[env:t-echo]
extends = nrf52840_base
board = t-echo
+board_check = true
debug_tool = jlink
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
-DGPS_POWER_TOGGLE
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_154_D67
-DEINK_WIDTH=200
-DEINK_HEIGHT=200
@@ -23,4 +24,4 @@ lib_deps =
${nrf52840_base.lib_deps}
https://github.com/meshtastic/GxEPD2#55f618961db45a23eff0233546430f1e5a80f63a
lewisxhe/PCF8563_Library@^1.0.1
-;upload_protocol = fs
+;upload_protocol = fs
\ No newline at end of file
diff --git a/variants/t-watch-s3/pins_arduino.h b/variants/t-watch-s3/pins_arduino.h
index d3dde6856..35f0e933e 100644
--- a/variants/t-watch-s3/pins_arduino.h
+++ b/variants/t-watch-s3/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < NUM_ANALOG_INPUTS) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < NUM_DIGITAL_PINS) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < EXTERNAL_NUM_INTERRUPTS)
-
// static const uint8_t LED_BUILTIN = -1;
// static const uint8_t TX = 43;
diff --git a/variants/t-watch-s3/platformio.ini b/variants/t-watch-s3/platformio.ini
index 5d5904b30..1f5fc278b 100644
--- a/variants/t-watch-s3/platformio.ini
+++ b/variants/t-watch-s3/platformio.ini
@@ -2,6 +2,7 @@
[env:t-watch-s3]
extends = esp32s3_base
board = t-watch-s3
+board_check = true
upload_protocol = esptool
build_flags = ${esp32_base.build_flags}
diff --git a/variants/tbeam-s3-core/platformio.ini b/variants/tbeam-s3-core/platformio.ini
index 99d315a69..e50d506b9 100644
--- a/variants/tbeam-s3-core/platformio.ini
+++ b/variants/tbeam-s3-core/platformio.ini
@@ -2,6 +2,7 @@
[env:tbeam-s3-core]
extends = esp32s3_base
board = tbeam-s3-core
+board_check = true
lib_deps =
${esp32s3_base.lib_deps}
diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini
index 76a03d126..85e66c2dd 100644
--- a/variants/tbeam/platformio.ini
+++ b/variants/tbeam/platformio.ini
@@ -2,9 +2,10 @@
[env:tbeam]
extends = esp32_base
board = ttgo-t-beam
+board_check = true
lib_deps =
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam
-DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely.
-upload_speed = 921600
+upload_speed = 921600
\ No newline at end of file
diff --git a/variants/tbeam_v07/platformio.ini b/variants/tbeam_v07/platformio.ini
index 5428b0e2a..105d65912 100644
--- a/variants/tbeam_v07/platformio.ini
+++ b/variants/tbeam_v07/platformio.ini
@@ -2,6 +2,5 @@
[env:tbeam0_7]
extends = esp32_base
board = ttgo-t-beam
-board_level = extra
build_flags =
${esp32_base.build_flags} -D TBEAM_V07 -I variants/tbeam_v07
\ No newline at end of file
diff --git a/variants/tlora_t3s3_v1/pins_arduino.h b/variants/tlora_t3s3_v1/pins_arduino.h
index 627dad19d..4ced1b446 100644
--- a/variants/tlora_t3s3_v1/pins_arduino.h
+++ b/variants/tlora_t3s3_v1/pins_arduino.h
@@ -6,14 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
// The default Wire will be mapped to PMU and RTC
static const uint8_t SDA = 18;
static const uint8_t SCL = 17;
diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini
index c848177ee..e4cc1d762 100644
--- a/variants/tlora_t3s3_v1/platformio.ini
+++ b/variants/tlora_t3s3_v1/platformio.ini
@@ -1,6 +1,7 @@
[env:tlora-t3s3-v1]
extends = esp32s3_base
board = tlora-t3s3-v1
+board_check = true
upload_protocol = esp-builtin
build_flags =
diff --git a/variants/tlora_v1_3/platformio.ini b/variants/tlora_v1_3/platformio.ini
index 739f76268..9d9f41a7c 100644
--- a/variants/tlora_v1_3/platformio.ini
+++ b/variants/tlora_v1_3/platformio.ini
@@ -1,6 +1,5 @@
[env:tlora_v1_3]
extends = esp32_base
-board_level = extra
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V1_3 -I variants/tlora_v1_3
\ No newline at end of file
diff --git a/variants/tlora_v2/platformio.ini b/variants/tlora_v2/platformio.ini
index 25ae3a360..8710068af 100644
--- a/variants/tlora_v2/platformio.ini
+++ b/variants/tlora_v2/platformio.ini
@@ -1,6 +1,5 @@
[env:tlora-v2]
extends = esp32_base
board = ttgo-lora32-v1
-board_level = extra
build_flags =
${esp32_base.build_flags} -D TLORA_V2 -I variants/tlora_v2
\ No newline at end of file
diff --git a/variants/tlora_v2_1_16/platformio.ini b/variants/tlora_v2_1_16/platformio.ini
index 167f6c37c..351f71676 100644
--- a/variants/tlora_v2_1_16/platformio.ini
+++ b/variants/tlora_v2_1_16/platformio.ini
@@ -1,6 +1,7 @@
[env:tlora-v2-1-1_6]
extends = esp32_base
board = ttgo-lora32-v21
+board_check = true
build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/tlora_v2_1_16
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
\ No newline at end of file
diff --git a/variants/trackerd/variant.h b/variants/trackerd/variant.h
index bd8017d8c..c4dfb9e93 100644
--- a/variants/trackerd/variant.h
+++ b/variants/trackerd/variant.h
@@ -20,16 +20,34 @@
#define LORA_DIO1 33
#define LORA_DIO2 32 // Not really used
-#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+#undef BAT_MEASURE_ADC_UNIT
+#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+#define ADC_MULTIPLIER 1.34 // tracked resistance divider is 100k+470k, so it can not fillfull well on esp32 adc
+#define ADC_CHANNEL ADC1_GPIO35_CHANNEL
+#define ADC_ATTENUATION ADC_ATTEN_DB_12 // lower dB for high resistance voltage divider
-// Battery
-// The battery sense is hooked to pin A0 (4)
-// it is defined in the anlaolgue pin section of this file
-// and has 12 bit resolution
-// #define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity.
-#define BATTERY_SENSE_RESOLUTION_BITS 12
-#define BATTERY_SENSE_RESOLUTION 4096.0
-#undef AREF_VOLTAGE
-#define AREF_VOLTAGE 3.0
-#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
-#define ADC_MULTIPLIER (2.0F)
\ No newline at end of file
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+#undef PIN_GPS_PPS
+
+#define PIN_GPS_EN 12
+#define GPS_EN_ACTIVE 1
+
+#define GPS_TX_PIN 10
+#define GPS_RX_PIN 9
+
+#define PIN_GPS_RESET 25
+// #define PIN_GPS_REINIT 25
+#define GPS_RESET_MODE 1
+
+#define GPS_L76K
+
+#undef PIN_LED1
+#undef PIN_LED2
+#undef PIN_LED3
+
+#define PIN_LED1 13
+#define PIN_LED2 15
+#define PIN_LED3 2
+
+#define ledOff(pin) pinMode(pin, INPUT)
\ No newline at end of file
diff --git a/variants/tracksenger/internal/pins_arduino.h b/variants/tracksenger/internal/pins_arduino.h
index 5c0b529b0..1052af961 100644
--- a/variants/tracksenger/internal/pins_arduino.h
+++ b/variants/tracksenger/internal/pins_arduino.h
@@ -11,18 +11,10 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/tracksenger/lcd/pins_arduino.h b/variants/tracksenger/lcd/pins_arduino.h
index 5c0b529b0..1052af961 100644
--- a/variants/tracksenger/lcd/pins_arduino.h
+++ b/variants/tracksenger/lcd/pins_arduino.h
@@ -11,18 +11,10 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/tracksenger/oled/pins_arduino.h b/variants/tracksenger/oled/pins_arduino.h
index 5c0b529b0..1052af961 100644
--- a/variants/tracksenger/oled/pins_arduino.h
+++ b/variants/tracksenger/oled/pins_arduino.h
@@ -11,18 +11,10 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
-#define EXTERNAL_NUM_INTERRUPTS 46
-#define NUM_DIGITAL_PINS 48
-#define NUM_ANALOG_INPUTS 20
-
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
-#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
-#define digitalPinToInterrupt(p) (((p) < 48) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 46)
-
static const uint8_t TX = 43;
static const uint8_t RX = 44;
diff --git a/variants/unphone/platformio.ini b/variants/unphone/platformio.ini
index e4a92fe4c..dbfa0599d 100644
--- a/variants/unphone/platformio.ini
+++ b/variants/unphone/platformio.ini
@@ -3,13 +3,13 @@
[env:unphone]
extends = esp32s3_base
-board_level = extra
board = unphone9
upload_speed = 921600
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
build_unflags =
+ ${esp32s3_base.build_unflags}
-D ARDUINO_USB_MODE
build_flags = ${esp32_base.build_flags}
diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini
new file mode 100644
index 000000000..8b1433dd1
--- /dev/null
+++ b/variants/wio-sdk-wm1110/platformio.ini
@@ -0,0 +1,15 @@
+; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921
+[env:wio-sdk-wm1110]
+extends = nrf52840_base
+board = wio-sdk-wm1110
+board_level = extra
+; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
+build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
+ -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+debug_tool = jlink
+; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
+upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/wio-sdk-wm1110/variant.cpp b/variants/wio-sdk-wm1110/variant.cpp
new file mode 100644
index 000000000..5a3587982
--- /dev/null
+++ b/variants/wio-sdk-wm1110/variant.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.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 "variant.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+ // P1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+
+void initVariant()
+{
+ // LED1 & LED2
+ pinMode(PIN_LED1, OUTPUT);
+ ledOff(PIN_LED1);
+
+ pinMode(PIN_LED2, OUTPUT);
+ ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
+}
\ No newline at end of file
diff --git a/variants/wio-sdk-wm1110/variant.h b/variants/wio-sdk-wm1110/variant.h
new file mode 100644
index 000000000..f027b469f
--- /dev/null
+++ b/variants/wio-sdk-wm1110/variant.h
@@ -0,0 +1,111 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.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
+*/
+
+#ifndef _VARIANT_WIO_SDK_WM1110_
+#define _VARIANT_WIO_SDK_WM1110_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+#define USE_LFXO // Board uses 32khz crystal for LF
+// define USE_LFRC // Board uses RC for LF
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (6)
+#define NUM_ANALOG_OUTPUTS (0)
+
+#define WIRE_INTERFACES_COUNT 1
+
+#define PIN_3V3_EN (0 + 7) // P0.7, Power to Sensors
+
+#define PIN_WIRE_SDA (0 + 27) // P0.27
+#define PIN_WIRE_SCL (0 + 26) // P0.26
+
+#define PIN_LED1 (0 + 13) // P0.13
+#define PIN_LED2 (0 + 14) // P0.14
+
+#define LED_BUILTIN PIN_LED1
+
+#define LED_GREEN PIN_LED1
+#define LED_BLUE PIN_LED2 // Actually red
+
+#define LED_STATE_ON 1 // State when LED is lit
+
+#define BUTTON_PIN (0 + 23) // P0.23
+
+/*
+ * Serial interfaces
+ */
+#define PIN_SERIAL1_RX (0 + 22) // P0.22
+#define PIN_SERIAL1_TX (0 + 24) // P0.24
+
+#define PIN_SERIAL2_RX (0 + 6) // P0.06
+#define PIN_SERIAL2_TX (0 + 8) // P0.08
+
+#define SPI_INTERFACES_COUNT 1
+
+#define PIN_SPI_MISO (32 + 15) // P1.15 47
+#define PIN_SPI_MOSI (32 + 14) // P1.14 46
+#define PIN_SPI_SCK (32 + 13) // P1.13 45
+#define PIN_SPI_NSS (32 + 12) // P1.12 44
+
+#define LORA_RESET (32 + 10) // P1.10 42 // RST
+#define LORA_DIO1 (32 + 8) // P1.08 40 // IRQ
+#define LORA_DIO2 (32 + 11) // P1.11 43 // BUSY
+#define LORA_SCK PIN_SPI_SCK
+#define LORA_MISO PIN_SPI_MISO
+#define LORA_MOSI PIN_SPI_MOSI
+#define LORA_CS PIN_SPI_NSS
+
+// supported modules list
+#define USE_LR1110
+
+#define LR1110_IRQ_PIN LORA_DIO1
+#define LR1110_NRESER_PIN LORA_RESET
+#define LR1110_BUSY_PIN LORA_DIO2
+#define LR1110_SPI_NSS_PIN LORA_CS
+#define LR1110_SPI_SCK_PIN LORA_SCK
+#define LR1110_SPI_MOSI_PIN LORA_MOSI
+#define LR1110_SPI_MISO_PIN LORA_MISO
+
+#define LR11X0_DIO3_TCXO_VOLTAGE 1.6
+#define LR11X0_DIO_AS_RF_SWITCH
+
+#define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#endif // _VARIANT_WIO_SDK_WM1110_
diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini
new file mode 100644
index 000000000..cba1b8741
--- /dev/null
+++ b/variants/wio-tracker-wm1110/platformio.ini
@@ -0,0 +1,14 @@
+; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921
+[env:wio-tracker-wm1110]
+extends = nrf52840_base
+board = wio-tracker-wm1110
+; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
+build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -DWIO_WM1110
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
+ -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
+build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110>
+lib_deps =
+ ${nrf52840_base.lib_deps}
+debug_tool = jlink
+; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
+;upload_protocol = jlink
\ No newline at end of file
diff --git a/variants/wio-tracker-wm1110/variant.cpp b/variants/wio-tracker-wm1110/variant.cpp
new file mode 100644
index 000000000..5a3587982
--- /dev/null
+++ b/variants/wio-tracker-wm1110/variant.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.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 "variant.h"
+#include "nrf.h"
+#include "wiring_constants.h"
+#include "wiring_digital.h"
+
+const uint32_t g_ADigitalPinMap[] = {
+ // P0
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+
+ // P1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
+
+void initVariant()
+{
+ // LED1 & LED2
+ pinMode(PIN_LED1, OUTPUT);
+ ledOff(PIN_LED1);
+
+ pinMode(PIN_LED2, OUTPUT);
+ ledOff(PIN_LED2);
+
+ // 3V3 Power Rail
+ pinMode(PIN_3V3_EN, OUTPUT);
+ digitalWrite(PIN_3V3_EN, HIGH);
+}
\ No newline at end of file
diff --git a/variants/wio-tracker-wm1110/variant.h b/variants/wio-tracker-wm1110/variant.h
new file mode 100644
index 000000000..e929332e6
--- /dev/null
+++ b/variants/wio-tracker-wm1110/variant.h
@@ -0,0 +1,111 @@
+/*
+ Copyright (c) 2014-2015 Arduino LLC. All right reserved.
+ Copyright (c) 2016 Sandeep Mistry All right reserved.
+ Copyright (c) 2018, Adafruit Industries (adafruit.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
+*/
+
+#ifndef _VARIANT_WIO_TRACKER_WM1110_
+#define _VARIANT_WIO_TRACKER_WM1110_
+
+/** Master clock frequency */
+#define VARIANT_MCK (64000000ul)
+
+#define USE_LFXO // Board uses 32khz crystal for LF
+// define USE_LFRC // Board uses RC for LF
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+
+#include "WVariant.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Number of pins defined in PinDescription array
+#define PINS_COUNT (48)
+#define NUM_DIGITAL_PINS (48)
+#define NUM_ANALOG_INPUTS (6)
+#define NUM_ANALOG_OUTPUTS (0)
+
+#define WIRE_INTERFACES_COUNT 1
+
+#define PIN_3V3_EN (32 + 1) // P1.01, Power to Sensors
+
+#define PIN_WIRE_SDA (0 + 5) // P0.05
+#define PIN_WIRE_SCL (0 + 4) // P0.04
+
+#define PIN_LED1 (0 + 6) // P0.06
+#define PIN_LED2 (PINS_COUNT) // P0.14
+
+#define LED_BUILTIN PIN_LED1
+
+#define LED_GREEN PIN_LED1
+#define LED_BLUE PIN_LED2
+
+#define LED_STATE_ON 0
+
+#define BUTTON_PIN (32 + 2) // P1.02
+
+/*
+ * Serial interfaces
+ */
+#define PIN_SERIAL1_RX (0 + 24) // P0.24
+#define PIN_SERIAL1_TX (0 + 25) // P0.25
+
+#define PIN_SERIAL2_RX (0 + 6) // P0.06
+#define PIN_SERIAL2_TX (0 + 8) // P0.08
+
+#define SPI_INTERFACES_COUNT 1
+
+#define PIN_SPI_MISO (32 + 15) // P1.15 47
+#define PIN_SPI_MOSI (32 + 14) // P1.14 46
+#define PIN_SPI_SCK (32 + 13) // P1.13 45
+#define PIN_SPI_NSS (32 + 12) // P1.12 44
+
+#define LORA_RESET (0 + 18) // P0.18 18 // RST
+#define LORA_DIO1 (0 + 2) // P0.02 2 // IRQ
+#define LORA_DIO2 (32 + 11) // P1.11 43 // BUSY
+#define LORA_SCK PIN_SPI_SCK
+#define LORA_MISO PIN_SPI_MISO
+#define LORA_MOSI PIN_SPI_MOSI
+#define LORA_CS PIN_SPI_NSS
+
+// supported modules list
+#define USE_LR1110
+
+#define LR1110_IRQ_PIN LORA_DIO1
+#define LR1110_NRESER_PIN LORA_RESET
+#define LR1110_BUSY_PIN LORA_DIO2
+#define LR1110_SPI_NSS_PIN LORA_CS
+#define LR1110_SPI_SCK_PIN LORA_SCK
+#define LR1110_SPI_MOSI_PIN LORA_MOSI
+#define LR1110_SPI_MISO_PIN LORA_MISO
+
+#define LR11X0_DIO3_TCXO_VOLTAGE 1.6
+#define LR11X0_DIO_AS_RF_SWITCH
+
+#define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * Arduino objects - C++ only
+ *----------------------------------------------------------------------------*/
+
+#endif // _VARIANT_WIO_TRACKER_WM1110_
diff --git a/variants/wiphone/pins_arduino.h b/variants/wiphone/pins_arduino.h
index bca9c1173..3759219d1 100644
--- a/variants/wiphone/pins_arduino.h
+++ b/variants/wiphone/pins_arduino.h
@@ -3,14 +3,6 @@
#include
-#define EXTERNAL_NUM_INTERRUPTS 16
-#define NUM_DIGITAL_PINS 20
-#define NUM_ANALOG_INPUTS 16
-
-#define analogInputToDigitalPin(p) (((p) < 20) ? (esp32_adc2gpio[(p)]) : -1)
-#define digitalPinToInterrupt(p) (((p) < 40) ? (p) : -1)
-#define digitalPinHasPWM(p) (p < 34)
-
static const uint8_t TX = 1;
static const uint8_t RX = 3;
diff --git a/variants/wiphone/platformio.ini b/variants/wiphone/platformio.ini
index 10c0de55e..0218f8930 100644
--- a/variants/wiphone/platformio.ini
+++ b/variants/wiphone/platformio.ini
@@ -1,6 +1,7 @@
[env:wiphone]
extends = esp32_base
board = wiphone
+board_level = extra
monitor_filters = esp32_exception_decoder
board_build.partitions = default_16MB.csv
build_flags =
@@ -9,5 +10,4 @@ lib_deps =
${esp32_base.lib_deps}
lovyan03/LovyanGFX@^1.1.8
sparkfun/SX1509 IO Expander@^3.0.5
- pololu/APA102@^3.0.0
-
\ No newline at end of file
+ pololu/APA102@^3.0.0
\ No newline at end of file
diff --git a/variants/xiao_ble/nrf52840_s140_v7.ld b/variants/xiao_ble/nrf52840_s140_v7.ld
new file mode 100644
index 000000000..6aaeb4034
--- /dev/null
+++ b/variants/xiao_ble/nrf52840_s140_v7.ld
@@ -0,0 +1,38 @@
+/* Linker script to configure memory regions. */
+
+SEARCH_DIR(.)
+GROUP(-lgcc -lc -lnosys)
+
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000
+
+ /* SRAM required by Softdevice depend on
+ * - Attribute Table Size (Number of Services and Characteristics)
+ * - Vendor UUID count
+ * - Max ATT MTU
+ * - Concurrent connection peripheral + central + secure links
+ * - Event Len, HVN queue, Write CMD queue
+ */
+ RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000
+}
+
+SECTIONS
+{
+ . = ALIGN(4);
+ .svc_data :
+ {
+ PROVIDE(__start_svc_data = .);
+ KEEP(*(.svc_data))
+ PROVIDE(__stop_svc_data = .);
+ } > RAM
+
+ .fs_data :
+ {
+ PROVIDE(__start_fs_data = .);
+ KEEP(*(.fs_data))
+ PROVIDE(__stop_fs_data = .);
+ } > RAM
+} INSERT AFTER .data;
+
+INCLUDE "nrf52_common.ld"
diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini
index c52e2c644..60e7cecbd 100644
--- a/variants/xiao_ble/platformio.ini
+++ b/variants/xiao_ble/platformio.ini
@@ -3,8 +3,9 @@
extends = nrf52840_base
board = xiao_ble_sense
board_level = extra
-build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Dxiao_ble -D EBYTE_E22
- -L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
+build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -D EBYTE_E22 -DPRIVATE_HW
+ -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
+board_build.ldscript = variants/xiao_ble/nrf52840_s140_v7.ld
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble>
lib_deps =
${nrf52840_base.lib_deps}
diff --git a/variants/xiao_ble/softdevice/ble.h b/variants/xiao_ble/softdevice/ble.h
new file mode 100644
index 000000000..177b436ad
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble.h
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_COMMON BLE SoftDevice Common
+ @{
+ @defgroup ble_api Events, type definitions and API calls
+ @{
+
+ @brief Module independent events, type definitions and API calls for the BLE SoftDevice.
+
+ */
+
+#ifndef BLE_H__
+#define BLE_H__
+
+#include "ble_err.h"
+#include "ble_gap.h"
+#include "ble_gatt.h"
+#include "ble_gattc.h"
+#include "ble_gatts.h"
+#include "ble_l2cap.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations
+ * @{ */
+
+/**
+ * @brief Common API SVC numbers.
+ */
+enum BLE_COMMON_SVCS {
+ SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */
+ SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */
+ SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */
+ SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */
+ SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */
+ SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */
+ SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */
+ SD_BLE_OPT_SET, /**< Set a BLE option. */
+ SD_BLE_OPT_GET, /**< Get a BLE option. */
+ SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */
+ SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */
+};
+
+/**
+ * @brief BLE Module Independent Event IDs.
+ */
+enum BLE_COMMON_EVTS {
+ BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t
+ \n Reply with @ref sd_ble_user_mem_reply. */
+ BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */
+};
+
+/**@brief BLE Connection Configuration IDs.
+ *
+ * IDs that uniquely identify a connection configuration.
+ */
+enum BLE_CONN_CFGS {
+ BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */
+ BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */
+ BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */
+ BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */
+ BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */
+};
+
+/**@brief BLE Common Configuration IDs.
+ *
+ * IDs that uniquely identify a common configuration.
+ */
+enum BLE_COMMON_CFGS {
+ BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */
+};
+
+/**@brief Common Option IDs.
+ * IDs that uniquely identify a common option.
+ */
+enum BLE_COMMON_OPTS {
+ BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */
+ BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */
+ BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */
+};
+
+/** @} */
+
+/** @addtogroup BLE_COMMON_DEFINES Defines
+ * @{ */
+
+/** @brief Required pointer alignment for BLE Events.
+ */
+#define BLE_EVT_PTR_ALIGNMENT 4
+
+/** @brief Leaves the maximum of the two arguments.
+ */
+#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a))
+
+/** @brief Maximum possible length for BLE Events.
+ * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a
+ * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead.
+ */
+#define BLE_EVT_LEN_MAX(ATT_MTU) \
+ (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t))
+
+/** @defgroup BLE_USER_MEM_TYPES User Memory Types
+ * @{ */
+#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */
+#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */
+/** @} */
+
+/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts
+ * @{
+ */
+#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */
+#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */
+/** @} */
+
+/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults.
+ * @{
+ */
+#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */
+
+/** @} */
+
+/** @} */
+
+/** @addtogroup BLE_COMMON_STRUCTURES Structures
+ * @{ */
+
+/**@brief User Memory Block. */
+typedef struct {
+ uint8_t *p_mem; /**< Pointer to the start of the user memory block. */
+ uint16_t len; /**< Length in bytes of the user memory block. */
+} ble_user_mem_block_t;
+
+/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */
+typedef struct {
+ uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */
+} ble_evt_user_mem_request_t;
+
+/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */
+typedef struct {
+ uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */
+ ble_user_mem_block_t mem_block; /**< User memory block */
+} ble_evt_user_mem_release_t;
+
+/**@brief Event structure for events not associated with a specific function module. */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle on which this event occurred. */
+ union {
+ ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */
+ ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */
+ } params; /**< Event parameter union. */
+} ble_common_evt_t;
+
+/**@brief BLE Event header. */
+typedef struct {
+ uint16_t evt_id; /**< Value from a BLE__EVT series. */
+ uint16_t evt_len; /**< Length in octets including this header. */
+} ble_evt_hdr_t;
+
+/**@brief Common BLE Event type, wrapping the module specific event reports. */
+typedef struct {
+ ble_evt_hdr_t header; /**< Event header. */
+ union {
+ ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */
+ ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */
+ ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */
+ ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */
+ ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */
+ } evt; /**< Event union. */
+} ble_evt_t;
+
+/**
+ * @brief Version Information.
+ */
+typedef struct {
+ uint8_t version_number; /**< Link Layer Version number. See
+ https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */
+ uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059)
+ (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */
+ uint16_t
+ subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */
+} ble_version_t;
+
+/**
+ * @brief Configuration parameters for the PA and LNA.
+ */
+typedef struct {
+ uint8_t enable : 1; /**< Enable toggling for this amplifier */
+ uint8_t active_high : 1; /**< Set the pin to be active high */
+ uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */
+} ble_pa_lna_cfg_t;
+
+/**
+ * @brief PA & LNA GPIO toggle configuration
+ *
+ * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or
+ * a low noise amplifier.
+ *
+ * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided
+ * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled.
+ *
+ * @note @ref sd_ble_opt_get is not supported for this option.
+ * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences
+ * and must be avoided by the application.
+ */
+typedef struct {
+ ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */
+ ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */
+
+ uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */
+ uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */
+ uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */
+} ble_common_opt_pa_lna_t;
+
+/**
+ * @brief Configuration of extended BLE connection events.
+ *
+ * When enabled the SoftDevice will dynamically extend the connection event when possible.
+ *
+ * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length.
+ * The connection event can be extended if there is time to send another packet pair before the start of the next connection
+ * interval, and if there are no conflicts with other BLE roles requesting radio time.
+ *
+ * @note @ref sd_ble_opt_get is not supported for this option.
+ */
+typedef struct {
+ uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */
+} ble_common_opt_conn_evt_ext_t;
+
+/**
+ * @brief Enable/disable extended RC calibration.
+ *
+ * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice
+ * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets
+ * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started.
+ * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When
+ * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the
+ * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand.
+ *
+ * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the
+ * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable().
+ *
+ * @note @ref sd_ble_opt_get is not supported for this option.
+ */
+typedef struct {
+ uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */
+} ble_common_opt_extended_rc_cal_t;
+
+/**@brief Option structure for common options. */
+typedef union {
+ ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */
+ ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */
+ ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */
+} ble_common_opt_t;
+
+/**@brief Common BLE Option type, wrapping the module specific options. */
+typedef union {
+ ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */
+ ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */
+ ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */
+} ble_opt_t;
+
+/**@brief BLE connection configuration type, wrapping the module specific configurations, set with
+ * @ref sd_ble_cfg_set.
+ *
+ * @note Connection configurations don't have to be set.
+ * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections,
+ * the default connection configuration will be automatically added for the remaining connections.
+ * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in
+ * place of @ref ble_conn_cfg_t::conn_cfg_tag.
+ *
+ * @sa sd_ble_gap_adv_start()
+ * @sa sd_ble_gap_connect()
+ *
+ * @mscs
+ * @mmsc{@ref BLE_CONN_CFG}
+ * @endmscs
+
+ */
+typedef struct {
+ uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the
+ @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls
+ to select this configuration when creating a connection.
+ Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */
+ union {
+ ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */
+ ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */
+ ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */
+ ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */
+ ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */
+ } params; /**< Connection configuration union. */
+} ble_conn_cfg_t;
+
+/**
+ * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set.
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured.
+ */
+typedef struct {
+ uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for.
+ Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is
+ @ref BLE_UUID_VS_COUNT_MAX. */
+} ble_common_cfg_vs_uuid_t;
+
+/**@brief Common BLE Configuration type, wrapping the common configurations. */
+typedef union {
+ ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */
+} ble_common_cfg_t;
+
+/**@brief BLE Configuration type, wrapping the module specific configurations. */
+typedef union {
+ ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */
+ ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */
+ ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */
+ ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */
+} ble_cfg_t;
+
+/** @} */
+
+/** @addtogroup BLE_COMMON_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Enable the BLE stack
+ *
+ * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the
+ * application RAM region (APP_RAM_BASE). On return, this will
+ * contain the minimum start address of the application RAM region
+ * required by the SoftDevice for this configuration.
+ * @warning After this call, the SoftDevice may generate several events. The list of events provided
+ * below require the application to initiate a SoftDevice API call. The corresponding API call
+ * is referenced in the event documentation.
+ * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop
+ * communicating with the peer device.
+ * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST
+ * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST
+ * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST
+ * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST
+ * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST
+ * - @ref BLE_GAP_EVT_SEC_REQUEST
+ * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST
+ * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST
+ * - @ref BLE_EVT_USER_MEM_REQUEST
+ * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST
+ *
+ * @note The memory requirement for a specific configuration will not increase between SoftDevices
+ * with the same major version number.
+ *
+ * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located
+ * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between
+ * APP_RAM_BASE and the start of the call stack.
+ *
+ * @details This call initializes the BLE stack, no BLE related function other than @ref
+ * sd_ble_cfg_set can be called before this one.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_COMMON_ENABLE}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully.
+ * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied.
+ * @retval ::NRF_ERROR_NO_MEM One or more of the following is true:
+ * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not
+ * large enough to fit this configuration's memory requirement. Check *p_app_ram_base
+ * and set the start address of the application RAM region accordingly.
+ * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which
+ * is currently not supported.
+ * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large.
+ */
+SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base));
+
+/**@brief Add configurations for the BLE stack
+ *
+ * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref
+ * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS.
+ * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value.
+ * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE).
+ * See @ref sd_ble_enable for details about APP_RAM_BASE.
+ *
+ * @note The memory requirement for a specific configuration will not increase between SoftDevices
+ * with the same major version number.
+ *
+ * @note If a configuration is set more than once, the last one set is the one that takes effect on
+ * @ref sd_ble_enable.
+ *
+ * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default
+ * configuration.
+ *
+ * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref
+ * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref
+ * sd_ble_enable).
+ *
+ * @note Error codes for the configurations are described in the configuration structs.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_COMMON_ENABLE}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS The configuration has been added successfully.
+ * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied.
+ * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not
+ * large enough to fit this configuration's memory requirement.
+ */
+SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base));
+
+/**@brief Get an event from the pending events queue.
+ *
+ * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length.
+ * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT.
+ * The buffer should be interpreted as a @ref ble_evt_t struct.
+ * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length.
+ *
+ * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that
+ * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt.
+ * The application is free to choose whether to call this function from thread mode (main context) or directly from the
+ * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher
+ * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned)
+ * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so
+ * could potentially leave events in the internal queue without the application being aware of this fact.
+ *
+ * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to
+ * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event,
+ * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size.
+ * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length
+ * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return:
+ *
+ * \code
+ * uint16_t len;
+ * errcode = sd_ble_evt_get(NULL, &len);
+ * \endcode
+ *
+ * @mscs
+ * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC}
+ * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied.
+ * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled.
+ * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer.
+ */
+SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len));
+
+/**@brief Add a Vendor Specific base UUID.
+ *
+ * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later
+ * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t
+ * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code
+ * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses
+ * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to
+ * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field
+ * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to
+ * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536,
+ * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array.
+ *
+ * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by
+ * the 16-bit uuid field in @ref ble_uuid_t.
+ *
+ * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in
+ * p_uuid_type along with an @ref NRF_SUCCESS error code.
+ *
+ * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding
+ * bytes 12 and 13.
+ * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be
+ * stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID.
+ * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid.
+ * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs.
+ */
+SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type));
+
+/**@brief Remove a Vendor Specific base UUID.
+ *
+ * @details This call removes a Vendor Specific base UUID. This function allows
+ * the application to reuse memory allocated for Vendor Specific base UUIDs.
+ *
+ * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID
+ * type.
+ *
+ * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed.
+ * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific
+ * base UUID will be removed. If the function returns successfully, the UUID type that was removed will
+ * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that
+ * is in use by the ATT Server.
+ *
+ * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID.
+ * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid.
+ * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type.
+ * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server.
+ */
+SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type));
+
+/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure.
+ *
+ * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared
+ * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs
+ * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index
+ * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type.
+ *
+ * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE.
+ *
+ * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes).
+ * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes.
+ * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length.
+ * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs.
+ */
+SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid));
+
+/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit).
+ *
+ * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is
+ * computed.
+ *
+ * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes.
+ * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes).
+ * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully encoded into the buffer.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type.
+ */
+SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le));
+
+/**@brief Get Version Information.
+ *
+ * @details This call allows the application to get the BLE stack version information.
+ *
+ * @param[out] p_version Pointer to a ble_version_t structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Version information stored successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure).
+ */
+SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version));
+
+/**@brief Provide a user memory block.
+ *
+ * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application.
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Successfully queued a response to the peer.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending.
+ */
+SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block));
+
+/**@brief Set a BLE option.
+ *
+ * @details This call allows the application to set the value of an option.
+ *
+ * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS.
+ * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value.
+ *
+ * @retval ::NRF_SUCCESS Option set successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints.
+ * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time.
+ * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed.
+ */
+SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt));
+
+/**@brief Get a BLE option.
+ *
+ * @details This call allows the application to retrieve the value of an option.
+ *
+ * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS.
+ * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Option retrieved successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints.
+ * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time.
+ * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported.
+ *
+ */
+SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt));
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+#endif /* BLE_H__ */
+
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_err.h b/variants/xiao_ble/softdevice/ble_err.h
new file mode 100644
index 000000000..d20f6d141
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_err.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_COMMON
+ @{
+ @addtogroup nrf_error
+ @{
+ @ingroup BLE_COMMON
+ @}
+
+ @defgroup ble_err General error codes
+ @{
+
+ @brief General error code definitions for the BLE API.
+
+ @ingroup BLE_COMMON
+*/
+#ifndef NRF_BLE_ERR_H__
+#define NRF_BLE_ERR_H__
+
+#include "nrf_error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @defgroup BLE_ERRORS Error Codes
+ * @{ */
+#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */
+#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */
+#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */
+#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */
+#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */
+#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \
+ (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */
+/** @} */
+
+/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges
+ * @brief Assignment of subranges for module specific error codes.
+ * @note For specific error codes, see ble_.h or ble_error_.h.
+ * @{ */
+#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */
+#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */
+#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */
+#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_gap.h b/variants/xiao_ble/softdevice/ble_gap.h
new file mode 100644
index 000000000..8ebdfa82b
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_gap.h
@@ -0,0 +1,2895 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_GAP Generic Access Profile (GAP)
+ @{
+ @brief Definitions and prototypes for the GAP interface.
+ */
+
+#ifndef BLE_GAP_H__
+#define BLE_GAP_H__
+
+#include "ble_err.h"
+#include "ble_hci.h"
+#include "ble_ranges.h"
+#include "ble_types.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations
+ * @{ */
+
+/**@brief GAP API SVC numbers.
+ */
+enum BLE_GAP_SVCS {
+ SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */
+ SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */
+ SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */
+ SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */
+ SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/
+ SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/
+ SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */
+ SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */
+ SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */
+ SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */
+ SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */
+ SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */
+ SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */
+ SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */
+ SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */
+ SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */
+ SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */
+ SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */
+ SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */
+ SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */
+ SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */
+ SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */
+ SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */
+ SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */
+ SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */
+ SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */
+ SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */
+ SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */
+ SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */
+ SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */
+ SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */
+ SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */
+ SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */
+ SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */
+ SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */
+ SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */
+ SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */
+ SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */
+ SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */
+ SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */
+ SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */
+ SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */
+ SD_BLE_GAP_CONN_EVT_TRIGGER_STOP =
+ BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */
+};
+
+/**@brief GAP Event IDs.
+ * IDs that uniquely identify an event coming from the stack to the application.
+ */
+enum BLE_GAP_EVTS {
+ BLE_GAP_EVT_CONNECTED =
+ BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */
+ BLE_GAP_EVT_DISCONNECTED =
+ BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */
+ BLE_GAP_EVT_CONN_PARAM_UPDATE =
+ BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */
+ BLE_GAP_EVT_SEC_PARAMS_REQUEST =
+ BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply.
+ \n See @ref ble_gap_evt_sec_params_request_t. */
+ BLE_GAP_EVT_SEC_INFO_REQUEST =
+ BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply.
+ \n See @ref ble_gap_evt_sec_info_request_t. */
+ BLE_GAP_EVT_PASSKEY_DISPLAY =
+ BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref
+ sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */
+ BLE_GAP_EVT_KEY_PRESSED =
+ BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */
+ BLE_GAP_EVT_AUTH_KEY_REQUEST =
+ BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply.
+ \n See @ref ble_gap_evt_auth_key_request_t. */
+ BLE_GAP_EVT_LESC_DHKEY_REQUEST =
+ BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref
+ sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */
+ BLE_GAP_EVT_AUTH_STATUS =
+ BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */
+ BLE_GAP_EVT_CONN_SEC_UPDATE =
+ BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */
+ BLE_GAP_EVT_TIMEOUT =
+ BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */
+ BLE_GAP_EVT_RSSI_CHANGED =
+ BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */
+ BLE_GAP_EVT_ADV_REPORT =
+ BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */
+ BLE_GAP_EVT_SEC_REQUEST =
+ BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate
+\n or with @ref sd_ble_gap_encrypt if required security information is available
+. \n See @ref ble_gap_evt_sec_request_t. */
+ BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST =
+ BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref
+ sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */
+ BLE_GAP_EVT_SCAN_REQ_REPORT =
+ BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */
+ BLE_GAP_EVT_PHY_UPDATE_REQUEST =
+ BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n
+ See @ref ble_gap_evt_phy_update_request_t. */
+ BLE_GAP_EVT_PHY_UPDATE =
+ BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */
+ BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST =
+ BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref
+ sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */
+ BLE_GAP_EVT_DATA_LENGTH_UPDATE =
+ BLE_GAP_EVT_BASE +
+ 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */
+ BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT =
+ BLE_GAP_EVT_BASE +
+ 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */
+ BLE_GAP_EVT_ADV_SET_TERMINATED =
+ BLE_GAP_EVT_BASE +
+ 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */
+};
+
+/**@brief GAP Option IDs.
+ * IDs that uniquely identify a GAP option.
+ */
+enum BLE_GAP_OPTS {
+ BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */
+ BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */
+ BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */
+ BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */
+ BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT =
+ BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */
+ BLE_GAP_OPT_SLAVE_LATENCY_DISABLE =
+ BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */
+};
+
+/**@brief GAP Configuration IDs.
+ *
+ * IDs that uniquely identify a GAP configuration.
+ */
+enum BLE_GAP_CFGS {
+ BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */
+ BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */
+ BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic
+ inclusion configuration. */
+ BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic
+ inclusion configuration. */
+};
+
+/**@brief GAP TX Power roles.
+ */
+enum BLE_GAP_TX_POWER_ROLES {
+ BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */
+ BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */
+ BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */
+};
+
+/** @} */
+
+/**@addtogroup BLE_GAP_DEFINES Defines
+ * @{ */
+
+/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP
+ * @{ */
+#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \
+ (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */
+#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \
+ (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */
+#define BLE_ERROR_GAP_INVALID_BLE_ADDR \
+ (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */
+#define BLE_ERROR_GAP_WHITELIST_IN_USE \
+ (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */
+#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \
+ (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */
+#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \
+ (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */
+/**@} */
+
+/**@defgroup BLE_GAP_ROLES GAP Roles
+ * @{ */
+#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */
+#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */
+#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */
+/**@} */
+
+/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources
+ * @{ */
+#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */
+#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */
+#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types
+ * @{ */
+#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/
+#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */
+#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */
+#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */
+#define BLE_GAP_ADDR_TYPE_ANONYMOUS \
+ 0x7F /**< An advertiser may advertise without its address. \
+ This type of advertising is called anonymous. */
+/**@} */
+
+/**@brief The default interval in seconds at which a private address is refreshed. */
+#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */
+/**@brief The maximum interval in seconds at which a private address can be refreshed. */
+#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */
+
+/** @brief BLE address length. */
+#define BLE_GAP_ADDR_LEN (6)
+
+/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes
+ * @{ */
+#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */
+#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */
+#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \
+ 0x02 /**< Device will send and accept only private addresses for its own address, \
+ and will not accept a peer using identity address as sender address when \
+ the peer IRK is exchanged, non-zero and added to the identity list. */
+/**@} */
+
+/** @brief Invalid power level. */
+#define BLE_GAP_POWER_LEVEL_INVALID 127
+
+/** @brief Advertising set handle not set. */
+#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF)
+
+/** @brief The default number of advertising sets. */
+#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1)
+
+/** @brief The maximum number of advertising sets supported by this SoftDevice. */
+#define BLE_GAP_ADV_SET_COUNT_MAX (1)
+
+/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes.
+ * @{ */
+#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \
+ (31) /**< Maximum data length for an advertising set. \
+ If more advertising data is required, use extended advertising instead. */
+#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \
+ (255) /**< Maximum supported data length for an extended advertising set. */
+
+#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \
+ (238) /**< Maximum supported data length for an extended connectable advertising set. */
+/**@}. */
+
+/** @brief Set ID not available in advertising report. */
+#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF
+
+/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons
+ * @{ */
+#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */
+#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */
+/**@} */
+
+/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format
+ * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm
+ * @{ */
+#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */
+#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */
+#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */
+#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */
+#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */
+#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */
+#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */
+#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */
+#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */
+#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */
+#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */
+#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */
+#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */
+#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */
+#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */
+#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */
+#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */
+#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */
+#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */
+#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */
+#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */
+#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */
+#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */
+#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */
+#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */
+#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */
+#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */
+#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */
+#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags
+ * @{ */
+#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */
+#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */
+#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */
+#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */
+#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */
+#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \
+ (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \
+ BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */
+#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \
+ (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \
+ BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min
+ * @{ */
+#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */
+#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */
+ /**@} */
+
+/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min
+ * @{ */
+#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */
+#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */
+ /** @} */
+
+/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min
+ * @{ */
+#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */
+#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */
+ /** @} */
+
+/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min
+ * @{ */
+#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */
+#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */
+ /** @} */
+
+/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size
+ *
+ * Scan buffers are used for storing advertising data received from an advertiser.
+ * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length.
+ * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN.
+ * @{ */
+#define BLE_GAP_SCAN_BUFFER_MIN \
+ (31) /**< Minimum data length for an \
+ advertising set. */
+#define BLE_GAP_SCAN_BUFFER_MAX \
+ (31) /**< Maximum data length for an \
+ advertising set. */
+#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \
+ (255) /**< Minimum data length for an \
+ extended advertising set. */
+#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \
+ (1650) /**< Maximum data length for an \
+ extended advertising set. */
+#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \
+ (255) /**< Maximum supported data length for \
+ an extended advertising set. */
+/** @} */
+
+/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types
+ *
+ * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2.
+ *
+ * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX.
+ * The maximum supported data length for an extended advertiser is defined by
+ * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED
+ * Note that some of the advertising types do not support advertising data. Non-scannable types do not support
+ * scan response data.
+ *
+ * @{ */
+#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \
+ 0x01 /**< Connectable and scannable undirected \
+ advertising events. */
+#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \
+ 0x02 /**< Connectable non-scannable directed advertising \
+ events. Advertising interval is less that 3.75 ms. \
+ Use this type for fast reconnections. \
+ @note Advertising data is not supported. */
+#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \
+ 0x03 /**< Connectable non-scannable directed advertising \
+ events. \
+ @note Advertising data is not supported. */
+#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \
+ 0x04 /**< Non-connectable scannable undirected \
+ advertising events. */
+#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \
+ 0x05 /**< Non-connectable non-scannable undirected \
+ advertising events. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \
+ 0x06 /**< Connectable non-scannable undirected advertising \
+ events using extended advertising PDUs. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \
+ 0x07 /**< Connectable non-scannable directed advertising \
+ events using extended advertising PDUs. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \
+ 0x08 /**< Non-connectable scannable undirected advertising \
+ events using extended advertising PDUs. \
+ @note Only scan response data is supported. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \
+ 0x09 /**< Non-connectable scannable directed advertising \
+ events using extended advertising PDUs. \
+ @note Only scan response data is supported. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \
+ 0x0A /**< Non-connectable non-scannable undirected advertising \
+ events using extended advertising PDUs. */
+#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \
+ 0x0B /**< Non-connectable non-scannable directed advertising \
+ events using extended advertising PDUs. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies
+ * @{ */
+#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */
+#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */
+#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */
+#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status
+ * @{ */
+#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */
+#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \
+ 0x01 /**< More data to be received. \
+ @note This value will only be used if \
+ @ref ble_gap_scan_params_t::report_incomplete_evts and \
+ @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */
+#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \
+ 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \
+ @note This value will only be used if \
+ @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */
+#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \
+ 0x03 /**< Failed to receive the remaining data. \
+ @note This value will only be used if \
+ @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */
+/**@} */
+
+/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies
+ * @{ */
+#define BLE_GAP_SCAN_FP_ACCEPT_ALL \
+ 0x00 /**< Accept all advertising packets except directed advertising packets \
+ not addressed to this device. */
+#define BLE_GAP_SCAN_FP_WHITELIST \
+ 0x01 /**< Accept advertising packets from devices in the whitelist except directed \
+ packets not addressed to this device. */
+#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \
+ 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \
+ In addition, accept directed advertising packets, where the advertiser's \
+ address is a resolvable private address that cannot be resolved. */
+#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \
+ 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \
+ In addition, accept directed advertising packets, where the advertiser's \
+ address is a resolvable private address that cannot be resolved. */
+/**@} */
+
+/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units
+ * @{ */
+#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \
+ (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \
+ */
+#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \
+ (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \
+ mode. */
+#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \
+ (0) /**< Unlimited advertising in general discoverable mode. \
+ For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */
+/**@} */
+
+/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes
+ * @{ */
+#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */
+#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */
+#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */
+/**@} */
+
+/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities
+ * @{ */
+#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */
+#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */
+#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */
+#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */
+#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */
+/**@} */
+
+/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types
+ * @{ */
+#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */
+#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */
+#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */
+/**@} */
+
+/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types
+ * @{ */
+#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */
+#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */
+#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */
+#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */
+#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */
+/**@} */
+
+/**@defgroup BLE_GAP_SEC_STATUS GAP Security status
+ * @{ */
+#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */
+#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */
+#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */
+#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */
+#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */
+#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */
+#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */
+#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */
+#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */
+#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */
+#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */
+#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */
+#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */
+#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */
+#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */
+#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */
+#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */
+#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */
+#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */
+#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */
+#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */
+/**@} */
+
+/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources
+ * @{ */
+#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */
+#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */
+/**@} */
+
+/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits
+ * @{ */
+#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */
+#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \
+ 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */
+#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \
+ 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \
+ */
+#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */
+#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \
+ 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */
+#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \
+ 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \
+ */
+#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */
+#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */
+#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */
+#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */
+/**@} */
+
+/**@defgroup BLE_GAP_DEVNAME GAP device name defines.
+ * @{ */
+#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */
+#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */
+#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */
+/**@} */
+
+/**@brief Disable RSSI events for connections */
+#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF
+
+/**@defgroup BLE_GAP_PHYS GAP PHYs
+ * @{ */
+#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/
+#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */
+#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */
+#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */
+#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */
+
+/**@brief Supported PHYs in connections, for scanning, and for advertising. */
+#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */
+
+/**@} */
+
+/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters
+ *
+ * See @ref ble_gap_conn_sec_mode_t.
+ * @{ */
+/**@brief Set sec_mode pointed to by ptr to have no access rights.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \
+ do { \
+ (ptr)->sm = 0; \
+ (ptr)->lv = 0; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \
+ do { \
+ (ptr)->sm = 1; \
+ (ptr)->lv = 1; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \
+ do { \
+ (ptr)->sm = 1; \
+ (ptr)->lv = 2; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \
+ do { \
+ (ptr)->sm = 1; \
+ (ptr)->lv = 3; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \
+ do { \
+ (ptr)->sm = 1; \
+ (ptr)->lv = 4; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \
+ do { \
+ (ptr)->sm = 2; \
+ (ptr)->lv = 1; \
+ } while (0)
+/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/
+#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \
+ do { \
+ (ptr)->sm = 2; \
+ (ptr)->lv = 2; \
+ } while (0)
+/**@} */
+
+/**@brief GAP Security Random Number Length. */
+#define BLE_GAP_SEC_RAND_LEN 8
+
+/**@brief GAP Security Key Length. */
+#define BLE_GAP_SEC_KEY_LEN 16
+
+/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */
+#define BLE_GAP_LESC_P256_PK_LEN 64
+
+/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */
+#define BLE_GAP_LESC_DHKEY_LEN 32
+
+/**@brief GAP Passkey Length. */
+#define BLE_GAP_PASSKEY_LEN 6
+
+/**@brief Maximum amount of addresses in the whitelist. */
+#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8)
+
+/**@brief Maximum amount of identities in the device identities list. */
+#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8)
+
+/**@brief Default connection count for a configuration. */
+#define BLE_GAP_CONN_COUNT_DEFAULT (1)
+
+/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines.
+ * @{ */
+#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */
+#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */
+#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */
+/**@} */
+
+/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines.
+ * @{ */
+#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */
+#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */
+#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \
+ (1) /**< Default number of SMP instances shared between all connections acting as centrals. */
+#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \
+ (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */
+
+/**@} */
+
+/**@brief Automatic data length parameter. */
+#define BLE_GAP_DATA_LENGTH_AUTO 0
+
+/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines.
+ * @{ */
+#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */
+#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */
+/**@} */
+
+/**@defgroup GAP_SEC_MODES GAP Security Modes
+ * @{ */
+#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */
+/**@} */
+
+/**@brief The total number of channels in Bluetooth Low Energy. */
+#define BLE_GAP_CHANNEL_COUNT (40)
+
+/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines
+ * @{ */
+#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */
+#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */
+#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */
+ /**@} */
+
+/** @} */
+
+/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations
+ * @{
+ */
+#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */
+#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \
+ (1) /**< Do not include the characteristic in the Attribute table. \
+ The SoftDevice will reserve the attribute handles \
+ which are otherwise used for this characteristic. \
+ By reserving the attribute handles it will be possible \
+ to upgrade the SoftDevice without changing handle of the \
+ Service Changed characteristic. */
+#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \
+ (2) /**< Do not include the characteristic in the Attribute table. \
+ The SoftDevice will not reserve the attribute handles \
+ which are otherwise used for this characteristic. */
+/**@} */
+
+/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values
+ * @{ */
+#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */
+#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */
+/**@} */
+
+/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options
+ * @{ */
+#define BLE_GAP_SLAVE_LATENCY_ENABLE \
+ (0) /**< Slave latency is enabled. When slave latency is enabled, \
+ the slave will wake up every time it has data to send, \
+ and/or every slave latency number of connection events. */
+#define BLE_GAP_SLAVE_LATENCY_DISABLE \
+ (1) /**< Disable slave latency. The slave will wake up every connection event \
+ regardless of the requested slave latency. \
+ This option consumes the most power. */
+#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \
+ (2) /**< The slave will wake up every connection event if it has not received \
+ an ACK from the master for at least slave latency events. This \
+ configuration may increase the power consumption in environments \
+ with a lot of radio activity. */
+/**@} */
+
+/**@addtogroup BLE_GAP_STRUCTURES Structures
+ * @{ */
+
+/**@brief Advertising event properties. */
+typedef struct {
+ uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */
+ uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs.
+ @note Anonymous advertising is only available for
+ @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and
+ @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */
+ uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */
+} ble_gap_adv_properties_t;
+
+/**@brief Advertising report type. */
+typedef struct {
+ uint16_t connectable : 1; /**< Connectable advertising event type. */
+ uint16_t scannable : 1; /**< Scannable advertising event type. */
+ uint16_t directed : 1; /**< Directed advertising event type. */
+ uint16_t scan_response : 1; /**< Received a scan response. */
+ uint16_t extended_pdu : 1; /**< Received an extended advertising set. */
+ uint16_t status : 2; /**< Data status. See @ref BLE_GAP_ADV_DATA_STATUS. */
+ uint16_t reserved : 9; /**< Reserved for future use. */
+} ble_gap_adv_report_type_t;
+
+/**@brief Advertising Auxiliary Pointer. */
+typedef struct {
+ uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */
+ uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */
+} ble_gap_aux_pointer_t;
+
+/**@brief Bluetooth Low Energy address. */
+typedef struct {
+ uint8_t
+ addr_id_peer : 1; /**< Only valid for peer addresses.
+ This bit is set by the SoftDevice to indicate whether the address has been resolved from
+ a Resolvable Private Address (when the peer is using privacy).
+ If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address.
+
+ This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions.
+ */
+ uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */
+ uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format.
+ @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */
+} ble_gap_addr_t;
+
+/**@brief GAP connection parameters.
+ *
+ * @note When ble_conn_params_t is received in an event, both min_conn_interval and
+ * max_conn_interval will be equal to the connection interval set by the central.
+ *
+ * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies:
+ * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval
+ * that corresponds to the following Bluetooth Spec requirement:
+ * The Supervision_Timeout in milliseconds shall be larger than
+ * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds.
+ */
+typedef struct {
+ uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
+ uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/
+ uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/
+ uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/
+} ble_gap_conn_params_t;
+
+/**@brief GAP connection security modes.
+ *
+ * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n
+ * Security Mode 1 Level 1: No security is needed (aka open link).\n
+ * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n
+ * Security Mode 1 Level 3: MITM protected encrypted link required.\n
+ * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n
+ * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n
+ * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n
+ */
+typedef struct {
+ uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */
+ uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */
+
+} ble_gap_conn_sec_mode_t;
+
+/**@brief GAP connection security status.*/
+typedef struct {
+ ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/
+ uint8_t
+ encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */
+} ble_gap_conn_sec_t;
+
+/**@brief Identity Resolving Key. */
+typedef struct {
+ uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */
+} ble_gap_irk_t;
+
+/**@brief Channel mask (40 bits).
+ * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0,
+ * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents
+ * channel index 39. If a bit is set to 1, the channel is not used.
+ */
+typedef uint8_t ble_gap_ch_mask_t[5];
+
+/**@brief GAP advertising parameters. */
+typedef struct {
+ ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */
+ ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer.
+ @note ble_gap_addr_t::addr_type cannot be
+ @ref BLE_GAP_ADDR_TYPE_ANONYMOUS.
+ - When privacy is enabled and the local device uses
+ @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses,
+ the device identity list is searched for a matching entry. If
+ the local IRK for that device identity is set, the local IRK
+ for that device will be used to generate the advertiser address
+ field in the advertising packet.
+ - If @ref ble_gap_adv_properties_t::type is directed, this must be
+ set to the targeted scanner or initiator. If the peer address is
+ in the device identity list, the peer IRK for that device will be
+ used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE
+ target addresses used in the advertising event PDUs. */
+ uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS.
+ @note If @ref ble_gap_adv_properties_t::type is set to
+ @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE
+ advertising, this parameter is ignored. */
+ uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached,
+ an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised.
+ @sa BLE_GAP_ADV_TIMEOUT_VALUES.
+ @note The SoftDevice will always complete at least one advertising
+ event even if the duration is set too low. */
+ uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling
+ advertising. Setting the value to 0 disables the limitation. When
+ the count of advertising events specified by this parameter
+ (if not 0) is reached, advertising will be automatically stopped
+ and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised
+ @note If @ref ble_gap_adv_properties_t::type is set to
+ @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE,
+ this parameter is ignored. */
+ ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels.
+ At least one of the primary channels, that is channel index 37-39, must be used.
+ Masking away secondary advertising channels is not supported. */
+ uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */
+ uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets
+ are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS
+ will be used.
+ Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED.
+ @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if
+ @ref ble_gap_adv_properties_t::type is not an extended advertising type. */
+ uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets
+ are transmitted.
+ If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used.
+ Valid values are
+ @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED.
+ If @ref ble_gap_adv_properties_t::type is an extended advertising type
+ and connectable, this is the PHY that will be used to establish a
+ connection and send AUX_ADV_IND packets on.
+ @note This parameter will be ignored when
+ @ref ble_gap_adv_properties_t::type is not an extended advertising type. */
+ uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other
+ advertising sets transmitted by this and other devices.
+ @note This parameter will be ignored when
+ @ref ble_gap_adv_properties_t::type is not an extended advertising type. */
+ uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a
+ scan request is received and the scanner address is allowed
+ by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised.
+ @note This parameter will be ignored when
+ @ref ble_gap_adv_properties_t::type is a non-scannable
+ advertising type. */
+} ble_gap_adv_params_t;
+
+/**@brief GAP advertising data buffers.
+ *
+ * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and
+ * shall never be modified while advertising. The data shall be kept alive until either:
+ * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised.
+ * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding
+ * advertising handle.
+ * - Advertising is stopped.
+ * - Advertising data is changed.
+ * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */
+typedef struct {
+ ble_data_t adv_data; /**< Advertising data.
+ @note
+ Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type
+ that is allowed to contain advertising data. */
+ ble_data_t scan_rsp_data; /**< Scan response data.
+ @note
+ Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type
+ that is scannable. */
+} ble_gap_adv_data_t;
+
+/**@brief GAP scanning parameters. */
+typedef struct {
+ uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets.
+ If set to 0, the scanner will not receive advertising packets
+ on secondary advertising channels, and will not be able
+ to receive long advertising PDUs. */
+ uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have
+ @ref ble_gap_adv_report_type_t::status set to
+ @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA.
+ This parameter is ignored when used with @ref sd_ble_gap_connect
+ @note This may be used to abort receiving more packets from an extended
+ advertising event, and is only available for extended
+ scanning, see @ref sd_ble_gap_scan_start.
+ @note This feature is not supported by this SoftDevice. */
+ uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests.
+ This parameter is ignored when used with @ref sd_ble_gap_connect. */
+ uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES.
+ @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and
+ @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with
+ @ref sd_ble_gap_connect */
+ uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO,
+ scan_phys will default to @ref BLE_GAP_PHY_1MBPS.
+ - If @ref ble_gap_scan_params_t::extended is set to 0, the only
+ supported PHY is @ref BLE_GAP_PHY_1MBPS.
+ - When used with @ref sd_ble_gap_scan_start,
+ the bitfield indicates the PHYs the scanner will use for scanning
+ on primary advertising channels. The scanner will accept
+ @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs.
+ - When used with @ref sd_ble_gap_connect, the bitfield indicates
+ the PHYs the initiator will use for scanning on primary advertising
+ channels. The initiator will accept connections initiated on either
+ of the @ref BLE_GAP_PHYS_SUPPORTED PHYs.
+ If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS,
+ the primary scan PHY is @ref BLE_GAP_PHY_1MBPS.
+ If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan
+ PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is
+ @ref BLE_GAP_PHY_CODED, the primary scan PHY is
+ @ref BLE_GAP_PHY_CODED only. */
+ uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */
+ uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW.
+ If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and
+ @ref BLE_GAP_PHY_CODED interval shall be larger than or
+ equal to twice the scan window. */
+ uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */
+ ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels.
+ At least one of the primary channels, that is channel index 37-39, must be
+ set to 0.
+ Masking away secondary channels is not supported. */
+} ble_gap_scan_params_t;
+
+/**@brief Privacy.
+ *
+ * The privacy feature provides a way for the device to avoid being tracked over a period of time.
+ * The privacy feature, when enabled, hides the local device identity and replaces it with a private address
+ * that is automatically refreshed at a specified interval.
+ *
+ * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK).
+ * With this key, a device can generate a random private address that can only be recognized by peers in possession of that
+ * key, and devices can establish connections without revealing their real identities.
+ *
+ * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref
+ * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported.
+ *
+ * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all
+ * bonding procedures performed after @ref sd_ble_gap_privacy_set returns.
+ * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is
+ * called.
+ */
+typedef struct {
+ uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */
+ uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or
+ @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */
+ uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use
+ the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */
+ ble_gap_irk_t
+ *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device
+ default IRK will be used. When used as output, pointer to IRK structure where the current default IRK
+ will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate
+ random private resolvable addresses for the local device unless instructed otherwise. */
+} ble_gap_privacy_params_t;
+
+/**@brief PHY preferences for TX and RX
+ * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each
+ * direction.
+ * @code
+ * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS;
+ * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS;
+ * @endcode
+ *
+ */
+typedef struct {
+ uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */
+ uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */
+} ble_gap_phys_t;
+
+/** @brief Keys that can be exchanged during a bonding procedure. */
+typedef struct {
+ uint8_t enc : 1; /**< Long Term Key and Master Identification. */
+ uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */
+ uint8_t sign : 1; /**< Connection Signature Resolving Key. */
+ uint8_t link : 1; /**< Derive the Link Key from the LTK. */
+} ble_gap_sec_kdist_t;
+
+/**@brief GAP security parameters. */
+typedef struct {
+ uint8_t bond : 1; /**< Perform bonding. */
+ uint8_t mitm : 1; /**< Enable Man In The Middle protection. */
+ uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */
+ uint8_t keypress : 1; /**< Enable generation of keypress notifications. */
+ uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
+ uint8_t oob : 1; /**< The OOB data flag.
+ - In LE legacy pairing, this flag is set if a device has out of band authentication data.
+ The OOB method is used if both of the devices have out of band authentication data.
+ - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band
+ authentication data. The OOB method is used if at least one device has the peer device's OOB data
+ available. */
+ uint8_t
+ min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
+ uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */
+ ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */
+ ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */
+} ble_gap_sec_params_t;
+
+/**@brief GAP Encryption Information. */
+typedef struct {
+ uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */
+ uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */
+ uint8_t auth : 1; /**< Authenticated Key. */
+ uint8_t ltk_len : 6; /**< LTK length in octets. */
+} ble_gap_enc_info_t;
+
+/**@brief GAP Master Identification. */
+typedef struct {
+ uint16_t ediv; /**< Encrypted Diversifier. */
+ uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */
+} ble_gap_master_id_t;
+
+/**@brief GAP Signing Information. */
+typedef struct {
+ uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */
+} ble_gap_sign_info_t;
+
+/**@brief GAP LE Secure Connections P-256 Public Key. */
+typedef struct {
+ uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the
+ standard SMP protocol format: {X,Y} both in little-endian. */
+} ble_gap_lesc_p256_pk_t;
+
+/**@brief GAP LE Secure Connections DHKey. */
+typedef struct {
+ uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */
+} ble_gap_lesc_dhkey_t;
+
+/**@brief GAP LE Secure Connections OOB data. */
+typedef struct {
+ ble_gap_addr_t addr; /**< Bluetooth address of the device. */
+ uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */
+ uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */
+} ble_gap_lesc_oob_data_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */
+typedef struct {
+ ble_gap_addr_t
+ peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref
+ ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */
+ uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */
+ ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */
+ uint8_t adv_handle; /**< Advertising handle in which advertising has ended.
+ This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */
+ ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated
+ advertising set. The advertising buffers provided in
+ @ref sd_ble_gap_adv_set_configure are now released.
+ This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */
+} ble_gap_evt_connected_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */
+typedef struct {
+ uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */
+} ble_gap_evt_disconnected_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */
+typedef struct {
+ ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */
+} ble_gap_evt_conn_param_update_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */
+typedef struct {
+ ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */
+} ble_gap_evt_phy_update_request_t;
+
+/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */
+typedef struct {
+ uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/
+ uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */
+ uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */
+} ble_gap_evt_phy_update_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */
+typedef struct {
+ ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */
+} ble_gap_evt_sec_params_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */
+typedef struct {
+ ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */
+ ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */
+ uint8_t enc_info : 1; /**< If 1, Encryption Information required. */
+ uint8_t id_info : 1; /**< If 1, Identity Information required. */
+ uint8_t sign_info : 1; /**< If 1, Signing Information required. */
+} ble_gap_evt_sec_info_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */
+typedef struct {
+ uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */
+ uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply
+ with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or
+ @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */
+} ble_gap_evt_passkey_display_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */
+typedef struct {
+ uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */
+} ble_gap_evt_key_pressed_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */
+typedef struct {
+ uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */
+} ble_gap_evt_auth_key_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */
+typedef struct {
+ ble_gap_lesc_p256_pk_t
+ *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory
+ inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */
+ uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the
+ procedure. */
+} ble_gap_evt_lesc_dhkey_request_t;
+
+/**@brief Security levels supported.
+ * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1.
+ */
+typedef struct {
+ uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */
+ uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */
+ uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */
+ uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */
+} ble_gap_sec_levels_t;
+
+/**@brief Encryption Key. */
+typedef struct {
+ ble_gap_enc_info_t enc_info; /**< Encryption Information. */
+ ble_gap_master_id_t master_id; /**< Master Identification. */
+} ble_gap_enc_key_t;
+
+/**@brief Identity Key. */
+typedef struct {
+ ble_gap_irk_t id_info; /**< Identity Resolving Key. */
+ ble_gap_addr_t id_addr_info; /**< Identity Address. */
+} ble_gap_id_key_t;
+
+/**@brief Security Keys. */
+typedef struct {
+ ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */
+ ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */
+ ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */
+ ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the
+ value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */
+} ble_gap_sec_keys_t;
+
+/**@brief Security key set for both local and peer keys. */
+typedef struct {
+ ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be
+ generated locally and will always be stored if bonding. */
+ ble_gap_sec_keys_t
+ keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */
+} ble_gap_sec_keyset_t;
+
+/**@brief Data Length Update Procedure parameters. */
+typedef struct {
+ uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link
+ Layer Data Channel PDU. */
+ uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer
+ Data Channel PDU. */
+ uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link
+ Layer Data Channel PDU. */
+ uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer
+ Data Channel PDU. */
+} ble_gap_data_length_params_t;
+
+/**@brief Data Length Update Procedure local limitation. */
+typedef struct {
+ uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */
+ uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */
+ uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many
+ microseconds. */
+} ble_gap_data_length_limitation_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */
+typedef struct {
+ uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */
+ uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */
+ uint8_t bonded : 1; /**< Procedure resulted in a bond. */
+ uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */
+ ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */
+ ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */
+ ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding
+ with LE Secure Connections, the enc bit will be always set. */
+ ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding
+ with LE Secure Connections, the enc bit will never be set. */
+} ble_gap_evt_auth_status_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */
+typedef struct {
+ ble_gap_conn_sec_t conn_sec; /**< Connection security level. */
+} ble_gap_evt_conn_sec_update_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */
+typedef struct {
+ uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */
+ union {
+ ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released
+ scan buffer is contained in this field. */
+ } params; /**< Event Parameters. */
+} ble_gap_evt_timeout_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */
+typedef struct {
+ int8_t rssi; /**< Received Signal Strength Indication in dBm.
+ @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature
+ measurement. */
+ uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */
+} ble_gap_evt_rssi_changed_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */
+typedef struct {
+ uint8_t reason; /**< Reason for why the advertising set terminated. See
+ @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */
+ uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */
+ uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0,
+ this field indicates the number of completed advertising events. */
+ ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated
+ advertising set. The advertising buffers provided in
+ @ref sd_ble_gap_adv_set_configure are now released. */
+} ble_gap_evt_adv_set_terminated_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_ADV_REPORT.
+ *
+ * @note If @ref ble_gap_adv_report_type_t::status is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
+ * not all fields in the advertising report may be available.
+ *
+ * @note When ble_gap_adv_report_type_t::status is not set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA,
+ * scanning will be paused. To continue scanning, call @ref sd_ble_gap_scan_start.
+ */
+typedef struct {
+ ble_gap_adv_report_type_t type; /**< Advertising report type. See @ref ble_gap_adv_report_type_t. */
+ ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr is resolved:
+ @ref ble_gap_addr_t::addr_id_peer is set to 1 and the address is the
+ peer's identity address. */
+ ble_gap_addr_t direct_addr; /**< Contains the target address of the advertising event if
+ @ref ble_gap_adv_report_type_t::directed is set to 1. If the
+ SoftDevice was able to resolve the address,
+ @ref ble_gap_addr_t::addr_id_peer is set to 1 and the direct_addr
+ contains the local identity address. If the target address of the
+ advertising event is @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE,
+ and the SoftDevice was unable to resolve it, the application may try
+ to resolve this address to find out if the advertising event was
+ directed to us. */
+ uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising packet was received.
+ See @ref BLE_GAP_PHYS. */
+ uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising packet was received.
+ See @ref BLE_GAP_PHYS. This field is set to @ref BLE_GAP_PHY_NOT_SET if no packets
+ were received on a secondary advertising channel. */
+ int8_t tx_power; /**< TX Power reported by the advertiser in the last packet header received.
+ This field is set to @ref BLE_GAP_POWER_LEVEL_INVALID if the
+ last received packet did not contain the Tx Power field.
+ @note TX Power is only included in extended advertising packets. */
+ int8_t rssi; /**< Received Signal Strength Indication in dBm of the last packet received.
+ @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature
+ measurement. */
+ uint8_t ch_index; /**< Channel Index on which the last advertising packet is received (0-39). */
+ uint8_t set_id; /**< Set ID of the received advertising data. Set ID is not present
+ if set to @ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
+ uint16_t data_id : 12; /**< The advertising data ID of the received advertising data. Data ID
+ is not present if @ref ble_gap_evt_adv_report_t::set_id is set to
+ @ref BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE. */
+ ble_data_t data; /**< Received advertising or scan response data. If
+ @ref ble_gap_adv_report_type_t::status is not set to
+ @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the data buffer provided
+ in @ref sd_ble_gap_scan_start is now released. */
+ ble_gap_aux_pointer_t aux_pointer; /**< The offset and PHY of the next advertising packet in this extended advertising
+ event. @note This field is only set if @ref ble_gap_adv_report_type_t::status
+ is set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. */
+} ble_gap_evt_adv_report_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */
+typedef struct {
+ uint8_t bond : 1; /**< Perform bonding. */
+ uint8_t mitm : 1; /**< Man In The Middle protection requested. */
+ uint8_t lesc : 1; /**< LE Secure Connections requested. */
+ uint8_t keypress : 1; /**< Generation of keypress notifications requested. */
+} ble_gap_evt_sec_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */
+typedef struct {
+ ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */
+} ble_gap_evt_conn_param_update_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */
+typedef struct {
+ uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */
+ int8_t rssi; /**< Received Signal Strength Indication in dBm.
+ @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature
+ measurement. */
+ ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref
+ ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */
+} ble_gap_evt_scan_req_report_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */
+typedef struct {
+ ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */
+} ble_gap_evt_data_length_update_request_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE.
+ *
+ * @note This event may also be raised after a PHY Update procedure.
+ */
+typedef struct {
+ ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */
+} ble_gap_evt_data_length_update_t;
+
+/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */
+typedef struct {
+ int8_t
+ channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy
+ channels, in dBm, indexed by Channel Index.
+ If no measurement is available for the given channel, channel_energy is set to
+ @ref BLE_GAP_POWER_LEVEL_INVALID. */
+} ble_gap_evt_qos_channel_survey_report_t;
+
+/**@brief GAP event structure. */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle on which event occurred. */
+ union /**< union alternative identified by evt_id in enclosing struct. */
+ {
+ ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */
+ ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */
+ ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */
+ ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */
+ ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */
+ ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */
+ ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */
+ ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */
+ ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */
+ ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */
+ ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */
+ ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */
+ ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */
+ ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */
+ ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */
+ ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */
+ ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */
+ ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */
+ ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */
+ ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */
+ ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */
+ ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */
+ ble_gap_evt_qos_channel_survey_report_t
+ qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */
+ } params; /**< Event Parameters. */
+} ble_gap_evt_t;
+
+/**
+ * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set.
+ *
+ * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero.
+ * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
+ * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX.
+ * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN.
+ */
+typedef struct {
+ uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration.
+ The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */
+ uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units.
+ The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref
+ BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters
+ for setting the throughput of a connection.
+ See the SoftDevice Specification for details on throughput. */
+} ble_gap_conn_cfg_t;
+
+/**
+ * @brief Configuration of maximum concurrent connections in the different connected roles, set with
+ * @ref sd_ble_cfg_set.
+ *
+ * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too
+ * large. The maximum supported sum of concurrent connections is
+ * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX.
+ * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count.
+ * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum
+ * supported advertising handles is
+ * @ref BLE_GAP_ADV_SET_COUNT_MAX.
+ */
+typedef struct {
+ uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */
+ uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref
+ BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */
+ uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref
+ BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */
+ uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is
+ @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */
+ uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to
+ the application using @ref sd_ble_gap_qos_channel_survey_start. */
+} ble_gap_cfg_role_count_t;
+
+/**
+ * @brief Device name and its properties, set with @ref sd_ble_cfg_set.
+ *
+ * @note If the device name is not configured, the default device name will be
+ * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be
+ * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name
+ * will have no write access.
+ *
+ * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK,
+ * the attribute table size must be increased to have room for the longer device name (see
+ * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t).
+ *
+ * @note If vloc is @ref BLE_GATTS_VLOC_STACK :
+ * - p_value must point to non-volatile memory (flash) or be NULL.
+ * - If p_value is NULL, the device name will initially be empty.
+ *
+ * @note If vloc is @ref BLE_GATTS_VLOC_USER :
+ * - p_value cannot be NULL.
+ * - If the device name is writable, p_value must point to volatile memory (RAM).
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
+ * - Invalid device name location (vloc).
+ * - Invalid device name security mode.
+ * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true:
+ * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN).
+ * - The device name length is too long for the given Attribute Table.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported.
+ */
+typedef struct {
+ ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
+ uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/
+ uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */
+ uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/
+ uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/
+} ble_gap_cfg_device_name_t;
+
+/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */
+typedef struct {
+ uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic.
+ See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */
+} ble_gap_cfg_ppcp_incl_cfg_t;
+
+/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */
+typedef struct {
+ uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic.
+ See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */
+} ble_gap_cfg_car_incl_cfg_t;
+
+/**@brief Configuration structure for GAP configurations. */
+typedef union {
+ ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */
+ ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */
+ ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include
+ configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */
+ ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration,
+ cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */
+} ble_gap_cfg_t;
+
+/**@brief Channel Map option.
+ *
+ * @details Used with @ref sd_ble_opt_get to get the current channel map
+ * or @ref sd_ble_opt_set to set a new channel map. When setting the
+ * channel map, it applies to all current and future connections. When getting the
+ * current channel map, it applies to a single connection and the connection handle
+ * must be supplied.
+ *
+ * @note Setting the channel map may take some time, depending on connection parameters.
+ * The time taken may be different for each connection and the get operation will
+ * return the previous channel map until the new one has taken effect.
+ *
+ * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed.
+ * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46.
+ *
+ * @retval ::NRF_SUCCESS Get or set successful.
+ * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
+ * - Less then two bits in @ref ch_map are set.
+ * - Bits for primary advertising channels (37-39) are set.
+ * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get.
+ *
+ */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle (only applicable for get) */
+ uint8_t ch_map[5]; /**< Channel Map (37-bit). */
+} ble_gap_opt_ch_map_t;
+
+/**@brief Local connection latency option.
+ *
+ * @details Local connection latency is a feature which enables the slave to improve
+ * current consumption by ignoring the slave latency set by the peer. The
+ * local connection latency can only be set to a multiple of the slave latency,
+ * and cannot be longer than half of the supervision timeout.
+ *
+ * @details Used with @ref sd_ble_opt_set to set the local connection latency. The
+ * @ref sd_ble_opt_get is not supported for this option, but the actual
+ * local connection latency (unless set to NULL) is set as a return parameter
+ * when setting the option.
+ *
+ * @note The latency set will be truncated down to the closest slave latency event
+ * multiple, or the nearest multiple before half of the supervision timeout.
+ *
+ * @note The local connection latency is disabled by default, and needs to be enabled for new
+ * connections and whenever the connection is updated.
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter.
+ */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle */
+ uint16_t requested_latency; /**< Requested local connection latency. */
+ uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return
+ value). */
+} ble_gap_opt_local_conn_latency_t;
+
+/**@brief Disable slave latency
+ *
+ * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection
+ * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the
+ * peripheral will ignore the slave_latency set by the central.
+ *
+ * @note Shall only be called on peripheral links.
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter.
+ */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle */
+ uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */
+} ble_gap_opt_slave_latency_disable_t;
+
+/**@brief Passkey Option.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC}
+ * @endmscs
+ *
+ * @details Structure containing the passkey to be used during pairing. This can be used with @ref
+ * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication
+ * instead of generating a random one.
+ *
+ * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks.
+ *
+ * @note @ref sd_ble_opt_get is not supported for this option.
+ *
+ */
+typedef struct {
+ uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used
+ during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/
+} ble_gap_opt_passkey_t;
+
+/**@brief Compatibility mode 1 option.
+ *
+ * @details This can be used with @ref sd_ble_opt_set to enable and disable
+ * compatibility mode 1. Compatibility mode 1 is disabled by default.
+ *
+ * @note Compatibility mode 1 enables interoperability with devices that do not support a value of
+ * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a
+ * limited set of legacy peripheral devices from another vendor. Enabling this compatibility
+ * mode will only have an effect if the local device will act as a central device and
+ * initiate a connection to a peripheral device. In that case it may lead to the connection
+ * creation taking up to one connection interval longer to complete for all connections.
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set.
+ */
+typedef struct {
+ uint8_t enable : 1; /**< Enable compatibility mode 1.*/
+} ble_gap_opt_compat_mode_1_t;
+
+/**@brief Authenticated payload timeout option.
+ *
+ * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other
+ * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX.
+ *
+ * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated
+ * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted
+ * link.
+ *
+ * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance
+ * to reset the timer. In addition the stack will try to prioritize running of LE ping over other
+ * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects
+ * on other activities, it is recommended to use high timeout values.
+ * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)).
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter.
+ */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle */
+ uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */
+} ble_gap_opt_auth_payload_timeout_t;
+
+/**@brief Option structure for GAP options. */
+typedef union {
+ ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */
+ ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */
+ ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/
+ ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/
+ ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/
+ ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */
+} ble_gap_opt_t;
+
+/**@brief Connection event triggering parameters. */
+typedef struct {
+ uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until
+ connection event PPI task triggering is stopped.
+ The PPI channel ID can not be one of the PPI channels reserved by
+ the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */
+ uint32_t task_endpoint; /**< Task Endpoint to trigger. */
+ uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */
+ uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767].
+ If the device is in slave role and slave latency is enabled,
+ this parameter should be set to a multiple of (slave latency + 1)
+ to ensure low power operation. */
+} ble_gap_conn_event_trigger_t;
+/**@} */
+
+/**@addtogroup BLE_GAP_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Set the local Bluetooth identity address.
+ *
+ * The local Bluetooth identity address is the address that identifies this device to other peers.
+ * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @note The identity address cannot be changed while advertising, scanning or creating a connection.
+ *
+ * @note This address will be distributed to the peer during bonding.
+ * If the address changes, the address stored in the peer device will not be valid and the ability to
+ * reconnect using the old address will be lost.
+ *
+ * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being
+ * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged
+ * for the lifetime of each IC.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_ADV_MSC}
+ * @endmscs
+ *
+ * @param[in] p_addr Pointer to address structure.
+ *
+ * @retval ::NRF_SUCCESS Address successfully set.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising,
+ * scanning or creating a connection.
+ */
+SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr));
+
+/**@brief Get local Bluetooth identity address.
+ *
+ * @note This will always return the identity address irrespective of the privacy settings,
+ * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @param[out] p_addr Pointer to address structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Address successfully retrieved.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied.
+ */
+SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr));
+
+/**@brief Get the Bluetooth device address used by the advertiser.
+ *
+ * @note This function will return the local Bluetooth address used in advertising PDUs. When
+ * using privacy, the SoftDevice will generate a new private address every
+ * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using
+ * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the
+ * address returned may not be the latest address that is used in the advertising PDUs.
+ *
+ * @param[in] adv_handle The advertising handle to get the address from.
+ * @param[out] p_addr Pointer to address structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Address successfully retrieved.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found.
+ * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising.
+ */
+SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr));
+
+/**@brief Set the active whitelist in the SoftDevice.
+ *
+ * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles.
+ * The whitelist cannot be set if a BLE role is using the whitelist.
+ *
+ * @note If an address is resolved using the information in the device identity list, then the whitelist
+ * filter policy applies to the peer identity address and not the resolvable address sent on air.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC}
+ * @endmscs
+ *
+ * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared.
+ * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ *
+ * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared.
+ * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid.
+ * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when
+ * pp_wl_addrs is not NULL.
+ */
+SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len));
+
+/**@brief Set device identity list.
+ *
+ * @note Only one device identity list can be used at a time and the list is shared between the BLE roles.
+ * The device identity list cannot be set if a BLE role is using the list.
+ *
+ * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will
+ * be cleared.
+ * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the
+ * same index. To fill in the list with the currently set device IRK for all peers, set to NULL.
+ * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS The device identity list successfully set/cleared.
+ * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid.
+ * This code may be returned if the local IRK list also has an invalid entry.
+ * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared.
+ * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity
+ * address.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can
+ * only return when pp_id_keys is not NULL.
+ */
+SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t,
+ sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks,
+ uint8_t len));
+
+/**@brief Set privacy settings.
+ *
+ * @note Privacy settings cannot be changed while advertising, scanning or creating a connection.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied.
+ * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid.
+ * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer.
+ * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution
+ characteristic is not configured to be included and the SoftDevice is configured
+ to support central roles.
+ See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t.
+ * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning
+ * or creating a connection.
+ */
+SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params));
+
+/**@brief Get privacy settings.
+ *
+ * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called.
+ * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return.
+ *
+ * @param[in,out] p_privacy_params Privacy settings.
+ *
+ * @retval ::NRF_SUCCESS Privacy settings read.
+ * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid.
+ * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer.
+ */
+SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params));
+
+/**@brief Configure an advertising set. Set, clear or update advertising and scan response data.
+ *
+ * @note The format of the advertising data will be checked by this call to ensure interoperability.
+ * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and
+ * duplicating the local name in the advertising data and scan response data.
+ *
+ * @note In order to update advertising data while advertising, new advertising buffers must be provided.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_ADV_MSC}
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @endmscs
+ *
+ * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref
+ * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the
+ * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set.
+ * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See
+ * @ref ble_gap_adv_data_t.
+ * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising
+ * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t.
+ *
+ * @retval ::NRF_SUCCESS Advertising set successfully configured.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied:
+ * - Invalid advertising data configuration specified. See @ref
+ * ble_gap_adv_data_t.
+ * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t.
+ * - Use of whitelist requested but whitelist has not been set,
+ * see @ref sd_ble_gap_whitelist_set.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - It is invalid to provide non-NULL advertising set parameters while
+ * advertising.
+ * - It is invalid to provide the same data buffers while advertising. To
+ * update advertising data, provide new advertising buffers.
+ * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible.
+ * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref
+ * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied.
+ * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format
+ * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11.
+ * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an
+ * existing advertising handle instead.
+ * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied.
+ */
+SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t,
+ sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data,
+ ble_gap_adv_params_t const *p_adv_params));
+
+/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure).
+ *
+ * @note Only one advertiser may be active at any time.
+ *
+ * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called.
+ * See @ref sd_ble_gap_privacy_set().
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.}
+ * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.}
+ * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_ADV_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC}
+ * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC}
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @endmscs
+ *
+ * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure.
+ * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or
+ * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable
+ * advertising, this is ignored.
+ *
+ * @retval ::NRF_SUCCESS The BLE stack has started advertising.
+ * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising.
+ * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration
+ * tag has been reached; connectable advertiser cannot be started.
+ * To increase the number of available connections,
+ * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP.
+ * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref
+ sd_ble_gap_adv_set_configure.
+ * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied:
+ * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t.
+ * - Use of whitelist requested but whitelist has not been set, see @ref
+ sd_ble_gap_whitelist_set.
+ * @retval ::NRF_ERROR_RESOURCES Either:
+ * - adv_handle is configured with connectable advertising, but the event_length parameter
+ * associated with conn_cfg_tag is too small to be able to establish a connection on
+ * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length.
+ * - Not enough BLE role slots available.
+ Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer)
+ and try again.
+ * - p_adv_params is configured with connectable advertising, but the event_length
+ parameter
+ * associated with conn_cfg_tag is too small to be able to establish a connection on
+ * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length.
+ */
+SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag));
+
+/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure).
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_ADV_MSC}
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @endmscs
+ *
+ * @param[in] adv_handle The advertising handle that should stop advertising.
+ *
+ * @retval ::NRF_SUCCESS The BLE stack has stopped advertising.
+ * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle.
+ * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising.
+ */
+SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle));
+
+/**@brief Update connection parameters.
+ *
+ * @details In the central role this will initiate a Link Layer connection parameter update procedure,
+ * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for
+ * the central to perform the procedure. In both cases, and regardless of success or failure, the application
+ * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event.
+ *
+ * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the
+ * procedure unrequested.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CPU_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC}
+ * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC}
+ * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role,
+ * the parameters in the PPCP characteristic of the GAP service will be used instead.
+ * If NULL is provided on a central role and in response to a @ref
+ * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected
+ *
+ * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints.
+ * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established.
+ * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ */
+SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t,
+ sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params));
+
+/**@brief Disconnect (GAP Link Termination).
+ *
+ * @details This call initiates the disconnection procedure, and its completion will be communicated to the application
+ * with a @ref BLE_GAP_EVT_DISCONNECTED event.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CONN_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref
+ * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE).
+ *
+ * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established.
+ */
+SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code));
+
+/**@brief Set the radio's transmit power.
+ *
+ * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for
+ * possible roles.
+ * @param[in] handle The handle parameter is interpreted depending on role:
+ * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle.
+ * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle,
+ * will use the specified transmit power, and include it in the advertising packet headers if
+ * @ref ble_gap_adv_properties_t::include_tx_power set.
+ * - For all other roles handle is ignored.
+ * @param[in] tx_power Radio transmit power in dBm (see note for accepted values).
+ *
+ * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm.
+ * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm.
+ * Setting these values on a chip that does not support them will result in undefined behaviour.
+ * @note The initiator will have the same transmit power as the scanner.
+ * @note When a connection is created it will inherit the transmit power from the initiator or
+ * advertiser leading to the connection.
+ *
+ * @retval ::NRF_SUCCESS Successfully changed the transmit power.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power));
+
+/**@brief Set GAP Appearance value.
+ *
+ * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES.
+ *
+ * @retval ::NRF_SUCCESS Appearance value set successfully.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ */
+SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance));
+
+/**@brief Get GAP Appearance value.
+ *
+ * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES.
+ *
+ * @retval ::NRF_SUCCESS Appearance value retrieved successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ */
+SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance));
+
+/**@brief Set GAP Peripheral Preferred Connection Parameters.
+ *
+ * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters.
+ *
+ * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table,
+ see @ref ble_gap_cfg_ppcp_incl_cfg_t.
+ */
+SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params));
+
+/**@brief Get GAP Peripheral Preferred Connection Parameters.
+ *
+ * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored.
+ *
+ * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table,
+ see @ref ble_gap_cfg_ppcp_incl_cfg_t.
+ */
+SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params));
+
+/**@brief Set GAP device name.
+ *
+ * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t),
+ * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned.
+ *
+ * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t.
+ * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string.
+ * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or
+ * equal than @ref BLE_GAP_DEVNAME_MAX_LEN).
+ *
+ * @retval ::NRF_SUCCESS GAP device name and permissions set successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
+ * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable.
+ */
+SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t,
+ sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len));
+
+/**@brief Get GAP device name.
+ *
+ * @note If the device name is longer than the size of the supplied buffer,
+ * p_len will return the complete device name length,
+ * and not the number of bytes actually returned in p_dev_name.
+ * The application may use this information to allocate a suitable buffer size.
+ *
+ * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to
+ * NULL to obtain the complete device name length.
+ * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output.
+ *
+ * @retval ::NRF_SUCCESS GAP device name retrieved successfully.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
+ */
+SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len));
+
+/**@brief Initiate the GAP Authentication procedure.
+ *
+ * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected),
+ * otherwise in the peripheral role, an SMP Security Request will be sent.
+ *
+ * @events
+ * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be
+ * generated:}
+ * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST}
+ * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST}
+ * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY}
+ * @event{@ref BLE_GAP_EVT_KEY_PRESSED}
+ * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST}
+ * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST}
+ * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE}
+ * @event{@ref BLE_GAP_EVT_AUTH_STATUS}
+ * @event{@ref BLE_GAP_EVT_TIMEOUT}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the
+ * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used.
+ * In the central role, this pointer may be NULL to reject a Security Request.
+ *
+ * @retval ::NRF_SUCCESS Successfully initiated authentication procedure.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - No link has been established.
+ * - An encryption is already executing or queued.
+ * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is
+ * reached.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported.
+ * Distribution of own Identity Information is only supported if the Central
+ * Address Resolution characteristic is configured to be included or
+ * the Softdevice is configured to support peripheral roles only.
+ * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t.
+ * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited.
+ */
+SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t,
+ sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params));
+
+/**@brief Reply with GAP security parameters.
+ *
+ * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in
+ * an @ref NRF_ERROR_INVALID_STATE.
+ * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected
+ * parameters.
+ *
+ * @events
+ * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref
+ * sd_ble_gap_authenticate.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS.
+ * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be
+ * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate.
+ * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or
+ * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this
+ * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event.
+ * Note that the SoftDevice expects the application to provide memory for storing the
+ * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The
+ * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application
+ * upon reception of the
+ * @ref BLE_GAP_EVT_AUTH_STATUS event.
+ *
+ * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported.
+ * Distribution of own Identity Information is only supported if the Central
+ * Address Resolution characteristic is configured to be included or
+ * the Softdevice is configured to support peripheral roles only.
+ * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t.
+ */
+SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t,
+ sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params,
+ ble_gap_sec_keyset_t const *p_sec_keyset));
+
+/**@brief Reply with an authentication key.
+ *
+ * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY,
+ * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE.
+ * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected
+ * parameters.
+ *
+ * @events
+ * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref
+ * sd_ble_gap_authenticate.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES.
+ * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL.
+ * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL
+ * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB,
+ * then a 16-byte OOB key value in little-endian format.
+ *
+ * @retval ::NRF_SUCCESS Authentication key successfully set.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t,
+ sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key));
+
+/**@brief Reply with an LE Secure connections DHKey.
+ *
+ * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in
+ * an @ref NRF_ERROR_INVALID_STATE.
+ * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected
+ * parameters.
+ *
+ * @events
+ * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref
+ * sd_ble_gap_authenticate.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_dhkey LE Secure Connections DHKey.
+ *
+ * @retval ::NRF_SUCCESS DHKey successfully set.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - The peer is not authenticated.
+ * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t,
+ sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey));
+
+/**@brief Notify the peer of a local keypress.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES.
+ *
+ * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - Authentication key not requested.
+ * - Passkey has not been entered.
+ * - Keypresses have not been enabled by both peers.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time.
+ */
+SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not));
+
+/**@brief Generate a set of OOB data to send to a peer out of band.
+ *
+ * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has
+ * already been established, the one used during connection setup). The application may manually overwrite it with an updated
+ * value.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet.
+ * @param[in] p_pk_own LE Secure Connections local P-256 Public Key.
+ * @param[out] p_oobd_own The OOB data to be sent out of band to a peer.
+ *
+ * @retval ::NRF_SUCCESS OOB data successfully generated.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t,
+ sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own,
+ ble_gap_lesc_oob_data_t *p_oobd_own));
+
+/**@brief Provide the OOB data sent/received out of band.
+ *
+ * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function.
+ * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this
+ * function.
+ *
+ * @events
+ * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref
+ * sd_ble_gap_authenticate.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data.
+ * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST.
+ * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received.
+ * Must correspond to @ref ble_gap_sec_params_t::oob flag
+ * in @ref sd_ble_gap_authenticate in the central role or
+ * in @ref sd_ble_gap_sec_params_reply in the peripheral role.
+ *
+ * @retval ::NRF_SUCCESS OOB data accepted.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - Authentication key not requested
+ * - Not expecting LESC OOB data
+ * - Have not actually exchanged passkeys.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t,
+ sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own,
+ ble_gap_lesc_oob_data_t const *p_oobd_peer));
+
+/**@brief Initiate GAP Encryption procedure.
+ *
+ * @details In the central role, this function will initiate the encryption procedure using the encryption information provided.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC}
+ * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure.
+ * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure.
+ *
+ * @retval ::NRF_SUCCESS Successfully initiated authentication procedure.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE No link has been established.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role.
+ * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and
+ * retry.
+ */
+SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t,
+ sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info));
+
+/**@brief Reply with GAP security information.
+ *
+ * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in
+ * @ref NRF_ERROR_INVALID_STATE.
+ * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected
+ * parameters.
+ * @note Data signing is not yet supported, and p_sign_info must therefore be NULL.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is
+ * available.
+ * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available.
+ * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is
+ * available.
+ *
+ * @retval ::NRF_SUCCESS Successfully accepted security information.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - No link has been established.
+ * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending.
+ * - Encryption information provided by the app without being requested. See @ref
+ * ble_gap_evt_sec_info_request_t::enc_info.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t,
+ sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info,
+ ble_gap_sign_info_t const *p_sign_info));
+
+/**@brief Get the current connection security.
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in.
+ *
+ * @retval ::NRF_SUCCESS Current connection security successfully retrieved.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec));
+
+/**@brief Start reporting the received signal strength to the application.
+ *
+ * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is
+ * dependent on the settings of the threshold_dbm
+ * and skip_count input parameters.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC}
+ * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are
+ * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID.
+ * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref
+ * BLE_GAP_EVT_RSSI_CHANGED event.
+ *
+ * @retval ::NRF_SUCCESS Successfully activated RSSI reporting.
+ * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count));
+
+/**@brief Stop reporting the received signal strength.
+ *
+ * @note An RSSI change detected before the call but not yet received by the application
+ * may be reported after @ref sd_ble_gap_rssi_stop has been called.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC}
+ * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ *
+ * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting.
+ * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ */
+SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle));
+
+/**@brief Get the received signal strength for the last connection event.
+ *
+ * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND
+ * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start.
+ * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement.
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored.
+ * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully read the RSSI.
+ * @retval ::NRF_ERROR_NOT_FOUND No sample is available.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing.
+ */
+SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index));
+
+/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure).
+ *
+ * @note A call to this function will require the application to keep the memory pointed by
+ * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped
+ * or when this function is called with another buffer.
+ *
+ * @note The scanner will automatically stop in the following cases:
+ * - @ref sd_ble_gap_scan_stop is called.
+ * - @ref sd_ble_gap_connect is called.
+ * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received.
+ * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to
+ * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application
+ * access received data. The application must call this function to continue scanning, or call @ref
+ * sd_ble_gap_scan_stop to stop scanning.
+ *
+ * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to
+ * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will
+ * receive more reports from this advertising event. The following reports will include the old and new received data.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.}
+ * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_SCAN_MSC}
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @endmscs
+ *
+ * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue
+ * scanning, this parameter must be NULL.
+ * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data.
+ * The memory pointed to should be kept alive until the scanning is stopped.
+ * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size.
+ * If the scanner receives advertising data larger than can be stored in the buffer,
+ * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status
+ * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED.
+ *
+ * @retval ::NRF_SUCCESS Successfully initiated scanning procedure.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either:
+ * - Scanning is already ongoing and p_scan_params was not NULL
+ * - Scanning is not running and p_scan_params was NULL.
+ * - The scanner has timed out when this function is called to continue scanning.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t.
+ * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN.
+ * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available.
+ * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again
+ */
+SVCALL(SD_BLE_GAP_SCAN_START, uint32_t,
+ sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer));
+
+/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure).
+ *
+ * @note The buffer provided in @ref sd_ble_gap_scan_start is released.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_SCAN_MSC}
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Successfully stopped scanning procedure.
+ * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state.
+ */
+SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void));
+
+/**@brief Create a connection (GAP Link Establishment).
+ *
+ * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function.
+ * The scanning procedure will be stopped even if the function returns an error.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.}
+ * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_WL_SHARE_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC}
+ * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC}
+ * @endmscs
+ *
+ * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use
+ * whitelist, then p_peer_addr is ignored.
+ * @param[in] p_scan_params Pointer to scan parameters structure.
+ * @param[in] p_conn_params Pointer to desired connection parameters.
+ * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or
+ * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration.
+ *
+ * @retval ::NRF_SUCCESS Successfully initiated connection procedure.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * - Invalid parameter(s) in p_scan_params or p_conn_params.
+ * - Use of whitelist requested but whitelist has not been set, see @ref
+ * sd_ble_gap_whitelist_set.
+ * - Peer address was not present in the device identity list, see @ref
+ * sd_ble_gap_device_identities_set.
+ * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found.
+ * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an
+ * existing locally initiated connect procedure, which must complete before initiating again.
+ * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address.
+ * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached.
+ * To increase the number of available connections,
+ * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP.
+ * @retval ::NRF_ERROR_RESOURCES Either:
+ * - Not enough BLE role slots available.
+ * Stop one or more currently active roles (Central, Peripheral or Observer) and try again.
+ * - The event_length parameter associated with conn_cfg_tag is too small to be able to
+ * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys.
+ * Use @ref sd_ble_cfg_set to increase the event length.
+ */
+SVCALL(SD_BLE_GAP_CONNECT, uint32_t,
+ sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params,
+ ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag));
+
+/**@brief Cancel a connection establishment.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure.
+ * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection
+ * completed occurred.
+ */
+SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void));
+
+/**@brief Initiate or respond to a PHY Update Procedure
+ *
+ * @details This function is used to initiate or respond to a PHY Update Procedure. It will always
+ * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed.
+ * If this function is used to initiate a PHY Update procedure and the only option
+ * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the
+ * currently active PHYs in the respective directions, the SoftDevice will generate a
+ * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the
+ * procedure in the Link Layer.
+ *
+ * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO,
+ * then the stack will select PHYs based on the peer's PHY preferences and the local link
+ * configuration. The PHY Update procedure will for this case result in a PHY combination
+ * that respects the time constraints configured with @ref sd_ble_cfg_set and the current
+ * link layer data length.
+ *
+ * When acting as a central, the SoftDevice will select the fastest common PHY in each direction.
+ *
+ * If the peer does not support the PHY Update Procedure, then the resulting
+ * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to
+ * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE.
+ *
+ * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status
+ * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or
+ * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION.
+ * If the peer responds to the PHY Update procedure with invalid parameters, the status
+ * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS.
+ * If the PHY Update procedure was rejected by the peer for a different reason, the status will
+ * contain the reason as specified by the peer.
+ *
+ * @events
+ * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE}
+ * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested.
+ * @param[in] p_gap_phys Pointer to PHY structure.
+ *
+ * @retval ::NRF_SUCCESS Successfully requested a PHY Update.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE No link has been established.
+ * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of
+ * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref
+ * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set.
+ * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the
+ * pending procedure to complete and retry.
+ *
+ */
+SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys));
+
+/**@brief Initiate or respond to a Data Length Update Procedure.
+ *
+ * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of
+ * p_dl_params, the SoftDevice will choose the highest value supported in current
+ * configuration and connection parameters.
+ * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime
+ * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and
+ * MaxRxTime will be limited to maximum 2120 us.
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update
+ * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let
+ * the SoftDevice automatically decide the value for that member.
+ * Set to NULL to use automatic values for all members.
+ * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not
+ * have enough resources or does not support the requested Data Length
+ * Update parameters. Ignored if NULL.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC}
+ * @endmscs
+ *
+ * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE No link has been established.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect
+ * p_dl_limitation to see which parameter is not supported.
+ * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested
+ * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation
+ * to see where the limitation is.
+ * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the
+ * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond.
+ */
+SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t,
+ sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params,
+ ble_gap_data_length_limitation_t *p_dl_limitation));
+
+/**@brief Start the Quality of Service (QoS) channel survey module.
+ *
+ * @details The channel survey module provides measurements of the energy levels on
+ * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT
+ * events will periodically report the measured energy levels for each channel.
+ *
+ * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles,
+ * Radio Timeslot API events and Flash API events.
+ *
+ * @note The channel survey module will attempt to do measurements so that the average interval
+ * between measurements will be interval_us. However due to the channel survey module
+ * having the lowest priority of all roles and modules, this may not be possible. In that
+ * case fewer than expected channel survey reports may be given.
+ *
+ * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available
+ * must be set. This is done using @ref sd_ble_cfg_set.
+ *
+ * @param[in] interval_us Requested average interval for the measurements and reports. See
+ * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set
+ * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel
+ * survey role will be scheduled at every available opportunity.
+ *
+ * @retval ::NRF_SUCCESS The module is successfully started.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the
+ * allowed range.
+ * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running.
+ * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application.
+ * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using
+ * @ref sd_ble_cfg_set.
+ */
+SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us));
+
+/**@brief Stop the Quality of Service (QoS) channel survey module.
+ *
+ * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this
+ * function is called.
+ *
+ * @retval ::NRF_SUCCESS The module is successfully stopped.
+ * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running.
+ */
+SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void));
+
+/**@brief Obtain the next connection event counter value.
+ *
+ * @details The connection event counter is initialized to zero on the first connection event. The value is incremented
+ * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B,
+ * Section 4.5.1.
+ *
+ * @note The connection event counter obtained through this API will be outdated if this API is called
+ * at the same time as the connection event counter is incremented.
+ *
+ * @note This API will always return the last connection event counter + 1.
+ * The actual connection event may be multiple connection events later if:
+ * - Slave latency is enabled and there is no data to transmit or receive.
+ * - Another role is scheduled with a higher priority at the same time as the next connection event.
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[out] p_counter Pointer to the variable where the next connection event counter will be written.
+ *
+ * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ */
+SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t,
+ sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter));
+
+/**@brief Start triggering a given task on connection event start.
+ *
+ * @details When enabled, this feature will trigger a PPI task at the start of connection events.
+ * The application can configure the SoftDevice to trigger every N connection events starting from
+ * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t.
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_params Connection event trigger parameters.
+ *
+ * @retval ::NRF_SUCCESS Success.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t.
+ * @retval ::NRF_ERROR_INVALID_STATE Either:
+ * - Trying to start connection event triggering when it is already ongoing.
+ * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past.
+ * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value
+ to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start.
+ */
+SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t,
+ sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params));
+
+/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start.
+ *
+ * @param[in] conn_handle Connection handle.
+ *
+ * @retval ::NRF_SUCCESS Success.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled.
+ */
+SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle));
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // BLE_GAP_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_gatt.h b/variants/xiao_ble/softdevice/ble_gatt.h
new file mode 100644
index 000000000..df0d728fc
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_gatt.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common
+ @{
+ @brief Common definitions and prototypes for the GATT interfaces.
+ */
+
+#ifndef BLE_GATT_H__
+#define BLE_GATT_H__
+
+#include "ble_err.h"
+#include "ble_hci.h"
+#include "ble_ranges.h"
+#include "ble_types.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup BLE_GATT_DEFINES Defines
+ * @{ */
+
+/** @brief Default ATT MTU, in bytes. */
+#define BLE_GATT_ATT_MTU_DEFAULT 23
+
+/**@brief Invalid Attribute Handle. */
+#define BLE_GATT_HANDLE_INVALID 0x0000
+
+/**@brief First Attribute Handle. */
+#define BLE_GATT_HANDLE_START 0x0001
+
+/**@brief Last Attribute Handle. */
+#define BLE_GATT_HANDLE_END 0xFFFF
+
+/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources
+ * @{ */
+#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */
+/** @} */
+
+/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations
+ * @{ */
+#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */
+#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */
+#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */
+#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */
+#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */
+#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */
+/** @} */
+
+/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags
+ * @{ */
+#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */
+#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */
+/** @} */
+
+/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations
+ * @{ */
+#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */
+#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */
+#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */
+/** @} */
+
+/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes
+ * @{ */
+#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */
+#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */
+#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */
+#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */
+#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */
+#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */
+#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */
+#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */
+#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */
+#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */
+#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */
+#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */
+#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */
+#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \
+ 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */
+#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */
+#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */
+#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */
+#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */
+#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \
+ 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */
+#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */
+#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */
+#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */
+#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */
+#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \
+ 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \
+ */
+#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \
+ 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */
+#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \
+ 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */
+#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */
+/** @} */
+
+/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats
+ * @note Found at
+ * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
+ * @{ */
+#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */
+#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */
+#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */
+#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */
+#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */
+#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */
+#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */
+#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */
+#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */
+#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */
+#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */
+#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */
+#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */
+#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */
+/** @} */
+
+/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces
+ * @{
+ */
+#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */
+#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */
+/** @} */
+
+/** @} */
+
+/** @addtogroup BLE_GATT_STRUCTURES Structures
+ * @{ */
+
+/**
+ * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set.
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT.
+ */
+typedef struct {
+ uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive.
+ The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT.
+ @mscs
+ @mmsc{@ref BLE_GATTC_MTU_EXCHANGE}
+ @mmsc{@ref BLE_GATTS_MTU_EXCHANGE}
+ @endmscs
+ */
+} ble_gatt_conn_cfg_t;
+
+/**@brief GATT Characteristic Properties. */
+typedef struct {
+ /* Standard properties */
+ uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */
+ uint8_t read : 1; /**< Reading the value permitted. */
+ uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */
+ uint8_t write : 1; /**< Writing the value with Write Request permitted. */
+ uint8_t notify : 1; /**< Notification of the value permitted. */
+ uint8_t indicate : 1; /**< Indications of the value permitted. */
+ uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */
+} ble_gatt_char_props_t;
+
+/**@brief GATT Characteristic Extended Properties. */
+typedef struct {
+ /* Extended properties */
+ uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */
+ uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */
+} ble_gatt_char_ext_props_t;
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // BLE_GATT_H__
+
+/** @} */
diff --git a/variants/xiao_ble/softdevice/ble_gattc.h b/variants/xiao_ble/softdevice/ble_gattc.h
new file mode 100644
index 000000000..f1df1782c
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_gattc.h
@@ -0,0 +1,764 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client
+ @{
+ @brief Definitions and prototypes for the GATT Client interface.
+ */
+
+#ifndef BLE_GATTC_H__
+#define BLE_GATTC_H__
+
+#include "ble_err.h"
+#include "ble_gatt.h"
+#include "ble_ranges.h"
+#include "ble_types.h"
+#include "nrf.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations
+ * @{ */
+
+/**@brief GATTC API SVC numbers. */
+enum BLE_GATTC_SVCS {
+ SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */
+ SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */
+ SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */
+ SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */
+ SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */
+ SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */
+ SD_BLE_GATTC_READ, /**< Generic read. */
+ SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */
+ SD_BLE_GATTC_WRITE, /**< Generic write. */
+ SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */
+ SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */
+};
+
+/**
+ * @brief GATT Client Event IDs.
+ */
+enum BLE_GATTC_EVTS {
+ BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref
+ ble_gattc_evt_prim_srvc_disc_rsp_t. */
+ BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t.
+ */
+ BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref
+ ble_gattc_evt_char_disc_rsp_t. */
+ BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref
+ ble_gattc_evt_desc_disc_rsp_t. */
+ BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref
+ ble_gattc_evt_attr_info_disc_rsp_t. */
+ BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref
+ ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
+ BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */
+ BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref
+ ble_gattc_evt_char_vals_read_rsp_t. */
+ BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */
+ BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref
+ sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */
+ BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref
+ ble_gattc_evt_exchange_mtu_rsp_t. */
+ BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */
+ BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref
+ ble_gattc_evt_write_cmd_tx_complete_t. */
+};
+
+/**@brief GATTC Option IDs.
+ * IDs that uniquely identify a GATTC option.
+ */
+enum BLE_GATTC_OPTS {
+ BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */
+};
+
+/** @} */
+
+/** @addtogroup BLE_GATTC_DEFINES Defines
+ * @{ */
+
+/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC
+ * @{ */
+#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */
+/** @} */
+
+/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats
+ * @{ */
+#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */
+#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */
+/** @} */
+
+/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults
+ * @{ */
+#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \
+ 1 /**< Default number of Write without Response that can be queued for transmission. */
+/** @} */
+
+/** @} */
+
+/** @addtogroup BLE_GATTC_STRUCTURES Structures
+ * @{ */
+
+/**
+ * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set.
+ */
+typedef struct {
+ uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for
+ transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */
+} ble_gattc_conn_cfg_t;
+
+/**@brief Operation Handle Range. */
+typedef struct {
+ uint16_t start_handle; /**< Start Handle. */
+ uint16_t end_handle; /**< End Handle. */
+} ble_gattc_handle_range_t;
+
+/**@brief GATT service. */
+typedef struct {
+ ble_uuid_t uuid; /**< Service UUID. */
+ ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
+} ble_gattc_service_t;
+
+/**@brief GATT include. */
+typedef struct {
+ uint16_t handle; /**< Include Handle. */
+ ble_gattc_service_t included_srvc; /**< Handle of the included service. */
+} ble_gattc_include_t;
+
+/**@brief GATT characteristic. */
+typedef struct {
+ ble_uuid_t uuid; /**< Characteristic UUID. */
+ ble_gatt_char_props_t char_props; /**< Characteristic Properties. */
+ uint8_t char_ext_props : 1; /**< Extended properties present. */
+ uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */
+ uint16_t handle_value; /**< Handle of the Characteristic Value. */
+} ble_gattc_char_t;
+
+/**@brief GATT descriptor. */
+typedef struct {
+ uint16_t handle; /**< Descriptor Handle. */
+ ble_uuid_t uuid; /**< Descriptor UUID. */
+} ble_gattc_desc_t;
+
+/**@brief Write Parameters. */
+typedef struct {
+ uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */
+ uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */
+ uint16_t handle; /**< Handle to the attribute to be written. */
+ uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */
+ uint16_t len; /**< Length of data in bytes. */
+ uint8_t const *p_value; /**< Pointer to the value data. */
+} ble_gattc_write_params_t;
+
+/**@brief Attribute Information for 16-bit Attribute UUID. */
+typedef struct {
+ uint16_t handle; /**< Attribute handle. */
+ ble_uuid_t uuid; /**< 16-bit Attribute UUID. */
+} ble_gattc_attr_info16_t;
+
+/**@brief Attribute Information for 128-bit Attribute UUID. */
+typedef struct {
+ uint16_t handle; /**< Attribute handle. */
+ ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */
+} ble_gattc_attr_info128_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */
+typedef struct {
+ uint16_t count; /**< Service count. */
+ ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use
+ event structures with variable length array members. */
+} ble_gattc_evt_prim_srvc_disc_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */
+typedef struct {
+ uint16_t count; /**< Include count. */
+ ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use
+ event structures with variable length array members. */
+} ble_gattc_evt_rel_disc_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */
+typedef struct {
+ uint16_t count; /**< Characteristic count. */
+ ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event
+ structures with variable length array members. */
+} ble_gattc_evt_char_disc_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */
+typedef struct {
+ uint16_t count; /**< Descriptor count. */
+ ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event
+ structures with variable length array members. */
+} ble_gattc_evt_desc_disc_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */
+typedef struct {
+ uint16_t count; /**< Attribute count. */
+ uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */
+ union {
+ ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID.
+ @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on
+ how to use event structures with variable length array members. */
+ ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID.
+ @note This is a variable length array. The size of 1 indicated is only a
+ placeholder for compilation. See @ref sd_ble_evt_get for more information on
+ how to use event structures with variable length array members. */
+ } info; /**< Attribute information union. */
+} ble_gattc_evt_attr_info_disc_rsp_t;
+
+/**@brief GATT read by UUID handle value pair. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+ uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref
+ ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */
+} ble_gattc_handle_value_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */
+typedef struct {
+ uint16_t count; /**< Handle-Value Pair Count. */
+ uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */
+ uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref
+ sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter.
+ @note This is a variable length array. The size of 1 indicated is only a placeholder for
+ compilation. See @ref sd_ble_evt_get for more information on how to use event structures with
+ variable length array members. */
+} ble_gattc_evt_char_val_by_uuid_read_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+ uint16_t offset; /**< Offset of the attribute data. */
+ uint16_t len; /**< Attribute data length. */
+ uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for
+ compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable
+ length array members. */
+} ble_gattc_evt_read_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */
+typedef struct {
+ uint16_t len; /**< Concatenated Attribute values length. */
+ uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder
+ for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with
+ variable length array members. */
+} ble_gattc_evt_char_vals_read_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+ uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */
+ uint16_t offset; /**< Data offset. */
+ uint16_t len; /**< Data length. */
+ uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for
+ compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable
+ length array members. */
+} ble_gattc_evt_write_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */
+typedef struct {
+ uint16_t handle; /**< Handle to which the HVx operation applies. */
+ uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
+ uint16_t len; /**< Attribute data length. */
+ uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for
+ compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable
+ length array members. */
+} ble_gattc_evt_hvx_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */
+typedef struct {
+ uint16_t server_rx_mtu; /**< Server RX MTU size. */
+} ble_gattc_evt_exchange_mtu_rsp_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */
+typedef struct {
+ uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */
+} ble_gattc_evt_timeout_t;
+
+/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */
+typedef struct {
+ uint8_t count; /**< Number of write without response transmissions completed. */
+} ble_gattc_evt_write_cmd_tx_complete_t;
+
+/**@brief GATTC event structure. */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle on which event occurred. */
+ uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */
+ uint16_t
+ error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */
+ union {
+ ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */
+ ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */
+ ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */
+ ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */
+ ble_gattc_evt_char_val_by_uuid_read_rsp_t
+ char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */
+ ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */
+ ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */
+ ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */
+ ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */
+ ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */
+ ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */
+ ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */
+ ble_gattc_evt_write_cmd_tx_complete_t
+ write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */
+ } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */
+} ble_gattc_evt_t;
+
+/**@brief UUID discovery option.
+ *
+ * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the
+ * Vendor Specific UUID table. Disabled by default.
+ * - When disabled, if a procedure initiated by
+ * @ref sd_ble_gattc_primary_services_discover,
+ * @ref sd_ble_gattc_relationships_discover,
+ * @ref sd_ble_gattc_characteristics_discover,
+ * @ref sd_ble_gattc_descriptors_discover
+ * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set
+ * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event.
+ * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use
+ * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding
+ * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will
+ * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event.
+ * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove.
+ *
+ * @note @ref sd_ble_opt_get is not supported for this option.
+ *
+ * @retval ::NRF_SUCCESS Set successfully.
+ *
+ */
+typedef struct {
+ uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */
+} ble_gattc_opt_uuid_disc_t;
+
+/**@brief Option structure for GATTC options. */
+typedef union {
+ ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */
+} ble_gattc_opt_t;
+
+/** @} */
+
+/** @addtogroup BLE_GATTC_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Initiate or continue a GATT Primary Service Discovery procedure.
+ *
+ * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle.
+ * If the last service has not been reached, this function must be called again with an updated start handle value to
+ * continue the search. See also @ref ble_gattc_opt_uuid_disc_t.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] start_handle Handle to start searching from.
+ * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t,
+ sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid));
+
+/**@brief Initiate or continue a GATT Relationship Discovery procedure.
+ *
+ * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been
+ * reached, this must be called again with an updated handle range to continue the search. See also @ref
+ * ble_gattc_opt_uuid_disc_t.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_REL_DISC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t,
+ sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
+
+/**@brief Initiate or continue a GATT Characteristic Discovery procedure.
+ *
+ * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been
+ * reached, this must be called again with an updated handle range to continue the discovery. See also @ref
+ * ble_gattc_opt_uuid_disc_t.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t,
+ sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
+
+/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure.
+ *
+ * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not
+ * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref
+ * ble_gattc_opt_uuid_disc_t.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t,
+ sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
+
+/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure.
+ *
+ * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been
+ * reached, this must be called again with an updated handle range to continue the discovery.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_READ_UUID_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_uuid Pointer to a Characteristic value UUID to read.
+ * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t,
+ sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid,
+ ble_gattc_handle_range_t const *p_handle_range));
+
+/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure.
+ *
+ * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or
+ * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read
+ * the complete value.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_READ_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] handle The handle of the attribute to be read.
+ * @param[in] offset Offset into the attribute value to be read.
+ *
+ * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset));
+
+/**@brief Initiate a GATT Read Multiple Characteristic Values procedure.
+ *
+ * @details This function initiates a GATT Read Multiple Characteristic Values procedure.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_READ_MULT_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read.
+ * @param[in] handle_count The number of handles in p_handles.
+ *
+ * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t,
+ sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count));
+
+/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable)
+ * procedure.
+ *
+ * @details This function can perform all write procedures described in GATT.
+ *
+ * @note Only one write with response procedure can be ongoing per connection at a time.
+ * If the application tries to write with response while another write with response procedure is ongoing,
+ * the function call will return @ref NRF_ERROR_BUSY.
+ * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer.
+ *
+ * @note The number of Write without Response that can be queued is configured by @ref
+ * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES.
+ * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without
+ * response is complete.
+ *
+ * @note The application can keep track of the available queue element count for writes without responses by following the
+ * procedure below:
+ * - Store initial queue element count in a variable.
+ * - Decrement the variable, which stores the currently available queue element count, by one when a call to this
+ * function returns @ref NRF_SUCCESS.
+ * - Increment the variable, which stores the current available queue element count, by the count variable in @ref
+ * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.}
+ * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC}
+ * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC}
+ * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC}
+ * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_write_params A pointer to a write parameters structure.
+ *
+ * @retval ::NRF_SUCCESS Successfully started the Write procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
+ * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event
+ * and retry.
+ * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued.
+ * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params));
+
+/**@brief Send a Handle Value Confirmation to the GATT Server.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_HVI_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] handle The handle of the attribute in the indication.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed.
+ * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle));
+
+/**@brief Discovers information about a range of attributes on a GATT server.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.}
+ * @endevents
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] p_handle_range The range of handles to request information about.
+ *
+ * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t,
+ sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
+
+/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server.
+ *
+ * @details The SoftDevice sets ATT_MTU to the minimum of:
+ * - The Client RX MTU value, and
+ * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP.
+ *
+ * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT.
+ *
+ * @events
+ * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] client_rx_mtu Client RX MTU size.
+ * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT.
+ * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration
+ used for this connection.
+ * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply
+ * if an ATT_MTU exchange has already been performed in the other direction.
+ *
+ * @retval ::NRF_SUCCESS Successfully sent request to the server.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied.
+ * @retval ::NRF_ERROR_BUSY Client procedure already in progress.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t,
+ sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu));
+
+/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event.
+ *
+ * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event.
+ * @note If the buffer contains different event, behavior is undefined.
+ * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with
+ * the next Handle-Value pair in each iteration. If the function returns other than
+ * @ref NRF_SUCCESS, it will not be changed.
+ * - To start iteration, initialize the structure to zero.
+ * - To continue, pass the value from previous iteration.
+ *
+ * \code
+ * ble_gattc_handle_value_t iter;
+ * memset(&iter, 0, sizeof(ble_gattc_handle_value_t));
+ * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS)
+ * {
+ * app_handle = iter.handle;
+ * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len);
+ * }
+ * \endcode
+ *
+ * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair.
+ * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list.
+ */
+__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt,
+ ble_gattc_handle_value_t *p_iter);
+
+/** @} */
+
+#ifndef SUPPRESS_INLINE_IMPLEMENTATION
+
+__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt,
+ ble_gattc_handle_value_t *p_iter)
+{
+ uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len;
+ uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value;
+ uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first;
+
+ if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) {
+ p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0];
+ p_iter->p_value = p_next + sizeof(uint16_t);
+ return NRF_SUCCESS;
+ } else {
+ return NRF_ERROR_NOT_FOUND;
+ }
+}
+
+#endif /* SUPPRESS_INLINE_IMPLEMENTATION */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* BLE_GATTC_H__ */
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_gatts.h b/variants/xiao_ble/softdevice/ble_gatts.h
new file mode 100644
index 000000000..dc94957cd
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_gatts.h
@@ -0,0 +1,904 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server
+ @{
+ @brief Definitions and prototypes for the GATTS interface.
+ */
+
+#ifndef BLE_GATTS_H__
+#define BLE_GATTS_H__
+
+#include "ble_err.h"
+#include "ble_gap.h"
+#include "ble_gatt.h"
+#include "ble_hci.h"
+#include "ble_ranges.h"
+#include "ble_types.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations
+ * @{ */
+
+/**
+ * @brief GATTS API SVC numbers.
+ */
+enum BLE_GATTS_SVCS {
+ SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */
+ SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */
+ SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */
+ SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */
+ SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */
+ SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */
+ SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */
+ SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */
+ SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more
+ attributes. */
+ SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */
+ SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */
+ SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */
+ SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */
+ SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */
+};
+
+/**
+ * @brief GATT Server Event IDs.
+ */
+enum BLE_GATTS_EVTS {
+ BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See
+ @ref ble_gatts_evt_write_t. */
+ BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with
+ @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t.
+ */
+ BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref
+ sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */
+ BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t.
+ */
+ BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event
+ structure applies. */
+ BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with
+ @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t.
+ */
+ BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref
+ ble_gatts_evt_timeout_t. */
+ BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref
+ ble_gatts_evt_hvn_tx_complete_t. */
+};
+
+/**@brief GATTS Configuration IDs.
+ *
+ * IDs that uniquely identify a GATTS configuration.
+ */
+enum BLE_GATTS_CFGS {
+ BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */
+ BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */
+ BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */
+};
+
+/** @} */
+
+/** @addtogroup BLE_GATTS_DEFINES Defines
+ * @{ */
+
+/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS
+ * @{ */
+#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */
+#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */
+/** @} */
+
+/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths
+ * @{ */
+#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */
+#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */
+/** @} */
+
+/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types
+ * @{ */
+#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */
+#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */
+#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */
+/** @} */
+
+/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types
+ * @{ */
+#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */
+#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */
+#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */
+#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */
+#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */
+#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */
+#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */
+#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */
+/** @} */
+
+/** @defgroup BLE_GATTS_OPS GATT Server Operations
+ * @{ */
+#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */
+#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */
+#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */
+#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */
+#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */
+#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */
+#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */
+/** @} */
+
+/** @defgroup BLE_GATTS_VLOCS GATT Value Locations
+ * @{ */
+#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */
+#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */
+#define BLE_GATTS_VLOC_USER \
+ 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \
+ of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \
+ There are no alignment requirements for the buffer. */
+/** @} */
+
+/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types
+ * @{ */
+#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */
+#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */
+#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */
+/** @} */
+
+/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags
+ * @{ */
+#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */
+#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */
+/** @} */
+
+/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values
+ * @{
+ */
+#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \
+ (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */
+/** @} */
+
+/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size
+ * @{
+ */
+#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */
+#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */
+/** @} */
+
+/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults
+ * @{
+ */
+#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \
+ 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */
+/** @} */
+
+/** @} */
+
+/** @addtogroup BLE_GATTS_STRUCTURES Structures
+ * @{ */
+
+/**
+ * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set.
+ */
+typedef struct {
+ uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission.
+ The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */
+} ble_gatts_conn_cfg_t;
+
+/**@brief Attribute metadata. */
+typedef struct {
+ ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
+ ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
+ uint8_t vlen : 1; /**< Variable length attribute. */
+ uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/
+ uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */
+ uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not
+ Write Command). */
+} ble_gatts_attr_md_t;
+
+/**@brief GATT Attribute. */
+typedef struct {
+ ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */
+ ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */
+ uint16_t init_len; /**< Initial attribute value length in bytes. */
+ uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the
+ attribute value will be left uninitialized. */
+ uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
+ uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is
+ selected in the attribute metadata, this will have to point to a buffer that remains valid through the
+ lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any
+ other temporary location. The stack may access that memory directly without the application's
+ knowledge. For writable characteristics, this value must not be a location in flash memory.*/
+} ble_gatts_attr_t;
+
+/**@brief GATT Attribute Value. */
+typedef struct {
+ uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/
+ uint16_t offset; /**< Attribute value offset. */
+ uint8_t *p_value; /**< Pointer to where value is stored or will be stored.
+ If value is stored in user memory, only the attribute length is updated when p_value == NULL.
+ Set to NULL when reading to obtain the complete length of the attribute value */
+} ble_gatts_value_t;
+
+/**@brief GATT Characteristic Presentation Format. */
+typedef struct {
+ uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */
+ int8_t exponent; /**< Exponent for integer data types. */
+ uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */
+ uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
+ uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
+} ble_gatts_char_pf_t;
+
+/**@brief GATT Characteristic metadata. */
+typedef struct {
+ ble_gatt_char_props_t char_props; /**< Characteristic Properties. */
+ ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */
+ uint8_t const *
+ p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */
+ uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */
+ uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */
+ ble_gatts_char_pf_t const
+ *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */
+ ble_gatts_attr_md_t const
+ *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */
+ ble_gatts_attr_md_t const
+ *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */
+ ble_gatts_attr_md_t const
+ *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */
+} ble_gatts_char_md_t;
+
+/**@brief GATT Characteristic Definition Handles. */
+typedef struct {
+ uint16_t value_handle; /**< Handle to the characteristic value. */
+ uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */
+ uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if
+ not present. */
+ uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if
+ not present. */
+} ble_gatts_char_handles_t;
+
+/**@brief GATT HVx parameters. */
+typedef struct {
+ uint16_t handle; /**< Characteristic Value Handle. */
+ uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
+ uint16_t offset; /**< Offset within the attribute value. */
+ uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */
+ uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */
+} ble_gatts_hvx_params_t;
+
+/**@brief GATT Authorization parameters. */
+typedef struct {
+ uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */
+ uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value.
+ Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set,
+ as the data to be written needs to be stored and later provided by the application. */
+ uint16_t offset; /**< Offset of the attribute value being updated. */
+ uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */
+ uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */
+} ble_gatts_authorize_params_t;
+
+/**@brief GATT Read or Write Authorize Reply parameters. */
+typedef struct {
+ uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */
+ union {
+ ble_gatts_authorize_params_t read; /**< Read authorization parameters. */
+ ble_gatts_authorize_params_t write; /**< Write authorization parameters. */
+ } params; /**< Reply Parameters. */
+} ble_gatts_rw_authorize_reply_params_t;
+
+/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */
+typedef struct {
+ uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref
+ BLE_GATTS_SERVICE_CHANGED_DEFAULT. */
+} ble_gatts_cfg_service_changed_t;
+
+/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set.
+ *
+ * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0.
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
+ * - @ref ble_gatts_attr_md_t::write_perm is out of range.
+ * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is
+ * not allowed by the Bluetooth Specification.
+ * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is
+ * allowed by the Bluetooth Specification.
+ * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported
+ */
+typedef struct {
+ ble_gatts_attr_md_t
+ perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */
+} ble_gatts_cfg_service_changed_cccd_perm_t;
+
+/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set.
+ *
+ * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true:
+ * - The specified Attribute Table size is too small.
+ * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN.
+ * - The specified Attribute Table size is not a multiple of 4.
+ */
+typedef struct {
+ uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref
+ BLE_GATTS_ATTR_TAB_SIZE_MIN. */
+} ble_gatts_cfg_attr_tab_size_t;
+
+/**@brief Config structure for GATTS configurations. */
+typedef union {
+ ble_gatts_cfg_service_changed_t
+ service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */
+ ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref
+ BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */
+ ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */
+} ble_gatts_cfg_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+ ble_uuid_t uuid; /**< Attribute UUID. */
+ uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */
+ uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref
+ sd_ble_gatts_value_set to finalize the writing operation. */
+ uint16_t offset; /**< Offset for the write operation. */
+ uint16_t len; /**< Length of the received data. */
+ uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for
+ compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable
+ length array members. */
+} ble_gatts_evt_write_t;
+
+/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+ ble_uuid_t uuid; /**< Attribute UUID. */
+ uint16_t offset; /**< Offset for the read operation. */
+} ble_gatts_evt_read_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */
+typedef struct {
+ uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */
+ union {
+ ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */
+ ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */
+ } request; /**< Request Parameters. */
+} ble_gatts_evt_rw_authorize_request_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */
+typedef struct {
+ uint8_t hint; /**< Hint (currently unused). */
+} ble_gatts_evt_sys_attr_missing_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */
+typedef struct {
+ uint16_t handle; /**< Attribute Handle. */
+} ble_gatts_evt_hvc_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */
+typedef struct {
+ uint16_t client_rx_mtu; /**< Client RX MTU size. */
+} ble_gatts_evt_exchange_mtu_request_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */
+typedef struct {
+ uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */
+} ble_gatts_evt_timeout_t;
+
+/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */
+typedef struct {
+ uint8_t count; /**< Number of notification transmissions completed. */
+} ble_gatts_evt_hvn_tx_complete_t;
+
+/**@brief GATTS event structure. */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle on which the event occurred. */
+ union {
+ ble_gatts_evt_write_t write; /**< Write Event Parameters. */
+ ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */
+ ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */
+ ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */
+ ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */
+ ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */
+ ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */
+ } params; /**< Event Parameters. */
+} ble_gatts_evt_t;
+
+/** @} */
+
+/** @addtogroup BLE_GATTS_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Add a service declaration to the Attribute Table.
+ *
+ * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to
+ * add a secondary service declaration that is not referenced by another service later in the Attribute Table.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
+ * @endmscs
+ *
+ * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES.
+ * @param[in] p_uuid Pointer to service UUID.
+ * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully added a service declaration.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table.
+ * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ */
+SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle));
+
+/**@brief Add an include declaration to the Attribute Table.
+ *
+ * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is
+ * supported at this time).
+ *
+ * @note The included service must already be present in the Attribute Table prior to this call.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
+ * @endmscs
+ *
+ * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID
+ * is used, it will be placed sequentially.
+ * @param[in] inc_srvc_handle Handle of the included service.
+ * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully added an include declaration.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service.
+ * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
+ */
+SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t,
+ sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle));
+
+/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations
+ * to the Attribute Table.
+ *
+ * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is
+ * supported at this time).
+ *
+ * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and
+ * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format
+ * values.
+ *
+ * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic
+ * permissions.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
+ * @endmscs
+ *
+ * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is
+ * used, it will be placed sequentially.
+ * @param[in] p_char_md Characteristic metadata.
+ * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value.
+ * @param[out] p_handles Pointer to the structure where the assigned handles will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully added a characteristic.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and
+ * permissions need to adhere to the constraints.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required.
+ * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
+ */
+SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t,
+ sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md,
+ ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles));
+
+/**@brief Add a descriptor to the Attribute Table.
+ *
+ * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is
+ * supported at this time).
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
+ * @endmscs
+ *
+ * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is
+ * used, it will be placed sequentially.
+ * @param[in] p_attr Pointer to the attribute structure.
+ * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully added a descriptor.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and
+ * permissions need to adhere to the constraints.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required.
+ * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
+ */
+SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t,
+ sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle));
+
+/**@brief Set the value of a given attribute.
+ *
+ * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute.
+ * @param[in] handle Attribute handle.
+ * @param[in,out] p_value Attribute value information.
+ *
+ * @retval ::NRF_SUCCESS Successfully set the value of the attribute.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
+ * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute.
+ */
+SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t,
+ sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value));
+
+/**@brief Get the value of a given attribute.
+ *
+ * @note If the attribute value is longer than the size of the supplied buffer,
+ * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset),
+ * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value.
+ * The application may use this information to allocate a suitable buffer size.
+ *
+ * @note When retrieving system attribute values with this function, the connection handle
+ * may refer to an already disconnected connection. Refer to the documentation of
+ * @ref sd_ble_gatts_sys_attr_get for further information.
+ *
+ * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute.
+ * @param[in] handle Attribute handle.
+ * @param[in,out] p_value Attribute value information.
+ *
+ * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute.
+ * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known
+ * value.
+ */
+SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t,
+ sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value));
+
+/**@brief Notify or Indicate an attribute value.
+ *
+ * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant
+ * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before
+ * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single
+ * API call.
+ *
+ * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during
+ * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE,
+ * @ref NRF_ERROR_BUSY,
+ * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES.
+ * The caller can check whether the value has been updated by looking at the contents of *(@ref
+ * ble_gatts_hvx_params_t::p_len).
+ *
+ * @note Only one indication procedure can be ongoing per connection at a time.
+ * If the application tries to indicate an attribute value while another indication procedure is ongoing,
+ * the function call will return @ref NRF_ERROR_BUSY.
+ * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer.
+ *
+ * @note The number of Handle Value Notifications that can be queued is configured by @ref
+ * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref
+ * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete.
+ *
+ * @note The application can keep track of the available queue element count for notifications by following the procedure
+ * below:
+ * - Store initial queue element count in a variable.
+ * - Decrement the variable, which stores the currently available queue element count, by one when a call to this
+ * function returns @ref NRF_SUCCESS.
+ * - Increment the variable, which stores the current available queue element count, by the count variable in @ref
+ * BLE_GATTS_EVT_HVN_TX_COMPLETE event.
+ *
+ * @events
+ * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.}
+ * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC}
+ * @mmsc{@ref BLE_GATTS_HVN_MSC}
+ * @mmsc{@ref BLE_GATTS_HVI_MSC}
+ * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data
+ * contains a non-NULL pointer the attribute value will be updated with the contents
+ * pointed by it before sending the notification or indication. If the attribute value
+ * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to
+ * contain the number of actual bytes written, else it will be set to 0.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute
+ * value.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true:
+ * - Invalid Connection State
+ * - Notifications and/or indications not enabled in the CCCD
+ * - An ATT_MTU exchange is ongoing
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application
+ * are available to notify and indicate.
+ * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and
+ * indicated.
+ * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
+ * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions
+ * of the CCCD associated with this characteristic.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
+ * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC
+ * event and retry.
+ * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known
+ * value.
+ * @retval ::NRF_ERROR_RESOURCES Too many notifications queued.
+ * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params));
+
+/**@brief Indicate the Service Changed attribute value.
+ *
+ * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute
+ * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will
+ * be issued.
+ *
+ * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here.
+ *
+ * @events
+ * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_SC_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] start_handle Start of affected attribute handle range.
+ * @param[in] end_handle End of affected attribute handle range.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref
+ * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t.
+ * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true:
+ * - Invalid Connection State
+ * - Notifications and/or indications not enabled in the CCCD
+ * - An ATT_MTU exchange is ongoing
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the
+ * application.
+ * @retval ::NRF_ERROR_BUSY Procedure already in progress.
+ * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known
+ * value.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t,
+ sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle));
+
+/**@brief Respond to a Read/Write authorization request.
+ *
+ * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
+ * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application.
+ *
+ * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond
+ * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update
+ * is set to 0.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute
+ * Table updated.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending.
+ * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid,
+ * handle supplied does not match requested handle,
+ * or invalid data to be written provided by the application.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t,
+ sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle,
+ ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params));
+
+/**@brief Update persistent system attribute information.
+ *
+ * @details Supply information about persistent system attributes to the stack,
+ * previously obtained using @ref sd_ble_gatts_sys_attr_get.
+ * This call is only allowed for active connections, and is usually
+ * made immediately after a connection is established with an known bonded device,
+ * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING.
+ *
+ * p_sysattrs may point directly to the application's stored copy of the system attributes
+ * obtained using @ref sd_ble_gatts_sys_attr_get.
+ * If the pointer is NULL, the system attribute info is initialized, assuming that
+ * the application does not have any previously saved system attribute data for this device.
+ *
+ * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration.
+ *
+ * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may
+ * have been completed only partially. This means that the state of the attribute table is undefined, and the application should
+ * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state.
+ *
+ * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system
+ * services will be modified.
+ * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user
+ * services will be modified.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC}
+ * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC}
+ * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle.
+ * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL.
+ * @param[in] len Size of data pointed by p_sys_attr_data, in octets.
+ * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS
+ *
+ * @retval ::NRF_SUCCESS Successfully set the system attribute information.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied.
+ * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref
+ * sd_ble_gatts_sys_attr_get.
+ * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
+ */
+SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t,
+ sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags));
+
+/**@brief Retrieve persistent system attribute information from the stack.
+ *
+ * @details This call is used to retrieve information about values to be stored persistently by the application
+ * during the lifetime of a connection or after it has been terminated. When a new connection is established with the
+ * same bonded device, the system attribute information retrieved with this function should be restored using using @ref
+ * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The
+ * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API
+ * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the
+ * system attributes may be written to at any time by the peer during a connection's lifetime.
+ *
+ * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system
+ * services will be returned.
+ * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user
+ * services will be returned.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection handle of the recently terminated connection.
+ * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The
+ * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data.
+ * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual
+ * length of system attribute data.
+ * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS
+ *
+ * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied.
+ * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer.
+ * @retval ::NRF_ERROR_NOT_FOUND No system attributes found.
+ */
+SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t,
+ sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags));
+
+/**@brief Retrieve the first valid user attribute handle.
+ *
+ * @param[out] p_handle Pointer to an integer where the handle will be stored.
+ *
+ * @retval ::NRF_SUCCESS Successfully retrieved the handle.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ */
+SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle));
+
+/**@brief Retrieve the attribute UUID and/or metadata.
+ *
+ * @param[in] handle Attribute handle
+ * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field.
+ * @param[out] p_md Metadata of the attribute. Use NULL to omit this field.
+ *
+ * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata,
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL.
+ * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found.
+ */
+SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md));
+
+/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client.
+ *
+ * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event.
+ *
+ * @details The SoftDevice sets ATT_MTU to the minimum of:
+ * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and
+ * - The Server RX MTU value.
+ *
+ * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE}
+ * @endmscs
+ *
+ * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
+ * @param[in] server_rx_mtu Server RX MTU size.
+ * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT.
+ * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration
+ * used for this connection.
+ * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request
+ * if an ATT_MTU exchange has already been performed in the other direction.
+ *
+ * @retval ::NRF_SUCCESS Successfully sent response to the client.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied.
+ * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without
+ * reestablishing the connection.
+ */
+SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu));
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // BLE_GATTS_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_hci.h b/variants/xiao_ble/softdevice/ble_hci.h
new file mode 100644
index 000000000..27f85d52e
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_hci.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_COMMON
+ @{
+*/
+
+#ifndef BLE_HCI_H__
+#define BLE_HCI_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes
+ * @{ */
+
+#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */
+#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */
+#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */
+/*0x03 Hardware Failure
+0x04 Page Timeout
+*/
+#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */
+#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */
+#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */
+#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */
+/*0x09 Connection Limit Exceeded
+0x0A Synchronous Connection Limit To A Device Exceeded
+0x0B ACL Connection Already Exists*/
+#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */
+/*0x0D Connection Rejected due to Limited Resources
+0x0E Connection Rejected Due To Security Reasons
+0x0F Connection Rejected due to Unacceptable BD_ADDR
+0x10 Connection Accept Timeout Exceeded
+0x11 Unsupported Feature or Parameter Value*/
+#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */
+#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */
+#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \
+ 0x14 /**< Remote Device Terminated Connection due to low \
+ resources.*/
+#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */
+#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */
+/*
+0x17 Repeated Attempts
+0x18 Pairing Not Allowed
+0x19 Unknown LMP PDU
+*/
+#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */
+/*
+0x1B SCO Offset Rejected
+0x1C SCO Interval Rejected
+0x1D SCO Air Mode Rejected*/
+#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */
+#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */
+/*0x20 Unsupported LMP Parameter Value
+0x21 Role Change Not Allowed
+*/
+#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */
+#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */
+#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */
+/*0x25 Encryption Mode Not Acceptable
+0x26 Link Key Can Not be Changed
+0x27 Requested QoS Not Supported
+*/
+#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */
+#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */
+#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */
+/*
+0x2B Reserved
+0x2C QoS Unacceptable Parameter
+0x2D QoS Rejected
+0x2E Channel Classification Not Supported
+0x2F Insufficient Security
+*/
+#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */
+/*
+0x31 Reserved
+0x32 Role Switch Pending
+0x33 Reserved
+0x34 Reserved Slot Violation
+0x35 Role Switch Failed
+0x36 Extended Inquiry Response Too Large
+0x37 Secure Simple Pairing Not Supported By Host.
+0x38 Host Busy - Pairing
+0x39 Connection Rejected due to No Suitable Channel Found*/
+#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */
+#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */
+#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */
+#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */
+#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // BLE_HCI_H__
+
+/** @} */
diff --git a/variants/xiao_ble/softdevice/ble_l2cap.h b/variants/xiao_ble/softdevice/ble_l2cap.h
new file mode 100644
index 000000000..5f4bd277d
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_l2cap.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP)
+ @{
+ @brief Definitions and prototypes for the L2CAP interface.
+ */
+
+#ifndef BLE_L2CAP_H__
+#define BLE_L2CAP_H__
+
+#include "ble_err.h"
+#include "ble_ranges.h"
+#include "ble_types.h"
+#include "nrf_error.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology
+ * @{
+ * @details
+ *
+ * L2CAP SDU
+ * - A data unit that the application can send/receive to/from a peer.
+ *
+ * L2CAP PDU
+ * - A data unit that is exchanged between local and remote L2CAP entities.
+ * It consists of L2CAP protocol control information and payload fields.
+ * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU.
+ *
+ * L2CAP MTU
+ * - The maximum length of an L2CAP SDU.
+ *
+ * L2CAP MPS
+ * - The maximum length of an L2CAP PDU payload field.
+ *
+ * Credits
+ * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer.
+ * @} */
+
+/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations
+ * @{ */
+
+/**@brief L2CAP API SVC numbers. */
+enum BLE_L2CAP_SVCS {
+ SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */
+ SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */
+ SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */
+ SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */
+ SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */
+};
+
+/**@brief L2CAP Event IDs. */
+enum BLE_L2CAP_EVTS {
+ BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event.
+ \n Reply with @ref sd_ble_l2cap_ch_setup.
+ \n See @ref ble_l2cap_evt_ch_setup_request_t. */
+ BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event.
+ \n See @ref ble_l2cap_evt_ch_setup_refused_t. */
+ BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event.
+ \n See @ref ble_l2cap_evt_ch_setup_t. */
+ BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event.
+ \n No additional event structure applies. */
+ BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event.
+ \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */
+ BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received.
+ \n See @ref ble_l2cap_evt_ch_credit_t. */
+ BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received.
+ \n See @ref ble_l2cap_evt_ch_rx_t. */
+ BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted.
+ \n See @ref ble_l2cap_evt_ch_tx_t. */
+};
+
+/** @} */
+
+/**@addtogroup BLE_L2CAP_DEFINES Defines
+ * @{ */
+
+/**@brief Maximum number of L2CAP channels per connection. */
+#define BLE_L2CAP_CH_COUNT_MAX (64)
+
+/**@brief Minimum L2CAP MTU, in bytes. */
+#define BLE_L2CAP_MTU_MIN (23)
+
+/**@brief Minimum L2CAP MPS, in bytes. */
+#define BLE_L2CAP_MPS_MIN (23)
+
+/**@brief Invalid CID. */
+#define BLE_L2CAP_CID_INVALID (0x0000)
+
+/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */
+#define BLE_L2CAP_CREDITS_DEFAULT (1)
+
+/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources
+ * @{ */
+#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */
+#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */
+ /** @} */
+
+/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes
+ * @{ */
+#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */
+#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */
+#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */
+#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */
+#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */
+#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */
+#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */
+#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */
+#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */
+#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */
+#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \
+ (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */
+#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */
+/** @} */
+
+/** @} */
+
+/**@addtogroup BLE_L2CAP_STRUCTURES Structures
+ * @{ */
+
+/**
+ * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set.
+ *
+ * @note These parameters are set per connection, so all L2CAP channels created on this connection
+ * will have the same parameters.
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true:
+ * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN.
+ * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN.
+ * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX.
+ * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high.
+ */
+typedef struct {
+ uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall
+ be able to receive on L2CAP channels on connections with this
+ configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */
+ uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall
+ be able to transmit on L2CAP channels on connections with this
+ configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */
+ uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per
+ L2CAP channel. The minimum value is one. */
+ uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission
+ per L2CAP channel. The minimum value is one. */
+ uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection
+ with this configuration. The default value is zero, the maximum
+ value is @ref BLE_L2CAP_CH_COUNT_MAX.
+ @note if this parameter is set to zero, all other parameters in
+ @ref ble_l2cap_conn_cfg_t are ignored. */
+} ble_l2cap_conn_cfg_t;
+
+/**@brief L2CAP channel RX parameters. */
+typedef struct {
+ uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to
+ receive on this L2CAP channel.
+ - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */
+ uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be
+ able to receive on this L2CAP channel.
+ - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN.
+ - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */
+ ble_data_t sdu_buf; /**< SDU data buffer for reception.
+ - If @ref ble_data_t::p_data is non-NULL, initial credits are
+ issued to the peer.
+ - If @ref ble_data_t::p_data is NULL, no initial credits are
+ issued to the peer. */
+} ble_l2cap_ch_rx_params_t;
+
+/**@brief L2CAP channel setup parameters. */
+typedef struct {
+ ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */
+ uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting
+ setup of an L2CAP channel, ignored otherwise. */
+ uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES.
+ Used when replying to a setup request of an L2CAP
+ channel, ignored otherwise. */
+} ble_l2cap_ch_setup_params_t;
+
+/**@brief L2CAP channel TX parameters. */
+typedef struct {
+ uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to
+ transmit on this L2CAP channel. */
+ uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is
+ able to receive on this L2CAP channel. */
+ uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able
+ to transmit on this L2CAP channel. This is effective tx_mps,
+ selected by the SoftDevice as
+ MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */
+ uint16_t credits; /**< Initial credits given by the peer. */
+} ble_l2cap_ch_tx_params_t;
+
+/**@brief L2CAP Channel Setup Request event. */
+typedef struct {
+ ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */
+ uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */
+} ble_l2cap_evt_ch_setup_request_t;
+
+/**@brief L2CAP Channel Setup Refused event. */
+typedef struct {
+ uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */
+ uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */
+} ble_l2cap_evt_ch_setup_refused_t;
+
+/**@brief L2CAP Channel Setup Completed event. */
+typedef struct {
+ ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */
+} ble_l2cap_evt_ch_setup_t;
+
+/**@brief L2CAP Channel SDU Data Buffer Released event. */
+typedef struct {
+ ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice
+ returns SDU data buffers supplied by the application, which have
+ not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or
+ @ref BLE_L2CAP_EVT_CH_TX event. */
+} ble_l2cap_evt_ch_sdu_buf_released_t;
+
+/**@brief L2CAP Channel Credit received event. */
+typedef struct {
+ uint16_t credits; /**< Additional credits given by the peer. */
+} ble_l2cap_evt_ch_credit_t;
+
+/**@brief L2CAP Channel received SDU event. */
+typedef struct {
+ uint16_t sdu_len; /**< Total SDU length, in bytes. */
+ ble_data_t sdu_buf; /**< SDU data buffer.
+ @note If there is not enough space in the buffer
+ (sdu_buf.len < sdu_len) then the rest of the SDU will be
+ silently discarded by the SoftDevice. */
+} ble_l2cap_evt_ch_rx_t;
+
+/**@brief L2CAP Channel transmitted SDU event. */
+typedef struct {
+ ble_data_t sdu_buf; /**< SDU data buffer. */
+} ble_l2cap_evt_ch_tx_t;
+
+/**@brief L2CAP event structure. */
+typedef struct {
+ uint16_t conn_handle; /**< Connection Handle on which the event occured. */
+ uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or
+ @ref BLE_L2CAP_CID_INVALID if not present. */
+ union {
+ ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */
+ ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */
+ ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */
+ ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */
+ ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */
+ ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */
+ ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */
+ } params; /**< Event Parameters. */
+} ble_l2cap_evt_t;
+
+/** @} */
+
+/**@addtogroup BLE_L2CAP_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Set up an L2CAP channel.
+ *
+ * @details This function is used to:
+ * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer.
+ * - Reply to a setup request of an L2CAP channel (if called in response to a
+ * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection
+ * Response packet to a peer.
+ *
+ * @note A call to this function will require the application to keep the SDU data buffer alive
+ * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or
+ * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event.
+ *
+ * @events
+ * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.}
+ * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection Handle.
+ * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel:
+ * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP
+ * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST
+ * event when replying to a setup request of an L2CAP channel.
+ * - As output: local_cid for this channel.
+ * @param[in] p_params L2CAP channel parameters.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued request or response for transmission.
+ * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
+ * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up).
+ * @retval ::NRF_ERROR_NOT_FOUND CID not found.
+ * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels,
+ * see @ref ble_l2cap_conn_cfg_t::ch_count.
+ */
+SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t,
+ sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params));
+
+/**@brief Release an L2CAP channel.
+ *
+ * @details This sends a Disconnection Request packet to a peer.
+ *
+ * @events
+ * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection Handle.
+ * @param[in] local_cid Local Channel ID of the L2CAP channel.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued request for transmission.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is
+ * in progress for the L2CAP channel).
+ * @retval ::NRF_ERROR_NOT_FOUND CID not found.
+ */
+SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid));
+
+/**@brief Receive an SDU on an L2CAP channel.
+ *
+ * @details This may issue additional credits to the peer using an LE Flow Control Credit packet.
+ *
+ * @note A call to this function will require the application to keep the memory pointed by
+ * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX
+ * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event.
+ *
+ * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers
+ * for reception per L2CAP channel.
+ *
+ * @events
+ * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_L2CAP_CH_RX_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection Handle.
+ * @param[in] local_cid Local Channel ID of the L2CAP channel.
+ * @param[in] p_sdu_buf Pointer to the SDU data buffer.
+ *
+ * @retval ::NRF_SUCCESS Buffer accepted.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is
+ * in progress for an L2CAP channel).
+ * @retval ::NRF_ERROR_NOT_FOUND CID not found.
+ * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a
+ * @ref BLE_L2CAP_EVT_CH_RX event and retry.
+ */
+SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf));
+
+/**@brief Transmit an SDU on an L2CAP channel.
+ *
+ * @note A call to this function will require the application to keep the memory pointed by
+ * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX
+ * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event.
+ *
+ * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for
+ * transmission per L2CAP channel.
+ *
+ * @note The application can keep track of the available credits for transmission by following
+ * the procedure below:
+ * - Store initial credits given by the peer in a variable.
+ * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.)
+ * - Decrement the variable, which stores the currently available credits, by
+ * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns
+ * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.)
+ * - Increment the variable, which stores the currently available credits, by additional
+ * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event.
+ *
+ * @events
+ * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.}
+ * @endevents
+ *
+ * @mscs
+ * @mmsc{@ref BLE_L2CAP_CH_TX_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection Handle.
+ * @param[in] local_cid Local Channel ID of the L2CAP channel.
+ * @param[in] p_sdu_buf Pointer to the SDU data buffer.
+ *
+ * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is
+ * in progress for the L2CAP channel).
+ * @retval ::NRF_ERROR_NOT_FOUND CID not found.
+ * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than
+ * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in
+ * @ref BLE_L2CAP_EVT_CH_SETUP event.
+ * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a
+ * @ref BLE_L2CAP_EVT_CH_TX event and retry.
+ */
+SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf));
+
+/**@brief Advanced SDU reception flow control.
+ *
+ * @details Adjust the way the SoftDevice issues credits to the peer.
+ * This may issue additional credits to the peer using an LE Flow Control Credit packet.
+ *
+ * @mscs
+ * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC}
+ * @endmscs
+ *
+ * @param[in] conn_handle Connection Handle.
+ * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set
+ * the value that will be used for newly created channels.
+ * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every
+ * time it starts using a new reception buffer.
+ * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will
+ * use if this function is not called.
+ * - If set to zero, the SoftDevice will stop issuing credits for new reception
+ * buffers the application provides or has provided. SDU reception that is
+ * currently ongoing will be allowed to complete.
+ * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be
+ * written by the SoftDevice with the number of credits that is or will be
+ * available to the peer. If the value written by the SoftDevice is 0 when
+ * credits parameter was set to 0, the peer will not be able to send more
+ * data until more credits are provided by calling this function again with
+ * credits > 0. This parameter is ignored when local_cid is set to
+ * @ref BLE_L2CAP_CID_INVALID.
+ *
+ * @note Application should take care when setting number of credits higher than default value. In
+ * this case the application must make sure that the SoftDevice always has reception buffers
+ * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have
+ * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic
+ * on the connection handle may be stalled until the SoftDevice again has an available
+ * reception buffer. This applies even if the application has used this call to set the
+ * credits back to default, or zero.
+ *
+ * @retval ::NRF_SUCCESS Flow control parameters accepted.
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
+ * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
+ * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is
+ * in progress for an L2CAP channel).
+ * @retval ::NRF_ERROR_NOT_FOUND CID not found.
+ */
+SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t,
+ sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits));
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // BLE_L2CAP_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_ranges.h b/variants/xiao_ble/softdevice/ble_ranges.h
new file mode 100644
index 000000000..2768e4996
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_ranges.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_COMMON
+ @{
+ @defgroup ble_ranges Module specific SVC, event and option number subranges
+ @{
+
+ @brief Definition of SVC, event and option number subranges for each API module.
+
+ @note
+ SVCs, event and option numbers are split into subranges for each API module.
+ Each module receives its entire allocated range of SVC calls, whether implemented or not,
+ but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range.
+
+ Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range,
+ rather than the last SVC function call actually defined and implemented.
+
+ Specific SVC, event and option values are defined in each module's ble_.h file,
+ which defines names of each individual SVC code based on the range start value.
+*/
+
+#ifndef BLE_RANGES_H__
+#define BLE_RANGES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */
+#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */
+
+#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */
+#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */
+
+#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */
+#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */
+
+#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */
+#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */
+
+#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */
+#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */
+
+#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */
+
+#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */
+#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */
+
+#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */
+#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */
+
+#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */
+#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */
+
+#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */
+#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */
+
+#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */
+#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */
+
+#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */
+
+#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */
+#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */
+
+#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */
+#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */
+
+#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */
+#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */
+
+#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */
+#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */
+
+#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */
+#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */
+
+#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */
+#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */
+
+#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */
+
+#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */
+#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */
+
+#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */
+#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */
+
+#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */
+#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */
+
+#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */
+#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */
+
+#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */
+#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */
+
+#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */
+#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */
+
+#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */
+#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* BLE_RANGES_H__ */
+
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/ble_types.h b/variants/xiao_ble/softdevice/ble_types.h
new file mode 100644
index 000000000..db3656cfd
--- /dev/null
+++ b/variants/xiao_ble/softdevice/ble_types.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup BLE_COMMON
+ @{
+ @defgroup ble_types Common types and macro definitions
+ @{
+
+ @brief Common types and macro definitions for the BLE SoftDevice.
+ */
+
+#ifndef BLE_TYPES_H__
+#define BLE_TYPES_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup BLE_TYPES_DEFINES Defines
+ * @{ */
+
+/** @defgroup BLE_CONN_HANDLES BLE Connection Handles
+ * @{ */
+#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */
+#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */
+/** @} */
+
+/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs
+ * @{ */
+/* Generic UUIDs, applicable to all services */
+#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */
+#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */
+#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */
+#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */
+#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */
+#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */
+#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */
+#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */
+#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */
+#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */
+#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */
+/* GATT specific UUIDs */
+#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */
+#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */
+/* GAP specific UUIDs */
+#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */
+#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */
+#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */
+#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */
+#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */
+#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */
+#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */
+/** @} */
+
+/** @defgroup BLE_UUID_TYPES Types of UUID
+ * @{ */
+#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */
+#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */
+#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */
+/** @} */
+
+/** @defgroup BLE_APPEARANCES Bluetooth Appearance values
+ * @note Retrieved from
+ * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
+ * @{ */
+#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */
+#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */
+#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */
+#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */
+#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */
+#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */
+#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */
+#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */
+#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */
+#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */
+#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */
+#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */
+#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */
+#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */
+#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */
+#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */
+#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */
+#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */
+#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */
+#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */
+#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */
+#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */
+#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */
+#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */
+#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */
+#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */
+#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */
+#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */
+#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */
+#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */
+#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */
+#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */
+#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */
+#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */
+#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */
+#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */
+#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */
+#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */
+#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */
+#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */
+#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */
+#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */
+#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */
+#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */
+#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \
+ 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \
+ 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */
+/** @} */
+
+/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */
+#define BLE_UUID_BLE_ASSIGN(instance, value) \
+ do { \
+ instance.type = BLE_UUID_TYPE_BLE; \
+ instance.uuid = value; \
+ } while (0)
+
+/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */
+#define BLE_UUID_COPY_PTR(dst, src) \
+ do { \
+ (dst)->type = (src)->type; \
+ (dst)->uuid = (src)->uuid; \
+ } while (0)
+
+/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */
+#define BLE_UUID_COPY_INST(dst, src) \
+ do { \
+ (dst).type = (src).type; \
+ (dst).uuid = (src).uuid; \
+ } while (0)
+
+/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */
+#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid))
+
+/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */
+#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid))
+
+/** @} */
+
+/** @addtogroup BLE_TYPES_STRUCTURES Structures
+ * @{ */
+
+/** @brief 128 bit UUID values. */
+typedef struct {
+ uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */
+} ble_uuid128_t;
+
+/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */
+typedef struct {
+ uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */
+ uint8_t
+ type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */
+} ble_uuid_t;
+
+/**@brief Data structure. */
+typedef struct {
+ uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */
+ uint16_t len; /**< Length of the data buffer, in bytes. */
+} ble_data_t;
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLE_TYPES_H__ */
+
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf52/nrf_mbr.h b/variants/xiao_ble/softdevice/nrf52/nrf_mbr.h
new file mode 100644
index 000000000..4e0bd752a
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf52/nrf_mbr.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @defgroup nrf_mbr_api Master Boot Record API
+ @{
+
+ @brief APIs for updating SoftDevice and BootLoader
+
+*/
+
+#ifndef NRF_MBR_H__
+#define NRF_MBR_H__
+
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup NRF_MBR_DEFINES Defines
+ * @{ */
+
+/**@brief MBR SVC Base number. */
+#define MBR_SVC_BASE (0x18)
+
+/**@brief Page size in words. */
+#define MBR_PAGE_SIZE_IN_WORDS (1024)
+
+/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash.
+This is the offset where the first byte of the SoftDevice hex file is written. */
+#define MBR_SIZE (0x1000)
+
+/** @brief Location (in the flash memory) of the bootloader address. */
+#define MBR_BOOTLOADER_ADDR (0xFF8)
+
+/** @brief Location (in UICR) of the bootloader address. */
+#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0]))
+
+/** @brief Location (in the flash memory) of the address of the MBR parameter page. */
+#define MBR_PARAM_PAGE_ADDR (0xFFC)
+
+/** @brief Location (in UICR) of the address of the MBR parameter page. */
+#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1]))
+
+/** @} */
+
+/** @addtogroup NRF_MBR_ENUMS Enumerations
+ * @{ */
+
+/**@brief nRF Master Boot Record API SVC numbers. */
+enum NRF_MBR_SVCS {
+ SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */
+};
+
+/**@brief Possible values for ::sd_mbr_command_t.command */
+enum NRF_MBR_COMMANDS {
+ SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/
+ SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/
+ SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any
+ parameters in ::sd_mbr_command_t params.*/
+ SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/
+ SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see
+ ::sd_mbr_command_vector_table_base_set_t*/
+ SD_MBR_COMMAND_RESERVED,
+ SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see
+ ::sd_mbr_command_irq_forward_address_set_t*/
+};
+
+/** @} */
+
+/** @addtogroup NRF_MBR_TYPES Types
+ * @{ */
+
+/**@brief This command copies part of a new SoftDevice
+ *
+ * The destination area is erased before copying.
+ * If dst is in the middle of a flash page, that whole flash page will be erased.
+ * If (dst+len) is in the middle of a flash page, that whole flash page will be erased.
+ *
+ * The user of this function is responsible for setting the BPROT registers.
+ *
+ * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly.
+ * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying.
+ */
+typedef struct {
+ uint32_t *src; /**< Pointer to the source of data to be copied.*/
+ uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/
+ uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/
+} sd_mbr_command_copy_sd_t;
+
+/**@brief This command works like memcmp, but takes the length in words.
+ *
+ * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal.
+ * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal.
+ */
+typedef struct {
+ uint32_t *ptr1; /**< Pointer to block of memory. */
+ uint32_t *ptr2; /**< Pointer to block of memory. */
+ uint32_t len; /**< Number of 32 bit words to compare.*/
+} sd_mbr_command_compare_t;
+
+/**@brief This command copies a new BootLoader.
+ *
+ * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to
+ * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize
+ * @ref MBR_BOOTLOADER_ADDR.
+ *
+ * The bootloader destination is erased by this function.
+ * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased.
+ *
+ * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set,
+ * see @ref sd_mbr_command.
+ *
+ * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is
+ * not intended to be written.
+ *
+ * On success, this function will not return. It will start the new bootloader from reset-vector as normal.
+ *
+ * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen.
+ * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set.
+ * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area.
+ * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command.
+ */
+typedef struct {
+ uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/
+ uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */
+} sd_mbr_command_copy_bl_t;
+
+/**@brief Change the address the MBR starts after a reset
+ *
+ * Once this function has been called, this address is where the MBR will start to forward
+ * interrupts to after a reset.
+ *
+ * To restore default forwarding, this function should be called with @ref address set to 0. If a
+ * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will
+ * be forwarded to the SoftDevice.
+ *
+ * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or
+ * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize
+ * @ref MBR_BOOTLOADER_ADDR.
+ *
+ * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set,
+ * see @ref sd_mbr_command.
+ *
+ * On success, this function will not return. It will reset the device.
+ *
+ * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen.
+ * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size.
+ * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command.
+ */
+typedef struct {
+ uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/
+} sd_mbr_command_vector_table_base_set_t;
+
+/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR
+ *
+ * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not
+ * change where the MBR starts after reset.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+typedef struct {
+ uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/
+} sd_mbr_command_irq_forward_address_set_t;
+
+/**@brief Input structure containing data used when calling ::sd_mbr_command
+ *
+ * Depending on what command value that is set, the corresponding params value type must also be
+ * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command
+ * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params.
+ */
+typedef struct {
+ uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */
+ union {
+ sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/
+ sd_mbr_command_compare_t compare; /**< Parameters for verify.*/
+ sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */
+ sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/
+ sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/
+ } params; /**< Command parameters. */
+} sd_mbr_command_t;
+
+/** @} */
+
+/** @addtogroup NRF_MBR_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Issue Master Boot Record commands
+ *
+ * Commands used when updating a SoftDevice and bootloader.
+ *
+ * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires
+ * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash
+ * page. The location of the flash page should be provided by the application in either
+ * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR
+ * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to
+ * store the command before reset. When an address is specified, the page it refers to must not be
+ * used by the application. If no address is provided by the application, i.e. both
+ * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use
+ * flash will be unavailable and return @ref NRF_ERROR_NO_MEM.
+ *
+ * @param[in] param Pointer to a struct describing the command.
+ *
+ * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t,
+ * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t,
+ * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t
+ *
+ * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided
+ * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given.
+ */
+SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param));
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_MBR_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf_error.h b/variants/xiao_ble/softdevice/nrf_error.h
new file mode 100644
index 000000000..fb2831e19
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_error.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @defgroup nrf_error SoftDevice Global Error Codes
+ @{
+
+ @brief Global Error definitions
+*/
+
+/* Header guard */
+#ifndef NRF_ERROR_H__
+#define NRF_ERROR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions
+ * @{ */
+#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base
+#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base
+#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base
+#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base
+/** @} */
+
+#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command
+#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing
+#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled
+#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error
+#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation
+#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found
+#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported
+#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter
+#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state
+#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length
+#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags
+#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data
+#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size
+#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out
+#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer
+#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation
+#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address
+#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy
+#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded.
+#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_ERROR_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf_error_sdm.h b/variants/xiao_ble/softdevice/nrf_error_sdm.h
new file mode 100644
index 000000000..2fd621057
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_error_sdm.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup nrf_sdm_api
+ @{
+ @defgroup nrf_sdm_error SoftDevice Manager Error Codes
+ @{
+
+ @brief Error definitions for the SDM API
+*/
+
+/* Header guard */
+#ifndef NRF_ERROR_SDM_H__
+#define NRF_ERROR_SDM_H__
+
+#include "nrf_error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source.
+#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \
+ (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having
+ ///< enabled SoftDevice interrupts).
+#define NRF_ERROR_SDM_INCORRECT_CLENR0 \
+ (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing).
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_ERROR_SDM_H__
+
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf_error_soc.h b/variants/xiao_ble/softdevice/nrf_error_soc.h
new file mode 100644
index 000000000..cbd0ba8ac
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_error_soc.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @addtogroup nrf_soc_api
+ @{
+ @defgroup nrf_soc_error SoC Library Error Codes
+ @{
+
+ @brief Error definitions for the SoC library
+
+*/
+
+/* Header guard */
+#ifndef NRF_ERROR_SOC_H__
+#define NRF_ERROR_SOC_H__
+
+#include "nrf_error.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Mutex Errors */
+#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken
+
+/* NVIC errors */
+#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available
+#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed
+#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return
+
+/* Power errors */
+#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown
+#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown
+#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return
+
+/* Rand errors */
+#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values
+
+/* PPI errors */
+#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel
+#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_ERROR_SOC_H__
+/**
+ @}
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf_nvic.h b/variants/xiao_ble/softdevice/nrf_nvic.h
new file mode 100644
index 000000000..d4ab204d9
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_nvic.h
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ * @defgroup nrf_nvic_api SoftDevice NVIC API
+ * @{
+ *
+ * @note In order to use this module, the following code has to be added to a .c file:
+ * \code
+ * nrf_nvic_state_t nrf_nvic_state = {0};
+ * \endcode
+ *
+ * @note Definitions and declarations starting with __ (double underscore) in this header file are
+ * not intended for direct use by the application.
+ *
+ * @brief APIs for the accessing NVIC when using a SoftDevice.
+ *
+ */
+
+#ifndef NRF_NVIC_H__
+#define NRF_NVIC_H__
+
+#include "nrf.h"
+#include "nrf_error.h"
+#include "nrf_error_soc.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@addtogroup NRF_NVIC_DEFINES Defines
+ * @{ */
+
+/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions
+ * @{ */
+
+#define __NRF_NVIC_NVMC_IRQn \
+ (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \
+ number in the MDK. */
+
+#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */
+
+/**@brief Interrupt priority levels used by the SoftDevice. */
+#define __NRF_NVIC_SD_IRQ_PRIOS \
+ ((uint8_t)((1U << 0) /**< Priority level high .*/ \
+ | (1U << 1) /**< Priority level medium. */ \
+ | (1U << 4) /**< Priority level low. */ \
+ ))
+
+/**@brief Interrupt priority levels available to the application. */
+#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS)
+
+/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */
+#define __NRF_NVIC_SD_IRQS_0 \
+ ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \
+ (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \
+ (1U << (uint32_t)SWI5_IRQn)))
+
+/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */
+#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0)
+
+/**@brief Interrupts available for to application, with IRQn in the range 0-31. */
+#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0)
+
+/**@brief Interrupts available for to application, with IRQn in the range 32-63. */
+#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1)
+
+/**@} */
+
+/**@} */
+
+/**@addtogroup NRF_NVIC_VARIABLES Variables
+ * @{ */
+
+/**@brief Type representing the state struct for the SoftDevice NVIC module. */
+typedef struct {
+ uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */
+ uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */
+} nrf_nvic_state_t;
+
+/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an
+ * application source file. */
+extern nrf_nvic_state_t nrf_nvic_state;
+
+/**@} */
+
+/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions
+ * @{ */
+
+/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts.
+ *
+ * @retval The value of PRIMASK prior to disabling the interrupts.
+ */
+__STATIC_INLINE int __sd_nvic_irq_disable(void);
+
+/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts.
+ */
+__STATIC_INLINE void __sd_nvic_irq_enable(void);
+
+/**@brief Checks if IRQn is available to application
+ * @param[in] IRQn IRQ to check
+ *
+ * @retval 1 (true) if the IRQ to check is available to the application
+ */
+__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn);
+
+/**@brief Checks if priority is available to application
+ * @param[in] priority priority to check
+ *
+ * @retval 1 (true) if the priority to check is available to the application
+ */
+__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority);
+
+/**@} */
+
+/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions
+ * @{ */
+
+/**@brief Enable External Interrupt.
+ * @note Corresponds to NVIC_EnableIRQ in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS.
+ *
+ * @retval ::NRF_SUCCESS The interrupt was enabled.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn);
+
+/**@brief Disable External Interrupt.
+ * @note Corresponds to NVIC_DisableIRQ in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS.
+ *
+ * @retval ::NRF_SUCCESS The interrupt was disabled.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn);
+
+/**@brief Get Pending Interrupt.
+ * @note Corresponds to NVIC_GetPendingIRQ in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS.
+ * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ.
+ *
+ * @retval ::NRF_SUCCESS The interrupt is available for the application.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq);
+
+/**@brief Set Pending Interrupt.
+ * @note Corresponds to NVIC_SetPendingIRQ in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS.
+ *
+ * @retval ::NRF_SUCCESS The interrupt is set pending.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn);
+
+/**@brief Clear Pending Interrupt.
+ * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS.
+ *
+ * @retval ::NRF_SUCCESS The interrupt pending flag is cleared.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn);
+
+/**@brief Set Interrupt Priority.
+ * @note Corresponds to NVIC_SetPriority in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ * @pre Priority is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS.
+ * @param[in] priority A valid IRQ priority for use by the application.
+ *
+ * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority);
+
+/**@brief Get Interrupt Priority.
+ * @note Corresponds to NVIC_GetPriority in CMSIS.
+ *
+ * @pre IRQn is valid and not reserved by the stack.
+ *
+ * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS.
+ * @param[out] p_priority Return value from NVIC_GetPriority.
+ *
+ * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority.
+ * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application.
+ */
+__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority);
+
+/**@brief System Reset.
+ * @note Corresponds to NVIC_SystemReset in CMSIS.
+ *
+ * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN
+ */
+__STATIC_INLINE uint32_t sd_nvic_SystemReset(void);
+
+/**@brief Enter critical region.
+ *
+ * @post Application interrupts will be disabled.
+ * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each
+ * execution context
+ * @sa sd_nvic_critical_region_exit
+ *
+ * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region);
+
+/**@brief Exit critical region.
+ *
+ * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter.
+ * @post If not in a nested critical region, the application interrupts will restored to the state before
+ * ::sd_nvic_critical_region_enter was called.
+ *
+ * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa
+ * sd_nvic_critical_region_enter.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region);
+
+/**@} */
+
+#ifndef SUPPRESS_INLINE_IMPLEMENTATION
+
+__STATIC_INLINE int __sd_nvic_irq_disable(void)
+{
+ int pm = __get_PRIMASK();
+ __disable_irq();
+ return pm;
+}
+
+__STATIC_INLINE void __sd_nvic_irq_enable(void)
+{
+ __enable_irq();
+}
+
+__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn)
+{
+ if (IRQn < 32) {
+ return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0;
+ } else if (IRQn < 64) {
+ return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0;
+ } else {
+ return 1;
+ }
+}
+
+__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority)
+{
+ if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) {
+ return 0;
+ }
+ return 1;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn)
+{
+ if (!__sd_nvic_app_accessible_irq(IRQn)) {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+ if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED;
+ }
+
+ if (nrf_nvic_state.__cr_flag) {
+ nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |=
+ (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F));
+ } else {
+ NVIC_EnableIRQ(IRQn);
+ }
+ return NRF_SUCCESS;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn)
+{
+ if (!__sd_nvic_app_accessible_irq(IRQn)) {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+
+ if (nrf_nvic_state.__cr_flag) {
+ nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F));
+ } else {
+ NVIC_DisableIRQ(IRQn);
+ }
+
+ return NRF_SUCCESS;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq)
+{
+ if (__sd_nvic_app_accessible_irq(IRQn)) {
+ *p_pending_irq = NVIC_GetPendingIRQ(IRQn);
+ return NRF_SUCCESS;
+ } else {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+}
+
+__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn)
+{
+ if (__sd_nvic_app_accessible_irq(IRQn)) {
+ NVIC_SetPendingIRQ(IRQn);
+ return NRF_SUCCESS;
+ } else {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+}
+
+__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn)
+{
+ if (__sd_nvic_app_accessible_irq(IRQn)) {
+ NVIC_ClearPendingIRQ(IRQn);
+ return NRF_SUCCESS;
+ } else {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+}
+
+__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority)
+{
+ if (!__sd_nvic_app_accessible_irq(IRQn)) {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+
+ if (!__sd_nvic_is_app_accessible_priority(priority)) {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED;
+ }
+
+ NVIC_SetPriority(IRQn, (uint32_t)priority);
+ return NRF_SUCCESS;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority)
+{
+ if (__sd_nvic_app_accessible_irq(IRQn)) {
+ *p_priority = (NVIC_GetPriority(IRQn) & 0xFF);
+ return NRF_SUCCESS;
+ } else {
+ return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
+ }
+}
+
+__STATIC_INLINE uint32_t sd_nvic_SystemReset(void)
+{
+ NVIC_SystemReset();
+ return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region)
+{
+ int was_masked = __sd_nvic_irq_disable();
+ if (!nrf_nvic_state.__cr_flag) {
+ nrf_nvic_state.__cr_flag = 1;
+ nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0);
+ NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0;
+ nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1);
+ NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1;
+ *p_is_nested_critical_region = 0;
+ } else {
+ *p_is_nested_critical_region = 1;
+ }
+ if (!was_masked) {
+ __sd_nvic_irq_enable();
+ }
+ return NRF_SUCCESS;
+}
+
+__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region)
+{
+ if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) {
+ int was_masked = __sd_nvic_irq_disable();
+ NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0];
+ NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1];
+ nrf_nvic_state.__cr_flag = 0;
+ if (!was_masked) {
+ __sd_nvic_irq_enable();
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+#endif /* SUPPRESS_INLINE_IMPLEMENTATION */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_NVIC_H__
+
+/**@} */
diff --git a/variants/xiao_ble/softdevice/nrf_sdm.h b/variants/xiao_ble/softdevice/nrf_sdm.h
new file mode 100644
index 000000000..2786a86a4
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_sdm.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ @defgroup nrf_sdm_api SoftDevice Manager API
+ @{
+
+ @brief APIs for SoftDevice management.
+
+*/
+
+#ifndef NRF_SDM_H__
+#define NRF_SDM_H__
+
+#include "nrf.h"
+#include "nrf_error.h"
+#include "nrf_error_sdm.h"
+#include "nrf_soc.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @addtogroup NRF_SDM_DEFINES Defines
+ * @{ */
+#ifdef NRFSOC_DOXYGEN
+/// Declared in nrf_mbr.h
+#define MBR_SIZE 0
+#warning test
+#endif
+
+/** @brief The major version for the SoftDevice binary distributed with this header file. */
+#define SD_MAJOR_VERSION (7)
+
+/** @brief The minor version for the SoftDevice binary distributed with this header file. */
+#define SD_MINOR_VERSION (3)
+
+/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */
+#define SD_BUGFIX_VERSION (0)
+
+/** @brief The SoftDevice variant of this firmware. */
+#define SD_VARIANT_ID 140
+
+/** @brief The full version number for the SoftDevice binary this header file was distributed
+ * with, as a decimal number in the form Mmmmbbb, where:
+ * - M is major version (one or more digits)
+ * - mmm is minor version (three digits)
+ * - bbb is bugfix version (three digits). */
+#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION)
+
+/** @brief SoftDevice Manager SVC Base number. */
+#define SDM_SVC_BASE 0x10
+
+/** @brief SoftDevice unique string size in bytes. */
+#define SD_UNIQUE_STR_SIZE 20
+
+/** @brief Invalid info field. Returned when an info field does not exist. */
+#define SDM_INFO_FIELD_INVALID (0)
+
+/** @brief Defines the SoftDevice Information Structure location (address) as an offset from
+the start of the SoftDevice (without MBR)*/
+#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000)
+
+/** @brief Defines the absolute SoftDevice Information Structure location (address) when the
+ * SoftDevice is installed just above the MBR (the usual case). */
+#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE)
+
+/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the
+ * SoftDevice base address. The size value is of type uint8_t. */
+#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET)
+
+/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address.
+ * The size value is of type uint32_t. */
+#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08)
+
+/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value
+ * is of type uint16_t. */
+#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C)
+
+/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID
+ * is of type uint32_t. */
+#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10)
+
+/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in
+ * the same format as @ref SD_VERSION, stored as an uint32_t. */
+#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14)
+
+/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address.
+ * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE.
+ */
+#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18)
+
+/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value
+ * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is
+ * installed just above the MBR (the usual case). */
+#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET)))
+
+/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base
+ * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above
+ * the MBR (the usual case). */
+#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET)))
+
+/** @brief Defines the amount of flash that is used by the SoftDevice.
+ * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed
+ * just above the MBR (the usual case).
+ */
+#define SD_FLASH_SIZE 0x26000
+
+/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use
+ * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual
+ * case). */
+#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET)))
+
+/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use
+ * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the
+ * usual case). */
+#define SD_ID_GET(baseaddr) \
+ ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \
+ ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \
+ : SDM_INFO_FIELD_INVALID)
+
+/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address.
+ * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR
+ * (the usual case). */
+#define SD_VERSION_GET(baseaddr) \
+ ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \
+ ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \
+ : SDM_INFO_FIELD_INVALID)
+
+/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address.
+ * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR
+ * (the usual case). */
+#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \
+ ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \
+ ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \
+ : SDM_INFO_FIELD_INVALID)
+
+/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges
+ * @{ */
+#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */
+#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */
+/**@} */
+
+/**@defgroup NRF_FAULT_IDS Fault ID types
+ * @{ */
+#define NRF_FAULT_ID_SD_ASSERT \
+ (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */
+#define NRF_FAULT_ID_APP_MEMACC \
+ (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \
+ in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \
+ register violation the info parameter will contain the sub-region number of \
+ PREGION[0], on whose address range the disallowed write access caused the \
+ memory access fault. */
+/**@} */
+
+/** @} */
+
+/** @addtogroup NRF_SDM_ENUMS Enumerations
+ * @{ */
+
+/**@brief nRF SoftDevice Manager API SVC numbers. */
+enum NRF_SD_SVCS {
+ SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */
+ SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */
+ SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */
+ SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */
+ SVC_SDM_LAST /**< Placeholder for last SDM SVC */
+};
+
+/** @} */
+
+/** @addtogroup NRF_SDM_DEFINES Defines
+ * @{ */
+
+/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy
+ * @{ */
+
+#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */
+#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */
+#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */
+#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */
+#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */
+#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */
+#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */
+#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */
+#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */
+#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */
+#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */
+#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */
+
+/** @} */
+
+/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources
+ * @{ */
+
+#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */
+#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */
+#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */
+
+/** @} */
+
+/** @} */
+
+/** @addtogroup NRF_SDM_TYPES Types
+ * @{ */
+
+/**@brief Type representing LFCLK oscillator source. */
+typedef struct {
+ uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */
+ uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second
+ units (nRF52: 1-32).
+ @note To avoid excessive clock drift, 0.5 degrees Celsius is the
+ maximum temperature change allowed in one calibration timer
+ interval. The interval should be selected to ensure this.
+
+ @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */
+ uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration
+ intervals) the RC oscillator shall be calibrated if the temperature
+ hasn't changed.
+ 0: Always calibrate even if the temperature hasn't changed.
+ 1: Only calibrate if the temperature has changed (legacy - nRF51 only).
+ 2-33: Check the temperature and only calibrate if it has changed,
+ however calibration will take place every rc_temp_ctiv
+ intervals in any case.
+
+ @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC.
+
+ @note For nRF52, the application must ensure calibration at least once
+ every 8 seconds to ensure +/-500 ppm clock stability. The
+ recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is
+ rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at
+ least once every 8 seconds and for temperature changes of 0.5
+ degrees Celsius every 4 seconds. See the Product Specification
+ for the nRF52 device being used for more information.*/
+ uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing
+ windows, see @ref NRF_CLOCK_LF_ACCURACY.*/
+} nrf_clock_lf_cfg_t;
+
+/**@brief Fault Handler type.
+ *
+ * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back.
+ * The protocol stack will be in an undefined state when this happens and the only way to recover will be to
+ * perform a reset, using e.g. CMSIS NVIC_SystemReset().
+ * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset().
+ *
+ * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device.
+ * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may
+ * continously transmit packets.
+ *
+ * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback.
+ *
+ * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS.
+ * @param[in] pc The program counter of the instruction that triggered the fault.
+ * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details.
+ *
+ * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time
+ * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the
+ * one that triggered the fault.
+ */
+typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info);
+
+/** @} */
+
+/** @addtogroup NRF_SDM_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Enables the SoftDevice and by extension the protocol stack.
+ *
+ * @note Some care must be taken if a low frequency clock source is already running when calling this function:
+ * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new
+ * clock source will be started.
+ *
+ * @note This function has no effect when returning with an error.
+ *
+ * @post If return code is ::NRF_SUCCESS
+ * - SoC library and protocol stack APIs are made available.
+ * - A portion of RAM will be unavailable (see relevant SDS documentation).
+ * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation).
+ * - Interrupts will not arrive from protected peripherals or interrupts.
+ * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice.
+ * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation).
+ * - Chosen low frequency clock source will be running.
+ *
+ * @param p_clock_lf_cfg Low frequency clock source and accuracy.
+ If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2
+ In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to
+ the actual characteristics of your XTAL clock.
+ * @param fault_handler Callback to be invoked in case of fault, cannot be NULL.
+ *
+ * @retval ::NRF_SUCCESS
+ * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied.
+ * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated.
+ * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has
+ an illegal priority level.
+ * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected.
+ * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg.
+ */
+SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t,
+ sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler));
+
+/**@brief Disables the SoftDevice and by extension the protocol stack.
+ *
+ * Idempotent function to disable the SoftDevice.
+ *
+ * @post SoC library and protocol stack APIs are made unavailable.
+ * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest).
+ * @post All peripherals used by the SoftDevice will be reset to default values.
+ * @post All of RAM become available.
+ * @post All interrupts are forwarded to the application.
+ * @post LFCLK source chosen in ::sd_softdevice_enable will be left running.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void));
+
+/**@brief Check if the SoftDevice is enabled.
+ *
+ * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled));
+
+/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice
+ *
+ * This function is only intended to be called when a bootloader is enabled.
+ *
+ * @param[in] address The base address of the interrupt vector table for forwarded interrupts.
+
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address));
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_SDM_H__
+
+/**
+ @}
+*/
diff --git a/variants/xiao_ble/softdevice/nrf_soc.h b/variants/xiao_ble/softdevice/nrf_soc.h
new file mode 100644
index 000000000..c649ca836
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_soc.h
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+/**
+ * @defgroup nrf_soc_api SoC Library API
+ * @{
+ *
+ * @brief APIs for the SoC library.
+ *
+ */
+
+#ifndef NRF_SOC_H__
+#define NRF_SOC_H__
+
+#include "nrf.h"
+#include "nrf_error.h"
+#include "nrf_error_soc.h"
+#include "nrf_svc.h"
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@addtogroup NRF_SOC_DEFINES Defines
+ * @{ */
+
+/**@brief The number of the lowest SVC number reserved for the SoC library. */
+#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */
+#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */
+
+/**@brief Guaranteed time for application to process radio inactive notification. */
+#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62)
+
+/**@brief The minimum allowed timeslot extension time. */
+#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200)
+
+/**@brief The maximum processing time to handle a timeslot extension. */
+#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20)
+
+/**@brief The latest time before the end of a timeslot the timeslot can be extended. */
+#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82)
+
+#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */
+#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */
+#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */
+
+#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */
+#define SD_EVT_IRQHandler \
+ (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \
+ The default interrupt priority for this handler is set to 6 */
+#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */
+#define RADIO_NOTIFICATION_IRQHandler \
+ (SWI1_IRQHandler) /**< The radio notification IRQ handler. \
+ The default interrupt priority for this handler is set to 6 */
+#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */
+#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */
+
+#define NRF_RADIO_DISTANCE_MAX_US \
+ (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \
+ nrf_radio_request_normal_t) in the request. */
+
+#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \
+ (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */
+
+#define NRF_RADIO_START_JITTER_US \
+ (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */
+
+/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */
+#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0))
+
+/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */
+#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \
+ ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \
+ (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31)))
+
+/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */
+#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0))
+
+/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */
+#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5)))
+
+/**@} */
+
+/**@addtogroup NRF_SOC_ENUMS Enumerations
+ * @{ */
+
+/**@brief The SVC numbers used by the SVC functions in the SoC library. */
+enum NRF_SOC_SVCS {
+ SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE,
+ SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1,
+ SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2,
+ SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3,
+ SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4,
+ SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5,
+ SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6,
+ SD_PPI_GROUP_GET = SOC_SVC_BASE + 7,
+ SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8,
+ SD_FLASH_WRITE = SOC_SVC_BASE + 9,
+ SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11,
+ SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE,
+ SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1,
+ SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2,
+ SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3,
+ SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4,
+ SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5,
+ SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6,
+ SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7,
+ SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8,
+ SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9,
+ SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10,
+ SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11,
+ SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12,
+ SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13,
+ SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14,
+ SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15,
+ SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16,
+ SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17,
+ SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18,
+ SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19,
+ SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20,
+ SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21,
+ SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22,
+ SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23,
+ SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24,
+ SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25,
+ SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26,
+ SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27,
+ SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28,
+ SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29,
+ SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30,
+ SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31,
+ SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32,
+ SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33,
+ SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34,
+ SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35,
+ SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36,
+ SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37
+};
+
+/**@brief Possible values of a ::nrf_mutex_t. */
+enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN };
+
+/**@brief Power modes. */
+enum NRF_POWER_MODES {
+ NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */
+ NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */
+};
+
+/**@brief Power failure thresholds */
+enum NRF_POWER_THRESHOLDS {
+ NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */
+ NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */
+};
+
+/**@brief Power failure thresholds for high voltage */
+enum NRF_POWER_THRESHOLDVDDHS {
+ NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */
+ NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */
+};
+
+/**@brief DC/DC converter modes. */
+enum NRF_POWER_DCDC_MODES {
+ NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */
+ NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */
+};
+
+/**@brief Radio notification distances. */
+enum NRF_RADIO_NOTIFICATION_DISTANCES {
+ NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */
+ NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */
+};
+
+/**@brief Radio notification types. */
+enum NRF_RADIO_NOTIFICATION_TYPES {
+ NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */
+ NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */
+ NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */
+ NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and
+ disabled. */
+};
+
+/**@brief The Radio signal callback types. */
+enum NRF_RADIO_CALLBACK_SIGNAL_TYPE {
+ NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */
+ NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */
+ NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */
+ NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */
+ NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */
+};
+
+/**@brief The actions requested by the signal callback.
+ *
+ * This code gives the SOC instructions about what action to take when the signal callback has
+ * returned.
+ */
+enum NRF_RADIO_SIGNAL_CALLBACK_ACTION {
+ NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */
+ NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current
+ timeslot. Maximum execution time for this action:
+ @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US.
+ This action must be started at least
+ @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before
+ the end of the timeslot. */
+ NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */
+ NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */
+};
+
+/**@brief Radio timeslot high frequency clock source configuration. */
+enum NRF_RADIO_HFCLK_CFG {
+ NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the
+ external crystal for the whole duration of the timeslot. This should be the
+ preferred option for events that use the radio or require high timing accuracy.
+ @note The SoftDevice will automatically turn on and off the external crystal,
+ at the beginning and end of the timeslot, respectively. The crystal may also
+ intentionally be left running after the timeslot, in cases where it is needed
+ by the SoftDevice shortly after the end of the timeslot. */
+ NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots.
+ The RC oscillator may be the clock source in part or for the whole duration of the
+ timeslot. The RC oscillator's accuracy must therefore be taken into consideration.
+ @note If the application will use the radio peripheral in timeslots with this
+ configuration, it must make sure that the crystal is running and stable before
+ starting the radio. */
+};
+
+/**@brief Radio timeslot priorities. */
+enum NRF_RADIO_PRIORITY {
+ NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */
+ NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */
+};
+
+/**@brief Radio timeslot request type. */
+enum NRF_RADIO_REQUEST_TYPE {
+ NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first
+ request in a session. */
+ NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */
+};
+
+/**@brief SoC Events. */
+enum NRF_SOC_EVTS {
+ NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */
+ NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */
+ NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */
+ NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */
+ NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */
+ NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */
+ NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was
+ invalid. */
+ NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */
+ NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */
+ NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */
+ NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */
+ NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */
+ NRF_EVT_NUMBER_OF_EVTS
+};
+
+/**@} */
+
+/**@addtogroup NRF_SOC_STRUCTURES Structures
+ * @{ */
+
+/**@brief Represents a mutex for use with the nrf_mutex functions.
+ * @note Accessing the value directly is not safe, use the mutex functions!
+ */
+typedef volatile uint8_t nrf_mutex_t;
+
+/**@brief Parameters for a request for a timeslot as early as possible. */
+typedef struct {
+ uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */
+ uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */
+ uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */
+ uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref
+ NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */
+} nrf_radio_request_earliest_t;
+
+/**@brief Parameters for a normal radio timeslot request. */
+typedef struct {
+ uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */
+ uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */
+ uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US
+ microseconds). */
+ uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */
+} nrf_radio_request_normal_t;
+
+/**@brief Radio timeslot request parameters. */
+typedef struct {
+ uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */
+ union {
+ nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */
+ nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */
+ } params; /**< Parameter union. */
+} nrf_radio_request_t;
+
+/**@brief Return parameters of the radio timeslot signal callback. */
+typedef struct {
+ uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref
+ NRF_RADIO_SIGNAL_CALLBACK_ACTION. */
+ union {
+ struct {
+ nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */
+ } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */
+ struct {
+ uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref
+ NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */
+ } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */
+ } params; /**< Parameter union. */
+} nrf_radio_signal_callback_return_param_t;
+
+/**@brief The radio timeslot signal callback type.
+ *
+ * @note In case of invalid return parameters, the radio timeslot will automatically end
+ * immediately after returning from the signal callback and the
+ * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent.
+ * @note The returned struct pointer must remain valid after the signal callback
+ * function returns. For instance, this means that it must not point to a stack variable.
+ *
+ * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE.
+ *
+ * @return Pointer to structure containing action requested by the application.
+ */
+typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type);
+
+/**@brief AES ECB parameter typedefs */
+typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */
+typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */
+typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */
+
+/**@brief AES ECB data structure */
+typedef struct {
+ soc_ecb_key_t key; /**< Encryption key. */
+ soc_ecb_cleartext_t cleartext; /**< Cleartext data. */
+ soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */
+} nrf_ecb_hal_data_t;
+
+/**@brief AES ECB block. Used to provide multiple blocks in a single call
+ to @ref sd_ecb_blocks_encrypt.*/
+typedef struct {
+ soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */
+ soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */
+ soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */
+} nrf_ecb_hal_data_block_t;
+
+/**@} */
+
+/**@addtogroup NRF_SOC_FUNCTIONS Functions
+ * @{ */
+
+/**@brief Initialize a mutex.
+ *
+ * @param[in] p_mutex Pointer to the mutex to initialize.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex));
+
+/**@brief Attempt to acquire a mutex.
+ *
+ * @param[in] p_mutex Pointer to the mutex to acquire.
+ *
+ * @retval ::NRF_SUCCESS The mutex was successfully acquired.
+ * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired.
+ */
+SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex));
+
+/**@brief Release a mutex.
+ *
+ * @param[in] p_mutex Pointer to the mutex to release.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex));
+
+/**@brief Query the capacity of the application random pool.
+ *
+ * @param[out] p_pool_capacity The capacity of the pool.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity));
+
+/**@brief Get number of random bytes available to the application.
+ *
+ * @param[out] p_bytes_available The number of bytes currently available in the pool.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available));
+
+/**@brief Get random bytes from the application pool.
+ *
+ * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes.
+ * @param[in] length Number of bytes to take from pool and place in p_buff.
+ *
+ * @retval ::NRF_SUCCESS The requested bytes were written to p_buff.
+ * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes
+ * available.
+ */
+SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length));
+
+/**@brief Gets the reset reason register.
+ *
+ * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason));
+
+/**@brief Clears the bits of the reset reason register.
+ *
+ * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk));
+
+/**@brief Sets the power mode when in CPU sleep.
+ *
+ * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait
+ *
+ * @retval ::NRF_SUCCESS The power mode was set.
+ * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown.
+ */
+SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode));
+
+/**@brief Puts the chip in System OFF mode.
+ *
+ * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN
+ */
+SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void));
+
+/**@brief Enables or disables the power-fail comparator.
+ *
+ * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs.
+ * The event can be retrieved with sd_evt_get();
+ *
+ * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable));
+
+/**@brief Enables or disables the USB power ready event.
+ *
+ * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready.
+ * The event can be retrieved with sd_evt_get();
+ *
+ * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled.
+ *
+ * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable));
+
+/**@brief Enables or disables the power USB-detected event.
+ *
+ * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS.
+ * The event can be retrieved with sd_evt_get();
+ *
+ * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled.
+ *
+ * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable));
+
+/**@brief Enables or disables the power USB-removed event.
+ *
+ * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS.
+ * The event can be retrieved with sd_evt_get();
+ *
+ * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled.
+ *
+ * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable));
+
+/**@brief Get USB supply status register content.
+ *
+ * @param[out] usbregstatus The content of USBREGSTATUS register.
+ *
+ * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus));
+
+/**@brief Sets the power failure comparator threshold value.
+ *
+ * @note: Power failure comparator threshold setting. This setting applies both for normal voltage
+ * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to
+ * VDDH only).
+ *
+ * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS.
+ *
+ * @retval ::NRF_SUCCESS The power failure threshold was set.
+ * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown.
+ */
+SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold));
+
+/**@brief Sets the power failure comparator threshold value for high voltage.
+ *
+ * @note: Power failure comparator threshold setting for high voltage mode (supply connected to
+ * VDDH only). This setting does not apply for normal voltage mode (supply connected to both
+ * VDD and VDDH).
+ *
+ * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS.
+ *
+ * @retval ::NRF_SUCCESS The power failure threshold was set.
+ * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown.
+ */
+SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold));
+
+/**@brief Writes the NRF_POWER->RAM[index].POWERSET register.
+ *
+ * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to.
+ * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset));
+
+/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register.
+ *
+ * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to.
+ * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr));
+
+/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks.
+ *
+ * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from.
+ * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power));
+
+/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*).
+ *
+ * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2.
+ * @param[in] gpregret_msk Bits to be set in the GPREGRET register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk));
+
+/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*).
+ *
+ * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2.
+ * @param[in] gpregret_msk Bits to be clear in the GPREGRET register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk));
+
+/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*).
+ *
+ * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2.
+ * @param[out] p_gpregret Contents of the GPREGRET register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret));
+
+/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1).
+ *
+ * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES.
+ *
+ * @retval ::NRF_SUCCESS
+ * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid.
+ */
+SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode));
+
+/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0).
+ *
+ * For more details on the REG0 stage, please see product specification.
+ *
+ * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES.
+ *
+ * @retval ::NRF_SUCCESS
+ * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid.
+ */
+SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode));
+
+/**@brief Request the high frequency crystal oscillator.
+ *
+ * Will start the high frequency crystal oscillator, the startup time of the crystal varies
+ * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started.
+ *
+ * @see sd_clock_hfclk_is_running
+ * @see sd_clock_hfclk_release
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void));
+
+/**@brief Releases the high frequency crystal oscillator.
+ *
+ * Will stop the high frequency crystal oscillator, this happens immediately.
+ *
+ * @see sd_clock_hfclk_is_running
+ * @see sd_clock_hfclk_request
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void));
+
+/**@brief Checks if the high frequency crystal oscillator is running.
+ *
+ * @see sd_clock_hfclk_request
+ * @see sd_clock_hfclk_release
+ *
+ * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running));
+
+/**@brief Waits for an application event.
+ *
+ * An application event is either an application interrupt or a pended interrupt when the interrupt
+ * is disabled.
+ *
+ * When the application waits for an application event by calling this function, an interrupt that
+ * is enabled will be taken immediately on pending since this function will wait in thread mode,
+ * then the execution will return in the application's main thread.
+ *
+ * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M
+ * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets
+ * pended, this function will return to the application's main thread.
+ *
+ * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ
+ * in order to sleep using this function. This is only necessary for disabled interrupts, as
+ * the interrupt handler will clear the pending flag automatically for enabled interrupts.
+ *
+ * @note If an application interrupt has happened since the last time sd_app_evt_wait was
+ * called this function will return immediately and not go to sleep. This is to avoid race
+ * conditions that can occur when a flag is updated in the interrupt handler and processed
+ * in the main loop.
+ *
+ * @post An application interrupt has happened or a interrupt pending flag is set.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void));
+
+/**@brief Get PPI channel enable register contents.
+ *
+ * @param[out] p_channel_enable The contents of the PPI CHEN register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable));
+
+/**@brief Set PPI channel enable register.
+ *
+ * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk));
+
+/**@brief Clear PPI channel enable register.
+ *
+ * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk));
+
+/**@brief Assign endpoints to a PPI channel.
+ *
+ * @param[in] channel_num Number of the PPI channel to assign.
+ * @param[in] evt_endpoint Event endpoint of the PPI channel.
+ * @param[in] task_endpoint Task endpoint of the PPI channel.
+ *
+ * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid.
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t,
+ sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint));
+
+/**@brief Task to enable a channel group.
+ *
+ * @param[in] group_num Number of the channel group.
+ *
+ * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num));
+
+/**@brief Task to disable a channel group.
+ *
+ * @param[in] group_num Number of the PPI group.
+ *
+ * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num));
+
+/**@brief Assign PPI channels to a channel group.
+ *
+ * @param[in] group_num Number of the channel group.
+ * @param[in] channel_msk Mask of the channels to assign to the group.
+ *
+ * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk));
+
+/**@brief Gets the PPI channels of a channel group.
+ *
+ * @param[in] group_num Number of the channel group.
+ * @param[out] p_channel_msk Mask of the channels assigned to the group.
+ *
+ * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk));
+
+/**@brief Configures the Radio Notification signal.
+ *
+ * @note
+ * - The notification signal latency depends on the interrupt priority settings of SWI used
+ * for notification signal.
+ * - To ensure that the radio notification signal behaves in a consistent way, the radio
+ * notifications must be configured when there is no protocol stack or other SoftDevice
+ * activity in progress. It is recommended that the radio notification signal is
+ * configured directly after the SoftDevice has been enabled.
+ * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice
+ * will interrupt the application to do Radio Event preparation.
+ * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have
+ * to shorten the connection events to have time for the Radio Notification signals.
+ *
+ * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES.
+ * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio
+ * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is
+ * recommended (but not required) to be used with
+ * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE.
+ *
+ * @param[in] distance Distance between the notification signal and start of radio activity, see @ref
+ * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or
+ * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used.
+ *
+ * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid.
+ * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all
+ * running activities and retry.
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance));
+
+/**@brief Encrypts a block according to the specified parameters.
+ *
+ * 128-bit AES encryption.
+ *
+ * @note:
+ * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while
+ * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application
+ * main or low interrupt level.
+ *
+ * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input
+ * parameters and one output parameter).
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data));
+
+/**@brief Encrypts multiple data blocks provided as an array of data block structures.
+ *
+ * @details: Performs 128-bit AES encryption on multiple data blocks
+ *
+ * @note:
+ * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while
+ * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application
+ * main or low interrupt level.
+ *
+ * @param[in] block_count Count of blocks in the p_data_blocks array.
+ * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of
+ * @ref nrf_ecb_hal_data_block_t structures.
+ *
+ * @retval ::NRF_SUCCESS
+ */
+SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks));
+
+/**@brief Gets any pending events generated by the SoC API.
+ *
+ * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned.
+ *
+ * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending.
+ *
+ * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter.
+ * @retval ::NRF_ERROR_NOT_FOUND No pending events.
+ */
+SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id));
+
+/**@brief Get the temperature measured on the chip
+ *
+ * This function will block until the temperature measurement is done.
+ * It takes around 50 us from call to return.
+ *
+ * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius.
+ *
+ * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp
+ */
+SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp));
+
+/**@brief Flash Write
+ *
+ * Commands to write a buffer to flash
+ *
+ * If the SoftDevice is enabled:
+ * This call initiates the flash access command, and its completion will be communicated to the
+ * application with exactly one of the following events:
+ * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed.
+ * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started.
+ *
+ * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the
+ * write has been completed
+ *
+ * @note
+ * - This call takes control over the radio and the CPU during flash erase and write to make sure that
+ * they will not interfere with the flash access. This means that all interrupts will be blocked
+ * for a predictable time (depending on the NVMC specification in the device's Product Specification
+ * and the command parameters).
+ * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS
+ * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled.
+ * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is
+ * protected.
+ *
+ *
+ * @param[in] p_dst Pointer to start of flash location to be written.
+ * @param[in] p_src Pointer to buffer with data to be written.
+ * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one
+ * flash page. See the device's Product Specification for details.
+ *
+ * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned.
+ * @retval ::NRF_ERROR_BUSY The previous command has not yet completed.
+ * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size.
+ * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area.
+ * @retval ::NRF_SUCCESS The command was accepted.
+ */
+SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size));
+
+/**@brief Flash Erase page
+ *
+ * Commands to erase a flash page
+ * If the SoftDevice is enabled:
+ * This call initiates the flash access command, and its completion will be communicated to the
+ * application with exactly one of the following events:
+ * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed.
+ * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started.
+ *
+ * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the
+ * erase has been completed
+ *
+ * @note
+ * - This call takes control over the radio and the CPU during flash erase and write to make sure that
+ * they will not interfere with the flash access. This means that all interrupts will be blocked
+ * for a predictable time (depending on the NVMC specification in the device's Product Specification
+ * and the command parameters).
+ * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is
+ * protected.
+ *
+ *
+ * @param[in] page_number Page number of the page to erase
+ *
+ * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error.
+ * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page.
+ * @retval ::NRF_ERROR_BUSY The previous command has not yet completed.
+ * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area.
+ * @retval ::NRF_SUCCESS The command was accepted.
+ */
+SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number));
+
+/**@brief Opens a session for radio timeslot requests.
+ *
+ * @note Only one session can be open at a time.
+ * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot
+ * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed
+ * by the application.
+ * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0
+ * interrupt occurs.
+ * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO
+ * interrupt occurs.
+ * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This
+ * implies that none of the sd_* API calls can be used from p_radio_signal_callback().
+ *
+ * @param[in] p_radio_signal_callback The signal callback.
+ *
+ * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer.
+ * @retval ::NRF_ERROR_BUSY If session cannot be opened.
+ * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error.
+ * @retval ::NRF_SUCCESS Otherwise.
+ */
+SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback));
+
+/**@brief Closes a session for radio timeslot requests.
+ *
+ * @note Any current radio timeslot will be finished before the session is closed.
+ * @note If a radio timeslot is scheduled when the session is closed, it will be canceled.
+ * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED
+ * event is received.
+ *
+ * @retval ::NRF_ERROR_FORBIDDEN If session not opened.
+ * @retval ::NRF_ERROR_BUSY If session is currently being closed.
+ * @retval ::NRF_SUCCESS Otherwise.
+ */
+SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void));
+
+/**@brief Requests a radio timeslot.
+ *
+ * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST
+ * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref
+ * NRF_RADIO_REQ_TYPE_EARLIEST.
+ * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by
+ * p_request->distance_us and is given relative to the start of the previous timeslot.
+ * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event.
+ * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event.
+ * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths.
+ * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this
+ * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent.
+ * The application may then try to schedule the first radio timeslot again.
+ * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START).
+ * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS.
+ * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us.
+ * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the
+ * specified radio timeslot start, but this does not affect the actual start time of the timeslot.
+ * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency
+ * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is
+ * guaranteed to be clocked from the external crystal.
+ * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral
+ * during the radio timeslot.
+ *
+ * @param[in] p_request Pointer to the request parameters.
+ *
+ * @retval ::NRF_ERROR_FORBIDDEN Either:
+ * - The session is not open.
+ * - The session is not IDLE.
+ * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST.
+ * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a
+ * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked.
+ * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid.
+ * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid.
+ * @retval ::NRF_SUCCESS Otherwise.
+ */
+SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request));
+
+/**@brief Write register protected by the SoftDevice
+ *
+ * This function writes to a register that is write-protected by the SoftDevice. Please refer to your
+ * SoftDevice Specification for more details about which registers that are protected by SoftDevice.
+ * This function can write to the following protected peripheral:
+ * - ACL
+ *
+ * @note Protected registers may be read directly.
+ * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in
+ * the register has not changed. See the Product Specification for more details about register
+ * properties.
+ *
+ * @param[in] p_register Pointer to register to be written.
+ * @param[in] value Value to be written to the register.
+ *
+ * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register.
+ * @retval ::NRF_SUCCESS Value successfully written to register.
+ *
+ */
+SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value));
+
+/**@} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_SOC_H__
+
+/**@} */
diff --git a/variants/xiao_ble/softdevice/nrf_svc.h b/variants/xiao_ble/softdevice/nrf_svc.h
new file mode 100644
index 000000000..1de44656f
--- /dev/null
+++ b/variants/xiao_ble/softdevice/nrf_svc.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) Nordic Semiconductor ASA
+ * 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, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, 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 Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
+ */
+
+#ifndef NRF_SVC__
+#define NRF_SVC__
+
+#include "stdint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Supervisor call declaration.
+ *
+ * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception.
+ * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice.
+ *
+ * @param[in] number The SVC number to be used.
+ * @param[in] return_type The return type of the SVC function.
+ * @param[in] signature Function signature. The function can have at most four arguments.
+ */
+
+#ifdef SVCALL_AS_NORMAL_FUNCTION
+#define SVCALL(number, return_type, signature) return_type signature
+#else
+
+#ifndef SVCALL
+#if defined(__CC_ARM)
+#define SVCALL(number, return_type, signature) return_type __svc(number) signature
+#elif defined(__GNUC__)
+#ifdef __cplusplus
+#define GCC_CAST_CPP (uint16_t)
+#else
+#define GCC_CAST_CPP
+#endif
+#define SVCALL(number, return_type, signature) \
+ _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \
+ __attribute__((unused)) static return_type signature \
+ { \
+ __asm("svc %0\n" \
+ "bx r14" \
+ : \
+ : "I"(GCC_CAST_CPP number) \
+ : "r0"); \
+ } \
+ _Pragma("GCC diagnostic pop")
+
+#elif defined(__ICCARM__)
+#define PRAGMA(x) _Pragma(#x)
+#define SVCALL(number, return_type, signature) \
+ PRAGMA(swi_number = (number)) \
+ __swi return_type signature;
+#else
+#define SVCALL(number, return_type, signature) return_type signature
+#endif
+#endif // SVCALL
+
+#endif // SVCALL_AS_NORMAL_FUNCTION
+
+#ifdef __cplusplus
+}
+#endif
+#endif // NRF_SVC__
diff --git a/version.properties b/version.properties
index 69761c0ac..a26da1996 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
-build = 10
+build = 13