Merge remote-tracking branch 'adafruit/main' into robots.txt
This commit is contained in:
commit
ce59b54361
109
.github/workflows/build.yml
vendored
109
.github/workflows/build.yml
vendored
@ -14,7 +14,7 @@ on:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
@ -28,20 +28,47 @@ jobs:
|
||||
- name: CircuitPython version
|
||||
run: |
|
||||
git describe --dirty --tags
|
||||
echo "::set-env name=CP_VERSION::$(git describe --dirty --tags)"
|
||||
echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags)
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y eatmydata
|
||||
sudo eatmydata apt-get install -y gettext librsvg2-bin mingw-w64
|
||||
pip install requests sh click setuptools cpp-coveralls "Sphinx<4" sphinx-rtd-theme recommonmark sphinx-autoapi sphinxcontrib-svg2pdfconverter polib pyyaml astroid isort black awscli
|
||||
sudo eatmydata apt-get install -y gettext librsvg2-bin mingw-w64 latexmk texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra
|
||||
pip install requests sh click setuptools cpp-coveralls "Sphinx<4" sphinx-rtd-theme recommonmark sphinx-autoapi sphinxcontrib-svg2pdfconverter polib pyyaml astroid isort black awscli mypy
|
||||
- name: Versions
|
||||
run: |
|
||||
gcc --version
|
||||
python3 --version
|
||||
- name: Translations
|
||||
run: make check-translate
|
||||
- name: New boards check
|
||||
run: python3 -u ci_new_boards_check.py
|
||||
working-directory: tools
|
||||
- name: Duplicate USB VID/PID Check
|
||||
run: python3 -u -m tools.ci_check_duplicate_usb_vid_pid
|
||||
- name: Build and Validate Stubs
|
||||
run: make check-stubs -j2
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: stubs
|
||||
path: circuitpython-stubs*
|
||||
- name: Test Documentation Build (HTML)
|
||||
run: sphinx-build -E -W -b html -D version=${{ env.CP_VERSION }} -D release=${{ env.CP_VERSION }} . _build/html
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: docs
|
||||
path: _build/html
|
||||
- name: Test Documentation Build (LaTeX/PDF)
|
||||
run: |
|
||||
make latexpdf
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: docs
|
||||
path: _build/latex
|
||||
- name: Build mpy-cross
|
||||
run: make -C mpy-cross -j2
|
||||
- name: Build unix port
|
||||
@ -67,23 +94,6 @@ jobs:
|
||||
- name: mpy Tests
|
||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 --via-mpy -d basics float
|
||||
working-directory: tests
|
||||
- name: Stubs
|
||||
run: make stubs -j2
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: stubs
|
||||
path: circuitpython-stubs*
|
||||
- name: Docs
|
||||
run: sphinx-build -E -W -b html -D version=${{ env.CP_VERSION }} -D release=${{ env.CP_VERSION }} . _build/html
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: docs
|
||||
path: _build/html
|
||||
- name: Translations
|
||||
run: make check-translate
|
||||
- name: New boards check
|
||||
run: python3 -u ci_new_boards_check.py
|
||||
working-directory: tools
|
||||
- name: Build mpy-cross.static-raspbian
|
||||
run: make -C mpy-cross -j2 -f Makefile.static-raspbian
|
||||
- uses: actions/upload-artifact@v2
|
||||
@ -102,12 +112,15 @@ jobs:
|
||||
with:
|
||||
name: mpy-cross.static-x64-windows
|
||||
path: mpy-cross/mpy-cross.static.exe
|
||||
- name: Upload mpy-cross builds to S3
|
||||
- name: Upload stubs and mpy-cross builds to S3
|
||||
run: |
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross.static-raspbian s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross.static-raspbian-${{ env.CP_VERSION }} --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross.static s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross.static-amd64-linux-${{ env.CP_VERSION }} --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross.static.exe s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross.static-x64-windows-${{ env.CP_VERSION }}.exe --no-progress --region us-east-1
|
||||
zip -9r circuitpython-stubs.zip circuitpython-stubs
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp circuitpython-stubs.zip s3://adafruit-circuit-python/bin/stubs/circuitpython-stubs-${{ env.CP_VERSION }}.zip --no-progress --region us-east-1
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
if: github.event_name == 'push' || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
@ -122,8 +135,8 @@ jobs:
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install gettext awscli
|
||||
echo "::set-env name=PATH::/usr/local/opt/gettext/bin:$PATH"
|
||||
brew install gettext
|
||||
echo >>$GITHUB_PATH /usr/local/opt/gettext/bin
|
||||
- name: Versions
|
||||
run: |
|
||||
gcc --version
|
||||
@ -137,7 +150,7 @@ jobs:
|
||||
- name: CircuitPython version
|
||||
run: |
|
||||
git describe --dirty --tags
|
||||
echo "::set-env name=CP_VERSION::$(git describe --dirty --tags)"
|
||||
echo >>$GITHUB_ENV CP_VERSION=$(git describe --dirty --tags)
|
||||
- name: Build mpy-cross
|
||||
run: make -C mpy-cross -j2
|
||||
- uses: actions/upload-artifact@v2
|
||||
@ -148,19 +161,21 @@ jobs:
|
||||
run: |
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-catalina-${{ env.CP_VERSION }} --no-progress --region us-east-1
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
if: github.event_name == 'push' || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
|
||||
|
||||
build-arm:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board:
|
||||
- "8086_commander"
|
||||
- "ADM_B_NRF52840_1"
|
||||
- "TG-Watch02A"
|
||||
- "aloriumtech_evo_m51"
|
||||
- "aramcon_badge_2019"
|
||||
@ -170,7 +185,9 @@ jobs:
|
||||
- "arduino_nano_33_iot"
|
||||
- "arduino_zero"
|
||||
- "bast_pro_mini_m0"
|
||||
- "bdmicro_vina_m0"
|
||||
- "bastble"
|
||||
- "bdmicro_vina_d21"
|
||||
- "bdmicro_vina_d51"
|
||||
- "bless_dev_board_multi_sensor"
|
||||
- "blm_badge"
|
||||
- "capablerobot_usbhub"
|
||||
@ -183,11 +200,15 @@ jobs:
|
||||
- "circuitplayground_express_displayio"
|
||||
- "clue_nrf52840_express"
|
||||
- "cp32-m4"
|
||||
- "cp_sapling_m0"
|
||||
- "cp_sapling_m0_spiflash"
|
||||
- "datalore_ip_m4"
|
||||
- "datum_distance"
|
||||
- "datum_imu"
|
||||
- "datum_light"
|
||||
- "datum_weather"
|
||||
- "dynossat_edu_eps"
|
||||
- "dynossat_edu_obc"
|
||||
- "electronut_labs_blip"
|
||||
- "electronut_labs_papyr"
|
||||
- "escornabot_makech"
|
||||
@ -201,6 +222,7 @@ jobs:
|
||||
- "feather_m0_rfm69"
|
||||
- "feather_m0_rfm9x"
|
||||
- "feather_m0_supersized"
|
||||
- "feather_m4_can"
|
||||
- "feather_m4_express"
|
||||
- "feather_m7_1011"
|
||||
- "feather_mimxrt1011"
|
||||
@ -227,11 +249,13 @@ jobs:
|
||||
- "makerdiary_nrf52840_m2_devkit"
|
||||
- "makerdiary_nrf52840_mdk"
|
||||
- "makerdiary_nrf52840_mdk_usb_dongle"
|
||||
- "matrixportal_m4"
|
||||
- "meowbit_v121"
|
||||
- "meowmeow"
|
||||
- "metro_m0_express"
|
||||
- "metro_m4_airlift_lite"
|
||||
- "metro_m4_express"
|
||||
- "metro_m7_1011"
|
||||
- "metro_nrf52840_express"
|
||||
- "mini_sam_m4"
|
||||
- "monster_m4sk"
|
||||
@ -267,6 +291,8 @@ jobs:
|
||||
- "pyportal"
|
||||
- "pyportal_titano"
|
||||
- "pyruler"
|
||||
- "qtpy_m0"
|
||||
- "qtpy_m0_haxpress"
|
||||
- "raytac_mdbt50q-db-40"
|
||||
- "robohatmm1_m4"
|
||||
- "sam32"
|
||||
@ -286,6 +312,7 @@ jobs:
|
||||
- "sparkfun_samd21_mini"
|
||||
- "sparkfun_samd51_thing_plus"
|
||||
- "spresense"
|
||||
- "stackrduino_m0_pro"
|
||||
- "stm32f411ce_blackpill"
|
||||
- "stm32f411ve_discovery"
|
||||
- "stm32f412zg_discovery"
|
||||
@ -295,7 +322,8 @@ jobs:
|
||||
- "teensy40"
|
||||
- "teensy41"
|
||||
- "teknikio_bluebird"
|
||||
- "thunderpack"
|
||||
- "thunderpack_v11"
|
||||
- "thunderpack_v12"
|
||||
- "tinkeringtech_scoutmakes_azul"
|
||||
- "trellis_m4_express"
|
||||
- "trinket_m0"
|
||||
@ -317,8 +345,8 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get install -y gettext
|
||||
pip install requests sh click setuptools awscli
|
||||
wget https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2
|
||||
sudo tar -C /usr --strip-components=1 -xaf gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2
|
||||
wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
|
||||
sudo tar -C /usr --strip-components=1 -xaf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
|
||||
- name: Versions
|
||||
run: |
|
||||
gcc --version
|
||||
@ -343,12 +371,13 @@ jobs:
|
||||
- name: Upload to S3
|
||||
run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/ s3://adafruit-circuit-python/bin/ --recursive --no-progress --region us-east-1"
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
if: github.event_name == 'push' || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
|
||||
build-riscv:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -391,19 +420,29 @@ jobs:
|
||||
- name: Upload to S3
|
||||
run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/ s3://adafruit-circuit-python/bin/ --recursive --no-progress --region us-east-1"
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
if: github.event_name == 'push' || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
build-xtensa:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
needs: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board:
|
||||
- "adafruit_magtag_2.9_grayscale"
|
||||
- "adafruit_metro_esp32s2"
|
||||
- "electroniccats_bastwifi"
|
||||
- "espressif_kaluga_1"
|
||||
- "espressif_saola_1_wroom"
|
||||
- "espressif_saola_1_wrover"
|
||||
- "microdev_micro_s2"
|
||||
- "muselab_nanoesp32_s2"
|
||||
- "targett_module_clip_wroom"
|
||||
- "targett_module_clip_wrover"
|
||||
- "unexpectedmaker_feathers2"
|
||||
- "unexpectedmaker_feathers2_prerelease"
|
||||
|
||||
steps:
|
||||
- name: Set up Python 3.8
|
||||
@ -423,6 +462,11 @@ jobs:
|
||||
with:
|
||||
path: ${{ github.workspace }}/.idf_tools
|
||||
key: ${{ runner.os }}-idf-tools-${{ hashFiles('.git/modules/ports/esp32s2/esp-idf/HEAD') }}-20200801
|
||||
- name: Clone IDF submodules
|
||||
run: |
|
||||
(cd $IDF_PATH && git submodule update --init)
|
||||
env:
|
||||
IDF_PATH: ${{ github.workspace }}/ports/esp32s2/esp-idf
|
||||
- name: Install IDF tools
|
||||
run: |
|
||||
$IDF_PATH/tools/idf_tools.py --non-interactive install required
|
||||
@ -471,6 +515,7 @@ jobs:
|
||||
- name: Upload to S3
|
||||
run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp bin/ s3://adafruit-circuit-python/bin/ --recursive --no-progress --region us-east-1"
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
if: github.event_name == 'push' || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
|
2
.github/workflows/create_website_pr.yml
vendored
2
.github/workflows/create_website_pr.yml
vendored
@ -10,7 +10,7 @@ on:
|
||||
|
||||
jobs:
|
||||
website:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
|
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@ -11,12 +11,12 @@ on:
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v1
|
||||
- name: set PY
|
||||
run: echo "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
|
||||
run: echo >>$GITHUB_ENV PY="$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -80,6 +80,7 @@ TAGS
|
||||
*.mo
|
||||
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# Python Virtual Environments
|
||||
####################
|
||||
|
11
.gitmodules
vendored
11
.gitmodules
vendored
@ -144,6 +144,15 @@
|
||||
[submodule "frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center"]
|
||||
path = frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center
|
||||
url = https://github.com/adafruit/Adafruit_CircuitPython_BLE_Apple_Notification_Center
|
||||
[submodule "frozen/Adafruit_CircuitPython_RFM9x"]
|
||||
path = frozen/Adafruit_CircuitPython_RFM9x
|
||||
url = https://github.com/adafruit/Adafruit_CircuitPython_RFM9x.git
|
||||
[submodule "frozen/Adafruit_CircuitPython_RFM69"]
|
||||
path = frozen/Adafruit_CircuitPython_RFM69
|
||||
url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git
|
||||
[submodule "ports/esp32s2/esp-idf"]
|
||||
path = ports/esp32s2/esp-idf
|
||||
url = https://github.com/tannewt/esp-idf.git
|
||||
url = https://github.com/adafruit/esp-idf.git
|
||||
[submodule "ports/esp32s2/certificates/nina-fw"]
|
||||
path = ports/esp32s2/certificates/nina-fw
|
||||
url = https://github.com/adafruit/nina-fw.git
|
||||
|
@ -8,6 +8,6 @@ repos:
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
exclude: '^(tests/.*\.exp|tests/cmdline/.*|tests/.*/data/.*)'
|
||||
exclude: '^(tests/.*\.exp|tests/cmdline/.*|tests/.*/data/.*|ports/esp32s2/esp-idf-config/.*|ports/esp32s2/boards/.*/sdkconfig)'
|
||||
- id: trailing-whitespace
|
||||
exclude: '^(tests/.*\.exp|tests/cmdline/.*|tests/.*/data/.*)'
|
||||
|
@ -12,6 +12,9 @@ submodules:
|
||||
include:
|
||||
- extmod/ulab
|
||||
|
||||
formats:
|
||||
- pdf
|
||||
|
||||
python:
|
||||
version: 3
|
||||
install:
|
||||
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: MIT
|
||||
|
||||
# Contributing
|
||||
Please note that this project is released with a
|
||||
[Contributor Code of Conduct](https://github.com/adafruit/circuitpython/blob/main/CODE_OF_CONDUCT.md).
|
||||
[Contributor Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
By participating in this project you agree to abide by its terms. Participation
|
||||
covers any forum used to converse about CircuitPython including unofficial and official spaces. Failure to do
|
||||
so will result in corrective actions such as time out or ban from the project.
|
||||
|
20
Makefile
20
Makefile
@ -40,7 +40,19 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(BASEOPTS)
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(BASEOPTS)
|
||||
|
||||
TRANSLATE_SOURCES = extmod lib main.c ports/atmel-samd ports/cxd56 ports/mimxrt10xx ports/nrf ports/stm py shared-bindings shared-module supervisor
|
||||
TRANSLATE_SOURCES = extmod lib main.c ports/atmel-samd ports/cxd56 ports/esp32s2 ports/mimxrt10xx ports/nrf ports/stm py shared-bindings shared-module supervisor
|
||||
# Paths to exclude from TRANSLATE_SOURCES
|
||||
# Each must be preceded by "-path"; if any wildcards, enclose in quotes.
|
||||
# Separate by "-o" (Find's "or" operand)
|
||||
TRANSLATE_SOURCES_EXC = -path "ports/*/build-*" \
|
||||
-o -path "ports/*/build" \
|
||||
-o -path ports/esp32s2/esp-idf \
|
||||
-o -path ports/cxd56/spresense-exported-sdk \
|
||||
-o -path ports/stm/st_driver \
|
||||
-o -path ports/atmel-samd/asf4 \
|
||||
-o -path ports/mimxrt10xx/sdk \
|
||||
-o -path lib/tinyusb \
|
||||
-o -path lib/lwip \
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext stubs
|
||||
|
||||
@ -210,7 +222,7 @@ pseudoxml:
|
||||
all-source:
|
||||
|
||||
locale/circuitpython.pot: all-source
|
||||
find $(TRANSLATE_SOURCES) -iname "*.c" -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot -p locale
|
||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot -p locale
|
||||
|
||||
# Historically, `make translate` updated the .pot file and ran msgmerge.
|
||||
# However, this was a frequent source of merge conflicts. Weblate can perform
|
||||
@ -235,7 +247,7 @@ merge-translate:
|
||||
|
||||
.PHONY: check-translate
|
||||
check-translate:
|
||||
find $(TRANSLATE_SOURCES) -iname "*.c" -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot.tmp -p locale
|
||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot.tmp -p locale
|
||||
$(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status
|
||||
|
||||
stubs:
|
||||
@ -253,7 +265,7 @@ update-frozen-libraries:
|
||||
@echo "Updating all frozen libraries to latest tagged version."
|
||||
cd frozen; for library in *; do cd $$library; ../../tools/git-checkout-latest-tag.sh; cd ..; done
|
||||
|
||||
one-of-each: samd21 samd51 esp32s2 litex mimxrt10xx nrf stm
|
||||
one-of-each: samd21 litex mimxrt10xx nrf stm
|
||||
|
||||
samd21:
|
||||
$(MAKE) -C ports/atmel-samd BOARD=trinket_m0
|
||||
|
30
README.rst
30
README.rst
@ -95,7 +95,6 @@ Differences from `MicroPython <https://github.com/micropython/micropython>`__
|
||||
CircuitPython:
|
||||
|
||||
- Supports native USB on all boards, allowing file editing without special tools.
|
||||
- Supports only SAMD21, SAMD51, nRF52840, CXD56, STM32F4 and i.MX RT ports.
|
||||
- Floats (aka decimals) are enabled for all builds.
|
||||
- Error messages are translated into 10+ languages.
|
||||
- Does not support concurrency within Python (including interrupts and threading). Some concurrency
|
||||
@ -115,14 +114,14 @@ Behavior
|
||||
finishes or is interrupted. After it is done running, the vm and
|
||||
hardware is reinitialized. **This means you cannot read state from**
|
||||
``code.py`` **in the REPL anymore.** CircuitPython's goal for this
|
||||
change includes reduce confusion about pins and memory being used.
|
||||
change includes reducing confusion about pins and memory being used.
|
||||
- After ``code.py`` the REPL can be entered by pressing any key. It no
|
||||
longer shares state with ``code.py`` so it is a fresh vm.
|
||||
- Autoreload state will be maintained across reload.
|
||||
- Adds a safe mode that does not run user code after a hard crash or
|
||||
brown out. The hope is that this will make it easier to fix code that
|
||||
causes nasty crashes by making it available through mass storage
|
||||
after the crash. A reset (the button) is needed after its fixed to
|
||||
after the crash. A reset (the button) is needed after it's fixed to
|
||||
get back into normal mode.
|
||||
- RGB status LED indicating CircuitPython state, and errors through a sequence of colored flashes.
|
||||
- Re-runs ``code.py`` or other main file after file system writes over USB mass storage. (Disable with
|
||||
@ -137,8 +136,8 @@ Behavior
|
||||
API
|
||||
~~~
|
||||
|
||||
- Unified hardware APIs. Documented
|
||||
`on ReadTheDocs <https://circuitpython.readthedocs.io/en/latest/shared-bindings/index.html>`_.
|
||||
- Unified hardware APIs. Documented on
|
||||
`ReadTheDocs <https://circuitpython.readthedocs.io/en/latest/shared-bindings/index.html>`_.
|
||||
- API docs are rST within the C files in ``shared-bindings``.
|
||||
- No ``machine`` API.
|
||||
|
||||
@ -201,14 +200,27 @@ Ports
|
||||
Ports include the code unique to a microcontroller line and also
|
||||
variations based on the board.
|
||||
|
||||
- ``atmel-samd`` Support for SAMD21 and SAMD51 based boards.
|
||||
- ``nrf`` Support for the nRF52840 based boards.
|
||||
- ``unix`` Support for UNIX. Only used for automated testing.
|
||||
================ ============================================================
|
||||
Supported Support status
|
||||
================ ============================================================
|
||||
atmel-samd ``SAMD21`` stable | ``SAMD51`` stable
|
||||
cxd56 stable
|
||||
esp32s2 beta
|
||||
litex alpha
|
||||
mimxrt10xx alpha
|
||||
nrf stable
|
||||
stm ``F4`` stable | ``others`` beta
|
||||
unix alpha
|
||||
================ ============================================================
|
||||
|
||||
- ``stable`` Highly unlikely to have bugs or missing functionality.
|
||||
- ``beta`` Being actively improved but may be missing functionality and have bugs.
|
||||
- ``alpha`` Will have bugs and missing functionality.
|
||||
|
||||
The remaining port directories not listed above are in the repo to maintain compatibility with the
|
||||
`MicroPython <https://github.com/micropython/micropython>`__ parent project.
|
||||
|
||||
`back to top <#circuitpython>`__
|
||||
`Back to Top <#circuitpython>`__
|
||||
|
||||
.. |Build Status| image:: https://github.com/adafruit/circuitpython/workflows/Build%20CI/badge.svg
|
||||
:target: https://github.com/adafruit/circuitpython/actions?query=branch%3Amain
|
||||
|
6
conf.py
6
conf.py
@ -42,6 +42,9 @@ master_doc = 'docs/index'
|
||||
# Grab the JSON values to use while building the module support matrix
|
||||
# in 'shared-bindings/index.rst'
|
||||
|
||||
# The stubs must be built before we calculate the shared bindings matrix
|
||||
subprocess.check_output(["make", "stubs"])
|
||||
|
||||
#modules_support_matrix = shared_bindings_matrix.support_matrix_excluded_boards()
|
||||
modules_support_matrix = shared_bindings_matrix.support_matrix_by_board()
|
||||
|
||||
@ -77,7 +80,6 @@ source_suffix = {
|
||||
'.md': 'markdown',
|
||||
}
|
||||
|
||||
subprocess.check_output(["make", "stubs"])
|
||||
extensions.append('autoapi.extension')
|
||||
|
||||
autoapi_type = 'python'
|
||||
@ -144,6 +146,7 @@ version = release = final_version
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ["**/build*",
|
||||
".git",
|
||||
".env",
|
||||
".venv",
|
||||
".direnv",
|
||||
"docs/autoapi",
|
||||
@ -169,6 +172,7 @@ exclude_patterns = ["**/build*",
|
||||
"ports/atmel-samd/tools",
|
||||
"ports/cxd56/mkspk",
|
||||
"ports/cxd56/spresense-exported-sdk",
|
||||
"ports/esp32s2/certificates",
|
||||
"ports/esp32s2/esp-idf",
|
||||
"ports/esp32s2/peripherals",
|
||||
"ports/litex/hw",
|
||||
|
957
devices/ble_hci/common-hal/_bleio/Adapter.c
Normal file
957
devices/ble_hci/common-hal/_bleio/Adapter.c
Normal file
@ -0,0 +1,957 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hci.h"
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "supervisor/shared/safe_mode.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
#include "supervisor/usb.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Adapter.h"
|
||||
#include "shared-bindings/_bleio/Address.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
#include "shared-bindings/_bleio/ScanEntry.h"
|
||||
#include "shared-bindings/time/__init__.h"
|
||||
|
||||
#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))
|
||||
#define SEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000000) / (RESOLUTION))
|
||||
#define UNITS_TO_SEC(TIME, RESOLUTION) (((TIME) * (RESOLUTION)) / 1000000)
|
||||
// 0.625 msecs (625 usecs)
|
||||
#define ADV_INTERVAL_UNIT_FLOAT_SECS (0.000625)
|
||||
// Microseconds is the base unit. The macros above know that.
|
||||
#define UNIT_0_625_MS (625)
|
||||
#define UNIT_1_25_MS (1250)
|
||||
#define UNIT_10_MS (10000)
|
||||
|
||||
#define MAX_ADVERTISEMENT_SIZE (31)
|
||||
|
||||
// TODO make this settable from Python.
|
||||
#define DEFAULT_TX_POWER 0 // 0 dBm
|
||||
#define MAX_ANONYMOUS_ADV_TIMEOUT_SECS (60*15)
|
||||
#define MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS (180)
|
||||
|
||||
#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS)
|
||||
#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS)
|
||||
#define BLE_SLAVE_LATENCY 0
|
||||
#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS)
|
||||
|
||||
bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];
|
||||
|
||||
STATIC void add_generic_services(bleio_adapter_obj_t *adapter) {
|
||||
// Create Generic Access UUID, Service, and Characteristics.
|
||||
|
||||
// Generic Access Service setup.
|
||||
|
||||
bleio_uuid_obj_t *generic_access_service_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
generic_access_service_uuid->base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(generic_access_service_uuid, 0x1800, NULL);
|
||||
|
||||
bleio_uuid_obj_t *device_name_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
device_name_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(device_name_characteristic_uuid, 0x2A00, NULL);
|
||||
|
||||
bleio_uuid_obj_t *appearance_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
appearance_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(appearance_characteristic_uuid, 0x2A01, NULL);
|
||||
|
||||
// Not implemented:
|
||||
// Peripheral Preferred Connection Parameters
|
||||
// Central Address Resolution
|
||||
|
||||
bleio_service_obj_t *generic_access_service = m_new_obj(bleio_service_obj_t);
|
||||
generic_access_service->base.type = &bleio_service_type;
|
||||
common_hal_bleio_service_construct(generic_access_service, generic_access_service_uuid, false);
|
||||
|
||||
adapter->device_name_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->device_name_characteristic->base.type = &bleio_characteristic_type;
|
||||
|
||||
char generic_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 'n', 'n', 'n', 'n' };
|
||||
mp_buffer_info_t generic_name_bufinfo = {
|
||||
.buf = generic_name,
|
||||
.len = sizeof(generic_name),
|
||||
};
|
||||
|
||||
// Will be added to service by constructor.
|
||||
common_hal_bleio_characteristic_construct(
|
||||
adapter->device_name_characteristic,
|
||||
generic_access_service,
|
||||
BLE_GATT_HANDLE_INVALID,
|
||||
device_name_characteristic_uuid,
|
||||
CHAR_PROP_READ,
|
||||
SECURITY_MODE_OPEN,
|
||||
SECURITY_MODE_NO_ACCESS,
|
||||
248, // max length, from Bluetooth spec
|
||||
false, // not fixed length
|
||||
&generic_name_bufinfo
|
||||
);
|
||||
|
||||
uint16_t zero_16 = 0;
|
||||
mp_buffer_info_t zero_16_value = {
|
||||
.buf = &zero_16,
|
||||
.len = sizeof(zero_16),
|
||||
};
|
||||
|
||||
adapter->appearance_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->appearance_characteristic->base.type = &bleio_characteristic_type;
|
||||
|
||||
common_hal_bleio_characteristic_construct(
|
||||
adapter->appearance_characteristic,
|
||||
generic_access_service,
|
||||
BLE_GATT_HANDLE_INVALID,
|
||||
appearance_characteristic_uuid,
|
||||
CHAR_PROP_READ,
|
||||
SECURITY_MODE_OPEN,
|
||||
SECURITY_MODE_NO_ACCESS,
|
||||
2, // max length, from Bluetooth spec
|
||||
true, // fixed length
|
||||
&zero_16_value
|
||||
);
|
||||
|
||||
// Generic Attribute Service setup.
|
||||
|
||||
bleio_uuid_obj_t *generic_attribute_service_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
generic_attribute_service_uuid->base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(generic_attribute_service_uuid, 0x1801, NULL);
|
||||
|
||||
bleio_uuid_obj_t *service_changed_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
service_changed_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(service_changed_characteristic_uuid, 0x2A05, NULL);
|
||||
|
||||
bleio_service_obj_t *generic_attribute_service = m_new_obj(bleio_service_obj_t);
|
||||
generic_attribute_service->base.type = &bleio_service_type;
|
||||
common_hal_bleio_service_construct(generic_attribute_service, generic_attribute_service_uuid, false);
|
||||
|
||||
adapter->service_changed_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->service_changed_characteristic->base.type = &bleio_characteristic_type;
|
||||
|
||||
uint32_t zero_32 = 0;
|
||||
mp_buffer_info_t zero_32_value = {
|
||||
.buf = &zero_32,
|
||||
.len = sizeof(zero_32),
|
||||
};
|
||||
|
||||
common_hal_bleio_characteristic_construct(
|
||||
adapter->service_changed_characteristic,
|
||||
generic_attribute_service,
|
||||
BLE_GATT_HANDLE_INVALID,
|
||||
service_changed_characteristic_uuid,
|
||||
CHAR_PROP_INDICATE,
|
||||
SECURITY_MODE_OPEN,
|
||||
SECURITY_MODE_NO_ACCESS,
|
||||
4, // max length, from Bluetooth spec
|
||||
true, // fixed length
|
||||
&zero_32_value
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
STATIC void check_enabled(bleio_adapter_obj_t *adapter) {
|
||||
if (!common_hal_bleio_adapter_get_enabled(adapter)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Adapter not enabled"));
|
||||
}
|
||||
}
|
||||
|
||||
// STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||
// bleio_adapter_obj_t *self = (bleio_adapter_obj_t*)self_in;
|
||||
|
||||
// // For debugging.
|
||||
// // mp_printf(&mp_plat_print, "Adapter event: 0x%04x\n", ble_evt->header.evt_id);
|
||||
|
||||
// switch (ble_evt->header.evt_id) {
|
||||
// case BLE_GAP_EVT_CONNECTED: {
|
||||
// // Find an empty connection. One must always be available because the SD has the same
|
||||
// // total connection limit.
|
||||
// bleio_connection_internal_t *connection;
|
||||
// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
// connection = &bleio_connections[i];
|
||||
// if (connection->conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Central has connected.
|
||||
// ble_gap_evt_connected_t* connected = &ble_evt->evt.gap_evt.params.connected;
|
||||
|
||||
// connection->conn_handle = ble_evt->evt.gap_evt.conn_handle;
|
||||
// connection->connection_obj = mp_const_none;
|
||||
// connection->pair_status = PAIR_NOT_PAIRED;
|
||||
// connection->mtu = 0;
|
||||
|
||||
// ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection);
|
||||
// self->connection_objs = NULL;
|
||||
|
||||
// // Save the current connection parameters.
|
||||
// memcpy(&connection->conn_params, &connected->conn_params, sizeof(ble_gap_conn_params_t));
|
||||
|
||||
// #if CIRCUITPY_VERBOSE_BLE
|
||||
// ble_gap_conn_params_t *cp = &connected->conn_params;
|
||||
// mp_printf(&mp_plat_print, "conn params: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout);
|
||||
// #endif
|
||||
|
||||
// // See if connection interval set by Central is out of range.
|
||||
// // If so, negotiate our preferred range.
|
||||
// ble_gap_conn_params_t conn_params;
|
||||
// sd_ble_gap_ppcp_get(&conn_params);
|
||||
// if (conn_params.min_conn_interval < connected->conn_params.min_conn_interval ||
|
||||
// conn_params.min_conn_interval > connected->conn_params.max_conn_interval) {
|
||||
// sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params);
|
||||
// }
|
||||
// self->current_advertising_data = NULL;
|
||||
// break;
|
||||
// }
|
||||
// case BLE_GAP_EVT_DISCONNECTED: {
|
||||
// // Find the connection that was disconnected.
|
||||
// bleio_connection_internal_t *connection;
|
||||
// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
// connection = &bleio_connections[i];
|
||||
// if (connection->conn_handle == ble_evt->evt.gap_evt.conn_handle) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// ble_drv_remove_event_handler(connection_on_ble_evt, connection);
|
||||
// connection->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
// connection->pair_status = PAIR_NOT_PAIRED;
|
||||
// if (connection->connection_obj != mp_const_none) {
|
||||
// bleio_connection_obj_t* obj = connection->connection_obj;
|
||||
// obj->connection = NULL;
|
||||
// obj->disconnect_reason = ble_evt->evt.gap_evt.params.disconnected.reason;
|
||||
// }
|
||||
// self->connection_objs = NULL;
|
||||
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_ADV_SET_TERMINATED:
|
||||
// self->current_advertising_data = NULL;
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// // For debugging.
|
||||
// // mp_printf(&mp_plat_print, "Unhandled adapter event: 0x%04x\n", ble_evt->header.evt_id);
|
||||
// return false;
|
||||
// break;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0};
|
||||
|
||||
// Get various values and limits set by the adapter.
|
||||
// Set event mask.
|
||||
STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) {
|
||||
|
||||
const size_t len = sizeof(default_ble_name);
|
||||
|
||||
bt_addr_t addr;
|
||||
hci_check_error(hci_read_bd_addr(&addr));
|
||||
|
||||
default_ble_name[len - 4] = nibble_to_hex_lower[addr.val[1] >> 4 & 0xf];
|
||||
default_ble_name[len - 3] = nibble_to_hex_lower[addr.val[1] & 0xf];
|
||||
default_ble_name[len - 2] = nibble_to_hex_lower[addr.val[0] >> 4 & 0xf];
|
||||
default_ble_name[len - 1] = nibble_to_hex_lower[addr.val[0] & 0xf];
|
||||
self->name = mp_obj_new_str(default_ble_name, len);
|
||||
|
||||
// Get version information.
|
||||
if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version,
|
||||
&self->manufacturer, &self->lmp_subversion) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read HCI version"));
|
||||
}
|
||||
// Get supported features.
|
||||
if (hci_le_read_local_supported_features(self->features) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read BLE features"));
|
||||
}
|
||||
|
||||
// Enabled desired events.
|
||||
// Most importantly, includes:
|
||||
// BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61)
|
||||
if (hci_set_event_mask(0x3FFFFFFFFFFFFFFF) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not set event mask"));
|
||||
}
|
||||
// The default events for LE are:
|
||||
// BT_EVT_MASK_LE_CONN_COMPLETE, BT_EVT_MASK_LE_ADVERTISING_REPORT,
|
||||
// BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE, BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE
|
||||
// BT_EVT_MASK_LE_LTK_REQUEST.
|
||||
// That's all we need right now, so we don't bother to set the LE event mask.
|
||||
|
||||
// Get ACL buffer info.
|
||||
uint16_t le_max_len;
|
||||
uint8_t le_max_num;
|
||||
if (hci_le_read_buffer_size(&le_max_len, &le_max_num) == HCI_OK) {
|
||||
self->max_acl_buffer_len = le_max_len;
|
||||
self->max_acl_num_buffers = le_max_num;
|
||||
} else {
|
||||
// LE Read Buffer Size not available; use the general Read Buffer Size.
|
||||
uint16_t acl_max_len;
|
||||
uint8_t sco_max_len;
|
||||
uint16_t acl_max_num;
|
||||
uint16_t sco_max_num;
|
||||
if (hci_read_buffer_size(&acl_max_len, &sco_max_len, &acl_max_num, &sco_max_num) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read BLE buffer info"));
|
||||
}
|
||||
self->max_acl_buffer_len = acl_max_len;
|
||||
self->max_acl_num_buffers = acl_max_num;
|
||||
}
|
||||
|
||||
// Get max advertising length if extended advertising is supported.
|
||||
if (BT_FEAT_LE_EXT_ADV(self->features)) {
|
||||
uint16_t max_adv_data_len;
|
||||
if (hci_le_read_maximum_advertising_data_length(&max_adv_data_len) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not get max advertising length"));
|
||||
}
|
||||
self->max_adv_data_len = max_adv_data_len;
|
||||
} else {
|
||||
self->max_adv_data_len = MAX_ADVERTISEMENT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_construct_hci_uart(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts) {
|
||||
self->allocated = true;
|
||||
self->hci_uart = uart;
|
||||
self->rts_digitalinout = rts;
|
||||
self->cts_digitalinout = cts;
|
||||
|
||||
// Advertising-related fields are initialized by common_hal_bleio_adapter_set_enabled().
|
||||
self->enabled = false;
|
||||
|
||||
common_hal_bleio_adapter_set_enabled(self, true);
|
||||
bleio_adapter_hci_init(self);
|
||||
common_hal_bleio_adapter_set_name(self, default_ble_name);
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) {
|
||||
const bool is_enabled = common_hal_bleio_adapter_get_enabled(self);
|
||||
|
||||
// Don't enable or disable twice
|
||||
if (is_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->enabled = enabled;
|
||||
|
||||
// We must poll for input from the HCI adapter.
|
||||
// TODO Can we instead trigger an interrupt on UART input traffic?
|
||||
if (enabled) {
|
||||
supervisor_enable_tick();
|
||||
} else {
|
||||
supervisor_disable_tick();
|
||||
}
|
||||
|
||||
// Enabling or disabling: stop any current activity; reset to known state.
|
||||
hci_reset();
|
||||
self->now_advertising = false;
|
||||
self->extended_advertising = false;
|
||||
self->circuitpython_advertising = false;
|
||||
self->advertising_timeout_msecs = 0;
|
||||
|
||||
if (enabled) {
|
||||
// Reset list of known attributes.
|
||||
// Indices into the list are handles. Handle 0x0000 designates an invalid handle,
|
||||
// so store None there to skip it.
|
||||
self->attributes = mp_obj_new_list(0, NULL);
|
||||
bleio_adapter_add_attribute(self, mp_const_none);
|
||||
add_generic_services(self);
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) {
|
||||
return self->enabled;
|
||||
}
|
||||
|
||||
bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) {
|
||||
check_enabled(self);
|
||||
|
||||
bt_addr_t addr;
|
||||
hci_check_error(hci_read_bd_addr(&addr));
|
||||
|
||||
bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t);
|
||||
address->base.type = &bleio_address_type;
|
||||
|
||||
common_hal_bleio_address_construct(address, addr.val, BT_ADDR_LE_PUBLIC);
|
||||
return address;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) {
|
||||
return false;
|
||||
}
|
||||
return hci_le_set_random_address(bufinfo.buf) == HCI_OK;
|
||||
}
|
||||
|
||||
mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) {
|
||||
return self->name;
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name) {
|
||||
self->name = mp_obj_new_str(name, strlen(name));
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(self->name, &bufinfo, MP_BUFFER_READ);
|
||||
bleio_characteristic_set_local_value(self->device_name_characteristic, &bufinfo);
|
||||
}
|
||||
|
||||
|
||||
// STATIC bool scan_on_ble_evt(ble_evt_t *ble_evt, void *scan_results_in) {
|
||||
// bleio_scanresults_obj_t *scan_results = (bleio_scanresults_obj_t*)scan_results_in;
|
||||
|
||||
// if (ble_evt->header.evt_id == BLE_GAP_EVT_TIMEOUT &&
|
||||
// ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN) {
|
||||
// shared_module_bleio_scanresults_set_done(scan_results, true);
|
||||
// ble_drv_remove_event_handler(scan_on_ble_evt, scan_results);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) {
|
||||
// return false;
|
||||
// }
|
||||
// ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report;
|
||||
|
||||
// shared_module_bleio_scanresults_append(scan_results,
|
||||
// supervisor_ticks_ms64(),
|
||||
// report->type.connectable,
|
||||
// report->type.scan_response,
|
||||
// report->rssi,
|
||||
// report->peer_addr.addr,
|
||||
// report->peer_addr.addr_type,
|
||||
// report->data.p_data,
|
||||
// report->data.len);
|
||||
|
||||
// const uint32_t err_code = sd_ble_gap_scan_start(NULL, scan_results->common_hal_data);
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// // TODO: Pass the error into the scan results so it can throw an exception.
|
||||
// scan_results->done = true;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) {
|
||||
// TODO
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
check_enabled(self);
|
||||
|
||||
if (self->scan_results != NULL) {
|
||||
if (!shared_module_bleio_scanresults_get_done(self->scan_results)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Scan already in progess. Stop with stop_scan."));
|
||||
}
|
||||
self->scan_results = NULL;
|
||||
}
|
||||
self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi);
|
||||
|
||||
// size_t max_packet_size = extended ? BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED : BLE_GAP_SCAN_BUFFER_MAX;
|
||||
// uint8_t *raw_data = m_malloc(sizeof(ble_data_t) + max_packet_size, false);
|
||||
// ble_data_t * sd_data = (ble_data_t *) raw_data;
|
||||
// self->scan_results->common_hal_data = sd_data;
|
||||
// sd_data->len = max_packet_size;
|
||||
// sd_data->p_data = raw_data + sizeof(ble_data_t);
|
||||
|
||||
// ble_drv_add_event_handler(scan_on_ble_evt, self->scan_results);
|
||||
|
||||
// uint32_t nrf_timeout = SEC_TO_UNITS(timeout, UNIT_10_MS);
|
||||
// if (timeout <= 0.0001) {
|
||||
// nrf_timeout = BLE_GAP_SCAN_TIMEOUT_UNLIMITED;
|
||||
// }
|
||||
|
||||
// ble_gap_scan_params_t scan_params = {
|
||||
// .extended = extended,
|
||||
// .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS),
|
||||
// .timeout = nrf_timeout,
|
||||
// .window = SEC_TO_UNITS(window, UNIT_0_625_MS),
|
||||
// .scan_phys = BLE_GAP_PHY_1MBPS,
|
||||
// .active = active
|
||||
// };
|
||||
// uint32_t err_code;
|
||||
// vm_used_ble = true;
|
||||
// err_code = sd_ble_gap_scan_start(&scan_params, sd_data);
|
||||
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// self->scan_results = NULL;
|
||||
// ble_drv_remove_event_handler(scan_on_ble_evt, self->scan_results);
|
||||
// check_nrf_error(err_code);
|
||||
// }
|
||||
|
||||
return MP_OBJ_FROM_PTR(self->scan_results);
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) {
|
||||
// TODO
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
check_enabled(self);
|
||||
|
||||
// If not already scanning, no problem.
|
||||
if (hci_le_set_scan_enable(BT_HCI_LE_SCAN_DISABLE, BT_HCI_LE_SCAN_FILTER_DUP_DISABLE) == HCI_OK) {
|
||||
shared_module_bleio_scanresults_set_done(self->scan_results, true);
|
||||
self->scan_results = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// typedef struct {
|
||||
// uint16_t conn_handle;
|
||||
// volatile bool done;
|
||||
// } connect_info_t;
|
||||
|
||||
// STATIC bool connect_on_ble_evt(ble_evt_t *ble_evt, void *info_in) {
|
||||
// connect_info_t *info = (connect_info_t*)info_in;
|
||||
|
||||
// switch (ble_evt->header.evt_id) {
|
||||
// case BLE_GAP_EVT_CONNECTED:
|
||||
// info->conn_handle = ble_evt->evt.gap_evt.conn_handle;
|
||||
// info->done = true;
|
||||
|
||||
// break;
|
||||
|
||||
// case BLE_GAP_EVT_TIMEOUT:
|
||||
// // Handle will be invalid.
|
||||
// info->done = true;
|
||||
// break;
|
||||
// default:
|
||||
// // For debugging.
|
||||
// // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id);
|
||||
// return false;
|
||||
// break;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) {
|
||||
// TODO
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
|
||||
check_enabled(self);
|
||||
|
||||
// ble_gap_addr_t addr;
|
||||
|
||||
// addr.addr_type = address->type;
|
||||
// mp_buffer_info_t address_buf_info;
|
||||
// mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ);
|
||||
// memcpy(addr.addr, (uint8_t *) address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES);
|
||||
|
||||
// ble_gap_scan_params_t scan_params = {
|
||||
// .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS),
|
||||
// .window = MSEC_TO_UNITS(100, UNIT_0_625_MS),
|
||||
// .scan_phys = BLE_GAP_PHY_1MBPS,
|
||||
// // timeout of 0 means no timeout
|
||||
// .timeout = SEC_TO_UNITS(timeout, UNIT_10_MS),
|
||||
// };
|
||||
|
||||
// ble_gap_conn_params_t conn_params = {
|
||||
// .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS),
|
||||
// .min_conn_interval = MSEC_TO_UNITS(15, UNIT_1_25_MS),
|
||||
// .max_conn_interval = MSEC_TO_UNITS(300, UNIT_1_25_MS),
|
||||
// .slave_latency = 0, // number of conn events
|
||||
// };
|
||||
|
||||
// connect_info_t event_info;
|
||||
// ble_drv_add_event_handler(connect_on_ble_evt, &event_info);
|
||||
// event_info.done = false;
|
||||
|
||||
vm_used_ble = true;
|
||||
// uint32_t err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM);
|
||||
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// ble_drv_remove_event_handler(connect_on_ble_evt, &event_info);
|
||||
// check_nrf_error(err_code);
|
||||
// }
|
||||
|
||||
// while (!event_info.done) {
|
||||
// RUN_BACKGROUND_TASKS;
|
||||
// }
|
||||
|
||||
// ble_drv_remove_event_handler(connect_on_ble_evt, &event_info);
|
||||
|
||||
// uint16_t conn_handle = event_info.conn_handle;
|
||||
// if (conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
// mp_raise_bleio_BluetoothError(translate("Failed to connect: timeout"));
|
||||
// }
|
||||
|
||||
// // Negotiate for better PHY, larger MTU and data lengths since we are the central. These are
|
||||
// // nice-to-haves so ignore any errors.
|
||||
// ble_gap_phys_t const phys = {
|
||||
// .rx_phys = BLE_GAP_PHY_AUTO,
|
||||
// .tx_phys = BLE_GAP_PHY_AUTO,
|
||||
// };
|
||||
// sd_ble_gap_phy_update(conn_handle, &phys);
|
||||
// sd_ble_gattc_exchange_mtu_request(conn_handle, BLE_GATTS_VAR_ATTR_LEN_MAX);
|
||||
// sd_ble_gap_data_length_update(conn_handle, NULL, NULL);
|
||||
|
||||
// Make the connection object and return it.
|
||||
// for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
// bleio_connection_internal_t *connection = &bleio_connections[i];
|
||||
// if (connection->conn_handle == conn_handle) {
|
||||
// return bleio_connection_new_from_internal(connection);
|
||||
// }
|
||||
// }
|
||||
|
||||
mp_raise_bleio_BluetoothError(translate("Failed to connect: internal error"));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void check_data_fit(size_t data_len, bool connectable) {
|
||||
if (data_len > MAX_ADVERTISEMENT_SIZE) {
|
||||
mp_raise_ValueError(translate("Data too large for advertisement packet"));
|
||||
}
|
||||
}
|
||||
|
||||
// STATIC bool advertising_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||
// bleio_adapter_obj_t *self = (bleio_adapter_obj_t*)self_in;
|
||||
|
||||
// switch (ble_evt->header.evt_id) {
|
||||
// case BLE_GAP_EVT_ADV_SET_TERMINATED:
|
||||
// common_hal_bleio_adapter_stop_advertising(self);
|
||||
// ble_drv_remove_event_handler(advertising_on_ble_evt, self_in);
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// // For debugging.
|
||||
// // mp_printf(&mp_plat_print, "Unhandled advertising event: 0x%04x\n", ble_evt->header.evt_id);
|
||||
// return false;
|
||||
// break;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len) {
|
||||
check_enabled(self);
|
||||
|
||||
if (self->now_advertising) {
|
||||
if (self->circuitpython_advertising) {
|
||||
common_hal_bleio_adapter_stop_advertising(self);
|
||||
} else {
|
||||
// User-requested advertising.
|
||||
// TODO allow multiple advertisements.
|
||||
// Already advertising. Can't advertise twice.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Peer address, which we don't use (no directed advertising).
|
||||
bt_addr_le_t empty_addr = { 0 };
|
||||
|
||||
bool extended =
|
||||
advertising_data_len > self->max_adv_data_len || scan_response_data_len > self->max_adv_data_len;
|
||||
|
||||
if (extended) {
|
||||
if (!BT_FEAT_LE_EXT_ADV(self->features)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Data length needs extended advertising, but this adapter does not support it"));
|
||||
}
|
||||
|
||||
uint16_t props = 0;
|
||||
if (connectable) {
|
||||
props |= BT_HCI_LE_ADV_PROP_CONN;
|
||||
}
|
||||
if (scan_response_data_len > 0) {
|
||||
props |= BT_HCI_LE_ADV_PROP_SCAN;
|
||||
}
|
||||
|
||||
// Advertising interval.
|
||||
uint32_t interval_units = SEC_TO_UNITS(interval, UNIT_0_625_MS);
|
||||
|
||||
hci_check_error(
|
||||
hci_le_set_extended_advertising_parameters(
|
||||
0, // handle
|
||||
props, // adv properties
|
||||
interval_units, // min interval
|
||||
interval_units, // max interval
|
||||
0b111, // channel map: channels 37, 38, 39
|
||||
anonymous ? BT_ADDR_LE_RANDOM : BT_ADDR_LE_PUBLIC,
|
||||
&empty_addr, // peer_addr,
|
||||
0x00, // filter policy: no filter
|
||||
DEFAULT_TX_POWER,
|
||||
BT_HCI_LE_EXT_SCAN_PHY_1M, // Secondary PHY to use
|
||||
0x00, // AUX_ADV_IND shall be sent prior to next adv event
|
||||
BT_HCI_LE_EXT_SCAN_PHY_1M, // Secondary PHY to use
|
||||
0x00, // Advertising SID
|
||||
0x00 // Scan req notify disable
|
||||
));
|
||||
|
||||
// We can use the duration mechanism provided, instead of our own.
|
||||
self->advertising_timeout_msecs = 0;
|
||||
|
||||
uint8_t handle[1] = { 0 };
|
||||
uint16_t duration_10msec[1] = { timeout * 100 };
|
||||
uint8_t max_ext_adv_evts[1] = { 0 };
|
||||
hci_check_error(
|
||||
hci_le_set_extended_advertising_enable(
|
||||
BT_HCI_LE_ADV_ENABLE,
|
||||
1, // one advertising set.
|
||||
handle,
|
||||
duration_10msec,
|
||||
max_ext_adv_evts
|
||||
));
|
||||
|
||||
self->extended_advertising = true;
|
||||
} else {
|
||||
// Legacy advertising (not extended).
|
||||
|
||||
uint8_t adv_type;
|
||||
if (connectable) {
|
||||
// Connectable, scannable, undirected.
|
||||
adv_type = BT_HCI_ADV_IND;
|
||||
} else if (scan_response_data_len > 0) {
|
||||
// Unconnectable, scannable, undirected.
|
||||
adv_type = BT_HCI_ADV_SCAN_IND;
|
||||
} else {
|
||||
// Unconnectable, unscannable, undirected.
|
||||
adv_type = BT_HCI_ADV_NONCONN_IND;
|
||||
}
|
||||
|
||||
// Advertising interval.
|
||||
uint16_t interval_units = SEC_TO_UNITS(interval, UNIT_0_625_MS);
|
||||
|
||||
hci_check_error(
|
||||
hci_le_set_advertising_parameters(
|
||||
interval_units, // min interval
|
||||
interval_units, // max interval
|
||||
adv_type,
|
||||
anonymous ? BT_ADDR_LE_RANDOM : BT_ADDR_LE_PUBLIC,
|
||||
&empty_addr,
|
||||
0b111, // channel map: channels 37, 38, 39
|
||||
0x00 // filter policy: no filter
|
||||
));
|
||||
|
||||
// The HCI commands expect MAX_ADVERTISEMENT_SIZE (31)octets,
|
||||
// even though the actual data length may be shorter.
|
||||
uint8_t full_data[MAX_ADVERTISEMENT_SIZE] = { 0 };
|
||||
memcpy(full_data, advertising_data, MIN(sizeof(full_data), advertising_data_len));
|
||||
hci_check_error(hci_le_set_advertising_data(advertising_data_len, full_data));
|
||||
memset(full_data, 0, sizeof(full_data));
|
||||
if (scan_response_data_len > 0) {
|
||||
memcpy(full_data, scan_response_data, MIN(sizeof(full_data), scan_response_data_len));
|
||||
hci_check_error(hci_le_set_scan_response_data(scan_response_data_len, full_data));
|
||||
}
|
||||
|
||||
// No duration mechanism is provided for legacy advertising, so we need to do our own.
|
||||
self->advertising_timeout_msecs = timeout * 1000;
|
||||
self->advertising_start_ticks = supervisor_ticks_ms64();
|
||||
|
||||
// Start advertising.
|
||||
hci_check_error(hci_le_set_advertising_enable(BT_HCI_LE_ADV_ENABLE));
|
||||
self->extended_advertising = false;
|
||||
} // end legacy advertising setup
|
||||
|
||||
vm_used_ble = true;
|
||||
self->now_advertising = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) {
|
||||
check_enabled(self);
|
||||
|
||||
// interval value has already been validated.
|
||||
|
||||
check_data_fit(advertising_data_bufinfo->len, connectable);
|
||||
check_data_fit(scan_response_data_bufinfo->len, connectable);
|
||||
|
||||
if (advertising_data_bufinfo->len > MAX_ADVERTISEMENT_SIZE && scan_response_data_bufinfo->len > 0) {
|
||||
mp_raise_bleio_BluetoothError(translate("Extended advertisements with scan response not supported."));
|
||||
}
|
||||
|
||||
// Anonymous mode requires a timeout so that we don't continue to broadcast
|
||||
// the same data while cycling the MAC address -- otherwise, what's the
|
||||
// point of randomizing the MAC address?
|
||||
if (timeout == 0 && anonymous) {
|
||||
timeout = MAX_ANONYMOUS_ADV_TIMEOUT_SECS;
|
||||
} else {
|
||||
if (timeout > MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS) {
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"),
|
||||
MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t result =_common_hal_bleio_adapter_start_advertising(
|
||||
self, connectable, anonymous, timeout, interval,
|
||||
advertising_data_bufinfo->buf,
|
||||
advertising_data_bufinfo->len,
|
||||
scan_response_data_bufinfo->buf,
|
||||
scan_response_data_bufinfo->len);
|
||||
|
||||
if (result) {
|
||||
mp_raise_bleio_BluetoothError(translate("Already advertising"));
|
||||
}
|
||||
self->circuitpython_advertising = false;
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) {
|
||||
check_enabled(self);
|
||||
|
||||
self->now_advertising = false;
|
||||
self->extended_advertising = false;
|
||||
self->circuitpython_advertising = false;
|
||||
|
||||
int result = hci_le_set_advertising_enable(BT_HCI_LE_ADV_DISABLE);
|
||||
// OK if we're already stopped. There seems to be an ESP32 HCI bug:
|
||||
// If advertising is already off, then LE_SET_ADV_ENABLE does not return a response.
|
||||
if (result != HCI_RESPONSE_TIMEOUT) {
|
||||
hci_check_error(result);
|
||||
}
|
||||
|
||||
//TODO startup CircuitPython advertising again.
|
||||
}
|
||||
|
||||
// Note that something stopped advertising, such as a connection happening.
|
||||
//Don't ask the adapter to stop.
|
||||
void bleio_adapter_advertising_was_stopped(bleio_adapter_obj_t *self) {
|
||||
self->now_advertising = false;
|
||||
self->extended_advertising = false;
|
||||
self->circuitpython_advertising = false;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) {
|
||||
check_enabled(self);
|
||||
|
||||
return self->now_advertising;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) {
|
||||
check_enabled(self);
|
||||
|
||||
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
bleio_connection_internal_t *connection = &bleio_connections[i];
|
||||
if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) {
|
||||
check_enabled(self);
|
||||
|
||||
if (self->connection_objs != NULL) {
|
||||
return self->connection_objs;
|
||||
}
|
||||
size_t total_connected = 0;
|
||||
mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT];
|
||||
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
bleio_connection_internal_t *connection = &bleio_connections[i];
|
||||
if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
if (connection->connection_obj == mp_const_none) {
|
||||
connection->connection_obj = bleio_connection_new_from_internal(connection);
|
||||
}
|
||||
items[total_connected] = connection->connection_obj;
|
||||
total_connected++;
|
||||
}
|
||||
}
|
||||
self->connection_objs = mp_obj_new_tuple(total_connected, items);
|
||||
return self->connection_objs;
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) {
|
||||
// TODO
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
check_enabled(self);
|
||||
|
||||
//FIX bonding_erase_storage();
|
||||
}
|
||||
|
||||
uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute) {
|
||||
check_enabled(adapter);
|
||||
|
||||
// The handle is the index of this attribute in the attributes list.
|
||||
uint16_t handle = (uint16_t) adapter->attributes->len;
|
||||
mp_obj_list_append(adapter->attributes, attribute);
|
||||
|
||||
if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) {
|
||||
adapter->last_added_service_handle = handle;
|
||||
}
|
||||
if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) {
|
||||
adapter->last_added_characteristic_handle = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle) {
|
||||
check_enabled(adapter);
|
||||
|
||||
if (handle == 0 || handle >= adapter->attributes->len) {
|
||||
return mp_const_none;
|
||||
}
|
||||
return adapter->attributes->items[handle];
|
||||
}
|
||||
|
||||
uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter) {
|
||||
check_enabled(adapter);
|
||||
|
||||
return adapter->attributes->len - 1;
|
||||
}
|
||||
|
||||
|
||||
void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter) {
|
||||
gc_collect_root((void**)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t));
|
||||
gc_collect_root((void**)bleio_connections, sizeof(bleio_connections) / sizeof(size_t));
|
||||
}
|
||||
|
||||
void bleio_adapter_reset(bleio_adapter_obj_t* adapter) {
|
||||
|
||||
if (!common_hal_bleio_adapter_get_enabled(adapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adapter will be reset.
|
||||
common_hal_bleio_adapter_set_enabled(adapter, false);
|
||||
|
||||
adapter->connection_objs = NULL;
|
||||
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
bleio_connection_internal_t *connection = &bleio_connections[i];
|
||||
// Disconnect all connections with Python state cleanly. Keep any supervisor-only connections.
|
||||
if (connection->connection_obj != mp_const_none &&
|
||||
connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
common_hal_bleio_connection_disconnect(connection);
|
||||
}
|
||||
connection->connection_obj = mp_const_none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void bleio_adapter_background(bleio_adapter_obj_t* adapter) {
|
||||
if (!common_hal_bleio_adapter_get_enabled(adapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (adapter->advertising_timeout_msecs > 0 &&
|
||||
supervisor_ticks_ms64() - adapter->advertising_start_ticks > adapter->advertising_timeout_msecs) {
|
||||
adapter->advertising_timeout_msecs = 0;
|
||||
common_hal_bleio_adapter_stop_advertising(adapter);
|
||||
}
|
||||
|
||||
hci_result_t result = hci_poll_for_incoming_pkt();
|
||||
if (result != HCI_OK) {
|
||||
mp_printf(&mp_plat_print, "bad hci_poll_for_incoming_pkt() result in background: %d\n", result);
|
||||
}
|
||||
}
|
99
devices/ble_hci/common-hal/_bleio/Adapter.h
Normal file
99
devices/ble_hci/common-hal/_bleio/Adapter.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ADAPTER_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ADAPTER_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/objtuple.h"
|
||||
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
#include "shared-bindings/_bleio/ScanResults.h"
|
||||
#include "shared-bindings/busio/UART.h"
|
||||
#include "shared-bindings/digitalio/DigitalInOut.h"
|
||||
|
||||
#ifndef BLEIO_TOTAL_CONNECTION_COUNT
|
||||
#define BLEIO_TOTAL_CONNECTION_COUNT 5
|
||||
#endif
|
||||
|
||||
extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT];
|
||||
|
||||
typedef struct _bleio_adapter_obj_t {
|
||||
mp_obj_base_t base;
|
||||
bleio_scanresults_obj_t *scan_results;
|
||||
mp_obj_t name;
|
||||
mp_obj_tuple_t *connection_objs;
|
||||
busio_uart_obj_t* hci_uart;
|
||||
digitalio_digitalinout_obj_t *rts_digitalinout;
|
||||
digitalio_digitalinout_obj_t *cts_digitalinout;
|
||||
bool allocated; // True when in use.
|
||||
bool now_advertising;
|
||||
bool extended_advertising;
|
||||
bool circuitpython_advertising;
|
||||
bool enabled;
|
||||
|
||||
// HCI adapter version info.
|
||||
uint8_t hci_version;
|
||||
uint8_t lmp_version;
|
||||
uint16_t hci_revision;
|
||||
uint16_t manufacturer;
|
||||
uint16_t lmp_subversion;
|
||||
|
||||
// Used to monitor advertising timeout for legacy avertising.
|
||||
uint64_t advertising_start_ticks;
|
||||
uint64_t advertising_timeout_msecs; // If zero, do not check.
|
||||
|
||||
// Generic services characteristics.
|
||||
bleio_characteristic_obj_t *device_name_characteristic;
|
||||
bleio_characteristic_obj_t *appearance_characteristic;
|
||||
bleio_characteristic_obj_t * service_changed_characteristic;
|
||||
|
||||
uint16_t max_acl_buffer_len;
|
||||
uint16_t max_acl_num_buffers;
|
||||
uint16_t max_adv_data_len;
|
||||
uint8_t features[8]; // Supported BLE features.
|
||||
|
||||
// All the local attributes for this device. The index into the list
|
||||
// corresponds to the handle.
|
||||
mp_obj_list_t *attributes;
|
||||
// Handle for last added service. Characteristics can only be added immediately after
|
||||
// the service they belong to. This vets that.
|
||||
uint16_t last_added_service_handle;
|
||||
uint16_t last_added_characteristic_handle;
|
||||
} bleio_adapter_obj_t;
|
||||
|
||||
uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute);
|
||||
void bleio_adapter_advertising_was_stopped(bleio_adapter_obj_t *self);
|
||||
mp_obj_t* bleio_adapter_get_attribute(bleio_adapter_obj_t *adapter, uint16_t handle);
|
||||
uint16_t bleio_adapter_max_attribute_handle(bleio_adapter_obj_t *adapter);
|
||||
void bleio_adapter_background(bleio_adapter_obj_t* adapter);
|
||||
void bleio_adapter_gc_collect(bleio_adapter_obj_t* adapter);
|
||||
void bleio_adapter_reset(bleio_adapter_obj_t* adapter);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ADAPTER_H
|
49
devices/ble_hci/common-hal/_bleio/Attribute.c
Normal file
49
devices/ble_hci/common-hal/_bleio/Attribute.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/_bleio/Attribute.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Descriptor.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
|
||||
|
||||
bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute) {
|
||||
if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) {
|
||||
bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute);
|
||||
return characteristic->uuid;
|
||||
}
|
||||
if (MP_OBJ_IS_TYPE(attribute, &bleio_descriptor_type)) {
|
||||
bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute);
|
||||
return descriptor->uuid;
|
||||
}
|
||||
if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) {
|
||||
bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute);
|
||||
return service->uuid;
|
||||
}
|
||||
mp_raise_RuntimeError(translate("Invalid BLE attribute"));
|
||||
}
|
35
devices/ble_hci/common-hal/_bleio/Attribute.h
Normal file
35
devices/ble_hci/common-hal/_bleio/Attribute.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H
|
||||
|
||||
#include "shared-module/_bleio/Attribute.h"
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
|
||||
bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H
|
228
devices/ble_hci/common-hal/_bleio/Characteristic.c
Normal file
228
devices/ble_hci/common-hal/_bleio/Characteristic.c
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/CharacteristicBuffer.h"
|
||||
#include "shared-bindings/_bleio/Descriptor.h"
|
||||
#include "shared-bindings/_bleio/PacketBuffer.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
|
||||
#include "common-hal/_bleio/Adapter.h"
|
||||
#include "common-hal/_bleio/att.h"
|
||||
|
||||
#define CCCD_NOTIFY 0x1
|
||||
#define CCCD_INDICATE 0x2
|
||||
|
||||
|
||||
void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) {
|
||||
self->service = service;
|
||||
self->uuid = uuid;
|
||||
self->decl_handle = BLE_GATT_HANDLE_INVALID;
|
||||
self->handle = BLE_GATT_HANDLE_INVALID;
|
||||
self->props = props;
|
||||
self->read_perm = read_perm;
|
||||
self->write_perm = write_perm;
|
||||
self->descriptor_list = mp_obj_new_list(0, NULL);
|
||||
self->observer = mp_const_none;
|
||||
self->user_desc = NULL;
|
||||
self->cccd = NULL;
|
||||
self->sccd = NULL;
|
||||
self->value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len);
|
||||
|
||||
const mp_int_t max_length_max = 512;
|
||||
if (max_length < 0 || max_length > max_length_max) {
|
||||
mp_raise_ValueError(translate("max_length must be <= 512"));
|
||||
}
|
||||
self->max_length = max_length;
|
||||
self->fixed_length = fixed_length;
|
||||
|
||||
if (service->is_remote) {
|
||||
self->handle = handle;
|
||||
} else {
|
||||
common_hal_bleio_service_add_characteristic(self->service, self, initial_value_bufinfo);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) {
|
||||
return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items);
|
||||
}
|
||||
|
||||
bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) {
|
||||
return self->service;
|
||||
}
|
||||
|
||||
size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len) {
|
||||
// Do GATT operations only if this characteristic has been added to a registered service.
|
||||
if (self->handle != BLE_GATT_HANDLE_INVALID) {
|
||||
//FIX uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
|
||||
if (common_hal_bleio_service_get_is_remote(self->service)) {
|
||||
//FIX read remote chars
|
||||
//uint8_t rsp[MAX(len, 512)];
|
||||
//FIX improve att_read_req to write into our requested buffer.
|
||||
// return att_read_req(conn_handle, self->handle, rsp);
|
||||
return 0; //FIX
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) {
|
||||
return 0;
|
||||
}
|
||||
const size_t actual_length = MIN(len, bufinfo.len);
|
||||
memcpy(buf, bufinfo.buf, actual_length);
|
||||
return actual_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length != required fixed length"));
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length > max_length"));
|
||||
}
|
||||
|
||||
// Do GATT operations only if this characteristic has been added to a registered service.
|
||||
if (self->handle != BLE_GATT_HANDLE_INVALID) {
|
||||
if (common_hal_bleio_service_get_is_remote(self->service)) {
|
||||
//FIX uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
|
||||
if (self->props & CHAR_PROP_WRITE) {
|
||||
//FIX writing remote chars
|
||||
//uint8_t rsp[sizeof(bt_att_error_rsp)];
|
||||
//att_write_req(conn_handle, self->handle, bufinfo->buf, bufinfo->len, rsp);
|
||||
} else if (self->props & CHAR_PROP_WRITE_NO_RESPONSE) {
|
||||
//att_write_cmd(conn_handle, self->handle, bufinfo->buff, bufinfo->len);
|
||||
} else {
|
||||
mp_raise_bleio_BluetoothError(translate("Characteristic not writable"));
|
||||
}
|
||||
} else {
|
||||
// Always write the value locally even if no connections are active.
|
||||
bleio_characteristic_set_local_value(self, bufinfo);
|
||||
// Notify or indicate all active connections.
|
||||
|
||||
uint16_t cccd_value = 0;
|
||||
mp_buffer_info_t cccd_bufinfo = {
|
||||
.buf = &cccd_value,
|
||||
.len = sizeof(cccd_value),
|
||||
};
|
||||
|
||||
const bool notify = self->props & CHAR_PROP_NOTIFY;
|
||||
const bool indicate = self->props & CHAR_PROP_INDICATE;
|
||||
// Read the CCCD value, if there is one.
|
||||
if ((notify | indicate) && self->cccd != NULL) {
|
||||
common_hal_bleio_descriptor_get_value(self->cccd, cccd_bufinfo.buf, cccd_bufinfo.len);
|
||||
}
|
||||
|
||||
// It's possible that both notify and indicate are set.
|
||||
if (notify && (cccd_value & CCCD_NOTIFY)) {
|
||||
att_notify(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length));
|
||||
}
|
||||
if (indicate && (cccd_value & CCCD_INDICATE)) {
|
||||
att_indicate(self->handle, bufinfo->buf, MIN(bufinfo->len, self->max_length));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) {
|
||||
return self->uuid;
|
||||
}
|
||||
|
||||
bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) {
|
||||
return self->props;
|
||||
}
|
||||
|
||||
void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) {
|
||||
if (self->handle != common_hal_bleio_adapter_obj.last_added_characteristic_handle) {
|
||||
mp_raise_bleio_BluetoothError(
|
||||
translate("Descriptor can only be added to most recently added characteristic"));
|
||||
}
|
||||
|
||||
descriptor->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(descriptor));
|
||||
// Include this descriptor in the service handle's range.
|
||||
self->service->end_handle = descriptor->handle;
|
||||
|
||||
mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list),
|
||||
MP_OBJ_FROM_PTR(descriptor));
|
||||
}
|
||||
|
||||
void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) {
|
||||
if (self->cccd == NULL) {
|
||||
mp_raise_bleio_BluetoothError(translate("No CCCD for this Characteristic"));
|
||||
}
|
||||
|
||||
if (!common_hal_bleio_service_get_is_remote(self->service)) {
|
||||
mp_raise_bleio_RoleError(translate("Can't set CCCD on local Characteristic"));
|
||||
}
|
||||
|
||||
const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
|
||||
common_hal_bleio_check_connected(conn_handle);
|
||||
|
||||
uint16_t cccd_value =
|
||||
(notify ? CCCD_NOTIFY : 0) |
|
||||
(indicate ? CCCD_INDICATE : 0);
|
||||
|
||||
//FIX do remote
|
||||
(void) cccd_value;
|
||||
// uint8_t rsp[sizeof(bt_att_error_rsp)];
|
||||
// if (att_write_req(conn_handle, self->cccd->handle, &cccd_value, sizeof(cccd_value)) == 0) {
|
||||
// mp_raise_bleio_BluetoothError(translate("Could not write CCCD"));
|
||||
// }
|
||||
}
|
||||
|
||||
bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
return false;
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len);
|
||||
|
||||
if (MP_OBJ_IS_TYPE(self->observer, &bleio_characteristic_buffer_type)) {
|
||||
bleio_characteristic_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo);
|
||||
} else if (MP_OBJ_IS_TYPE(self->observer, &bleio_packet_buffer_type)) {
|
||||
bleio_packet_buffer_update(MP_OBJ_FROM_PTR(self->observer), bufinfo);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) {
|
||||
self->observer = observer;
|
||||
}
|
||||
|
||||
void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self) {
|
||||
self->observer = mp_const_none;
|
||||
}
|
63
devices/ble_hci/common-hal/_bleio/Characteristic.h
Normal file
63
devices/ble_hci/common-hal/_bleio/Characteristic.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H
|
||||
|
||||
#include "shared-bindings/_bleio/Attribute.h"
|
||||
#include "common-hal/_bleio/Descriptor.h"
|
||||
#include "shared-module/_bleio/Characteristic.h"
|
||||
#include "common-hal/_bleio/Service.h"
|
||||
#include "common-hal/_bleio/UUID.h"
|
||||
|
||||
typedef struct _bleio_characteristic_obj {
|
||||
mp_obj_base_t base;
|
||||
// Will be MP_OBJ_NULL before being assigned to a Service.
|
||||
bleio_service_obj_t *service;
|
||||
bleio_uuid_obj_t *uuid;
|
||||
mp_obj_t value;
|
||||
mp_obj_t observer;
|
||||
mp_obj_list_t *descriptor_list;
|
||||
uint16_t max_length;
|
||||
bool fixed_length;
|
||||
uint16_t decl_handle;
|
||||
uint16_t handle; // Should be decl_handle+1.
|
||||
bleio_characteristic_properties_t props;
|
||||
bleio_attribute_security_mode_t read_perm;
|
||||
bleio_attribute_security_mode_t write_perm;
|
||||
bleio_descriptor_obj_t *descriptor_linked_list;
|
||||
bleio_descriptor_obj_t *user_desc;
|
||||
bleio_descriptor_obj_t *cccd;
|
||||
bleio_descriptor_obj_t *sccd;
|
||||
} bleio_characteristic_obj_t;
|
||||
|
||||
bool bleio_characteristic_set_local_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo);
|
||||
|
||||
void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer);
|
||||
void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTIC_H
|
104
devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c
Normal file
104
devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
#include "common-hal/_bleio/CharacteristicBuffer.h"
|
||||
|
||||
// Push all the data onto the ring buffer. When the buffer is full, new bytes will be dropped.
|
||||
STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) {
|
||||
ringbuf_put_n(&self->ringbuf, data, len);
|
||||
}
|
||||
|
||||
void bleio_characteristic_buffer_update(bleio_characteristic_buffer_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
write_to_ringbuf(self, bufinfo->buf, bufinfo->len);
|
||||
}
|
||||
|
||||
// Assumes that timeout and buffer_size have been validated before call.
|
||||
void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self,
|
||||
bleio_characteristic_obj_t *characteristic,
|
||||
mp_float_t timeout,
|
||||
size_t buffer_size) {
|
||||
|
||||
self->characteristic = characteristic;
|
||||
self->timeout_ms = timeout * 1000;
|
||||
// This is a macro.
|
||||
// true means long-lived, so it won't be moved.
|
||||
ringbuf_alloc(&self->ringbuf, buffer_size, true);
|
||||
|
||||
bleio_characteristic_set_observer(characteristic, self);
|
||||
}
|
||||
|
||||
uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) {
|
||||
uint64_t start_ticks = supervisor_ticks_ms64();
|
||||
|
||||
// Wait for all bytes received or timeout
|
||||
while ( (ringbuf_num_filled(&self->ringbuf) < len) && (supervisor_ticks_ms64() - start_ticks < self->timeout_ms) ) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
// Allow user to break out of a timeout with a KeyboardInterrupt.
|
||||
if ( mp_hal_is_interrupted() ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t num_bytes_read = ringbuf_get_n(&self->ringbuf, data, len);
|
||||
return num_bytes_read;
|
||||
}
|
||||
|
||||
uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) {
|
||||
uint16_t count = ringbuf_num_filled(&self->ringbuf);
|
||||
return count;
|
||||
}
|
||||
|
||||
void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) {
|
||||
ringbuf_clear(&self->ringbuf);
|
||||
}
|
||||
|
||||
bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) {
|
||||
return self->characteristic == NULL;
|
||||
}
|
||||
|
||||
void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) {
|
||||
if (!common_hal_bleio_characteristic_buffer_deinited(self)) {
|
||||
bleio_characteristic_clear_observer(self->characteristic);
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) {
|
||||
return self->characteristic != NULL &&
|
||||
self->characteristic->service != NULL &&
|
||||
(!self->characteristic->service->is_remote ||
|
||||
(self->characteristic->service->connection != MP_OBJ_NULL &&
|
||||
common_hal_bleio_connection_get_connected(self->characteristic->service->connection)));
|
||||
}
|
43
devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h
Normal file
43
devices/ble_hci/common-hal/_bleio/CharacteristicBuffer.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H
|
||||
|
||||
#include "py/ringbuf.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bleio_characteristic_obj_t *characteristic;
|
||||
uint32_t timeout_ms;
|
||||
// Ring buffer storing consecutive incoming values.
|
||||
ringbuf_t ringbuf;
|
||||
} bleio_characteristic_buffer_obj_t;
|
||||
|
||||
void bleio_characteristic_buffer_update(bleio_characteristic_buffer_obj_t *self, mp_buffer_info_t *bufinfo);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CHARACTERISTICBUFFER_H
|
772
devices/ble_hci/common-hal/_bleio/Connection.c
Normal file
772
devices/ble_hci/common-hal/_bleio/Connection.c
Normal file
@ -0,0 +1,772 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
|
||||
#include "att.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/qstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Adapter.h"
|
||||
#include "shared-bindings/_bleio/Attribute.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
#define BLE_ADV_LENGTH_FIELD_SIZE 1
|
||||
#define BLE_ADV_AD_TYPE_FIELD_SIZE 1
|
||||
#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1
|
||||
|
||||
// static const ble_gap_sec_params_t pairing_sec_params = {
|
||||
// .bond = 1,
|
||||
// .mitm = 0,
|
||||
// .lesc = 0,
|
||||
// .keypress = 0,
|
||||
// .oob = 0,
|
||||
// .io_caps = BLE_GAP_IO_CAPS_NONE,
|
||||
// .min_key_size = 7,
|
||||
// .max_key_size = 16,
|
||||
// .kdist_own = { .enc = 1, .id = 1},
|
||||
// .kdist_peer = { .enc = 1, .id = 1},
|
||||
// };
|
||||
|
||||
#define CONNECTION_DEBUG (1)
|
||||
#if CONNECTION_DEBUG
|
||||
#define CONNECTION_DEBUG_PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define CONNECTION_DEBUG_PRINTF(...)
|
||||
#endif
|
||||
|
||||
static volatile bool m_discovery_in_process;
|
||||
static volatile bool m_discovery_successful;
|
||||
|
||||
//FIX static bleio_service_obj_t *m_char_discovery_service;
|
||||
//FIX static bleio_characteristic_obj_t *m_desc_discovery_characteristic;
|
||||
|
||||
// bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
|
||||
// bleio_connection_internal_t *self = (bleio_connection_internal_t*)self_in;
|
||||
|
||||
// if (BLE_GAP_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GAP_EVT_LAST &&
|
||||
// ble_evt->evt.gap_evt.conn_handle != self->conn_handle) {
|
||||
// return false;
|
||||
// }
|
||||
// if (BLE_GATTS_EVT_BASE <= ble_evt->header.evt_id && ble_evt->header.evt_id <= BLE_GATTS_EVT_LAST &&
|
||||
// ble_evt->evt.gatts_evt.conn_handle != self->conn_handle) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// switch (ble_evt->header.evt_id) {
|
||||
// case BLE_GAP_EVT_DISCONNECTED:
|
||||
// // Adapter.c does the work for this event.
|
||||
// break;
|
||||
|
||||
// case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
|
||||
// ble_gap_phys_t const phys = {
|
||||
// .rx_phys = BLE_GAP_PHY_AUTO,
|
||||
// .tx_phys = BLE_GAP_PHY_AUTO,
|
||||
// };
|
||||
// sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_PHY_UPDATE: { // 0x22
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
|
||||
// // SoftDevice will respond to a length update request.
|
||||
// sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL);
|
||||
// break;
|
||||
|
||||
// case BLE_GAP_EVT_DATA_LENGTH_UPDATE: { // 0x24
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: {
|
||||
// ble_gatts_evt_exchange_mtu_request_t *request =
|
||||
// &ble_evt->evt.gatts_evt.params.exchange_mtu_request;
|
||||
|
||||
// uint16_t new_mtu = BLE_GATTS_VAR_ATTR_LEN_MAX;
|
||||
// if (request->client_rx_mtu < new_mtu) {
|
||||
// new_mtu = request->client_rx_mtu;
|
||||
// }
|
||||
// if (new_mtu < BLE_GATT_ATT_MTU_DEFAULT) {
|
||||
// new_mtu = BLE_GATT_ATT_MTU_DEFAULT;
|
||||
// }
|
||||
// if (self->mtu > 0) {
|
||||
// new_mtu = self->mtu;
|
||||
// }
|
||||
|
||||
// self->mtu = new_mtu;
|
||||
// sd_ble_gatts_exchange_mtu_reply(self->conn_handle, new_mtu);
|
||||
// break;
|
||||
// }
|
||||
|
||||
|
||||
// case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: {
|
||||
// ble_gattc_evt_exchange_mtu_rsp_t *response =
|
||||
// &ble_evt->evt.gattc_evt.params.exchange_mtu_rsp;
|
||||
|
||||
// self->mtu = response->server_rx_mtu;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GATTS_EVT_WRITE:
|
||||
// // A client wrote a value.
|
||||
// // If we are bonded and it's a CCCD (UUID 0x2902), store the CCCD value.
|
||||
// if (self->conn_handle != BLE_CONN_HANDLE_INVALID &&
|
||||
// self->pair_status == PAIR_PAIRED &&
|
||||
// ble_evt->evt.gatts_evt.params.write.uuid.type == BLE_UUID_TYPE_BLE &&
|
||||
// ble_evt->evt.gatts_evt.params.write.uuid.uuid == 0x2902) {
|
||||
// //
|
||||
// // Save sys_attr data (CCCD state) in bonding area at
|
||||
// // next opportunity, but also remember time of this
|
||||
// // request, so we can consolidate closely-spaced requests.
|
||||
// self->do_bond_cccds = true;
|
||||
// self->do_bond_cccds_request_time = supervisor_ticks_ms64();
|
||||
// }
|
||||
// // Return false so other handlers get this event as well.
|
||||
// return false;
|
||||
|
||||
// case BLE_GATTS_EVT_SYS_ATTR_MISSING:
|
||||
// sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
||||
// break;
|
||||
|
||||
// #if CIRCUITPY_VERBOSE_BLE
|
||||
// // Use read authorization to snoop on all reads when doing verbose debugging.
|
||||
// case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: {
|
||||
|
||||
// ble_gatts_evt_rw_authorize_request_t *request =
|
||||
// &ble_evt->evt.gatts_evt.params.authorize_request;
|
||||
|
||||
// mp_printf(&mp_plat_print, "Read %x offset %d ", request->request.read.handle, request->request.read.offset);
|
||||
// uint8_t value_bytes[22];
|
||||
// ble_gatts_value_t value;
|
||||
// value.offset = request->request.read.offset;
|
||||
// value.len = 22;
|
||||
// value.p_value = value_bytes;
|
||||
|
||||
// sd_ble_gatts_value_get(self->conn_handle, request->request.read.handle, &value);
|
||||
// size_t len = value.len;
|
||||
// if (len > 22) {
|
||||
// len = 22;
|
||||
// }
|
||||
// for (uint8_t i = 0; i < len; i++) {
|
||||
// mp_printf(&mp_plat_print, " %02x", value_bytes[i]);
|
||||
// }
|
||||
// mp_printf(&mp_plat_print, "\n");
|
||||
// ble_gatts_rw_authorize_reply_params_t reply;
|
||||
// reply.type = request->type;
|
||||
// reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
// reply.params.read.update = false;
|
||||
// reply.params.read.offset = request->request.read.offset;
|
||||
// sd_ble_gatts_rw_authorize_reply(self->conn_handle, &reply);
|
||||
// break;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// case BLE_GATTS_EVT_HVN_TX_COMPLETE: // Capture this for now. 0x55
|
||||
// break;
|
||||
// case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: {
|
||||
// self->conn_params_updating = true;
|
||||
// ble_gap_evt_conn_param_update_request_t *request =
|
||||
// &ble_evt->evt.gap_evt.params.conn_param_update_request;
|
||||
// sd_ble_gap_conn_param_update(self->conn_handle, &request->conn_params);
|
||||
// break;
|
||||
// }
|
||||
// case BLE_GAP_EVT_CONN_PARAM_UPDATE: { // 0x12
|
||||
// ble_gap_evt_conn_param_update_t *result =
|
||||
// &ble_evt->evt.gap_evt.params.conn_param_update;
|
||||
|
||||
// #if CIRCUITPY_VERBOSE_BLE
|
||||
// ble_gap_conn_params_t *cp = &ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
|
||||
// mp_printf(&mp_plat_print, "conn params updated: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout);
|
||||
// #endif
|
||||
|
||||
// memcpy(&self->conn_params, &result->conn_params, sizeof(ble_gap_conn_params_t));
|
||||
// self->conn_params_updating = false;
|
||||
// break;
|
||||
// }
|
||||
// case BLE_GAP_EVT_SEC_PARAMS_REQUEST: {
|
||||
// // First time pairing.
|
||||
// // 1. Either we or peer initiate the process
|
||||
// // 2. Peer asks for security parameters using BLE_GAP_EVT_SEC_PARAMS_REQUEST.
|
||||
// // 3. Pair Key exchange ("just works" implemented now; TODO: out-of-band key pairing)
|
||||
// // 4. Connection is secured: BLE_GAP_EVT_CONN_SEC_UPDATE
|
||||
// // 5. Long-term Keys exchanged: BLE_GAP_EVT_AUTH_STATUS
|
||||
|
||||
// bonding_clear_keys(&self->bonding_keys);
|
||||
// self->ediv = EDIV_INVALID;
|
||||
// ble_gap_sec_keyset_t keyset = {
|
||||
// .keys_own = {
|
||||
// .p_enc_key = &self->bonding_keys.own_enc,
|
||||
// .p_id_key = NULL,
|
||||
// .p_sign_key = NULL,
|
||||
// .p_pk = NULL
|
||||
// },
|
||||
|
||||
// .keys_peer = {
|
||||
// .p_enc_key = &self->bonding_keys.peer_enc,
|
||||
// .p_id_key = &self->bonding_keys.peer_id,
|
||||
// .p_sign_key = NULL,
|
||||
// .p_pk = NULL
|
||||
// }
|
||||
// };
|
||||
|
||||
// sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS,
|
||||
// self->is_central ? NULL : &pairing_sec_params,
|
||||
// &keyset);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
|
||||
// // TODO for LESC pairing:
|
||||
// // sd_ble_gap_lesc_dhkey_reply(...);
|
||||
// break;
|
||||
|
||||
// case BLE_GAP_EVT_AUTH_STATUS: { // 0x19
|
||||
// // Key exchange completed.
|
||||
// ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status;
|
||||
// self->sec_status = status->auth_status;
|
||||
// if (status->auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||
// self->ediv = self->bonding_keys.own_enc.master_id.ediv;
|
||||
// self->pair_status = PAIR_PAIRED;
|
||||
// // Save keys in bonding area at next opportunity.
|
||||
// self->do_bond_keys = true;
|
||||
// } else {
|
||||
// // Inform busy-waiter pairing has failed.
|
||||
// self->pair_status = PAIR_NOT_PAIRED;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_SEC_INFO_REQUEST: { // 0x14
|
||||
// // Peer asks for the stored keys.
|
||||
// // - load key and return if bonded previously.
|
||||
// // - Else return NULL --> Initiate key exchange
|
||||
// ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request;
|
||||
// (void) sec_info_request;
|
||||
// if ( bonding_load_keys(self->is_central, sec_info_request->master_id.ediv, &self->bonding_keys) ) {
|
||||
// sd_ble_gap_sec_info_reply(
|
||||
// self->conn_handle,
|
||||
// &self->bonding_keys.own_enc.enc_info,
|
||||
// &self->bonding_keys.peer_id.id_info,
|
||||
// NULL);
|
||||
// self->ediv = self->bonding_keys.own_enc.master_id.ediv;
|
||||
// } else {
|
||||
// // We don't have stored keys. Ask for keys.
|
||||
// sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case BLE_GAP_EVT_CONN_SEC_UPDATE: { // 0x1a
|
||||
// // We get this both on first-time pairing and on subsequent pairings using stored keys.
|
||||
// ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec;
|
||||
// if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) {
|
||||
// // Security setup did not succeed:
|
||||
// // mode 0, level 0 means no access
|
||||
// // mode 1, level 1 means open link
|
||||
// // mode >=1 and/or level >=1 means encryption is set up
|
||||
// self->pair_status = PAIR_NOT_PAIRED;
|
||||
// } else {
|
||||
// if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) {
|
||||
// // Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values.
|
||||
// } else {
|
||||
// // No matching bonding found, so use fresh system attributes.
|
||||
// sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
|
||||
// }
|
||||
// self->pair_status = PAIR_PAIRED;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
// default:
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
void bleio_connection_clear(bleio_connection_internal_t *self) {
|
||||
mp_obj_list_clear(MP_OBJ_FROM_PTR(self->remote_service_list));
|
||||
|
||||
self->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
self->pair_status = PAIR_NOT_PAIRED;
|
||||
self->is_central = false;
|
||||
//FIX bonding_clear_keys(&self->bonding_keys);
|
||||
}
|
||||
|
||||
bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) {
|
||||
if (self->connection == NULL) {
|
||||
return false;
|
||||
}
|
||||
return self->connection->pair_status == PAIR_PAIRED;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) {
|
||||
if (self->connection == NULL) {
|
||||
return false;
|
||||
}
|
||||
return self->connection->conn_handle != BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) {
|
||||
hci_disconnect(self->conn_handle);
|
||||
}
|
||||
|
||||
void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) {
|
||||
self->pair_status = PAIR_WAITING;
|
||||
|
||||
//FIX check_nrf_error(sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params));
|
||||
|
||||
while (self->pair_status == PAIR_WAITING && !mp_hal_is_interrupted()) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
if (mp_hal_is_interrupted()) {
|
||||
return;
|
||||
}
|
||||
//FIX check_sec_status(self->sec_status);
|
||||
}
|
||||
|
||||
mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) {
|
||||
while (self->conn_params_updating && !mp_hal_is_interrupted()) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
//FIX return 1.25f * self->conn_params.min_conn_interval;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Return the current negotiated MTU length, minus overhead.
|
||||
mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) {
|
||||
return (self->mtu == 0 ? BT_ATT_DEFAULT_LE_MTU : self->mtu) - 3;
|
||||
}
|
||||
|
||||
void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) {
|
||||
// self->conn_params_updating = true;
|
||||
// uint16_t interval = new_interval / 1.25f;
|
||||
// self->conn_params.min_conn_interval = interval;
|
||||
// self->conn_params.max_conn_interval = interval;
|
||||
// uint32_t status = NRF_ERROR_BUSY;
|
||||
// while (status == NRF_ERROR_BUSY) {
|
||||
// status = sd_ble_gap_conn_param_update(self->conn_handle, &self->conn_params);
|
||||
// RUN_BACKGROUND_TASKS;
|
||||
// }
|
||||
// check_nrf_error(status);
|
||||
}
|
||||
|
||||
// service_uuid may be NULL, to discover all services.
|
||||
// STATIC bool discover_next_services(bleio_connection_internal_t* connection, uint16_t start_handle, ble_uuid_t *service_uuid) {
|
||||
// m_discovery_successful = false;
|
||||
// m_discovery_in_process = true;
|
||||
|
||||
// uint32_t nrf_err = NRF_ERROR_BUSY;
|
||||
// while (nrf_err == NRF_ERROR_BUSY) {
|
||||
// nrf_err = sd_ble_gattc_primary_services_discover(connection->conn_handle, start_handle, service_uuid);
|
||||
// }
|
||||
// check_nrf_error(nrf_err);
|
||||
|
||||
// // Wait for a discovery event.
|
||||
// while (m_discovery_in_process) {
|
||||
// MICROPY_VM_HOOK_LOOP;
|
||||
// }
|
||||
// return m_discovery_successful;
|
||||
// }
|
||||
|
||||
// STATIC bool discover_next_characteristics(bleio_connection_internal_t* connection, bleio_service_obj_t *service, uint16_t start_handle) {
|
||||
// m_char_discovery_service = service;
|
||||
|
||||
// ble_gattc_handle_range_t handle_range;
|
||||
// handle_range.start_handle = start_handle;
|
||||
// handle_range.end_handle = service->end_handle;
|
||||
|
||||
// m_discovery_successful = false;
|
||||
// m_discovery_in_process = true;
|
||||
|
||||
// uint32_t err_code = sd_ble_gattc_characteristics_discover(connection->conn_handle, &handle_range);
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // Wait for a discovery event.
|
||||
// while (m_discovery_in_process) {
|
||||
// MICROPY_VM_HOOK_LOOP;
|
||||
// }
|
||||
// return m_discovery_successful;
|
||||
// }
|
||||
|
||||
// STATIC bool discover_next_descriptors(bleio_connection_internal_t* connection, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) {
|
||||
// m_desc_discovery_characteristic = characteristic;
|
||||
|
||||
// ble_gattc_handle_range_t handle_range;
|
||||
// handle_range.start_handle = start_handle;
|
||||
// handle_range.end_handle = end_handle;
|
||||
|
||||
// m_discovery_successful = false;
|
||||
// m_discovery_in_process = true;
|
||||
|
||||
// uint32_t err_code = sd_ble_gattc_descriptors_discover(connection->conn_handle, &handle_range);
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // Wait for a discovery event.
|
||||
// while (m_discovery_in_process) {
|
||||
// MICROPY_VM_HOOK_LOOP;
|
||||
// }
|
||||
// return m_discovery_successful;
|
||||
// }
|
||||
|
||||
// STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_connection_internal_t* connection) {
|
||||
// for (size_t i = 0; i < response->count; ++i) {
|
||||
// ble_gattc_service_t *gattc_service = &response->services[i];
|
||||
|
||||
// bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
|
||||
// service->base.type = &bleio_service_type;
|
||||
|
||||
// // Initialize several fields at once.
|
||||
// bleio_service_from_connection(service, bleio_connection_new_from_internal(connection));
|
||||
|
||||
// service->is_remote = true;
|
||||
// service->start_handle = gattc_service->handle_range.start_handle;
|
||||
// service->end_handle = gattc_service->handle_range.end_handle;
|
||||
// service->handle = gattc_service->handle_range.start_handle;
|
||||
|
||||
// if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known service UUID.
|
||||
// bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid);
|
||||
// service->uuid = uuid;
|
||||
// } else {
|
||||
// // The discovery response contained a 128-bit UUID that has not yet been registered with the
|
||||
// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it.
|
||||
// // For now, just set the UUID to NULL.
|
||||
// service->uuid = NULL;
|
||||
// }
|
||||
//
|
||||
// mp_obj_list_append(MP_OBJ_FROM_PTR(connection->remote_service_list),
|
||||
// MP_OBJ_FROM_PTR(service));
|
||||
// }
|
||||
//
|
||||
// if (response->count > 0) {
|
||||
// m_discovery_successful = true;
|
||||
// }
|
||||
// m_discovery_in_process = false;
|
||||
// }
|
||||
|
||||
// STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_connection_internal_t* connection) {
|
||||
// for (size_t i = 0; i < response->count; ++i) {
|
||||
// ble_gattc_char_t *gattc_char = &response->chars[i];
|
||||
|
||||
// bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
// characteristic->base.type = &bleio_characteristic_type;
|
||||
|
||||
// bleio_uuid_obj_t *uuid = NULL;
|
||||
|
||||
// if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known characteristic UUID.
|
||||
// uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid);
|
||||
// } else {
|
||||
// // The discovery response contained a 128-bit UUID that has not yet been registered with the
|
||||
// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it.
|
||||
// // For now, just leave the UUID as NULL.
|
||||
// }
|
||||
|
||||
// bleio_characteristic_properties_t props =
|
||||
// (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) |
|
||||
// (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) |
|
||||
// (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) |
|
||||
// (gattc_char->char_props.read ? CHAR_PROP_READ : 0) |
|
||||
// (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) |
|
||||
// (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0);
|
||||
|
||||
// // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler.
|
||||
// common_hal_bleio_characteristic_construct(
|
||||
// characteristic, m_char_discovery_service, gattc_char->handle_value, uuid,
|
||||
// props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN,
|
||||
// GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc
|
||||
// NULL);
|
||||
|
||||
// mp_obj_list_append(MP_OBJ_FROM_PTR(m_char_discovery_service->characteristic_list),
|
||||
// MP_OBJ_FROM_PTR(characteristic));
|
||||
// }
|
||||
|
||||
// if (response->count > 0) {
|
||||
// m_discovery_successful = true;
|
||||
// }
|
||||
// m_discovery_in_process = false;
|
||||
// }
|
||||
|
||||
// STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_connection_internal_t* connection) {
|
||||
// for (size_t i = 0; i < response->count; ++i) {
|
||||
// ble_gattc_desc_t *gattc_desc = &response->descs[i];
|
||||
|
||||
// // Remember handles for certain well-known descriptors.
|
||||
// switch (gattc_desc->uuid.uuid) {
|
||||
// case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG:
|
||||
// m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle;
|
||||
// break;
|
||||
|
||||
// case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG:
|
||||
// m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle;
|
||||
// break;
|
||||
|
||||
// case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC:
|
||||
// m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle;
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors,
|
||||
// // so ignore those.
|
||||
// // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors
|
||||
// break;
|
||||
// }
|
||||
|
||||
// bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t);
|
||||
// descriptor->base.type = &bleio_descriptor_type;
|
||||
|
||||
// bleio_uuid_obj_t *uuid = NULL;
|
||||
|
||||
// if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known descriptor UUID.
|
||||
// uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid);
|
||||
// } else {
|
||||
// // The discovery response contained a 128-bit UUID that has not yet been registered with the
|
||||
// // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it.
|
||||
// // For now, just leave the UUID as NULL.
|
||||
// }
|
||||
|
||||
// common_hal_bleio_descriptor_construct(
|
||||
// descriptor, m_desc_discovery_characteristic, uuid,
|
||||
// SECURITY_MODE_OPEN, SECURITY_MODE_OPEN,
|
||||
// GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes);
|
||||
// descriptor->handle = gattc_desc->handle;
|
||||
|
||||
// mp_obj_list_append(MP_OBJ_FROM_PTR(m_desc_discovery_characteristic->descriptor_list),
|
||||
// MP_OBJ_FROM_PTR(descriptor));
|
||||
// }
|
||||
|
||||
// if (response->count > 0) {
|
||||
// m_discovery_successful = true;
|
||||
// }
|
||||
// m_discovery_in_process = false;
|
||||
// }
|
||||
|
||||
// STATIC bool discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t payload) {
|
||||
// bleio_connection_internal_t* connection = MP_OBJ_TO_PTR(payload);
|
||||
// switch (ble_evt->header.evt_id) {
|
||||
// case BLE_GAP_EVT_DISCONNECTED:
|
||||
// m_discovery_successful = false;
|
||||
// m_discovery_in_process = false;
|
||||
// break;
|
||||
|
||||
// case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
|
||||
// on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, connection);
|
||||
// break;
|
||||
|
||||
// case BLE_GATTC_EVT_CHAR_DISC_RSP:
|
||||
// on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, connection);
|
||||
// break;
|
||||
|
||||
// case BLE_GATTC_EVT_DESC_DISC_RSP:
|
||||
// on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, connection);
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// // CONNECTION_DEBUG_PRINTF(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id);
|
||||
// return false;
|
||||
// break;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service_uuids_whitelist) {
|
||||
// ble_drv_add_event_handler(discovery_on_ble_evt, self);
|
||||
|
||||
// // Start over with an empty list.
|
||||
// self->remote_service_list = mp_obj_new_list(0, NULL);
|
||||
|
||||
|
||||
// if (service_uuids_whitelist == mp_const_none) {
|
||||
// // List of service UUID's not given, so discover all available services.
|
||||
|
||||
// uint16_t next_service_start_handle = BLE_GATT_HANDLE_START;
|
||||
|
||||
// while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) {
|
||||
// // discover_next_services() appends to remote_services_list.
|
||||
|
||||
// // Get the most recently discovered service, and then ask for services
|
||||
// // whose handles start after the last attribute handle inside that service.
|
||||
// // There must be at least one if discover_next_services() returned true.
|
||||
// const bleio_service_obj_t *service =
|
||||
// self->remote_service_list->items[self->remote_service_list->len - 1];
|
||||
// next_service_start_handle = service->end_handle + 1;
|
||||
// }
|
||||
// } else {
|
||||
// mp_obj_iter_buf_t iter_buf;
|
||||
// mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf);
|
||||
// mp_obj_t uuid_obj;
|
||||
// while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
// if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) {
|
||||
// mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist"));
|
||||
// }
|
||||
// bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj);
|
||||
|
||||
// ble_uuid_t nrf_uuid;
|
||||
// bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid);
|
||||
|
||||
// // Service might or might not be discovered; that's ok. Caller has to check
|
||||
// // Central.remote_services to find out.
|
||||
// // We only need to call this once for each service to discover.
|
||||
// discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// for (size_t i = 0; i < self->remote_service_list->len; i++) {
|
||||
// bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]);
|
||||
// // Skip the service if it had an unknown (unregistered) UUID.
|
||||
// if (service->uuid == NULL) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// uint16_t next_char_start_handle = service->start_handle;
|
||||
|
||||
// // Stop when we go past the end of the range of handles for this service or
|
||||
// // discovery call returns nothing.
|
||||
// // discover_next_characteristics() appends to the characteristic_list.
|
||||
// while (next_char_start_handle <= service->end_handle &&
|
||||
// discover_next_characteristics(self, service, next_char_start_handle)) {
|
||||
|
||||
|
||||
// // Get the most recently discovered characteristic, and then ask for characteristics
|
||||
// // whose handles start after the last attribute handle inside that characteristic.
|
||||
// const bleio_characteristic_obj_t *characteristic =
|
||||
// MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]);
|
||||
|
||||
// next_char_start_handle = characteristic->handle + 1;
|
||||
// }
|
||||
|
||||
// // Got characteristics for this service. Now discover descriptors for each characteristic.
|
||||
// size_t char_list_len = service->characteristic_list->len;
|
||||
// for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) {
|
||||
// bleio_characteristic_obj_t *characteristic =
|
||||
// MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]);
|
||||
// const bool last_characteristic = char_idx == char_list_len - 1;
|
||||
// bleio_characteristic_obj_t *next_characteristic = last_characteristic
|
||||
// ? NULL
|
||||
// : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]);
|
||||
|
||||
// // Skip the characteristic if it had an unknown (unregistered) UUID.
|
||||
// if (characteristic->uuid == NULL) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// uint16_t next_desc_start_handle = characteristic->handle + 1;
|
||||
|
||||
// // Don't run past the end of this service or the beginning of the next characteristic.
|
||||
// uint16_t next_desc_end_handle = next_characteristic == NULL
|
||||
// ? service->end_handle
|
||||
// : next_characteristic->handle - 1;
|
||||
|
||||
// // Stop when we go past the end of the range of handles for this service or
|
||||
// // discovery call returns nothing.
|
||||
// // discover_next_descriptors() appends to the descriptor_linked_list.
|
||||
// while (next_desc_start_handle <= service->end_handle &&
|
||||
// next_desc_start_handle <= next_desc_end_handle &&
|
||||
// discover_next_descriptors(self, characteristic,
|
||||
// next_desc_start_handle, next_desc_end_handle)) {
|
||||
// // Get the most recently discovered descriptor, and then ask for descriptors
|
||||
// // whose handles start after that descriptor's handle.
|
||||
// // There must be at least one if discover_next_descriptors() returned true.
|
||||
// const bleio_descriptor_obj_t *descriptor =
|
||||
// characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1];
|
||||
// next_desc_start_handle = descriptor->handle + 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // This event handler is no longer needed.
|
||||
// ble_drv_remove_event_handler(discovery_on_ble_evt, self);
|
||||
|
||||
// }
|
||||
|
||||
mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) {
|
||||
//FIX discover_remote_services(self->connection, service_uuids_whitelist);
|
||||
bleio_connection_ensure_connected(self);
|
||||
// Convert to a tuple and then clear the list so the callee will take ownership.
|
||||
mp_obj_tuple_t *services_tuple =
|
||||
mp_obj_new_tuple(self->connection->remote_service_list->len,
|
||||
self->connection->remote_service_list->items);
|
||||
mp_obj_list_clear(MP_OBJ_FROM_PTR(self->connection->remote_service_list));
|
||||
return services_tuple;
|
||||
}
|
||||
|
||||
uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) {
|
||||
if (self == NULL || self->connection == NULL) {
|
||||
return BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
return self->connection->conn_handle;
|
||||
}
|
||||
|
||||
mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* internal) {
|
||||
if (internal->connection_obj != mp_const_none) {
|
||||
return internal->connection_obj;
|
||||
}
|
||||
bleio_connection_obj_t *connection = m_new_obj(bleio_connection_obj_t);
|
||||
connection->base.type = &bleio_connection_type;
|
||||
connection->connection = internal;
|
||||
internal->connection_obj = connection;
|
||||
|
||||
return MP_OBJ_FROM_PTR(connection);
|
||||
}
|
||||
|
||||
// Find the connection that uses the given conn_handle. Return NULL if not found.
|
||||
bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle) {
|
||||
bleio_connection_internal_t *connection;
|
||||
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
|
||||
connection = &bleio_connections[i];
|
||||
if (connection->conn_handle == conn_handle) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
89
devices/ble_hci/common-hal/_bleio/Connection.h
Normal file
89
devices/ble_hci/common-hal/_bleio/Connection.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CONNECTION_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CONNECTION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/objlist.h"
|
||||
|
||||
#include "common-hal/_bleio/__init__.h"
|
||||
#include "shared-module/_bleio/Address.h"
|
||||
#include "common-hal/_bleio/Service.h"
|
||||
|
||||
typedef enum {
|
||||
PAIR_NOT_PAIRED,
|
||||
PAIR_WAITING,
|
||||
PAIR_PAIRED,
|
||||
} pair_status_t;
|
||||
|
||||
// We split the Connection object into two so that the internal mechanics can live outside of the
|
||||
// VM. If it were one object, then we'd risk user code seeing a connection object of theirs be
|
||||
// reused.
|
||||
typedef struct {
|
||||
uint16_t conn_handle;
|
||||
bool is_central;
|
||||
// Remote services discovered when this peripheral is acting as a client.
|
||||
mp_obj_list_t *remote_service_list;
|
||||
// The advertising data and scan response buffers are held by us, not by the SD, so we must
|
||||
// maintain them and not change it. If we need to change the contents during advertising,
|
||||
// there are tricks to get the SD to notice (see DevZone - TBS).
|
||||
bonding_keys_t bonding_keys;
|
||||
// EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing.
|
||||
uint16_t ediv;
|
||||
volatile pair_status_t pair_status;
|
||||
uint8_t sec_status; // Internal security status.
|
||||
mp_obj_t connection_obj;
|
||||
//REMOVE ble_gap_conn_params_t conn_params;
|
||||
volatile bool conn_params_updating;
|
||||
uint16_t mtu;
|
||||
// Request that CCCD values for this connection be saved, using sys_attr values.
|
||||
volatile bool do_bond_cccds;
|
||||
// Request that security key info for this connection be saved.
|
||||
volatile bool do_bond_keys;
|
||||
// Time of setting do_bond_ccds: we delay a bit to consolidate multiple CCCD changes
|
||||
// into one write. Time is currently in ticks_ms.
|
||||
uint64_t do_bond_cccds_request_time;
|
||||
//FIX from att.c
|
||||
uint8_t role;
|
||||
bt_addr_le_t addr;
|
||||
} bleio_connection_internal_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bleio_connection_internal_t* connection;
|
||||
// The HCI disconnect reason.
|
||||
uint8_t disconnect_reason;
|
||||
} bleio_connection_obj_t;
|
||||
|
||||
uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self);
|
||||
mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t* connection);
|
||||
bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_CONNECTION_H
|
114
devices/ble_hci/common-hal/_bleio/Descriptor.c
Normal file
114
devices/ble_hci/common-hal/_bleio/Descriptor.c
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Descriptor.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
|
||||
void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) {
|
||||
self->characteristic = characteristic;
|
||||
self->uuid = uuid;
|
||||
self->handle = BLE_GATT_HANDLE_INVALID;
|
||||
self->read_perm = read_perm;
|
||||
self->write_perm = write_perm;
|
||||
self->value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len);
|
||||
|
||||
const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX;
|
||||
if (max_length < 0 || max_length > max_length_max) {
|
||||
mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"),
|
||||
max_length_max, fixed_length ? "True" : "False");
|
||||
}
|
||||
self->max_length = max_length;
|
||||
self->fixed_length = fixed_length;
|
||||
|
||||
common_hal_bleio_descriptor_set_value(self, initial_value_bufinfo);
|
||||
}
|
||||
|
||||
bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) {
|
||||
return self->uuid;
|
||||
}
|
||||
|
||||
bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) {
|
||||
return self->characteristic;
|
||||
}
|
||||
|
||||
size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t* buf, size_t len) {
|
||||
// Do GATT operations only if this descriptor has been registered
|
||||
if (self->handle != BLE_GATT_HANDLE_INVALID) {
|
||||
if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) {
|
||||
//uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection);
|
||||
//FIX have att_read_req fill in a buffer
|
||||
//uint8_t rsp[MAX(len, 512)];
|
||||
//return att_read_req(conn_handle, self->handle, rsp, len);
|
||||
return 0;
|
||||
} else {
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (!mp_get_buffer(self->value, &bufinfo, MP_BUFFER_READ)) {
|
||||
return 0;
|
||||
}
|
||||
const size_t actual_length = MIN(len, bufinfo.len);
|
||||
memcpy(buf, bufinfo.buf, actual_length);
|
||||
return actual_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length != required fixed length"));
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length > max_length"));
|
||||
}
|
||||
|
||||
self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len);
|
||||
|
||||
// Do GATT operations only if this descriptor has been registered.
|
||||
if (self->handle != BLE_GATT_HANDLE_INVALID) {
|
||||
if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) {
|
||||
//FIX
|
||||
// uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
|
||||
// att_write_req(conn_handle, self->handle, bufinfo->buf, bufinfo->len, rsp);
|
||||
} else {
|
||||
// Always write the value locally even if no connections are active.
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
return;
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len);
|
||||
}
|
||||
}
|
||||
}
|
53
devices/ble_hci/common-hal/_bleio/Descriptor.h
Normal file
53
devices/ble_hci/common-hal/_bleio/Descriptor.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_DESCRIPTOR_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_DESCRIPTOR_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
#include "common-hal/_bleio/UUID.h"
|
||||
|
||||
// Forward declare characteristic because it includes a Descriptor.
|
||||
struct _bleio_characteristic_obj;
|
||||
|
||||
typedef struct _bleio_descriptor_obj {
|
||||
mp_obj_base_t base;
|
||||
// Will be MP_OBJ_NULL before being assigned to a Characteristic.
|
||||
struct _bleio_characteristic_obj *characteristic;
|
||||
bleio_uuid_obj_t *uuid;
|
||||
mp_obj_t value;
|
||||
uint16_t max_length;
|
||||
bool fixed_length;
|
||||
uint16_t handle;
|
||||
bleio_attribute_security_mode_t read_perm;
|
||||
bleio_attribute_security_mode_t write_perm;
|
||||
struct _bleio_descriptor_obj* next;
|
||||
} bleio_descriptor_obj_t;
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_DESCRIPTOR_H
|
265
devices/ble_hci/common-hal/_bleio/PacketBuffer.c
Normal file
265
devices/ble_hci/common-hal/_bleio/PacketBuffer.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
#include "shared-bindings/_bleio/PacketBuffer.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) {
|
||||
if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) {
|
||||
// This shouldn't happen.
|
||||
return;
|
||||
}
|
||||
// Push all the data onto the ring buffer.
|
||||
// Make room for the new value by dropping the oldest packets first.
|
||||
while (ringbuf_capacity(&self->ringbuf) - ringbuf_num_filled(&self->ringbuf) < len + sizeof(uint16_t)) {
|
||||
uint16_t packet_length;
|
||||
ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t));
|
||||
for (uint16_t i = 0; i < packet_length; i++) {
|
||||
ringbuf_get(&self->ringbuf);
|
||||
}
|
||||
// set an overflow flag?
|
||||
}
|
||||
ringbuf_put_n(&self->ringbuf, (uint8_t*) &len, sizeof(uint16_t));
|
||||
ringbuf_put_n(&self->ringbuf, data, len);
|
||||
}
|
||||
|
||||
STATIC uint32_t queue_next_write(bleio_packet_buffer_obj_t *self) {
|
||||
// Queue up the next outgoing buffer. We use two, one that has been passed to the SD for
|
||||
// transmission (when packet_queued is true) and the other is `pending` and can still be
|
||||
// modified. By primarily appending to the `pending` buffer we can reduce the protocol overhead
|
||||
// of the lower level link and ATT layers.
|
||||
self->packet_queued = false;
|
||||
if (self->pending_size > 0) {
|
||||
mp_buffer_info_t bufinfo = {
|
||||
.buf = self->outgoing[self->pending_index],
|
||||
.len = self->pending_size,
|
||||
};
|
||||
common_hal_bleio_characteristic_set_value(self->characteristic, &bufinfo);
|
||||
|
||||
self->pending_size = 0;
|
||||
self->pending_index = (self->pending_index + 1) % 2;
|
||||
self->packet_queued = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
write_to_ringbuf(self, bufinfo->buf, bufinfo->len);
|
||||
}
|
||||
|
||||
void common_hal_bleio_packet_buffer_construct(
|
||||
bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic,
|
||||
size_t buffer_size) {
|
||||
|
||||
self->characteristic = characteristic;
|
||||
self->client = self->characteristic->service->is_remote;
|
||||
bleio_characteristic_properties_t incoming =
|
||||
self->characteristic->props & (CHAR_PROP_WRITE_NO_RESPONSE | CHAR_PROP_WRITE);
|
||||
bleio_characteristic_properties_t outgoing =
|
||||
self->characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE);
|
||||
|
||||
if (self->client) {
|
||||
// Swap if we're the client.
|
||||
bleio_characteristic_properties_t temp = incoming;
|
||||
incoming = outgoing;
|
||||
outgoing = temp;
|
||||
self->conn_handle = bleio_connection_get_conn_handle(MP_OBJ_TO_PTR(self->characteristic->service->connection));
|
||||
} else {
|
||||
self->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (incoming) {
|
||||
if (!ringbuf_alloc(&self->ringbuf, buffer_size * (sizeof(uint16_t) + characteristic->max_length), false)) {
|
||||
mp_raise_ValueError(translate("Buffer too large and unable to allocate"));
|
||||
}
|
||||
}
|
||||
|
||||
if (outgoing) {
|
||||
self->packet_queued = false;
|
||||
self->pending_index = 0;
|
||||
self->pending_size = 0;
|
||||
self->outgoing[0] = m_malloc(characteristic->max_length, false);
|
||||
self->outgoing[1] = m_malloc(characteristic->max_length, false);
|
||||
} else {
|
||||
self->outgoing[0] = NULL;
|
||||
self->outgoing[1] = NULL;
|
||||
}
|
||||
|
||||
bleio_characteristic_set_observer(self->characteristic, self);
|
||||
}
|
||||
|
||||
mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) {
|
||||
if (ringbuf_num_filled(&self->ringbuf) < 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy received data.
|
||||
// Get packet length, which is in first two bytes of packet.
|
||||
uint16_t packet_length;
|
||||
ringbuf_get_n(&self->ringbuf, (uint8_t*) &packet_length, sizeof(uint16_t));
|
||||
|
||||
mp_int_t ret;
|
||||
if (packet_length > len) {
|
||||
// Packet is longer than requested. Return negative of overrun value.
|
||||
ret = len - packet_length;
|
||||
// Discard the packet if it's too large. Don't fill data.
|
||||
while (packet_length--) {
|
||||
(void) ringbuf_get(&self->ringbuf);
|
||||
}
|
||||
} else {
|
||||
// Read as much as possible, but might be shorter than len.
|
||||
ringbuf_get_n(&self->ringbuf, data, packet_length);
|
||||
ret = packet_length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len) {
|
||||
if (self->outgoing[0] == NULL) {
|
||||
mp_raise_bleio_BluetoothError(translate("Writes not supported on Characteristic"));
|
||||
}
|
||||
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t outgoing_packet_length = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self);
|
||||
|
||||
if (len + header_len > outgoing_packet_length) {
|
||||
// Supplied data will not fit in a single BLE packet.
|
||||
mp_raise_ValueError(translate("Total data to write is larger than outgoing_packet_length"));
|
||||
}
|
||||
|
||||
if (len + self->pending_size > outgoing_packet_length) {
|
||||
// No room to append len bytes to packet. Wait until we get a free buffer,
|
||||
// and keep checking that we haven't been disconnected.
|
||||
while (self->pending_size != 0 && self->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
}
|
||||
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t num_bytes_written = 0;
|
||||
|
||||
uint8_t* pending = self->outgoing[self->pending_index];
|
||||
|
||||
if (self->pending_size == 0) {
|
||||
memcpy(pending, header, header_len);
|
||||
self->pending_size += header_len;
|
||||
num_bytes_written += header_len;
|
||||
}
|
||||
memcpy(pending + self->pending_size, data, len);
|
||||
self->pending_size += len;
|
||||
num_bytes_written += len;
|
||||
|
||||
// If no writes are queued then sneak in this data.
|
||||
if (!self->packet_queued) {
|
||||
queue_next_write(self);
|
||||
}
|
||||
return num_bytes_written;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) {
|
||||
// If this PacketBuffer is coming from a remote service via NOTIFY or INDICATE
|
||||
// the maximum size is what can be sent in one
|
||||
// BLE packet. But we must be connected to know that value.
|
||||
//
|
||||
// Otherwise it can be as long as the characteristic
|
||||
// will permit, whether or not we're connected.
|
||||
|
||||
if (self->characteristic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->characteristic->service != NULL &&
|
||||
self->characteristic->service->is_remote &&
|
||||
(common_hal_bleio_characteristic_get_properties(self->characteristic) &
|
||||
(CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) {
|
||||
// We are talking to a remote service, and data is arriving via NOTIFY or INDICATE.
|
||||
if (self->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle);
|
||||
if (connection) {
|
||||
return MIN(common_hal_bleio_connection_get_max_packet_length(connection),
|
||||
self->characteristic->max_length);
|
||||
}
|
||||
}
|
||||
// There's no current connection, so we don't know the MTU, and
|
||||
// we can't tell what the largest incoming packet length would be.
|
||||
return -1;
|
||||
}
|
||||
return self->characteristic->max_length;
|
||||
}
|
||||
|
||||
mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) {
|
||||
// If we are sending data via NOTIFY or INDICATE, the maximum size
|
||||
// is what can be sent in one BLE packet. But we must be connected
|
||||
// to know that value.
|
||||
//
|
||||
// Otherwise it can be as long as the characteristic
|
||||
// will permit, whether or not we're connected.
|
||||
|
||||
if (self->characteristic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->characteristic->service != NULL &&
|
||||
!self->characteristic->service->is_remote &&
|
||||
(common_hal_bleio_characteristic_get_properties(self->characteristic) &
|
||||
(CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) {
|
||||
// We are sending to a client, via NOTIFY or INDICATE.
|
||||
if (self->conn_handle != BLE_CONN_HANDLE_INVALID) {
|
||||
bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle);
|
||||
if (connection) {
|
||||
return MIN(common_hal_bleio_connection_get_max_packet_length(connection),
|
||||
self->characteristic->max_length);
|
||||
}
|
||||
}
|
||||
// There's no current connection, so we don't know the MTU, and
|
||||
// we can't tell what the largest outgoing packet length would be.
|
||||
return -1;
|
||||
}
|
||||
return self->characteristic->max_length;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) {
|
||||
return self->characteristic == NULL;
|
||||
}
|
||||
|
||||
void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) {
|
||||
if (!common_hal_bleio_packet_buffer_deinited(self)) {
|
||||
bleio_characteristic_clear_observer(self->characteristic);
|
||||
}
|
||||
}
|
53
devices/ble_hci/common-hal/_bleio/PacketBuffer.h
Normal file
53
devices/ble_hci/common-hal/_bleio/PacketBuffer.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H
|
||||
|
||||
#include "py/ringbuf.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
bleio_characteristic_obj_t *characteristic;
|
||||
// Ring buffer storing consecutive incoming values.
|
||||
ringbuf_t ringbuf;
|
||||
// Two outgoing buffers to alternate between. One will be queued for transmission by the SD and
|
||||
// the other is waiting to be queued and can be extended.
|
||||
uint8_t* outgoing[2];
|
||||
volatile uint16_t pending_size;
|
||||
// We remember the conn_handle so we can do a NOTIFY/INDICATE to a client.
|
||||
// We can find out the conn_handle on a Characteristic write or a CCCD write (but not a read).
|
||||
volatile uint16_t conn_handle;
|
||||
uint8_t pending_index;
|
||||
uint8_t write_type;
|
||||
bool client;
|
||||
bool packet_queued;
|
||||
} bleio_packet_buffer_obj_t;
|
||||
|
||||
void bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_PACKETBUFFER_H
|
129
devices/ble_hci/common-hal/_bleio/Service.c
Normal file
129
devices/ble_hci/common-hal/_bleio/Service.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Descriptor.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/Adapter.h"
|
||||
|
||||
uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t * characteristic_list) {
|
||||
self->uuid = uuid;
|
||||
self->characteristic_list = characteristic_list;
|
||||
self->is_remote = false;
|
||||
self->connection = NULL;
|
||||
self->is_secondary = is_secondary;
|
||||
|
||||
vm_used_ble = true;
|
||||
|
||||
self->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(self));
|
||||
self->start_handle = self->handle;
|
||||
self->end_handle = self->handle;
|
||||
if (self->handle == BLE_GATT_HANDLE_INVALID) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) {
|
||||
if (_common_hal_bleio_service_construct(self, uuid, is_secondary,
|
||||
mp_obj_new_list(0, NULL)) != 0) {
|
||||
mp_raise_RuntimeError(translate("Failed to add service"));
|
||||
}
|
||||
}
|
||||
|
||||
void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection) {
|
||||
self->handle = 0xFFFF;
|
||||
self->uuid = NULL;
|
||||
self->characteristic_list = mp_obj_new_list(0, NULL);
|
||||
self->is_remote = true;
|
||||
self->is_secondary = false;
|
||||
self->connection = connection;
|
||||
}
|
||||
|
||||
bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) {
|
||||
return self->uuid;
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self) {
|
||||
return mp_obj_new_tuple(self->characteristic_list->len, self->characteristic_list->items);
|
||||
}
|
||||
|
||||
bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) {
|
||||
return self->is_remote;
|
||||
}
|
||||
|
||||
bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) {
|
||||
return self->is_secondary;
|
||||
}
|
||||
|
||||
void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
|
||||
bleio_characteristic_obj_t *characteristic,
|
||||
mp_buffer_info_t *initial_value_bufinfo) {
|
||||
|
||||
if (self->handle != common_hal_bleio_adapter_obj.last_added_service_handle) {
|
||||
mp_raise_bleio_BluetoothError(
|
||||
translate("Characteristic can only be added to most recently added service"));
|
||||
}
|
||||
characteristic->decl_handle = bleio_adapter_add_attribute(
|
||||
&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(characteristic));
|
||||
// This is the value handle.
|
||||
characteristic->handle = bleio_adapter_add_attribute(
|
||||
&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(characteristic));
|
||||
|
||||
self->end_handle = characteristic->handle;
|
||||
|
||||
if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) {
|
||||
// We need a CCCD if this characteristic is doing notify or indicate.
|
||||
bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t);
|
||||
cccd->base.type = &bleio_descriptor_type;
|
||||
|
||||
uint16_t zero = 0;
|
||||
mp_buffer_info_t zero_cccd_value = {
|
||||
.buf = &zero,
|
||||
.len = sizeof(zero),
|
||||
};
|
||||
|
||||
common_hal_bleio_descriptor_construct(
|
||||
cccd,
|
||||
characteristic,
|
||||
&cccd_uuid, // 0x2902
|
||||
SECURITY_MODE_OPEN, // CCCD read perm
|
||||
characteristic->read_perm, // Make CCCD write perm match characteristic read perm.
|
||||
2, // 2 bytes
|
||||
true, // fixed length
|
||||
&zero_cccd_value // Initial value is 0.
|
||||
);
|
||||
|
||||
// Adds CCCD to attribute table, and also extends self->end_handle to include the CCCD.
|
||||
common_hal_bleio_characteristic_add_descriptor(characteristic, cccd);
|
||||
characteristic->cccd = cccd;
|
||||
}
|
||||
|
||||
mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic));
|
||||
}
|
54
devices/ble_hci/common-hal/_bleio/Service.h
Normal file
54
devices/ble_hci/common-hal/_bleio/Service.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_SERVICE_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_SERVICE_H
|
||||
|
||||
#include "py/objlist.h"
|
||||
#include "common-hal/_bleio/UUID.h"
|
||||
|
||||
typedef struct bleio_service_obj {
|
||||
mp_obj_base_t base;
|
||||
// Handle for the local service.
|
||||
uint16_t handle;
|
||||
// True if created during discovery.
|
||||
bool is_remote;
|
||||
bool is_secondary;
|
||||
bleio_uuid_obj_t *uuid;
|
||||
// The connection object is set only when this is a remote service.
|
||||
// A local service doesn't know the connection.
|
||||
mp_obj_t connection;
|
||||
mp_obj_list_t *characteristic_list;
|
||||
// Range of attribute handles of this service.
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
struct bleio_service_obj* next;
|
||||
} bleio_service_obj_t;
|
||||
|
||||
void bleio_service_from_connection(bleio_service_obj_t *self, mp_obj_t connection);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_SERVICE_H
|
75
devices/ble_hci/common-hal/_bleio/UUID.c
Normal file
75
devices/ble_hci/common-hal/_bleio/UUID.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "common-hal/_bleio/UUID.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Adapter.h"
|
||||
|
||||
// If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID.
|
||||
// If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where
|
||||
// the 16-bit part goes. Those 16 bits are passed in uuid16.
|
||||
void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) {
|
||||
self->size = uuid128 == NULL ? 16 : 128;
|
||||
self->uuid16 = uuid16;
|
||||
if (uuid128) {
|
||||
memcpy(self->uuid128, uuid128, 16);
|
||||
self->uuid128[12] = uuid16 & 0xff;
|
||||
self->uuid128[13] = uuid16 >> 8;
|
||||
} else {
|
||||
memset(self->uuid128, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) {
|
||||
return self->size;
|
||||
}
|
||||
|
||||
uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) {
|
||||
return self->uuid16;
|
||||
}
|
||||
|
||||
void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) {
|
||||
memcpy(uuid128, self->uuid128, 16);
|
||||
}
|
||||
|
||||
void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf) {
|
||||
if (self->size == 16) {
|
||||
buf[0] = self->uuid16 & 0xff;
|
||||
buf[1] = self->uuid16 >> 8;
|
||||
} else {
|
||||
common_hal_bleio_uuid_get_uuid128(self, buf);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a uui16 only if this is a standard uuid. Otherwise return BLE_UUID_UNKNOWN.
|
||||
uint16_t bleio_uuid_get_uuid16_or_unknown(bleio_uuid_obj_t *uuid) {
|
||||
return uuid->size == 16 ? uuid->uuid16 : BLE_UUID_UNKNOWN;
|
||||
}
|
58
devices/ble_hci/common-hal/_bleio/UUID.h
Normal file
58
devices/ble_hci/common-hal/_bleio/UUID.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// Types returned by attribute table lookups. These are UUIDs.
|
||||
typedef enum {
|
||||
BLE_UUID_UNKNOWN = 0x0000,
|
||||
BLE_UUID_SERVICE_PRIMARY = 0x2800,
|
||||
BLE_UUID_SERVICE_SECONDARY = 0x2801,
|
||||
BLE_UUID_SERVICE_INCLUDE = 0x2802, // not yet implemented by us
|
||||
BLE_UUID_CHARACTERISTIC = 0x2803,
|
||||
BLE_UUID_CHAR_EXTENDED_PROPS = 0x2900, // not yet implemented by us
|
||||
BLE_UUID_CHAR_USER_DESC = 0x2901, // not yet implemented by us
|
||||
BLE_UUID_CCCD = 0x2902,
|
||||
BLE_UUID_SCCD = 0x2903, // not yet implemented by us
|
||||
BLE_UUID_CHAR_PRESENTATION_FMT = 0x2904, // not yet implemented by us
|
||||
BLE_UUID_CHAR_AGGREGATE_FMT = 0x2905, // not yet implemented by us
|
||||
} ble_standard_uuid;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
uint8_t size;
|
||||
uint16_t uuid16;
|
||||
uint8_t uuid128[16];
|
||||
} bleio_uuid_obj_t;
|
||||
|
||||
uint16_t bleio_uuid_get_uuid16_or_unknown(bleio_uuid_obj_t *uuid);
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_UUID_H
|
112
devices/ble_hci/common-hal/_bleio/__init__.c
Normal file
112
devices/ble_hci/common-hal/_bleio/__init__.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
* Copyright (c) 2018 Artur Pacholec
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "shared-bindings/_bleio/Adapter.h"
|
||||
#include "shared-bindings/_bleio/Characteristic.h"
|
||||
#include "shared-bindings/_bleio/Connection.h"
|
||||
#include "shared-bindings/_bleio/Descriptor.h"
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
#include "supervisor/shared/bluetooth.h"
|
||||
|
||||
// UUID shared by all cccd's.
|
||||
bleio_uuid_obj_t cccd_uuid;
|
||||
|
||||
bool vm_used_ble;
|
||||
|
||||
// void check_sec_status(uint8_t sec_status) {
|
||||
// if (sec_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// switch (sec_status) {
|
||||
// case BLE_GAP_SEC_STATUS_UNSPECIFIED:
|
||||
// mp_raise_bleio_SecurityError(translate("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored."));
|
||||
// return;
|
||||
// default:
|
||||
// mp_raise_bleio_SecurityError(translate("Unknown security error: 0x%04x"), sec_status);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Turn off BLE on a reset or reload.
|
||||
void bleio_reset() {
|
||||
// Create a UUID object for all CCCD's.
|
||||
cccd_uuid.base.type = &bleio_uuid_type;
|
||||
common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL);
|
||||
|
||||
bleio_hci_reset();
|
||||
|
||||
if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) {
|
||||
return;
|
||||
}
|
||||
bleio_adapter_reset(&common_hal_bleio_adapter_obj);
|
||||
if (!vm_used_ble) {
|
||||
// No user-code BLE operations were done, so we can maintain the supervisor state.
|
||||
return;
|
||||
}
|
||||
common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false);
|
||||
common_hal_bleio_adapter_obj.allocated = false;
|
||||
|
||||
bleio_set_adapter(mp_const_none);
|
||||
|
||||
//FIX bonding_reset();
|
||||
supervisor_start_bluetooth();
|
||||
}
|
||||
|
||||
// The singleton _bleio.Adapter object, bound to _bleio.adapter
|
||||
bleio_adapter_obj_t common_hal_bleio_adapter_obj = {
|
||||
.base = {
|
||||
.type = &bleio_adapter_type,
|
||||
},
|
||||
};
|
||||
|
||||
bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) {
|
||||
if (common_hal_bleio_adapter_obj.allocated) {
|
||||
mp_raise_RuntimeError(translate("Too many Adapters"));
|
||||
}
|
||||
return &common_hal_bleio_adapter_obj;
|
||||
}
|
||||
|
||||
void common_hal_bleio_check_connected(uint16_t conn_handle) {
|
||||
if (conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
mp_raise_ConnectionError(translate("Not connected"));
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_bleio_gc_collect(void) {
|
||||
bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj);
|
||||
}
|
||||
|
||||
|
||||
void bleio_background(void) {
|
||||
bleio_adapter_background(&common_hal_bleio_adapter_obj);
|
||||
}
|
62
devices/ble_hci/common-hal/_bleio/__init__.h
Normal file
62
devices/ble_hci/common-hal/_bleio/__init__.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H
|
||||
#define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
|
||||
#include "att.h"
|
||||
#include "hci.h"
|
||||
|
||||
void bleio_background(void);
|
||||
void bleio_reset(void);
|
||||
|
||||
typedef struct {
|
||||
// ble_gap_enc_key_t own_enc;
|
||||
// ble_gap_enc_key_t peer_enc;
|
||||
// ble_gap_id_key_t peer_id;
|
||||
} bonding_keys_t;
|
||||
|
||||
// We assume variable length data.
|
||||
// 20 bytes max (23 - 3).
|
||||
#define GATT_MAX_DATA_LENGTH (BT_ATT_DEFAULT_LE_MTU - 3)
|
||||
|
||||
//FIX
|
||||
#define BLE_GATT_HANDLE_INVALID 0x0000
|
||||
#define BLE_CONN_HANDLE_INVALID 0xFFFF
|
||||
#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. */
|
||||
|
||||
// Track if the user code modified the BLE state to know if we need to undo it on reload.
|
||||
extern bool vm_used_ble;
|
||||
|
||||
// UUID shared by all CCCD's.
|
||||
extern bleio_uuid_obj_t cccd_uuid;
|
||||
|
||||
#endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H
|
1790
devices/ble_hci/common-hal/_bleio/att.c
Normal file
1790
devices/ble_hci/common-hal/_bleio/att.c
Normal file
File diff suppressed because it is too large
Load Diff
57
devices/ble_hci/common-hal/_bleio/att.h
Normal file
57
devices/ble_hci/common-hal/_bleio/att.h
Normal file
@ -0,0 +1,57 @@
|
||||
// Derived from ArduinoBLE.
|
||||
// Copyright 2020 Dan Halbert for Adafruit Industries
|
||||
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H
|
||||
#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hci_include/addr.h"
|
||||
#include "hci_include/att.h"
|
||||
#include "hci_include/att_internal.h"
|
||||
|
||||
void bleio_att_reset(void);
|
||||
|
||||
//FIX void att_set_event_handler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler);
|
||||
bool att_address_is_connected(bt_addr_le_t *addr);
|
||||
bool att_connect_to_address(bt_addr_le_t *addr);
|
||||
bool att_disconnect(uint16_t conn_handle);
|
||||
bool att_disconnect_all(void);
|
||||
bool att_discover_attributes(bt_addr_le_t *addr, const char* service_uuid_filter);
|
||||
bool att_exchange_mtu(uint16_t conn_handle);
|
||||
bool att_handle_is_connected(uint16_t handle);
|
||||
bool att_indicate(uint16_t handle, const uint8_t* value, int length);
|
||||
bool att_is_connected(void);
|
||||
bool att_notify(uint16_t handle, const uint8_t* value, int length);
|
||||
int att_read_req(uint16_t conn_handle, uint16_t handle, uint8_t response_buffer[]);
|
||||
int att_write_req(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len, uint8_t response_buffer[]);
|
||||
uint16_t att_conn_handle(bt_addr_le_t *addr);
|
||||
uint16_t att_mtu(uint16_t handle);
|
||||
void att_add_connection(uint16_t handle, uint8_t role, bt_addr_le_t *peer_addr, uint16_t interval, uint16_t latency, uint16_t supervision_timeout, uint8_t master_clock_accuracy);
|
||||
void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]);
|
||||
void att_remove_connection(uint16_t conn_handle, uint8_t reason);
|
||||
void att_set_max_mtu(uint16_t max_mtu);
|
||||
void att_set_timeout(unsigned long timeout);
|
||||
void att_write_cmd(uint16_t conn_handle, uint16_t handle, const uint8_t* data, uint8_t data_len);
|
||||
|
||||
#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_ATT_H
|
806
devices/ble_hci/common-hal/_bleio/hci.c
Normal file
806
devices/ble_hci/common-hal/_bleio/hci.c
Normal file
@ -0,0 +1,806 @@
|
||||
// This file is derived from the ArduinoBLE library. Its header is below.
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "att.h"
|
||||
#include "hci.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
// Zephyr include files to define HCI communication values and structs.
|
||||
#include "hci_include/hci.h"
|
||||
#include "hci_include/hci_err.h"
|
||||
#include "hci_include/l2cap_internal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mphal.h" //*****************************
|
||||
#include "supervisor/shared/tick.h"
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#include "common-hal/_bleio/Adapter.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
|
||||
// Set to 1 for extensive HCI packet logging.
|
||||
#define HCI_DEBUG 0
|
||||
|
||||
// HCI H4 protocol packet types: first byte in the packet.
|
||||
#define H4_CMD 0x01
|
||||
#define H4_ACL 0x02
|
||||
#define H4_SCO 0x03
|
||||
#define H4_EVT 0x04
|
||||
|
||||
#define CTS_TIMEOUT_MSECS (1000)
|
||||
#define RESPONSE_TIMEOUT_MSECS (1000)
|
||||
|
||||
// These are the headers of the full packets that are sent over the serial interface.
|
||||
// They all have a one-byte type-field at the front, one of the H4_xxx packet types.
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint16_t opcode;
|
||||
uint8_t param_len;
|
||||
uint8_t params[];
|
||||
} h4_hci_cmd_pkt_t;
|
||||
|
||||
#define ACL_DATA_PB_FIRST_NON_FLUSH 0
|
||||
#define ACL_DATA_PB_MIDDLE 1
|
||||
#define ACL_DATA_PB_FIRST_FLUSH 2
|
||||
#define ACL_DATA_PB_FULL 3
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint16_t handle : 12;
|
||||
uint8_t pb: 2; // Packet boundary flag: ACL_DATA_PB values.
|
||||
uint8_t bc: 2; // Broadcast flag: always 0b00 for BLE.
|
||||
uint16_t data_len; // length of data[] in this packet.
|
||||
uint8_t data[];
|
||||
} h4_hci_acl_pkt_t;
|
||||
|
||||
// The ACL data in an h4_hci_acl_pkt_t may be fragmented across
|
||||
// multiple ACL_DATA packets, and need to be recombined. This is the
|
||||
// structure of the combined packet or the first fragment.
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t acl_data_len; // Length of acl_data. Does not include this header.
|
||||
uint16_t cid; // Channel ID.
|
||||
uint8_t acl_data[]; // Length is acl_data_len of full packet.
|
||||
} acl_data_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint8_t evt;
|
||||
uint8_t param_len;
|
||||
uint8_t params[];
|
||||
} h4_hci_evt_pkt_t;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Static storage:
|
||||
|
||||
//FIX size
|
||||
#define RX_BUFFER_SIZE (3 + 255)
|
||||
#define ACL_DATA_BUFFER_SIZE (255)
|
||||
|
||||
STATIC uint8_t rx_buffer[RX_BUFFER_SIZE];
|
||||
STATIC size_t rx_idx;
|
||||
|
||||
STATIC uint8_t acl_data_buffer[ACL_DATA_BUFFER_SIZE];
|
||||
STATIC size_t acl_data_len;
|
||||
|
||||
STATIC size_t num_command_packets_allowed;
|
||||
STATIC volatile size_t pending_pkt;
|
||||
|
||||
// Results from parsing a command response packet.
|
||||
STATIC bool cmd_response_received;
|
||||
STATIC uint16_t cmd_response_opcode;
|
||||
STATIC uint8_t cmd_response_status;
|
||||
STATIC size_t cmd_response_len;
|
||||
STATIC uint8_t* cmd_response_data;
|
||||
|
||||
STATIC volatile bool hci_poll_in_progress = false;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if HCI_DEBUG
|
||||
#include "hci_debug.c"
|
||||
#endif // HCI_DEBUG
|
||||
|
||||
STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t*) pkt_data;
|
||||
|
||||
if (pkt->pb != ACL_DATA_PB_MIDDLE) {
|
||||
// This is the start of a fragmented acl_data packet or is a full packet.
|
||||
memcpy(acl_data_buffer, pkt->data, pkt->data_len);
|
||||
acl_data_len = pkt->data_len;
|
||||
} else {
|
||||
// This is a middle or end fragment of acl data.
|
||||
// Append to the accumulated data so far.
|
||||
memcpy(&acl_data_buffer[acl_data_len], pkt->data, pkt->data_len);
|
||||
acl_data_len += pkt->data_len;
|
||||
}
|
||||
|
||||
acl_data_t *acl = (acl_data_t *) &acl_data_buffer;
|
||||
if (acl_data_len != sizeof(acl) + acl->acl_data_len) {
|
||||
// We don't have the full packet yet.
|
||||
return;
|
||||
}
|
||||
|
||||
if (acl->cid == BT_L2CAP_CID_ATT) {
|
||||
att_process_data(pkt->handle, acl->acl_data_len, acl->acl_data);
|
||||
}
|
||||
// } else if (aclHdr->cid == BT_L2CAP_CID_LE_SIG) {
|
||||
// L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]);
|
||||
// } else {
|
||||
// struct __attribute__ ((packed)) {
|
||||
// uint8_t op;
|
||||
// uint8_t id;
|
||||
// uint16_t length;
|
||||
// uint16_t reason;
|
||||
// uint16_t localCid;
|
||||
// uint16_t remoteCid;
|
||||
// } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 };
|
||||
|
||||
// sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid);
|
||||
// }
|
||||
}
|
||||
|
||||
// Process number of completed packets. Reduce number of pending packets by reported
|
||||
// number of completed.
|
||||
STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) {
|
||||
if (num_pkts && pending_pkt > num_pkts) {
|
||||
pending_pkt -= num_pkts;
|
||||
} else {
|
||||
pending_pkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt_data[])
|
||||
{
|
||||
h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t*) pkt_data;
|
||||
|
||||
switch (pkt->evt) {
|
||||
case BT_HCI_EVT_DISCONN_COMPLETE: {
|
||||
struct bt_hci_evt_disconn_complete *disconn_complete =
|
||||
(struct bt_hci_evt_disconn_complete*) pkt->params;
|
||||
(void) disconn_complete;
|
||||
|
||||
att_remove_connection(disconn_complete->handle, disconn_complete->reason);
|
||||
//FIX L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason);
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_CMD_COMPLETE: {
|
||||
struct cmd_complete_with_status {
|
||||
struct bt_hci_evt_cmd_complete cmd_complete;
|
||||
struct bt_hci_evt_cc_status cc_status;
|
||||
} __packed;
|
||||
|
||||
struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) pkt->params;
|
||||
|
||||
num_command_packets_allowed = evt->cmd_complete.ncmd;
|
||||
|
||||
cmd_response_received = true;
|
||||
cmd_response_opcode = evt->cmd_complete.opcode;
|
||||
cmd_response_status = evt->cc_status.status;
|
||||
// All the bytes following cmd_complete, -including- the status byte, which is
|
||||
// included in all the _bt_hci_rp_* structs.
|
||||
cmd_response_data = (uint8_t *) &evt->cc_status;
|
||||
// Includes status byte.
|
||||
cmd_response_len = pkt->param_len - sizeof_field(struct cmd_complete_with_status, cmd_complete);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_CMD_STATUS: {
|
||||
struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) pkt->params;
|
||||
|
||||
num_command_packets_allowed = evt->ncmd;
|
||||
|
||||
cmd_response_received = true;
|
||||
cmd_response_opcode = evt->opcode;
|
||||
cmd_response_status = evt->status;
|
||||
cmd_response_data = NULL;
|
||||
cmd_response_len = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_NUM_COMPLETED_PACKETS: {
|
||||
struct bt_hci_evt_num_completed_packets *evt =
|
||||
(struct bt_hci_evt_num_completed_packets *) pkt->params;
|
||||
|
||||
// Start at zero-th pair: (conn handle, num completed packets).
|
||||
struct bt_hci_handle_count *handle_and_count = &(evt->h[0]);
|
||||
for (uint8_t i = 0; i < evt->num_handles; i++) {
|
||||
process_num_comp_pkts(handle_and_count->handle, handle_and_count->count);
|
||||
handle_and_count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_LE_META_EVENT: {
|
||||
struct bt_hci_evt_le_meta_event *meta_evt = (struct bt_hci_evt_le_meta_event *) pkt->params;
|
||||
uint8_t *le_evt = pkt->params + sizeof (struct bt_hci_evt_le_meta_event);
|
||||
|
||||
if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) {
|
||||
// Advertising stops when connection occurs.
|
||||
// We don't tell the adapter to stop, because stopping advertising
|
||||
// when it's already stopped seems to exercise a bug in the ESP32 HCI code:
|
||||
// It doesn't return a response.
|
||||
bleio_adapter_advertising_was_stopped(&common_hal_bleio_adapter_obj);
|
||||
|
||||
struct bt_hci_evt_le_conn_complete *le_conn_complete =
|
||||
(struct bt_hci_evt_le_conn_complete *) le_evt;
|
||||
|
||||
if (le_conn_complete->status == BT_HCI_ERR_SUCCESS) {
|
||||
att_add_connection(
|
||||
le_conn_complete->handle,
|
||||
le_conn_complete->role,
|
||||
&le_conn_complete->peer_addr,
|
||||
le_conn_complete->interval,
|
||||
le_conn_complete->latency,
|
||||
le_conn_complete->supv_timeout,
|
||||
le_conn_complete->clock_accuracy);
|
||||
|
||||
}
|
||||
} else if (meta_evt->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT) {
|
||||
struct bt_hci_evt_le_advertising_info *le_advertising_info =
|
||||
(struct bt_hci_evt_le_advertising_info *) le_evt;
|
||||
if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) {
|
||||
//FIX
|
||||
// last byte is RSSI
|
||||
// GAP.handleLeAdvertisingReport(leAdvertisingReport->type,
|
||||
// leAdvertisingReport->peerBdaddrType,
|
||||
// leAdvertisingReport->peerBdaddr,
|
||||
// leAdvertisingReport->eirLength,
|
||||
// leAdvertisingReport->eirData,
|
||||
// rssi); //FIX, don't separate
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
#if HCI_DEBUG
|
||||
mp_printf(&mp_plat_print, "process_evt_pkt: Unknown event: %02x\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bleio_hci_reset(void) {
|
||||
rx_idx = 0;
|
||||
pending_pkt = 0;
|
||||
hci_poll_in_progress = false;
|
||||
bleio_att_reset();
|
||||
}
|
||||
|
||||
hci_result_t hci_poll_for_incoming_pkt(void) {
|
||||
common_hal_mcu_disable_interrupts();
|
||||
if (hci_poll_in_progress) {
|
||||
common_hal_mcu_enable_interrupts();
|
||||
return HCI_OK;
|
||||
}
|
||||
hci_poll_in_progress = true;
|
||||
common_hal_mcu_enable_interrupts();
|
||||
|
||||
// Assert RTS low to say we're ready to read data.
|
||||
common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, false);
|
||||
|
||||
int errcode = 0;
|
||||
bool packet_is_complete = false;
|
||||
|
||||
// Read bytes until we run out. There may be more than one packet in the input buffer.
|
||||
while (!packet_is_complete &&
|
||||
common_hal_busio_uart_rx_characters_available(common_hal_bleio_adapter_obj.hci_uart) > 0) {
|
||||
|
||||
// Read just one character a a time, so we don't accidentally get part of a second
|
||||
// packet.
|
||||
size_t num_read =
|
||||
common_hal_busio_uart_read(common_hal_bleio_adapter_obj.hci_uart, rx_buffer + rx_idx, 1, &errcode);
|
||||
if (num_read == 0) {
|
||||
return HCI_OK;
|
||||
}
|
||||
if (errcode) {
|
||||
if (errcode == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
hci_poll_in_progress = false;
|
||||
mp_printf(&mp_plat_print, "HCI_READ_ERROR, errcode: %x\n", errcode);
|
||||
return HCI_READ_ERROR;
|
||||
}
|
||||
rx_idx++;
|
||||
if (rx_idx >= sizeof(rx_buffer)) {
|
||||
// Incoming packet is too large. Should not happen.
|
||||
return HCI_READ_ERROR;
|
||||
}
|
||||
|
||||
switch (rx_buffer[0]) {
|
||||
case H4_ACL:
|
||||
if (rx_idx >= sizeof(h4_hci_acl_pkt_t)) {
|
||||
const size_t total_len =
|
||||
sizeof(h4_hci_acl_pkt_t) + ((h4_hci_acl_pkt_t *) rx_buffer)->data_len;
|
||||
if (rx_idx == total_len) {
|
||||
packet_is_complete = true;
|
||||
}
|
||||
if (rx_idx > total_len) {
|
||||
return HCI_PACKET_SIZE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case H4_EVT:
|
||||
if (rx_idx >= sizeof(h4_hci_evt_pkt_t)) {
|
||||
const size_t total_len =
|
||||
sizeof(h4_hci_evt_pkt_t) + ((h4_hci_evt_pkt_t *) rx_buffer)->param_len;
|
||||
if (rx_idx == total_len) {
|
||||
packet_is_complete = true;
|
||||
}
|
||||
if (rx_idx > total_len) {
|
||||
return HCI_PACKET_SIZE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown or bad packet type. Start over.
|
||||
rx_idx = 0;
|
||||
break;
|
||||
}
|
||||
} // end while
|
||||
|
||||
if (packet_is_complete) {
|
||||
// Stop incoming data while processing packet.
|
||||
common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, true);
|
||||
size_t pkt_len = rx_idx;
|
||||
|
||||
// Reset for next packet.
|
||||
rx_idx = 0;
|
||||
packet_is_complete = false;
|
||||
|
||||
switch (rx_buffer[0]) {
|
||||
case H4_ACL:
|
||||
#if HCI_DEBUG
|
||||
dump_acl_pkt(false, pkt_len, rx_buffer);
|
||||
#endif
|
||||
process_acl_data_pkt(pkt_len, rx_buffer);
|
||||
break;
|
||||
|
||||
case H4_EVT:
|
||||
#if HCI_DEBUG
|
||||
dump_evt_pkt(false, pkt_len, rx_buffer);
|
||||
#endif
|
||||
process_evt_pkt(pkt_len, rx_buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
#if HCI_DEBUG
|
||||
mp_printf(&mp_plat_print, "Unknown HCI packet type: %d\n", rx_buffer[0]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
// Let incoming bytes flow again.
|
||||
common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, false);
|
||||
}
|
||||
|
||||
// All done with this batch. Hold off receiving bytes until we're ready again.
|
||||
///common_hal_digitalio_digitalinout_set_value(common_hal_bleio_adapter_obj.rts_digitalinout, true);
|
||||
hci_poll_in_progress = false;
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
|
||||
STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) {
|
||||
// Wait for CTS to go low before writing to HCI adapter.
|
||||
uint64_t start = supervisor_ticks_ms64();
|
||||
|
||||
while (common_hal_digitalio_digitalinout_get_value(common_hal_bleio_adapter_obj.cts_digitalinout)) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
if (supervisor_ticks_ms64() - start > CTS_TIMEOUT_MSECS) {
|
||||
return HCI_WRITE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(common_hal_bleio_adapter_obj.hci_uart, buffer, len, &errcode);
|
||||
if (errcode) {
|
||||
return HCI_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* params) {
|
||||
uint8_t cmd_pkt_len = sizeof(h4_hci_cmd_pkt_t) + params_len;
|
||||
uint8_t tx_buffer[cmd_pkt_len];
|
||||
|
||||
// cmd header is at the beginning of tx_buffer
|
||||
h4_hci_cmd_pkt_t *cmd_pkt = (h4_hci_cmd_pkt_t *) tx_buffer;
|
||||
cmd_pkt->pkt_type = H4_CMD;
|
||||
cmd_pkt->opcode = opcode;
|
||||
cmd_pkt->param_len = params_len;
|
||||
|
||||
memcpy(cmd_pkt->params, params, params_len);
|
||||
|
||||
#if HCI_DEBUG
|
||||
dump_cmd_pkt(true, sizeof(tx_buffer), tx_buffer);
|
||||
#endif
|
||||
|
||||
int result = write_pkt(tx_buffer, cmd_pkt_len);
|
||||
if (result != HCI_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
cmd_response_received = false;
|
||||
|
||||
// Wait for a response. Note that other packets may be received that are not
|
||||
// command responses.
|
||||
uint64_t start = supervisor_ticks_ms64();
|
||||
while (supervisor_ticks_ms64() - start < RESPONSE_TIMEOUT_MSECS) {
|
||||
// RUN_BACKGROUND_TASKS includes hci_poll_for_incoming_pkt();
|
||||
RUN_BACKGROUND_TASKS;
|
||||
if (cmd_response_received && cmd_response_opcode == opcode) {
|
||||
// If this is definitely a response to the command that was sent,
|
||||
// return the status value, which will will be
|
||||
// BT_HCI_ERR_SUCCESS (0x00) if the command succeeded,
|
||||
// or a BT_HCI_ERR_x value (> 0x00) if there was a problem.
|
||||
return cmd_response_status;
|
||||
}
|
||||
}
|
||||
|
||||
// No I/O error, but no response sent back in time.
|
||||
return HCI_RESPONSE_TIMEOUT;
|
||||
}
|
||||
|
||||
hci_result_t hci_send_acl_pkt(uint16_t handle, uint8_t cid, uint16_t data_len, uint8_t *data) {
|
||||
// Wait for all backlogged packets to finish.
|
||||
while (pending_pkt >= common_hal_bleio_adapter_obj.max_acl_num_buffers) {
|
||||
// RUN_BACKGROUND_TASKS includes hci_poll_for_incoming_pkt();
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
|
||||
// buf_len is size of entire packet including header.
|
||||
const size_t buf_len = sizeof(h4_hci_acl_pkt_t) + sizeof(acl_data_t) + data_len;
|
||||
uint8_t tx_buffer[buf_len];
|
||||
|
||||
h4_hci_acl_pkt_t *acl_pkt = (h4_hci_acl_pkt_t *) tx_buffer;
|
||||
acl_data_t *acl_data = (acl_data_t *) acl_pkt->data;
|
||||
acl_pkt->pkt_type = H4_ACL;
|
||||
acl_pkt->handle = handle;
|
||||
acl_pkt->pb = ACL_DATA_PB_FIRST_FLUSH;
|
||||
acl_pkt->bc = 0;
|
||||
acl_pkt->data_len = (uint16_t)(sizeof(acl_data_t) + data_len);
|
||||
acl_data->acl_data_len = data_len;
|
||||
acl_data->cid = cid;
|
||||
|
||||
memcpy(&acl_data->acl_data, data, data_len);
|
||||
|
||||
#if HCI_DEBUG
|
||||
dump_acl_pkt(true, buf_len, tx_buffer);
|
||||
#endif
|
||||
|
||||
pending_pkt++;
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(common_hal_bleio_adapter_obj.hci_uart, tx_buffer, buf_len, &errcode);
|
||||
if (errcode) {
|
||||
return HCI_WRITE_ERROR;
|
||||
}
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
hci_result_t hci_reset(void) {
|
||||
return send_command(BT_HCI_OP_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion) {
|
||||
hci_result_t result = send_command(BT_HCI_OP_READ_LOCAL_VERSION_INFO, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_local_version_info *response =
|
||||
(struct bt_hci_rp_read_local_version_info *) cmd_response_data;
|
||||
*hci_version = response->hci_version;
|
||||
*hci_revision = response->hci_revision;
|
||||
*lmp_version = response->lmp_version;
|
||||
*manufacturer = response->manufacturer;
|
||||
*lmp_subversion = response->lmp_subversion;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_read_bd_addr(bt_addr_t *addr) {
|
||||
int result = send_command(BT_HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_bd_addr *response = (struct bt_hci_rp_read_bd_addr *) cmd_response_data;
|
||||
memcpy(addr->val, response->bdaddr.val, sizeof_field(bt_addr_t, val));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_read_rssi(uint16_t handle, int *rssi) {
|
||||
int result = send_command(BT_HCI_OP_READ_RSSI, sizeof(handle), &handle);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_rssi *response = (struct bt_hci_rp_read_rssi *) cmd_response_data;
|
||||
*rssi = response->rssi;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_set_event_mask(uint64_t event_mask) {
|
||||
return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num) {
|
||||
int result = send_command(BT_HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_le_read_buffer_size *response =
|
||||
(struct bt_hci_rp_le_read_buffer_size *) cmd_response_data;
|
||||
*le_max_len = response->le_max_len;
|
||||
*le_max_num = response->le_max_num;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num) {
|
||||
int result = send_command(BT_HCI_OP_READ_BUFFER_SIZE, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_buffer_size *response =
|
||||
(struct bt_hci_rp_read_buffer_size *) cmd_response_data;
|
||||
*acl_max_len = response->acl_max_len;
|
||||
*sco_max_len = response->sco_max_len;
|
||||
*acl_max_num = response->acl_max_num;
|
||||
*sco_max_num = response->sco_max_num;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_random_address(uint8_t addr[6]) {
|
||||
return send_command(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, 6, addr);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy) {
|
||||
struct bt_hci_cp_le_set_adv_param params = {
|
||||
.min_interval = min_interval,
|
||||
.max_interval = max_interval,
|
||||
.type = type,
|
||||
.own_addr_type = own_addr_type,
|
||||
// .direct_addr set below.
|
||||
.channel_map = channel_map,
|
||||
.filter_policy = filter_policy,
|
||||
};
|
||||
params.direct_addr.type = direct_addr->type;
|
||||
memcpy(params.direct_addr.a.val, direct_addr->a.val, sizeof(params.direct_addr.a.val));
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable) {
|
||||
struct bt_hci_cp_le_set_ext_adv_param params = {
|
||||
.handle = handle,
|
||||
.props = props,
|
||||
// .prim_min_interval and .prim_max_interval set below
|
||||
.prim_channel_map = prim_channel_map,
|
||||
.own_addr_type = own_addr_type,
|
||||
// .peer_addr set below.
|
||||
.tx_power = tx_power,
|
||||
.sec_adv_max_skip = sec_adv_max_skip,
|
||||
.sec_adv_phy = sec_adv_phy,
|
||||
.sid = sid,
|
||||
.scan_req_notify_enable = scan_req_notify_enable,
|
||||
};
|
||||
// Assumes little-endian.
|
||||
memcpy(params.prim_min_interval, (void *) &prim_min_interval,
|
||||
sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_min_interval));
|
||||
memcpy(params.prim_max_interval, (void *) &prim_max_interval,
|
||||
sizeof_field(struct bt_hci_cp_le_set_ext_adv_param, prim_max_interval));
|
||||
memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof_field(bt_addr_le_t, a.val));
|
||||
return send_command(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len) {
|
||||
int result = send_command(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_le_read_max_adv_data_len *response =
|
||||
(struct bt_hci_rp_le_read_max_adv_data_len *) cmd_response_data;
|
||||
*max_adv_data_len = response->max_adv_data_len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_le_read_local_supported_features(uint8_t features[8]) {
|
||||
int result = send_command(BT_HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_le_read_local_features *response =
|
||||
(struct bt_hci_rp_le_read_local_features *) cmd_response_data;
|
||||
memcpy(features, response->features,
|
||||
sizeof_field(struct bt_hci_rp_le_read_local_features, features));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) {
|
||||
struct bt_hci_cp_le_set_adv_data params = {
|
||||
// Zero out unused data bytes.
|
||||
.data = { 0 },
|
||||
};
|
||||
|
||||
params.len = len;
|
||||
memcpy(params.data, data, len);
|
||||
|
||||
// All data bytes are sent even if some are unused.
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_DATA, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]) {
|
||||
const uint8_t max_len = sizeof_field(struct bt_hci_cp_le_set_ext_adv_data, data);
|
||||
uint8_t valid_len = MIN(len, max_len);
|
||||
struct bt_hci_cp_le_set_ext_adv_data params = {
|
||||
.handle = handle,
|
||||
.op = op,
|
||||
.frag_pref = frag_pref,
|
||||
.len = valid_len,
|
||||
};
|
||||
memcpy(params.data, data, valid_len);
|
||||
return send_command(BT_HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(params) - (max_len - valid_len), ¶ms);
|
||||
}
|
||||
|
||||
|
||||
hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) {
|
||||
struct bt_hci_cp_le_set_scan_rsp_data params = {
|
||||
// Zero out unused data bytes.
|
||||
.data = { 0 },
|
||||
};
|
||||
params.len = len;
|
||||
memcpy(params.data, data, len);
|
||||
|
||||
// All data bytes are sent even if some are unused.
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertising_enable(uint8_t enable) {
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]) {
|
||||
uint8_t params[sizeof(struct bt_hci_cp_le_set_ext_adv_enable) +
|
||||
set_num * (sizeof(struct bt_hci_ext_adv_set))];
|
||||
struct bt_hci_cp_le_set_ext_adv_enable *params_p = (struct bt_hci_cp_le_set_ext_adv_enable *) ¶ms;
|
||||
params_p->enable = enable;
|
||||
params_p->set_num = set_num;
|
||||
for (size_t i = 0; i < set_num; i++) {
|
||||
params_p->s[i].handle = handle[i];
|
||||
params_p->s[i].duration = duration[i];
|
||||
params_p->s[i].max_ext_adv_evts = max_ext_adv_evts[i];
|
||||
}
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_EXT_ADV_ENABLE, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy) {
|
||||
struct bt_hci_cp_le_set_scan_param params = {
|
||||
.scan_type = scan_type,
|
||||
.interval = interval,
|
||||
.window = window,
|
||||
.addr_type = addr_type,
|
||||
.filter_policy = filter_policy,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) {
|
||||
struct bt_hci_cp_le_set_scan_enable params = {
|
||||
.enable = enable,
|
||||
.filter_dup = filter_dup,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len) {
|
||||
struct bt_hci_cp_le_create_conn params = {
|
||||
.scan_interval = scan_interval,
|
||||
.scan_window = scan_window,
|
||||
.filter_policy = filter_policy,
|
||||
// .peer_addr is set below
|
||||
.own_addr_type = own_addr_type,
|
||||
.conn_interval_min = conn_interval_min,
|
||||
.conn_interval_max = conn_interval_max,
|
||||
.conn_latency = conn_latency,
|
||||
.supervision_timeout = supervision_timeout,
|
||||
.min_ce_len = min_ce_len,
|
||||
.max_ce_len = max_ce_len,
|
||||
};
|
||||
params.peer_addr.type = peer_addr->type;
|
||||
memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof(params.peer_addr.a.val));
|
||||
|
||||
return send_command(BT_HCI_OP_LE_CREATE_CONN, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_cancel_conn(void) {
|
||||
return send_command(BT_HCI_OP_CONNECT_CANCEL, 0, NULL);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) {
|
||||
struct hci_cp_le_conn_update params = {
|
||||
.handle = handle,
|
||||
.conn_interval_min = conn_interval_min,
|
||||
.conn_interval_max = conn_interval_max,
|
||||
.conn_latency = conn_latency,
|
||||
.supervision_timeout = supervision_timeout,
|
||||
.min_ce_len = 4,
|
||||
.max_ce_len = 6,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_CONN_UPDATE, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_disconnect(uint16_t handle) {
|
||||
struct bt_hci_cp_disconnect params = {
|
||||
.handle = handle,
|
||||
.reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_DISCONNECT, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
void hci_check_error(hci_result_t result) {
|
||||
switch (result) {
|
||||
case HCI_OK:
|
||||
return;
|
||||
|
||||
case HCI_RESPONSE_TIMEOUT:
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout waiting for HCI response"));
|
||||
return;
|
||||
|
||||
case HCI_WRITE_TIMEOUT:
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout waiting to write HCI request"));
|
||||
return;
|
||||
|
||||
case HCI_READ_ERROR:
|
||||
mp_raise_bleio_BluetoothError(translate("Error reading from HCI adapter"));
|
||||
return;
|
||||
|
||||
case HCI_WRITE_ERROR:
|
||||
mp_raise_bleio_BluetoothError(translate("Error writing to HCI adapter"));
|
||||
return;
|
||||
|
||||
case HCI_PACKET_SIZE_ERROR:
|
||||
mp_raise_RuntimeError(translate("HCI packet size mismatch"));
|
||||
return;
|
||||
|
||||
case HCI_ATT_ERROR:
|
||||
mp_raise_RuntimeError(translate("Error in ATT protocol code"));
|
||||
return;
|
||||
|
||||
default:
|
||||
// Should be an HCI status error, > 0.
|
||||
if (result > 0) {
|
||||
mp_raise_bleio_BluetoothError(translate("HCI status error: %02x"), result);
|
||||
} else {
|
||||
mp_raise_bleio_BluetoothError(translate("Unknown hci_result_t: %d"), result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
81
devices/ble_hci/common-hal/_bleio/hci.h
Normal file
81
devices/ble_hci/common-hal/_bleio/hci.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
||||
#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common-hal/_bleio/hci_include/hci.h"
|
||||
#include "common-hal/_bleio/hci_include/hci_err.h"
|
||||
|
||||
// Incomplete forward declaration to get around mutually-dependent include files.
|
||||
typedef struct _bleio_adapter_obj_t bleio_adapter_obj_t;
|
||||
|
||||
// An hci_result_t is one of the HCI_x values below,
|
||||
// or it is > 0 and is an HCI command status value (see hci_include/hci_err.h)
|
||||
typedef int hci_result_t;
|
||||
#define HCI_OK (0)
|
||||
#define HCI_RESPONSE_TIMEOUT (-1)
|
||||
#define HCI_WRITE_TIMEOUT (-2)
|
||||
#define HCI_READ_ERROR (-3)
|
||||
#define HCI_WRITE_ERROR (-4)
|
||||
#define HCI_ATT_ERROR (-5)
|
||||
#define HCI_PACKET_SIZE_ERROR (-6)
|
||||
|
||||
extern void bleio_hci_reset(void);
|
||||
|
||||
void hci_check_error(hci_result_t result);
|
||||
|
||||
hci_result_t hci_disconnect(uint16_t handle);
|
||||
|
||||
hci_result_t hci_le_cancel_conn(void);
|
||||
hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout);
|
||||
hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len);
|
||||
|
||||
hci_result_t hci_le_read_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num);
|
||||
hci_result_t hci_le_read_maximum_advertising_data_length(uint16_t *max_adv_data_len);
|
||||
hci_result_t hci_le_read_local_supported_features(uint8_t features[8]);
|
||||
|
||||
hci_result_t hci_le_set_advertising_data(uint8_t length, uint8_t data[]);
|
||||
hci_result_t hci_le_set_advertising_enable(uint8_t enable);
|
||||
hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy);
|
||||
|
||||
hci_result_t hci_le_set_extended_advertising_data(uint8_t handle, uint8_t op, uint8_t frag_pref, uint8_t len, uint8_t data[]);
|
||||
hci_result_t hci_le_set_extended_advertising_enable(uint8_t enable, uint8_t set_num, uint8_t handle[], uint16_t duration[], uint8_t max_ext_adv_evts[]);
|
||||
hci_result_t hci_le_set_extended_advertising_parameters(uint8_t handle, uint16_t props, uint32_t prim_min_interval, uint32_t prim_max_interval, uint8_t prim_channel_map, uint8_t own_addr_type, bt_addr_le_t *peer_addr, uint8_t filter_policy, int8_t tx_power, uint8_t prim_adv_phy, uint8_t sec_adv_max_skip, uint8_t sec_adv_phy, uint8_t sid, uint8_t scan_req_notify_enable);
|
||||
|
||||
hci_result_t hci_le_set_random_address(uint8_t addr[6]);
|
||||
hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup);
|
||||
hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy);
|
||||
hci_result_t hci_le_set_scan_response_data(uint8_t length, uint8_t data[]);
|
||||
|
||||
hci_result_t hci_poll_for_incoming_pkt(void);
|
||||
|
||||
hci_result_t hci_read_bd_addr(bt_addr_t *addr);
|
||||
hci_result_t hci_read_buffer_size(uint16_t *acl_max_len, uint8_t *sco_max_len, uint16_t *acl_max_num, uint16_t *sco_max_num);
|
||||
hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion);
|
||||
hci_result_t hci_read_rssi(uint16_t handle, int *rssi);
|
||||
|
||||
hci_result_t hci_reset(void);
|
||||
|
||||
hci_result_t hci_send_acl_pkt(uint16_t handle, uint8_t cid, uint16_t data_len, uint8_t *data);
|
||||
hci_result_t hci_set_event_mask(uint64_t event_mask);
|
||||
|
||||
#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
335
devices/ble_hci/common-hal/_bleio/hci_debug.c
Normal file
335
devices/ble_hci/common-hal/_bleio/hci_debug.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This file is #include'd in hci.c when HCI_DEBUG is non-zero.
|
||||
|
||||
STATIC const char* att_opcode_name(uint16_t opcode) {
|
||||
switch (opcode) {
|
||||
case BT_ATT_OP_ERROR_RSP: return "ERROR_RSP";
|
||||
case BT_ATT_OP_MTU_REQ: return "MTU_REQ";
|
||||
case BT_ATT_OP_MTU_RSP: return "MTU_RSP";
|
||||
case BT_ATT_OP_FIND_INFO_REQ: return "FIND_INFO_REQ";
|
||||
case BT_ATT_OP_FIND_INFO_RSP: return "FIND_INFO_RSP";
|
||||
case BT_ATT_OP_FIND_TYPE_REQ: return "FIND_TYPE_REQ";
|
||||
case BT_ATT_OP_FIND_TYPE_RSP: return "FIND_TYPE_RSP";
|
||||
case BT_ATT_OP_READ_TYPE_REQ: return "READ_TYPE_REQ";
|
||||
case BT_ATT_OP_READ_TYPE_RSP: return "READ_TYPE_RSP";
|
||||
case BT_ATT_OP_READ_REQ: return "READ_REQ";
|
||||
case BT_ATT_OP_READ_RSP: return "READ_RSP";
|
||||
case BT_ATT_OP_READ_BLOB_REQ: return "READ_BLOB_REQ";
|
||||
case BT_ATT_OP_READ_BLOB_RSP: return "READ_BLOB_RSP";
|
||||
case BT_ATT_OP_READ_MULT_REQ: return "READ_MULT_REQ";
|
||||
case BT_ATT_OP_READ_MULT_RSP: return "READ_MULT_RSP";
|
||||
case BT_ATT_OP_READ_GROUP_REQ: return "READ_GROUP_REQ";
|
||||
case BT_ATT_OP_READ_GROUP_RSP: return "READ_GROUP_RSP";
|
||||
case BT_ATT_OP_WRITE_REQ: return "WRITE_REQ";
|
||||
case BT_ATT_OP_WRITE_RSP: return "WRITE_RSP";
|
||||
case BT_ATT_OP_PREPARE_WRITE_REQ: return "PREPARE_WRITE_REQ";
|
||||
case BT_ATT_OP_PREPARE_WRITE_RSP: return "PREPARE_WRITE_RSP";
|
||||
case BT_ATT_OP_EXEC_WRITE_REQ: return "EXEC_WRITE_REQ";
|
||||
case BT_ATT_OP_EXEC_WRITE_RSP: return "EXEC_WRITE_RSP";
|
||||
case BT_ATT_OP_NOTIFY: return "NOTIFY";
|
||||
case BT_ATT_OP_INDICATE: return "INDICATE";
|
||||
case BT_ATT_OP_CONFIRM: return "CONFIRM";
|
||||
case BT_ATT_OP_READ_MULT_VL_REQ: return "READ_MULT_VL_REQ";
|
||||
case BT_ATT_OP_READ_MULT_VL_RSP: return "READ_MULT_VL_RSP";
|
||||
case BT_ATT_OP_NOTIFY_MULT: return "NOTIFY_MULT";
|
||||
case BT_ATT_OP_WRITE_CMD: return "WRITE_CMD";
|
||||
case BT_ATT_OP_SIGNED_WRITE_CMD: return "SIGNED_WRITE_CMD";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const char* hci_evt_name(uint8_t evt) {
|
||||
switch (evt) {
|
||||
case BT_HCI_EVT_UNKNOWN: return "UNKNOWN";
|
||||
case BT_HCI_EVT_VENDOR: return "VENDOR";
|
||||
case BT_HCI_EVT_INQUIRY_COMPLETE: return "INQUIRY_COMPLETE";
|
||||
case BT_HCI_EVT_CONN_COMPLETE: return "CONN_COMPLETE";
|
||||
case BT_HCI_EVT_CONN_REQUEST: return "CONN_REQUEST";
|
||||
case BT_HCI_EVT_DISCONN_COMPLETE: return "DISCONN_COMPLETE";
|
||||
case BT_HCI_EVT_AUTH_COMPLETE: return "AUTH_COMPLETE";
|
||||
case BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE: return "REMOTE_NAME_REQ_COMPLETE";
|
||||
case BT_HCI_EVT_ENCRYPT_CHANGE: return "ENCRYPT_CHANGE";
|
||||
case BT_HCI_EVT_REMOTE_FEATURES: return "REMOTE_FEATURES";
|
||||
case BT_HCI_EVT_REMOTE_VERSION_INFO: return "REMOTE_VERSION_INFO";
|
||||
case BT_HCI_EVT_CMD_COMPLETE: return "CMD_COMPLETE";
|
||||
case BT_HCI_EVT_CMD_STATUS: return "CMD_STATUS";
|
||||
case BT_HCI_EVT_ROLE_CHANGE: return "ROLE_CHANGE";
|
||||
case BT_HCI_EVT_NUM_COMPLETED_PACKETS: return "NUM_COMPLETED_PACKETS";
|
||||
case BT_HCI_EVT_PIN_CODE_REQ: return "PIN_CODE_REQ";
|
||||
case BT_HCI_EVT_LINK_KEY_REQ: return "LINK_KEY_REQ";
|
||||
case BT_HCI_EVT_LINK_KEY_NOTIFY: return "LINK_KEY_NOTIFY";
|
||||
case BT_HCI_EVT_DATA_BUF_OVERFLOW: return "DATA_BUF_OVERFLOW";
|
||||
case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: return "INQUIRY_RESULT_WITH_RSSI";
|
||||
case BT_HCI_EVT_REMOTE_EXT_FEATURES: return "REMOTE_EXT_FEATURES";
|
||||
case BT_HCI_EVT_SYNC_CONN_COMPLETE: return "SYNC_CONN_COMPLETE";
|
||||
case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: return "EXTENDED_INQUIRY_RESULT";
|
||||
case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE: return "ENCRYPT_KEY_REFRESH_COMPLETE";
|
||||
case BT_HCI_EVT_IO_CAPA_REQ: return "IO_CAPA_REQ";
|
||||
case BT_HCI_EVT_IO_CAPA_RESP: return "IO_CAPA_RESP";
|
||||
case BT_HCI_EVT_USER_CONFIRM_REQ: return "USER_CONFIRM_REQ";
|
||||
case BT_HCI_EVT_USER_PASSKEY_REQ: return "USER_PASSKEY_REQ";
|
||||
case BT_HCI_EVT_SSP_COMPLETE: return "SSP_COMPLETE";
|
||||
case BT_HCI_EVT_USER_PASSKEY_NOTIFY: return "USER_PASSKEY_NOTIFY";
|
||||
case BT_HCI_EVT_LE_META_EVENT: return "LE_META_EVENT";
|
||||
case BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP: return "AUTH_PAYLOAD_TIMEOUT_EXP";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const char* hci_evt_le_name(uint8_t evt_le) {
|
||||
switch (evt_le) {
|
||||
case BT_HCI_EVT_LE_CONN_COMPLETE: return "LE_CONN_COMPLETE";
|
||||
case BT_HCI_EVT_LE_ADVERTISING_REPORT: return "LE_ADVERTISING_REPORT";
|
||||
case BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE: return "LE_CONN_UPDATE_COMPLETE";
|
||||
case BT_HCI_EVT_LE_LTK_REQUEST: return "LE_LTK_REQUEST";
|
||||
case BT_HCI_EVT_LE_CONN_PARAM_REQ: return "LE_CONN_PARAM_REQ";
|
||||
case BT_HCI_EVT_LE_DATA_LEN_CHANGE: return "LE_DATA_LEN_CHANGE";
|
||||
case BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE: return "LE_P256_PUBLIC_KEY_COMPLETE";
|
||||
case BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE: return "LE_GENERATE_DHKEY_COMPLETE";
|
||||
case BT_HCI_EVT_LE_ENH_CONN_COMPLETE: return "LE_ENH_CONN_COMPLETE";
|
||||
case BT_HCI_EVT_LE_DIRECT_ADV_REPORT: return "LE_DIRECT_ADV_REPORT";
|
||||
case BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE: return "LE_PHY_UPDATE_COMPLETE";
|
||||
case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: return "LE_EXT_ADVERTISING_REPORT";
|
||||
case BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED: return "LE_PER_ADV_SYNC_ESTABLISHED";
|
||||
case BT_HCI_EVT_LE_PER_ADVERTISING_REPORT: return "LE_PER_ADVERTISING_REPORT";
|
||||
case BT_HCI_EVT_LE_PER_ADV_SYNC_LOST: return "LE_PER_ADV_SYNC_LOST";
|
||||
case BT_HCI_EVT_LE_SCAN_TIMEOUT: return "LE_SCAN_TIMEOUT";
|
||||
case BT_HCI_EVT_LE_ADV_SET_TERMINATED: return "LE_ADV_SET_TERMINATED";
|
||||
case BT_HCI_EVT_LE_SCAN_REQ_RECEIVED: return "LE_SCAN_REQ_RECEIVED";
|
||||
case BT_HCI_EVT_LE_CHAN_SEL_ALGO: return "LE_CHAN_SEL_ALGO";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const char* hci_opcode_name(uint16_t opcode) {
|
||||
switch (opcode) {
|
||||
case BT_OP_NOP: return "NOP";
|
||||
case BT_HCI_OP_INQUIRY: return "INQUIRY";
|
||||
case BT_HCI_OP_INQUIRY_CANCEL: return "INQUIRY_CANCEL";
|
||||
case BT_HCI_OP_CONNECT: return "CONNECT";
|
||||
case BT_HCI_OP_DISCONNECT: return "DISCONNECT";
|
||||
case BT_HCI_OP_CONNECT_CANCEL: return "CONNECT_CANCEL";
|
||||
case BT_HCI_OP_ACCEPT_CONN_REQ: return "ACCEPT_CONN_REQ";
|
||||
case BT_HCI_OP_SETUP_SYNC_CONN: return "SETUP_SYNC_CONN";
|
||||
case BT_HCI_OP_ACCEPT_SYNC_CONN_REQ: return "ACCEPT_SYNC_CONN_REQ";
|
||||
case BT_HCI_OP_REJECT_CONN_REQ: return "REJECT_CONN_REQ";
|
||||
case BT_HCI_OP_LINK_KEY_REPLY: return "LINK_KEY_REPLY";
|
||||
case BT_HCI_OP_LINK_KEY_NEG_REPLY: return "LINK_KEY_NEG_REPLY";
|
||||
case BT_HCI_OP_PIN_CODE_REPLY: return "PIN_CODE_REPLY";
|
||||
case BT_HCI_OP_PIN_CODE_NEG_REPLY: return "PIN_CODE_NEG_REPLY";
|
||||
case BT_HCI_OP_AUTH_REQUESTED: return "AUTH_REQUESTED";
|
||||
case BT_HCI_OP_SET_CONN_ENCRYPT: return "SET_CONN_ENCRYPT";
|
||||
case BT_HCI_OP_REMOTE_NAME_REQUEST: return "REMOTE_NAME_REQUEST";
|
||||
case BT_HCI_OP_REMOTE_NAME_CANCEL: return "REMOTE_NAME_CANCEL";
|
||||
case BT_HCI_OP_READ_REMOTE_FEATURES: return "READ_REMOTE_FEATURES";
|
||||
case BT_HCI_OP_READ_REMOTE_EXT_FEATURES: return "READ_REMOTE_EXT_FEATURES";
|
||||
case BT_HCI_OP_READ_REMOTE_VERSION_INFO: return "READ_REMOTE_VERSION_INFO";
|
||||
case BT_HCI_OP_IO_CAPABILITY_REPLY: return "IO_CAPABILITY_REPLY";
|
||||
case BT_HCI_OP_USER_CONFIRM_REPLY: return "USER_CONFIRM_REPLY";
|
||||
case BT_HCI_OP_USER_CONFIRM_NEG_REPLY: return "USER_CONFIRM_NEG_REPLY";
|
||||
case BT_HCI_OP_USER_PASSKEY_REPLY: return "USER_PASSKEY_REPLY";
|
||||
case BT_HCI_OP_USER_PASSKEY_NEG_REPLY: return "USER_PASSKEY_NEG_REPLY";
|
||||
case BT_HCI_OP_IO_CAPABILITY_NEG_REPLY: return "IO_CAPABILITY_NEG_REPLY";
|
||||
case BT_HCI_OP_SET_EVENT_MASK: return "SET_EVENT_MASK";
|
||||
case BT_HCI_OP_RESET: return "RESET";
|
||||
case BT_HCI_OP_WRITE_LOCAL_NAME: return "WRITE_LOCAL_NAME";
|
||||
case BT_HCI_OP_WRITE_PAGE_TIMEOUT: return "WRITE_PAGE_TIMEOUT";
|
||||
case BT_HCI_OP_WRITE_SCAN_ENABLE: return "WRITE_SCAN_ENABLE";
|
||||
case BT_HCI_OP_READ_TX_POWER_LEVEL: return "READ_TX_POWER_LEVEL";
|
||||
case BT_HCI_OP_SET_CTL_TO_HOST_FLOW: return "SET_CTL_TO_HOST_FLOW";
|
||||
case BT_HCI_OP_HOST_BUFFER_SIZE: return "HOST_BUFFER_SIZE";
|
||||
case BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS: return "HOST_NUM_COMPLETED_PACKETS";
|
||||
case BT_HCI_OP_WRITE_INQUIRY_MODE: return "WRITE_INQUIRY_MODE";
|
||||
case BT_HCI_OP_WRITE_SSP_MODE: return "WRITE_SSP_MODE";
|
||||
case BT_HCI_OP_SET_EVENT_MASK_PAGE_2: return "SET_EVENT_MASK_PAGE_2";
|
||||
case BT_HCI_OP_LE_WRITE_LE_HOST_SUPP: return "LE_WRITE_LE_HOST_SUPP";
|
||||
case BT_HCI_OP_WRITE_SC_HOST_SUPP: return "WRITE_SC_HOST_SUPP";
|
||||
case BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT: return "READ_AUTH_PAYLOAD_TIMEOUT";
|
||||
case BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT: return "WRITE_AUTH_PAYLOAD_TIMEOUT";
|
||||
case BT_HCI_OP_READ_LOCAL_VERSION_INFO: return "READ_LOCAL_VERSION_INFO";
|
||||
case BT_HCI_OP_READ_SUPPORTED_COMMANDS: return "READ_SUPPORTED_COMMANDS";
|
||||
case BT_HCI_OP_READ_LOCAL_EXT_FEATURES: return "READ_LOCAL_EXT_FEATURES";
|
||||
case BT_HCI_OP_READ_LOCAL_FEATURES: return "READ_LOCAL_FEATURES";
|
||||
case BT_HCI_OP_READ_BUFFER_SIZE: return "READ_BUFFER_SIZE";
|
||||
case BT_HCI_OP_READ_BD_ADDR: return "READ_BD_ADDR";
|
||||
case BT_HCI_OP_READ_RSSI: return "READ_RSSI";
|
||||
case BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE: return "READ_ENCRYPTION_KEY_SIZE";
|
||||
case BT_HCI_OP_LE_SET_EVENT_MASK: return "LE_SET_EVENT_MASK";
|
||||
case BT_HCI_OP_LE_READ_BUFFER_SIZE: return "LE_READ_BUFFER_SIZE";
|
||||
case BT_HCI_OP_LE_READ_LOCAL_FEATURES: return "LE_READ_LOCAL_FEATURES";
|
||||
case BT_HCI_OP_LE_SET_RANDOM_ADDRESS: return "LE_SET_RANDOM_ADDRESS";
|
||||
case BT_HCI_OP_LE_SET_ADV_PARAM: return "LE_SET_ADV_PARAM";
|
||||
case BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER: return "LE_READ_ADV_CHAN_TX_POWER";
|
||||
case BT_HCI_OP_LE_SET_ADV_DATA: return "LE_SET_ADV_DATA";
|
||||
case BT_HCI_OP_LE_SET_SCAN_RSP_DATA: return "LE_SET_SCAN_RSP_DATA";
|
||||
case BT_HCI_OP_LE_SET_ADV_ENABLE: return "LE_SET_ADV_ENABLE";
|
||||
case BT_HCI_OP_LE_SET_SCAN_PARAM: return "LE_SET_SCAN_PARAM";
|
||||
case BT_HCI_OP_LE_SET_SCAN_ENABLE: return "LE_SET_SCAN_ENABLE";
|
||||
case BT_HCI_OP_LE_CREATE_CONN: return "LE_CREATE_CONN";
|
||||
case BT_HCI_OP_LE_CREATE_CONN_CANCEL: return "LE_CREATE_CONN_CANCEL";
|
||||
case BT_HCI_OP_LE_READ_WL_SIZE: return "LE_READ_WL_SIZE";
|
||||
case BT_HCI_OP_LE_CLEAR_WL: return "LE_CLEAR_WL";
|
||||
case BT_HCI_OP_LE_ADD_DEV_TO_WL: return "LE_ADD_DEV_TO_WL";
|
||||
case BT_HCI_OP_LE_REM_DEV_FROM_WL: return "LE_REM_DEV_FROM_WL";
|
||||
case BT_HCI_OP_LE_CONN_UPDATE: return "LE_CONN_UPDATE";
|
||||
case BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF: return "LE_SET_HOST_CHAN_CLASSIF";
|
||||
case BT_HCI_OP_LE_READ_CHAN_MAP: return "LE_READ_CHAN_MAP";
|
||||
case BT_HCI_OP_LE_READ_REMOTE_FEATURES: return "LE_READ_REMOTE_FEATURES";
|
||||
case BT_HCI_OP_LE_ENCRYPT: return "LE_ENCRYPT";
|
||||
case BT_HCI_OP_LE_RAND: return "LE_RAND";
|
||||
case BT_HCI_OP_LE_START_ENCRYPTION: return "LE_START_ENCRYPTION";
|
||||
case BT_HCI_OP_LE_LTK_REQ_REPLY: return "LE_LTK_REQ_REPLY";
|
||||
case BT_HCI_OP_LE_LTK_REQ_NEG_REPLY: return "LE_LTK_REQ_NEG_REPLY";
|
||||
case BT_HCI_OP_LE_READ_SUPP_STATES: return "LE_READ_SUPP_STATES";
|
||||
case BT_HCI_OP_LE_RX_TEST: return "LE_RX_TEST";
|
||||
case BT_HCI_OP_LE_TX_TEST: return "LE_TX_TEST";
|
||||
case BT_HCI_OP_LE_TEST_END: return "LE_TEST_END";
|
||||
case BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY: return "LE_CONN_PARAM_REQ_REPLY";
|
||||
case BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY: return "LE_CONN_PARAM_REQ_NEG_REPLY";
|
||||
case BT_HCI_OP_LE_SET_DATA_LEN: return "LE_SET_DATA_LEN";
|
||||
case BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN: return "LE_READ_DEFAULT_DATA_LEN";
|
||||
case BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN: return "LE_WRITE_DEFAULT_DATA_LEN";
|
||||
case BT_HCI_OP_LE_P256_PUBLIC_KEY: return "LE_P256_PUBLIC_KEY";
|
||||
case BT_HCI_OP_LE_GENERATE_DHKEY: return "LE_GENERATE_DHKEY";
|
||||
case BT_HCI_OP_LE_ADD_DEV_TO_RL: return "LE_ADD_DEV_TO_RL";
|
||||
case BT_HCI_OP_LE_REM_DEV_FROM_RL: return "LE_REM_DEV_FROM_RL";
|
||||
case BT_HCI_OP_LE_CLEAR_RL: return "LE_CLEAR_RL";
|
||||
case BT_HCI_OP_LE_READ_RL_SIZE: return "LE_READ_RL_SIZE";
|
||||
case BT_HCI_OP_LE_READ_PEER_RPA: return "LE_READ_PEER_RPA";
|
||||
case BT_HCI_OP_LE_READ_LOCAL_RPA: return "LE_READ_LOCAL_RPA";
|
||||
case BT_HCI_OP_LE_SET_ADDR_RES_ENABLE: return "LE_SET_ADDR_RES_ENABLE";
|
||||
case BT_HCI_OP_LE_SET_RPA_TIMEOUT: return "LE_SET_RPA_TIMEOUT";
|
||||
case BT_HCI_OP_LE_READ_MAX_DATA_LEN: return "LE_READ_MAX_DATA_LEN";
|
||||
case BT_HCI_OP_LE_READ_PHY: return "LE_READ_PHY";
|
||||
case BT_HCI_OP_LE_SET_DEFAULT_PHY: return "LE_SET_DEFAULT_PHY";
|
||||
case BT_HCI_OP_LE_SET_PHY: return "LE_SET_PHY";
|
||||
case BT_HCI_OP_LE_ENH_RX_TEST: return "LE_ENH_RX_TEST";
|
||||
case BT_HCI_OP_LE_ENH_TX_TEST: return "LE_ENH_TX_TEST";
|
||||
case BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR: return "LE_SET_ADV_SET_RANDOM_ADDR";
|
||||
case BT_HCI_OP_LE_SET_EXT_ADV_PARAM: return "LE_SET_EXT_ADV_PARAM";
|
||||
case BT_HCI_OP_LE_SET_EXT_ADV_DATA: return "LE_SET_EXT_ADV_DATA";
|
||||
case BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA: return "LE_SET_EXT_SCAN_RSP_DATA";
|
||||
case BT_HCI_OP_LE_SET_EXT_ADV_ENABLE: return "LE_SET_EXT_ADV_ENABLE";
|
||||
case BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN: return "LE_READ_MAX_ADV_DATA_LEN";
|
||||
case BT_HCI_OP_LE_READ_NUM_ADV_SETS: return "LE_READ_NUM_ADV_SETS";
|
||||
case BT_HCI_OP_LE_REMOVE_ADV_SET: return "LE_REMOVE_ADV_SET";
|
||||
case BT_HCI_OP_CLEAR_ADV_SETS: return "CLEAR_ADV_SETS";
|
||||
case BT_HCI_OP_LE_SET_PER_ADV_PARAM: return "LE_SET_PER_ADV_PARAM";
|
||||
case BT_HCI_OP_LE_SET_PER_ADV_DATA: return "LE_SET_PER_ADV_DATA";
|
||||
case BT_HCI_OP_LE_SET_PER_ADV_ENABLE: return "LE_SET_PER_ADV_ENABLE";
|
||||
case BT_HCI_OP_LE_SET_EXT_SCAN_PARAM: return "LE_SET_EXT_SCAN_PARAM";
|
||||
case BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE: return "LE_SET_EXT_SCAN_ENABLE";
|
||||
case BT_HCI_OP_LE_EXT_CREATE_CONN: return "LE_EXT_CREATE_CONN";
|
||||
case BT_HCI_OP_LE_PER_ADV_CREATE_SYNC: return "LE_PER_ADV_CREATE_SYNC";
|
||||
case BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL: return "LE_PER_ADV_CREATE_SYNC_CANCEL";
|
||||
case BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC: return "LE_PER_ADV_TERMINATE_SYNC";
|
||||
case BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST: return "LE_ADD_DEV_TO_PER_ADV_LIST";
|
||||
case BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST: return "LE_REM_DEV_FROM_PER_ADV_LIST";
|
||||
case BT_HCI_OP_LE_CLEAR_PER_ADV_LIST: return "LE_CLEAR_PER_ADV_LIST";
|
||||
case BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE: return "LE_READ_PER_ADV_LIST_SIZE";
|
||||
case BT_HCI_OP_LE_READ_TX_POWER: return "LE_READ_TX_POWER";
|
||||
case BT_HCI_OP_LE_READ_RF_PATH_COMP: return "LE_READ_RF_PATH_COMP";
|
||||
case BT_HCI_OP_LE_WRITE_RF_PATH_COMP: return "LE_WRITE_RF_PATH_COMP";
|
||||
case BT_HCI_OP_LE_SET_PRIVACY_MODE: return "LE_SET_PRIVACY_MODE";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC void dump_cmd_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
h4_hci_cmd_pkt_t *pkt = (h4_hci_cmd_pkt_t *) pkt_data;
|
||||
mp_printf(&mp_plat_print,
|
||||
"%s HCI COMMAND (%x) op: %s (%04x), len: %d, data: ",
|
||||
tx ? "TX->" : "RX<-",
|
||||
pkt->pkt_type,
|
||||
hci_opcode_name(pkt->opcode), pkt->opcode, pkt->param_len);
|
||||
for (size_t i = 0; i < pkt->param_len; i++) {
|
||||
mp_printf(&mp_plat_print, "%02x ", pkt->params[i]);
|
||||
}
|
||||
if (pkt_len != sizeof(h4_hci_cmd_pkt_t) + pkt->param_len) {
|
||||
mp_printf(&mp_plat_print, " LENGTH MISMATCH, pkt_len: %d", pkt_len);
|
||||
}
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
||||
|
||||
STATIC void dump_acl_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
h4_hci_acl_pkt_t *pkt = (h4_hci_acl_pkt_t *) pkt_data;
|
||||
acl_data_t *acl = (acl_data_t *) pkt->data;
|
||||
|
||||
mp_printf(&mp_plat_print,
|
||||
"%s HCI ACLDATA (%x) ",
|
||||
tx ? "TX->" : "RX<-", pkt->pkt_type);
|
||||
|
||||
if (pkt->pb != ACL_DATA_PB_MIDDLE && acl->cid == BT_L2CAP_CID_ATT) {
|
||||
// This is the start of a fragmented acl_data packet or is a full packet,
|
||||
// and is an ATT protocol packet.
|
||||
mp_printf(&mp_plat_print, "att: %s (%02x), ", att_opcode_name(acl->acl_data[0]), acl->acl_data[0]);
|
||||
}
|
||||
|
||||
mp_printf(&mp_plat_print,
|
||||
"handle: %04x, pb: %d, bc: %d, data_len: %d, ",
|
||||
pkt->handle, pkt->pb, pkt->bc, pkt->data_len);
|
||||
|
||||
if (pkt->pb != ACL_DATA_PB_MIDDLE) {
|
||||
// This is the start of a fragmented acl_data packet or is a full packet.
|
||||
mp_printf(&mp_plat_print,
|
||||
"acl data_len: %d, cid: %04x, data: ",
|
||||
acl->acl_data_len, acl->cid);
|
||||
for (size_t i = 0; i < acl->acl_data_len; i++) {
|
||||
mp_printf(&mp_plat_print, "%02x ", acl->acl_data[i]);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < pkt->data_len; i++) {
|
||||
mp_printf(&mp_plat_print, "more data: %02x ", pkt->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (pkt_len != sizeof(h4_hci_acl_pkt_t) + pkt->data_len) {
|
||||
mp_printf(&mp_plat_print, " LENGTH MISMATCH, pkt_len: %d", pkt_len);
|
||||
}
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
||||
|
||||
STATIC void dump_evt_pkt(bool tx, uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
h4_hci_evt_pkt_t *pkt = (h4_hci_evt_pkt_t *) pkt_data;
|
||||
mp_printf(&mp_plat_print,
|
||||
"%s HCI EVENT (%x) evt: %s (%02x), param_len: %d, data: ",
|
||||
tx ? "TX->" : "RX<-",
|
||||
pkt->pkt_type,
|
||||
pkt->evt == BT_HCI_EVT_LE_META_EVENT
|
||||
? hci_evt_le_name(pkt->params[0])
|
||||
: hci_evt_name(pkt->evt),
|
||||
pkt->evt, pkt->param_len);
|
||||
for (size_t i = 0; i < pkt->param_len; i++) {
|
||||
mp_printf(&mp_plat_print, "%02x ", pkt->params[i]);
|
||||
}
|
||||
if (pkt_len != sizeof(h4_hci_evt_pkt_t) + pkt->param_len) {
|
||||
mp_printf(&mp_plat_print, " LENGTH MISMATCH, pkt_len: %d", pkt_len);
|
||||
}
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
2
devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt
Normal file
2
devices/ble_hci/common-hal/_bleio/hci_include/NOTE.txt
Normal file
@ -0,0 +1,2 @@
|
||||
The HCI-related include files here were copied from the Zephyr project, from this commit:
|
||||
https://github.com/zephyrproject-rtos/zephyr/tree/0a87f9359edf1ec1c169626df3e19c2b4a4e9646/include/bluetooth
|
101
devices/ble_hci/common-hal/_bleio/hci_include/addr.h
Normal file
101
devices/ble_hci/common-hal/_bleio/hci_include/addr.h
Normal file
@ -0,0 +1,101 @@
|
||||
// CircuitPython: Adapted from Zephyer include files.
|
||||
/** @file
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
* Copyright 2020 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
* @defgroup bt_addr Device Address
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define BT_ADDR_LE_PUBLIC 0x00
|
||||
#define BT_ADDR_LE_RANDOM 0x01
|
||||
#define BT_ADDR_LE_PUBLIC_ID 0x02
|
||||
#define BT_ADDR_LE_RANDOM_ID 0x03
|
||||
|
||||
/** Bluetooth Device Address */
|
||||
typedef struct {
|
||||
uint8_t val[6];
|
||||
} bt_addr_t;
|
||||
|
||||
/** Bluetooth LE Device Address */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
bt_addr_t a;
|
||||
} bt_addr_le_t;
|
||||
|
||||
#define BT_ADDR_ANY ((bt_addr_t[]) { { { 0, 0, 0, 0, 0, 0 } } })
|
||||
#define BT_ADDR_NONE ((bt_addr_t[]) { { \
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } })
|
||||
#define BT_ADDR_LE_ANY ((bt_addr_le_t[]) { { 0, { { 0, 0, 0, 0, 0, 0 } } } })
|
||||
#define BT_ADDR_LE_NONE ((bt_addr_le_t[]) { { 0, \
|
||||
{ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } })
|
||||
|
||||
static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
static inline void bt_addr_copy(bt_addr_t *dst, const bt_addr_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
#define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40)
|
||||
#define BT_ADDR_IS_NRPA(a) (((a)->val[5] & 0xc0) == 0x00)
|
||||
#define BT_ADDR_IS_STATIC(a) (((a)->val[5] & 0xc0) == 0xc0)
|
||||
|
||||
#define BT_ADDR_SET_RPA(a) ((a)->val[5] = (((a)->val[5] & 0x3f) | 0x40))
|
||||
#define BT_ADDR_SET_NRPA(a) ((a)->val[5] &= 0x3f)
|
||||
#define BT_ADDR_SET_STATIC(a) ((a)->val[5] |= 0xc0)
|
||||
|
||||
int bt_addr_le_create_nrpa(bt_addr_le_t *addr);
|
||||
int bt_addr_le_create_static(bt_addr_le_t *addr);
|
||||
|
||||
static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type != BT_ADDR_LE_RANDOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_RPA(&addr->a);
|
||||
}
|
||||
|
||||
static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type == BT_ADDR_LE_PUBLIC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_STATIC(&addr->a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ */
|
41
devices/ble_hci/common-hal/_bleio/hci_include/att.h
Normal file
41
devices/ble_hci/common-hal/_bleio/hci_include/att.h
Normal file
@ -0,0 +1,41 @@
|
||||
// CircuitPython: Adapted from Zephyr include file.
|
||||
/** @file
|
||||
* @brief Attribute Protocol handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_
|
||||
|
||||
/* Error codes for Error response PDU */
|
||||
#define BT_ATT_ERR_INVALID_HANDLE 0x01
|
||||
#define BT_ATT_ERR_READ_NOT_PERMITTED 0x02
|
||||
#define BT_ATT_ERR_WRITE_NOT_PERMITTED 0x03
|
||||
#define BT_ATT_ERR_INVALID_PDU 0x04
|
||||
#define BT_ATT_ERR_AUTHENTICATION 0x05
|
||||
#define BT_ATT_ERR_NOT_SUPPORTED 0x06
|
||||
#define BT_ATT_ERR_INVALID_OFFSET 0x07
|
||||
#define BT_ATT_ERR_AUTHORIZATION 0x08
|
||||
#define BT_ATT_ERR_PREPARE_QUEUE_FULL 0x09
|
||||
#define BT_ATT_ERR_ATTRIBUTE_NOT_FOUND 0x0a
|
||||
#define BT_ATT_ERR_ATTRIBUTE_NOT_LONG 0x0b
|
||||
#define BT_ATT_ERR_ENCRYPTION_KEY_SIZE 0x0c
|
||||
#define BT_ATT_ERR_INVALID_ATTRIBUTE_LEN 0x0d
|
||||
#define BT_ATT_ERR_UNLIKELY 0x0e
|
||||
#define BT_ATT_ERR_INSUFFICIENT_ENCRYPTION 0x0f
|
||||
#define BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE 0x10
|
||||
#define BT_ATT_ERR_INSUFFICIENT_RESOURCES 0x11
|
||||
#define BT_ATT_ERR_DB_OUT_OF_SYNC 0x12
|
||||
#define BT_ATT_ERR_VALUE_NOT_ALLOWED 0x13
|
||||
|
||||
/* Common Profile Error Codes (from CSS) */
|
||||
#define BT_ATT_ERR_WRITE_REQ_REJECTED 0xfc
|
||||
#define BT_ATT_ERR_CCC_IMPROPER_CONF 0xfd
|
||||
#define BT_ATT_ERR_PROCEDURE_IN_PROGRESS 0xfe
|
||||
#define BT_ATT_ERR_OUT_OF_RANGE 0xff
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ATT_H_ */
|
272
devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h
Normal file
272
devices/ble_hci/common-hal/_bleio/hci_include/att_internal.h
Normal file
@ -0,0 +1,272 @@
|
||||
// CircuitPython: Adapted from Zephyr include file.
|
||||
|
||||
/* att_internal.h - Attribute protocol handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
// for __packed
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define BT_EATT_PSM 0x27
|
||||
#define BT_ATT_DEFAULT_LE_MTU 23
|
||||
#define BT_ATT_TIMEOUT K_SECONDS(30)
|
||||
|
||||
//FIX #if BT_L2CAP_RX_MTU < CONFIG_BT_L2CAP_TX_MTU
|
||||
// #define BT_ATT_MTU BT_L2CAP_RX_MTU
|
||||
// #else
|
||||
// #define BT_ATT_MTU CONFIG_BT_L2CAP_TX_MTU
|
||||
// #endif
|
||||
|
||||
struct bt_att_hdr {
|
||||
uint8_t code;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_ERROR_RSP 0x01
|
||||
struct bt_att_error_rsp {
|
||||
uint8_t request;
|
||||
uint16_t handle;
|
||||
uint8_t error;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_MTU_REQ 0x02
|
||||
struct bt_att_exchange_mtu_req {
|
||||
uint16_t mtu;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_MTU_RSP 0x03
|
||||
struct bt_att_exchange_mtu_rsp {
|
||||
uint16_t mtu;
|
||||
} __packed;
|
||||
|
||||
/* Find Information Request */
|
||||
#define BT_ATT_OP_FIND_INFO_REQ 0x04
|
||||
struct bt_att_find_info_req {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
} __packed;
|
||||
|
||||
/* Format field values for BT_ATT_OP_FIND_INFO_RSP */
|
||||
#define BT_ATT_INFO_16 0x01
|
||||
#define BT_ATT_INFO_128 0x02
|
||||
|
||||
struct bt_att_info_16 {
|
||||
uint16_t handle;
|
||||
uint16_t uuid;
|
||||
} __packed;
|
||||
|
||||
struct bt_att_info_128 {
|
||||
uint16_t handle;
|
||||
uint8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
/* Find Information Response */
|
||||
#define BT_ATT_OP_FIND_INFO_RSP 0x05
|
||||
struct bt_att_find_info_rsp {
|
||||
uint8_t format;
|
||||
uint8_t info[];
|
||||
} __packed;
|
||||
|
||||
/* Find By Type Value Request */
|
||||
#define BT_ATT_OP_FIND_TYPE_REQ 0x06
|
||||
struct bt_att_find_type_req {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
uint16_t type;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_handle_group {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
} __packed;
|
||||
|
||||
/* Find By Type Value Response */
|
||||
#define BT_ATT_OP_FIND_TYPE_RSP 0x07
|
||||
struct bt_att_find_type_rsp {
|
||||
uint8_t _dummy[0];
|
||||
struct bt_att_handle_group list[];
|
||||
} __packed;
|
||||
|
||||
/* Read By Type Request */
|
||||
#define BT_ATT_OP_READ_TYPE_REQ 0x08
|
||||
struct bt_att_read_type_req {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
uint8_t uuid[];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_data {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Read By Type Response */
|
||||
#define BT_ATT_OP_READ_TYPE_RSP 0x09
|
||||
struct bt_att_read_type_rsp {
|
||||
uint8_t len;
|
||||
struct bt_att_data data[];
|
||||
} __packed;
|
||||
|
||||
/* Read Request */
|
||||
#define BT_ATT_OP_READ_REQ 0x0a
|
||||
struct bt_att_read_req {
|
||||
uint16_t handle;
|
||||
} __packed;
|
||||
|
||||
/* Read Response */
|
||||
#define BT_ATT_OP_READ_RSP 0x0b
|
||||
struct bt_att_read_rsp {
|
||||
uint8_t _dummy[0];
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Read Blob Request */
|
||||
#define BT_ATT_OP_READ_BLOB_REQ 0x0c
|
||||
struct bt_att_read_blob_req {
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
} __packed;
|
||||
|
||||
/* Read Blob Response */
|
||||
#define BT_ATT_OP_READ_BLOB_RSP 0x0d
|
||||
struct bt_att_read_blob_rsp {
|
||||
uint8_t _dummy[0];
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Read Multiple Request */
|
||||
#define BT_ATT_READ_MULT_MIN_LEN_REQ 0x04
|
||||
|
||||
#define BT_ATT_OP_READ_MULT_REQ 0x0e
|
||||
struct bt_att_read_mult_req {
|
||||
uint8_t _dummy[0];
|
||||
uint16_t handles[];
|
||||
} __packed;
|
||||
|
||||
/* Read Multiple Respose */
|
||||
#define BT_ATT_OP_READ_MULT_RSP 0x0f
|
||||
struct bt_att_read_mult_rsp {
|
||||
uint8_t _dummy[0];
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Read by Group Type Request */
|
||||
#define BT_ATT_OP_READ_GROUP_REQ 0x10
|
||||
struct bt_att_read_group_req {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
uint8_t uuid[];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_group_data {
|
||||
uint16_t start_handle;
|
||||
uint16_t end_handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Read by Group Type Response */
|
||||
#define BT_ATT_OP_READ_GROUP_RSP 0x11
|
||||
struct bt_att_read_group_rsp {
|
||||
uint8_t len;
|
||||
struct bt_att_group_data data[];
|
||||
} __packed;
|
||||
|
||||
/* Write Request */
|
||||
#define BT_ATT_OP_WRITE_REQ 0x12
|
||||
struct bt_att_write_req {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Write Response */
|
||||
#define BT_ATT_OP_WRITE_RSP 0x13
|
||||
|
||||
/* Prepare Write Request */
|
||||
#define BT_ATT_OP_PREPARE_WRITE_REQ 0x16
|
||||
struct bt_att_prepare_write_req {
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Prepare Write Respond */
|
||||
#define BT_ATT_OP_PREPARE_WRITE_RSP 0x17
|
||||
struct bt_att_prepare_write_rsp {
|
||||
uint16_t handle;
|
||||
uint16_t offset;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Execute Write Request */
|
||||
#define BT_ATT_FLAG_CANCEL 0x00
|
||||
#define BT_ATT_FLAG_EXEC 0x01
|
||||
|
||||
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
|
||||
struct bt_att_exec_write_req {
|
||||
uint8_t flags;
|
||||
} __packed;
|
||||
|
||||
/* Execute Write Response */
|
||||
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
|
||||
|
||||
/* Handle Value Notification */
|
||||
#define BT_ATT_OP_NOTIFY 0x1b
|
||||
struct bt_att_notify {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Handle Value Indication */
|
||||
#define BT_ATT_OP_INDICATE 0x1d
|
||||
struct bt_att_indicate {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Handle Value Confirm */
|
||||
#define BT_ATT_OP_CONFIRM 0x1e
|
||||
|
||||
struct bt_att_signature {
|
||||
uint8_t value[12];
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_READ_MULT_VL_REQ 0x20
|
||||
struct bt_att_read_mult_vl_req {
|
||||
uint8_t _dummy[0];
|
||||
uint16_t handles[];
|
||||
} __packed;
|
||||
|
||||
/* Read Multiple Respose */
|
||||
#define BT_ATT_OP_READ_MULT_VL_RSP 0x21
|
||||
struct bt_att_read_mult_vl_rsp {
|
||||
uint16_t len;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Handle Multiple Value Notification */
|
||||
#define BT_ATT_OP_NOTIFY_MULT 0x23
|
||||
struct bt_att_notify_mult {
|
||||
uint16_t handle;
|
||||
uint16_t len;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Write Command */
|
||||
#define BT_ATT_OP_WRITE_CMD 0x52
|
||||
struct bt_att_write_cmd {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
||||
|
||||
/* Signed Write Command */
|
||||
#define BT_ATT_OP_SIGNED_WRITE_CMD 0xd2
|
||||
struct bt_att_signed_write_cmd {
|
||||
uint16_t handle;
|
||||
uint8_t value[];
|
||||
} __packed;
|
1772
devices/ble_hci/common-hal/_bleio/hci_include/hci.h
Normal file
1772
devices/ble_hci/common-hal/_bleio/hci_include/hci.h
Normal file
File diff suppressed because it is too large
Load Diff
92
devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h
Normal file
92
devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h
Normal file
@ -0,0 +1,92 @@
|
||||
/** @file
|
||||
* @brief Bluetooth Host Control Interface status codes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */
|
||||
#define BT_HCI_ERR_SUCCESS 0x00
|
||||
#define BT_HCI_ERR_UNKNOWN_CMD 0x01
|
||||
#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02
|
||||
#define BT_HCI_ERR_HW_FAILURE 0x03
|
||||
#define BT_HCI_ERR_PAGE_TIMEOUT 0x04
|
||||
#define BT_HCI_ERR_AUTH_FAIL 0x05
|
||||
#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06
|
||||
#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07
|
||||
#define BT_HCI_ERR_CONN_TIMEOUT 0x08
|
||||
#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09
|
||||
#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a
|
||||
#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b
|
||||
#define BT_HCI_ERR_CMD_DISALLOWED 0x0c
|
||||
#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d
|
||||
#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e
|
||||
#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f
|
||||
#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10
|
||||
#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11
|
||||
#define BT_HCI_ERR_INVALID_PARAM 0x12
|
||||
#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13
|
||||
#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14
|
||||
#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15
|
||||
#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16
|
||||
#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17
|
||||
#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18
|
||||
#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19
|
||||
#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a
|
||||
#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b
|
||||
#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c
|
||||
#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d
|
||||
#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e
|
||||
#define BT_HCI_ERR_UNSPECIFIED 0x1f
|
||||
#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20
|
||||
#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
|
||||
#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22
|
||||
#define BT_HCI_ERR_LL_PROC_COLLISION 0x23
|
||||
#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24
|
||||
#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25
|
||||
#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26
|
||||
#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27
|
||||
#define BT_HCI_ERR_INSTANT_PASSED 0x28
|
||||
#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29
|
||||
#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a
|
||||
#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c
|
||||
#define BT_HCI_ERR_QOS_REJECTED 0x2d
|
||||
#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e
|
||||
#define BT_HCI_ERR_INSUFF_SECURITY 0x2f
|
||||
#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30
|
||||
#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32
|
||||
#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34
|
||||
#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35
|
||||
#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36
|
||||
#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37
|
||||
#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38
|
||||
#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39
|
||||
#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a
|
||||
#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b
|
||||
#define BT_HCI_ERR_ADV_TIMEOUT 0x3c
|
||||
#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d
|
||||
#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e
|
||||
#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f
|
||||
#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40
|
||||
#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41
|
||||
#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42
|
||||
#define BT_HCI_ERR_LIMIT_REACHED 0x43
|
||||
#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44
|
||||
#define BT_HCI_ERR_PACKET_TOO_LONG 0x45
|
||||
|
||||
#define BT_HCI_ERR_AUTHENTICATION_FAIL __DEPRECATED_MACRO BT_HCI_ERR_AUTH_FAIL
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ */
|
152
devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h
Normal file
152
devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h
Normal file
@ -0,0 +1,152 @@
|
||||
/** @file
|
||||
* @brief Bluetooth HCI RAW channel handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_
|
||||
|
||||
/**
|
||||
* @brief HCI RAW channel
|
||||
* @defgroup hci_raw HCI RAW channel
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
||||
#else
|
||||
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
||||
#endif /* CONFIG_BT_CTLR */
|
||||
|
||||
/** Data size needed for ACL buffers */
|
||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
||||
#define BT_HCI_ACL_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
||||
#else
|
||||
#define BT_HCI_ACL_COUNT 6
|
||||
#endif
|
||||
|
||||
#define BT_BUF_TX_SIZE MAX(BT_BUF_RX_SIZE, BT_BUF_ACL_SIZE)
|
||||
|
||||
/** @brief Send packet to the Bluetooth controller
|
||||
*
|
||||
* Send packet to the Bluetooth controller. Caller needs to
|
||||
* implement netbuf pool.
|
||||
*
|
||||
* @param buf netbuf packet to be send
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_send(struct net_buf *buf);
|
||||
|
||||
enum {
|
||||
/** Passthrough mode
|
||||
*
|
||||
* While in this mode the buffers are passed as is between the stack
|
||||
* and the driver.
|
||||
*/
|
||||
BT_HCI_RAW_MODE_PASSTHROUGH = 0x00,
|
||||
|
||||
/** H:4 mode
|
||||
*
|
||||
* While in this mode H:4 headers will added into the buffers
|
||||
* according to the buffer type when coming from the stack and will be
|
||||
* removed and used to set the buffer type.
|
||||
*/
|
||||
BT_HCI_RAW_MODE_H4 = 0x01,
|
||||
};
|
||||
|
||||
/** @brief Set Bluetooth RAW channel mode
|
||||
*
|
||||
* Set access mode of Bluetooth RAW channel.
|
||||
*
|
||||
* @param mode Access mode.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_hci_raw_set_mode(uint8_t mode);
|
||||
|
||||
/** @brief Get Bluetooth RAW channel mode
|
||||
*
|
||||
* Get access mode of Bluetooth RAW channel.
|
||||
*
|
||||
* @return Access mode.
|
||||
*/
|
||||
uint8_t bt_hci_raw_get_mode(void);
|
||||
|
||||
#define BT_HCI_ERR_EXT_HANDLED 0xff
|
||||
|
||||
/** Helper macro to define a command extension
|
||||
*
|
||||
* @param _op Opcode of the command.
|
||||
* @param _min_len Minimal length of the command.
|
||||
* @param _func Handler function to be called.
|
||||
*/
|
||||
#define BT_HCI_RAW_CMD_EXT(_op, _min_len, _func) \
|
||||
{ \
|
||||
.op = _op, \
|
||||
.min_len = _min_len, \
|
||||
.func = _func, \
|
||||
}
|
||||
|
||||
struct bt_hci_raw_cmd_ext {
|
||||
/** Opcode of the command */
|
||||
uint16_t op;
|
||||
|
||||
/** Minimal length of the command */
|
||||
size_t min_len;
|
||||
|
||||
/** Handler function.
|
||||
*
|
||||
* Handler function to be called when a command is intercepted.
|
||||
*
|
||||
* @param buf Buffer containing the command.
|
||||
*
|
||||
* @return HCI Status code or BT_HCI_ERR_EXT_HANDLED if command has
|
||||
* been handled already and a response has been sent as oppose to
|
||||
* BT_HCI_ERR_SUCCESS which just indicates that the command can be
|
||||
* sent to the controller to be processed.
|
||||
*/
|
||||
uint8_t (*func)(struct net_buf *buf);
|
||||
};
|
||||
|
||||
/** @brief Register Bluetooth RAW command extension table
|
||||
*
|
||||
* Register Bluetooth RAW channel command extension table, opcodes in this
|
||||
* table are intercepted to sent to the handler function.
|
||||
*
|
||||
* @param cmds Pointer to the command extension table.
|
||||
* @param size Size of the command extension table.
|
||||
*/
|
||||
void bt_hci_raw_cmd_ext_register(struct bt_hci_raw_cmd_ext *cmds, size_t size);
|
||||
|
||||
/** @brief Enable Bluetooth RAW channel:
|
||||
*
|
||||
* Enable Bluetooth RAW HCI channel.
|
||||
*
|
||||
* @param rx_queue netbuf queue where HCI packets received from the Bluetooth
|
||||
* controller are to be queued. The queue is defined in the caller while
|
||||
* the available buffers pools are handled in the stack.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_enable_raw(struct k_fifo *rx_queue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_ */
|
379
devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h
Normal file
379
devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h
Normal file
@ -0,0 +1,379 @@
|
||||
/* hci_vs.h - Bluetooth Host Control Interface Vendor Specific definitions */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017-2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_
|
||||
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BT_VS_CMD_BIT_VERSION 0
|
||||
#define BT_VS_CMD_BIT_SUP_CMD 1
|
||||
#define BT_VS_CMD_BIT_SUP_FEAT 2
|
||||
#define BT_VS_CMD_BIT_SET_EVT_MASK 3
|
||||
#define BT_VS_CMD_BIT_RESET 4
|
||||
#define BT_VS_CMD_BIT_WRITE_BDADDR 5
|
||||
#define BT_VS_CMD_BIT_SET_TRACE_ENABLE 6
|
||||
#define BT_VS_CMD_BIT_READ_BUILD_INFO 7
|
||||
#define BT_VS_CMD_BIT_READ_STATIC_ADDRS 8
|
||||
#define BT_VS_CMD_BIT_READ_KEY_ROOTS 9
|
||||
#define BT_VS_CMD_BIT_READ_CHIP_TEMP 10
|
||||
#define BT_VS_CMD_BIT_READ_HOST_STACK_CMD 11
|
||||
#define BT_VS_CMD_BIT_SET_SCAN_REP_ENABLE 12
|
||||
#define BT_VS_CMD_BIT_WRITE_TX_POWER 13
|
||||
#define BT_VS_CMD_BIT_READ_TX_POWER 14
|
||||
|
||||
#define BT_VS_CMD_SUP_FEAT(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_SUP_FEAT)
|
||||
#define BT_VS_CMD_READ_STATIC_ADDRS(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_READ_STATIC_ADDRS)
|
||||
#define BT_VS_CMD_READ_KEY_ROOTS(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_READ_KEY_ROOTS)
|
||||
|
||||
#define BT_HCI_VS_HW_PLAT_INTEL 0x0001
|
||||
#define BT_HCI_VS_HW_PLAT_NORDIC 0x0002
|
||||
#define BT_HCI_VS_HW_PLAT_NXP 0x0003
|
||||
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF51X 0x0001
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF52X 0x0002
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF53X 0x0003
|
||||
|
||||
#define BT_HCI_VS_FW_VAR_STANDARD_CTLR 0x0001
|
||||
#define BT_HCI_VS_FW_VAR_VS_CTLR 0x0002
|
||||
#define BT_HCI_VS_FW_VAR_FW_LOADER 0x0003
|
||||
#define BT_HCI_VS_FW_VAR_RESCUE_IMG 0x0004
|
||||
#define BT_HCI_OP_VS_READ_VERSION_INFO BT_OP(BT_OGF_VS, 0x0001)
|
||||
struct bt_hci_rp_vs_read_version_info {
|
||||
uint8_t status;
|
||||
uint16_t hw_platform;
|
||||
uint16_t hw_variant;
|
||||
uint8_t fw_variant;
|
||||
uint8_t fw_version;
|
||||
uint16_t fw_revision;
|
||||
uint32_t fw_build;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_VS, 0x0002)
|
||||
struct bt_hci_rp_vs_read_supported_commands {
|
||||
uint8_t status;
|
||||
uint8_t commands[64];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_SUPPORTED_FEATURES BT_OP(BT_OGF_VS, 0x0003)
|
||||
struct bt_hci_rp_vs_read_supported_features {
|
||||
uint8_t status;
|
||||
uint8_t features[8];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_SET_EVENT_MASK BT_OP(BT_OGF_VS, 0x0004)
|
||||
struct bt_hci_cp_vs_set_event_mask {
|
||||
uint8_t event_mask[8];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_RESET_SOFT 0x00
|
||||
#define BT_HCI_VS_RESET_HARD 0x01
|
||||
#define BT_HCI_OP_VS_RESET BT_OP(BT_OGF_VS, 0x0005)
|
||||
struct bt_hci_cp_vs_reset {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_WRITE_BD_ADDR BT_OP(BT_OGF_VS, 0x0006)
|
||||
struct bt_hci_cp_vs_write_bd_addr {
|
||||
bt_addr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_TRACE_DISABLED 0x00
|
||||
#define BT_HCI_VS_TRACE_ENABLED 0x01
|
||||
|
||||
#define BT_HCI_VS_TRACE_HCI_EVTS 0x00
|
||||
#define BT_HCI_VS_TRACE_VDC 0x01
|
||||
#define BT_HCI_OP_VS_SET_TRACE_ENABLE BT_OP(BT_OGF_VS, 0x0007)
|
||||
struct bt_hci_cp_vs_set_trace_enable {
|
||||
uint8_t enable;
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_BUILD_INFO BT_OP(BT_OGF_VS, 0x0008)
|
||||
struct bt_hci_rp_vs_read_build_info {
|
||||
uint8_t status;
|
||||
uint8_t info[];
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_vs_static_addr {
|
||||
bt_addr_t bdaddr;
|
||||
uint8_t ir[16];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_STATIC_ADDRS BT_OP(BT_OGF_VS, 0x0009)
|
||||
struct bt_hci_rp_vs_read_static_addrs {
|
||||
uint8_t status;
|
||||
uint8_t num_addrs;
|
||||
struct bt_hci_vs_static_addr a[];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS BT_OP(BT_OGF_VS, 0x000a)
|
||||
struct bt_hci_rp_vs_read_key_hierarchy_roots {
|
||||
uint8_t status;
|
||||
uint8_t ir[16];
|
||||
uint8_t er[16];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_CHIP_TEMP BT_OP(BT_OGF_VS, 0x000b)
|
||||
struct bt_hci_rp_vs_read_chip_temp {
|
||||
uint8_t status;
|
||||
int8_t temps;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_vs_cmd {
|
||||
uint16_t vendor_id;
|
||||
uint16_t opcode_base;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_VID_ANDROID 0x0001
|
||||
#define BT_HCI_VS_VID_MICROSOFT 0x0002
|
||||
#define BT_HCI_OP_VS_READ_HOST_STACK_CMDS BT_OP(BT_OGF_VS, 0x000c)
|
||||
struct bt_hci_rp_vs_read_host_stack_cmds {
|
||||
uint8_t status;
|
||||
uint8_t num_cmds;
|
||||
struct bt_hci_vs_cmd c[];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_SCAN_REQ_REPORTS_DISABLED 0x00
|
||||
#define BT_HCI_VS_SCAN_REQ_REPORTS_ENABLED 0x01
|
||||
#define BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS BT_OP(BT_OGF_VS, 0x000d)
|
||||
struct bt_hci_cp_vs_set_scan_req_reports {
|
||||
uint8_t enable;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_ADV 0x00
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_SCAN 0x01
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_CONN 0x02
|
||||
#define BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF 0x7F
|
||||
#define BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000e)
|
||||
struct bt_hci_cp_vs_write_tx_power_level {
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t tx_power_level;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_rp_vs_write_tx_power_level {
|
||||
uint8_t status;
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t selected_tx_power;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000f)
|
||||
struct bt_hci_cp_vs_read_tx_power_level {
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_rp_vs_read_tx_power_level {
|
||||
uint8_t status;
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t tx_power_level;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0010)
|
||||
|
||||
struct bt_hci_rp_vs_read_usb_transport_mode {
|
||||
uint8_t status;
|
||||
uint8_t num_supported_modes;
|
||||
uint8_t supported_mode[];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_USB_H2_MODE 0x00
|
||||
#define BT_HCI_VS_USB_H4_MODE 0x01
|
||||
|
||||
#define BT_HCI_OP_VS_SET_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0011)
|
||||
|
||||
struct bt_hci_cp_vs_set_usb_transport_mode {
|
||||
uint8_t mode;
|
||||
} __packed;
|
||||
|
||||
/* Events */
|
||||
|
||||
struct bt_hci_evt_vs {
|
||||
uint8_t subevent;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_VS_FATAL_ERROR 0x02
|
||||
struct bt_hci_evt_vs_fatal_error {
|
||||
uint64_t pc;
|
||||
uint8_t err_info[];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_TRACE_LMP_TX 0x01
|
||||
#define BT_HCI_VS_TRACE_LMP_RX 0x02
|
||||
#define BT_HCI_VS_TRACE_LLCP_TX 0x03
|
||||
#define BT_HCI_VS_TRACE_LLCP_RX 0x04
|
||||
#define BT_HCI_VS_TRACE_LE_CONN_IND 0x05
|
||||
#define BT_HCI_EVT_VS_TRACE_INFO 0x03
|
||||
struct bt_hci_evt_vs_trace_info {
|
||||
uint8_t type;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_VS_SCAN_REQ_RX 0x04
|
||||
struct bt_hci_evt_vs_scan_req_rx {
|
||||
bt_addr_le_t addr;
|
||||
int8_t rssi;
|
||||
} __packed;
|
||||
|
||||
/* Event mask bits */
|
||||
|
||||
#define BT_EVT_MASK_VS_FATAL_ERROR BT_EVT_BIT(1)
|
||||
#define BT_EVT_MASK_VS_TRACE_INFO BT_EVT_BIT(2)
|
||||
#define BT_EVT_MASK_VS_SCAN_REQ_RX BT_EVT_BIT(3)
|
||||
|
||||
/* Mesh HCI commands */
|
||||
#define BT_HCI_MESH_REVISION 0x01
|
||||
|
||||
#define BT_HCI_OP_VS_MESH BT_OP(BT_OGF_VS, 0x0042)
|
||||
#define BT_HCI_MESH_EVT_PREFIX 0xF0
|
||||
|
||||
struct bt_hci_cp_mesh {
|
||||
uint8_t opcode;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_GET_OPTS 0x00
|
||||
struct bt_hci_rp_mesh_get_opts {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t revision;
|
||||
uint8_t ch_map;
|
||||
int8_t min_tx_power;
|
||||
int8_t max_tx_power;
|
||||
uint8_t max_scan_filter;
|
||||
uint8_t max_filter_pattern;
|
||||
uint8_t max_adv_slot;
|
||||
uint8_t max_tx_window;
|
||||
uint8_t evt_prefix_len;
|
||||
uint8_t evt_prefix;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_MESH_PATTERN_LEN_MAX 0x0f
|
||||
|
||||
#define BT_HCI_OC_MESH_SET_SCAN_FILTER 0x01
|
||||
struct bt_hci_mesh_pattern {
|
||||
uint8_t pattern_len;
|
||||
uint8_t pattern[];
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_cp_mesh_set_scan_filter {
|
||||
uint8_t scan_filter;
|
||||
uint8_t filter_dup;
|
||||
uint8_t num_patterns;
|
||||
struct bt_hci_mesh_pattern patterns[];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_set_scan_filter {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t scan_filter;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE 0x02
|
||||
struct bt_hci_cp_mesh_advertise {
|
||||
uint8_t adv_slot;
|
||||
uint8_t own_addr_type;
|
||||
bt_addr_t random_addr;
|
||||
uint8_t ch_map;
|
||||
int8_t tx_power;
|
||||
uint8_t min_tx_delay;
|
||||
uint8_t max_tx_delay;
|
||||
uint8_t retx_count;
|
||||
uint8_t retx_interval;
|
||||
uint8_t scan_delay;
|
||||
uint16_t scan_duration;
|
||||
uint8_t scan_filter;
|
||||
uint8_t data_len;
|
||||
uint8_t data[31];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE_TIMED 0x03
|
||||
struct bt_hci_cp_mesh_advertise_timed {
|
||||
uint8_t adv_slot;
|
||||
uint8_t own_addr_type;
|
||||
bt_addr_t random_addr;
|
||||
uint8_t ch_map;
|
||||
int8_t tx_power;
|
||||
uint8_t retx_count;
|
||||
uint8_t retx_interval;
|
||||
uint32_t instant;
|
||||
uint16_t tx_delay;
|
||||
uint16_t tx_window;
|
||||
uint8_t data_len;
|
||||
uint8_t data[31];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise_timed {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE_CANCEL 0x04
|
||||
struct bt_hci_cp_mesh_advertise_cancel {
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise_cancel {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_SET_SCANNING 0x05
|
||||
struct bt_hci_cp_mesh_set_scanning {
|
||||
uint8_t enable;
|
||||
uint8_t ch_map;
|
||||
uint8_t scan_filter;
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_set_scanning {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
} __packed;
|
||||
|
||||
/* Events */
|
||||
struct bt_hci_evt_mesh {
|
||||
uint8_t prefix;
|
||||
uint8_t subevent;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_MESH_ADV_COMPLETE 0x00
|
||||
struct bt_hci_evt_mesh_adv_complete {
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_MESH_SCANNING_REPORT 0x01
|
||||
struct bt_hci_evt_mesh_scan_report {
|
||||
bt_addr_le_t addr;
|
||||
uint8_t chan;
|
||||
int8_t rssi;
|
||||
uint32_t instant;
|
||||
uint8_t data_len;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
struct bt_hci_evt_mesh_scanning_report {
|
||||
uint8_t num_reports;
|
||||
struct bt_hci_evt_mesh_scan_report reports[];
|
||||
} __packed;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_ */
|
230
devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h
Normal file
230
devices/ble_hci/common-hal/_bleio/hci_include/l2cap_internal.h
Normal file
@ -0,0 +1,230 @@
|
||||
// CircuitPython: Adapted from Zephyr include file.
|
||||
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth L2CAP handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
// for __packed
|
||||
#include <string.h>
|
||||
|
||||
enum l2cap_conn_list_action {
|
||||
BT_L2CAP_CHAN_LOOKUP,
|
||||
BT_L2CAP_CHAN_DETACH,
|
||||
};
|
||||
|
||||
#define BT_L2CAP_CID_BR_SIG 0x0001
|
||||
#define BT_L2CAP_CID_ATT 0x0004
|
||||
#define BT_L2CAP_CID_LE_SIG 0x0005
|
||||
#define BT_L2CAP_CID_SMP 0x0006
|
||||
#define BT_L2CAP_CID_BR_SMP 0x0007
|
||||
|
||||
#define BT_L2CAP_PSM_RFCOMM 0x0003
|
||||
|
||||
struct bt_l2cap_hdr {
|
||||
uint16_t len;
|
||||
uint16_t cid;
|
||||
} __packed;
|
||||
|
||||
struct bt_l2cap_sig_hdr {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
|
||||
#define BT_L2CAP_REJ_MTU_EXCEEDED 0x0001
|
||||
#define BT_L2CAP_REJ_INVALID_CID 0x0002
|
||||
|
||||
#define BT_L2CAP_CMD_REJECT 0x01
|
||||
struct bt_l2cap_cmd_reject {
|
||||
uint16_t reason;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct bt_l2cap_cmd_reject_cid_data {
|
||||
uint16_t scid;
|
||||
uint16_t dcid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_REQ 0x02
|
||||
struct bt_l2cap_conn_req {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
} __packed;
|
||||
|
||||
/* command statuses in reposnse */
|
||||
#define BT_L2CAP_CS_NO_INFO 0x0000
|
||||
#define BT_L2CAP_CS_AUTHEN_PEND 0x0001
|
||||
|
||||
/* valid results in conn response on BR/EDR */
|
||||
#define BT_L2CAP_BR_SUCCESS 0x0000
|
||||
#define BT_L2CAP_BR_PENDING 0x0001
|
||||
#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002
|
||||
#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003
|
||||
#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004
|
||||
#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006
|
||||
#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007
|
||||
|
||||
#define BT_L2CAP_CONN_RSP 0x03
|
||||
struct bt_l2cap_conn_rsp {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint16_t result;
|
||||
uint16_t status;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONF_SUCCESS 0x0000
|
||||
#define BT_L2CAP_CONF_UNACCEPT 0x0001
|
||||
#define BT_L2CAP_CONF_REJECT 0x0002
|
||||
|
||||
#define BT_L2CAP_CONF_REQ 0x04
|
||||
struct bt_l2cap_conf_req {
|
||||
uint16_t dcid;
|
||||
uint16_t flags;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONF_RSP 0x05
|
||||
struct bt_l2cap_conf_rsp {
|
||||
uint16_t scid;
|
||||
uint16_t flags;
|
||||
uint16_t result;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
/* Option type used by MTU config request data */
|
||||
#define BT_L2CAP_CONF_OPT_MTU 0x01
|
||||
/* Options bits selecting most significant bit (hint) in type field */
|
||||
#define BT_L2CAP_CONF_HINT 0x80
|
||||
#define BT_L2CAP_CONF_MASK 0x7f
|
||||
|
||||
struct bt_l2cap_conf_opt {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_DISCONN_REQ 0x06
|
||||
struct bt_l2cap_disconn_req {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_DISCONN_RSP 0x07
|
||||
struct bt_l2cap_disconn_rsp {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_INFO_FEAT_MASK 0x0002
|
||||
#define BT_L2CAP_INFO_FIXED_CHAN 0x0003
|
||||
|
||||
#define BT_L2CAP_INFO_REQ 0x0a
|
||||
struct bt_l2cap_info_req {
|
||||
uint16_t type;
|
||||
} __packed;
|
||||
|
||||
/* info result */
|
||||
#define BT_L2CAP_INFO_SUCCESS 0x0000
|
||||
#define BT_L2CAP_INFO_NOTSUPP 0x0001
|
||||
|
||||
#define BT_L2CAP_INFO_RSP 0x0b
|
||||
struct bt_l2cap_info_rsp {
|
||||
uint16_t type;
|
||||
uint16_t result;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_REQ 0x12
|
||||
struct bt_l2cap_conn_param_req {
|
||||
uint16_t min_interval;
|
||||
uint16_t max_interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_ACCEPTED 0x0000
|
||||
#define BT_L2CAP_CONN_PARAM_REJECTED 0x0001
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_RSP 0x13
|
||||
struct bt_l2cap_conn_param_rsp {
|
||||
uint16_t result;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_LE_CONN_REQ 0x14
|
||||
struct bt_l2cap_le_conn_req {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
uint16_t credits;
|
||||
} __packed;
|
||||
|
||||
/* valid results in conn response on LE */
|
||||
#define BT_L2CAP_LE_SUCCESS 0x0000
|
||||
#define BT_L2CAP_LE_ERR_PSM_NOT_SUPP 0x0002
|
||||
#define BT_L2CAP_LE_ERR_NO_RESOURCES 0x0004
|
||||
#define BT_L2CAP_LE_ERR_AUTHENTICATION 0x0005
|
||||
#define BT_L2CAP_LE_ERR_AUTHORIZATION 0x0006
|
||||
#define BT_L2CAP_LE_ERR_KEY_SIZE 0x0007
|
||||
#define BT_L2CAP_LE_ERR_ENCRYPTION 0x0008
|
||||
#define BT_L2CAP_LE_ERR_INVALID_SCID 0x0009
|
||||
#define BT_L2CAP_LE_ERR_SCID_IN_USE 0x000A
|
||||
#define BT_L2CAP_LE_ERR_UNACCEPT_PARAMS 0x000B
|
||||
#define BT_L2CAP_LE_ERR_INVALID_PARAMS 0x000C
|
||||
|
||||
#define BT_L2CAP_LE_CONN_RSP 0x15
|
||||
struct bt_l2cap_le_conn_rsp {
|
||||
uint16_t dcid;
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
uint16_t credits;
|
||||
uint16_t result;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_LE_CREDITS 0x16
|
||||
struct bt_l2cap_le_credits {
|
||||
uint16_t cid;
|
||||
uint16_t credits;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_ECRED_CONN_REQ 0x17
|
||||
struct bt_l2cap_ecred_conn_req {
|
||||
uint16_t psm;
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
uint16_t credits;
|
||||
uint16_t scid[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_ECRED_CONN_RSP 0x18
|
||||
struct bt_l2cap_ecred_conn_rsp {
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
uint16_t credits;
|
||||
uint16_t result;
|
||||
uint16_t dcid[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_ECRED_RECONF_REQ 0x19
|
||||
struct bt_l2cap_ecred_reconf_req {
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
uint16_t scid[];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_RECONF_SUCCESS 0x0000
|
||||
#define BT_L2CAP_RECONF_INVALID_MTU 0x0001
|
||||
#define BT_L2CAP_RECONF_INVALID_MPS 0x0002
|
||||
|
||||
#define BT_L2CAP_ECRED_RECONF_RSP 0x1a
|
||||
struct bt_l2cap_ecred_reconf_rsp {
|
||||
uint16_t result;
|
||||
} __packed;
|
29
devices/ble_hci/supervisor/bluetooth.c
Normal file
29
devices/ble_hci/supervisor/bluetooth.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if CIRCUITPY_BLE_FILE_SERVICE
|
||||
#error CIRCUITPY_BLE_FILE_SERVICE not implemented for CIRCUITPY_BLEIO_HCI
|
||||
#endif
|
34
devices/ble_hci/supervisor/bluetooth.h
Normal file
34
devices/ble_hci/supervisor/bluetooth.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H
|
||||
#define MICROPY_INCLUDED_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H
|
||||
|
||||
void supervisor_start_bluetooth(void);
|
||||
bool supervisor_bluetooth_hook(ble_evt_t *ble_evt);
|
||||
void supervisor_bluetooth_background(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_DEVICE_BLE_HCI_SUPERVISOR_BLUETOOTH_H
|
@ -421,7 +421,7 @@ SPI Example
|
||||
"""Widget's one register."""
|
||||
with self.spi_device as spi:
|
||||
spi.write(b'0x00')
|
||||
i2c.readinto(self.buf)
|
||||
spi.readinto(self.buf)
|
||||
return self.buf[0]
|
||||
|
||||
Use composition
|
||||
@ -462,7 +462,7 @@ like properties for state even if it sacrifices a bit of speed.
|
||||
Avoid allocations in drivers
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Although Python doesn't require managing memory, its still a good practice for
|
||||
Although Python doesn't require managing memory, it's still a good practice for
|
||||
library writers to think about memory allocations. Avoid them in drivers if
|
||||
you can because you never know how much something will be called. Fewer
|
||||
allocations means less time spent cleaning up. So, where you can, prefer
|
||||
@ -471,7 +471,7 @@ object with methods that read or write into the buffer instead of creating new
|
||||
objects. Unified hardware API classes such as `busio.SPI` are design to read and
|
||||
write to subsections of buffers.
|
||||
|
||||
Its ok to allocate an object to return to the user. Just beware of causing more
|
||||
It's ok to allocate an object to return to the user. Just beware of causing more
|
||||
than one allocation per call due to internal logic.
|
||||
|
||||
**However**, this is a memory tradeoff so do not do it for large or rarely used
|
||||
@ -485,6 +485,19 @@ struct.pack
|
||||
|
||||
Use `struct.pack_into` instead of `struct.pack`.
|
||||
|
||||
Use of MicroPython ``const()``
|
||||
--------------------------------------------------------------------------------
|
||||
The MicroPython ``const()`` feature, as discussed in `this forum post
|
||||
<https://forum.micropython.org/viewtopic.php?t=450>`_, and in `this issue thread
|
||||
<https://github.com/micropython/micropython/issues/573>`_, provides some
|
||||
optimizations that can be useful on smaller, memory constrained devices. However,
|
||||
when using ``const()``, keep in mind these general guide lines:
|
||||
|
||||
- Always use via an import, ex: ``from micropython import const``
|
||||
- Limit use to global (module level) variables only.
|
||||
- If user will not need access to variable, prefix name with a leading
|
||||
underscore, ex: ``_SOME_CONST``.
|
||||
|
||||
Sensor properties and units
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -567,4 +580,4 @@ MicroPython compatibility
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Keeping compatibility with MicroPython isn't a high priority. It should be done
|
||||
when its not in conflict with any of the above goals.
|
||||
when it's not in conflict with any of the above goals.
|
||||
|
@ -12,7 +12,7 @@ Adafruit CircuitPython Library Bundle
|
||||
We provide a bundle of all our libraries to ease installation of drivers and
|
||||
their dependencies. The bundle is primarily geared to the Adafruit Express line
|
||||
of boards which feature a relatively large external flash. With Express boards,
|
||||
its easy to copy them all onto the filesystem. However, if you don't have
|
||||
it's easy to copy them all onto the filesystem. However, if you don't have
|
||||
enough space simply copy things over as they are needed.
|
||||
|
||||
- The Adafruit bundles are available on GitHub: <https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases>.
|
||||
|
@ -20,10 +20,10 @@ be implemented:
|
||||
* SHA1 - A previous generation algorithm. Not recommended for new usages,
|
||||
but SHA1 is a part of number of Internet standards and existing
|
||||
applications, so boards targeting network connectivity and
|
||||
interoperatiability will try to provide this.
|
||||
interoperability will try to provide this.
|
||||
|
||||
* MD5 - A legacy algorithm, not considered cryptographically secure. Only
|
||||
selected boards, targeting interoperatibility with legacy applications,
|
||||
selected boards, targeting interoperability with legacy applications,
|
||||
will offer this.
|
||||
|
||||
Constructors
|
||||
|
@ -21,7 +21,7 @@ standard Python library.
|
||||
You may need to change your code later if you rely
|
||||
on any non-standard functionality they currently provide.
|
||||
|
||||
CircuitPython's goal long-term goalis that code written in CircuitPython
|
||||
CircuitPython's long-term goal is that code written in CircuitPython
|
||||
using Python standard libraries will be runnable on CPython without changes.
|
||||
|
||||
Some libraries below are not enabled on CircuitPython builds with
|
||||
@ -69,7 +69,7 @@ CircuitPython/MicroPython-specific libraries
|
||||
--------------------------------------------
|
||||
|
||||
Functionality specific to the CircuitPython/MicroPython implementation is available in
|
||||
the following libraries. These libraries may change signficantly or be removed in future
|
||||
the following libraries. These libraries may change significantly or be removed in future
|
||||
versions of CircuitPython.
|
||||
|
||||
.. toctree::
|
||||
|
@ -71,7 +71,7 @@ parameter should be `id`.
|
||||
(password) required to access said service. There can be further
|
||||
arbitrary keyword-only parameters, depending on the networking medium
|
||||
type and/or particular device. Parameters can be used to: a)
|
||||
specify alternative service identifer types; b) provide additional
|
||||
specify alternative service identifier types; b) provide additional
|
||||
connection parameters. For various medium types, there are different
|
||||
sets of predefined/recommended parameters, among them:
|
||||
|
||||
|
@ -51,10 +51,15 @@ as a natural "TODO" list. An example minimal build list is shown below:
|
||||
.. code-block:: makefile
|
||||
|
||||
# These modules are implemented in ports/<port>/common-hal:
|
||||
CIRCUITPY_MICROCONTROLLER = 0 # Typically the first module to create
|
||||
CIRCUITPY_DIGITALIO = 0 # Typically the second module to create
|
||||
|
||||
# Typically the first module to create
|
||||
CIRCUITPY_MICROCONTROLLER = 0
|
||||
# Typically the second module to create
|
||||
CIRCUITPY_DIGITALIO = 0
|
||||
# Other modules:
|
||||
CIRCUITPY_ANALOGIO = 0
|
||||
CIRCUITPY_BUSIO = 0
|
||||
CIRCUITPY_COUNTIO = 0
|
||||
CIRCUITPY_NEOPIXEL_WRITE = 0
|
||||
CIRCUITPY_PULSEIO = 0
|
||||
CIRCUITPY_OS = 0
|
||||
@ -63,22 +68,34 @@ as a natural "TODO" list. An example minimal build list is shown below:
|
||||
CIRCUITPY_AUDIOIO = 0
|
||||
CIRCUITPY_ROTARYIO = 0
|
||||
CIRCUITPY_RTC = 0
|
||||
CIRCUITPY_SDCARDIO = 0
|
||||
CIRCUITPY_FRAMEBUFFERIO = 0
|
||||
CIRCUITPY_FREQUENCYIO = 0
|
||||
CIRCUITPY_I2CPERIPHERAL = 0
|
||||
CIRCUITPY_DISPLAYIO = 0 # Requires SPI, PulseIO (stub ok)
|
||||
# Requires SPI, PulseIO (stub ok):
|
||||
CIRCUITPY_DISPLAYIO = 0
|
||||
|
||||
# These modules are implemented in shared-module/ - they can be included in
|
||||
# any port once their prerequisites in common-hal are complete.
|
||||
CIRCUITPY_BITBANGIO = 0 # Requires DigitalIO
|
||||
CIRCUITPY_GAMEPAD = 0 # Requires DigitalIO
|
||||
CIRCUITPY_PIXELBUF = 0 # Requires neopixel_write or SPI (dotstar)
|
||||
CIRCUITPY_RANDOM = 0 # Requires OS
|
||||
CIRCUITPY_STORAGE = 0 # Requires OS, filesystem
|
||||
CIRCUITPY_TOUCHIO = 0 # Requires Microcontroller
|
||||
CIRCUITPY_USB_HID = 0 # Requires USB
|
||||
CIRCUITPY_USB_MIDI = 0 # Requires USB
|
||||
CIRCUITPY_REQUIRE_I2C_PULLUPS = 0 # Does nothing without I2C
|
||||
CIRCUITPY_ULAB = 0 # No requirements, but takes extra flash
|
||||
# Requires DigitalIO:
|
||||
CIRCUITPY_BITBANGIO = 0
|
||||
# Requires DigitalIO
|
||||
CIRCUITPY_GAMEPAD = 0
|
||||
# Requires neopixel_write or SPI (dotstar)
|
||||
CIRCUITPY_PIXELBUF = 0
|
||||
# Requires OS
|
||||
CIRCUITPY_RANDOM = 0
|
||||
# Requires OS, filesystem
|
||||
CIRCUITPY_STORAGE = 0
|
||||
# Requires Microcontroller
|
||||
CIRCUITPY_TOUCHIO = 0
|
||||
# Requires USB
|
||||
CIRCUITPY_USB_HID = 0
|
||||
CIRCUITPY_USB_MIDI = 0
|
||||
# Does nothing without I2C
|
||||
CIRCUITPY_REQUIRE_I2C_PULLUPS = 0
|
||||
# No requirements, but takes extra flash
|
||||
CIRCUITPY_ULAB = 0
|
||||
|
||||
Step 2: Init
|
||||
--------------
|
||||
@ -89,7 +106,7 @@ request a safe mode state which prevents the supervisor from running user code
|
||||
while still allowing access to the REPL and other resources.
|
||||
|
||||
The core port initialization and reset methods are defined in
|
||||
``supervisor/port.c`` and should be the first to be implemented. Its required
|
||||
``supervisor/port.c`` and should be the first to be implemented. It's required
|
||||
that they be implemented in the ``supervisor`` directory within the port
|
||||
directory. That way, they are always in the expected place.
|
||||
|
||||
|
@ -6,18 +6,28 @@ def rstjinja(app, docname, source):
|
||||
Render our pages as a jinja template for fancy templating goodness.
|
||||
"""
|
||||
# Make sure we're outputting HTML
|
||||
if app.builder.format != 'html':
|
||||
if app.builder.format not in ("html", "latex"):
|
||||
return
|
||||
|
||||
# we only want our one jinja template to run through this func
|
||||
if "shared-bindings/support_matrix" not in docname:
|
||||
return
|
||||
|
||||
src = source[0]
|
||||
src = rendered = source[0]
|
||||
print(docname)
|
||||
rendered = app.builder.templates.render_string(
|
||||
src, app.config.html_context
|
||||
)
|
||||
|
||||
if app.builder.format == "html":
|
||||
rendered = app.builder.templates.render_string(
|
||||
src, app.config.html_context
|
||||
)
|
||||
else:
|
||||
from sphinx.util.template import BaseRenderer
|
||||
renderer = BaseRenderer()
|
||||
rendered = renderer.render_string(
|
||||
src,
|
||||
app.config.html_context
|
||||
)
|
||||
|
||||
source[0] = rendered
|
||||
|
||||
def setup(app):
|
||||
|
@ -28,6 +28,7 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
SUPPORTED_PORTS = ['atmel-samd', 'esp32s2', 'litex', 'mimxrt10xx', 'nrf', 'stm']
|
||||
|
||||
@ -43,7 +44,7 @@ def get_shared_bindings():
|
||||
""" Get a list of modules in shared-bindings based on folder names
|
||||
"""
|
||||
shared_bindings_dir = get_circuitpython_root_dir() / "shared-bindings"
|
||||
return [item.name for item in shared_bindings_dir.iterdir()]
|
||||
return [item.name for item in shared_bindings_dir.iterdir()] + ["ulab"]
|
||||
|
||||
|
||||
def read_mpconfig():
|
||||
@ -131,38 +132,46 @@ def lookup_setting(settings, key, default=''):
|
||||
key = value[2:-1]
|
||||
return value
|
||||
|
||||
def all_ports_all_boards(ports=SUPPORTED_PORTS):
|
||||
for port in ports:
|
||||
|
||||
port_dir = get_circuitpython_root_dir() / "ports" / port
|
||||
for entry in (port_dir / "boards").iterdir():
|
||||
if not entry.is_dir():
|
||||
continue
|
||||
yield (port, entry)
|
||||
|
||||
def support_matrix_by_board(use_branded_name=True):
|
||||
""" Compiles a list of the available core modules available for each
|
||||
board.
|
||||
"""
|
||||
base = build_module_map()
|
||||
|
||||
boards = dict()
|
||||
for port in SUPPORTED_PORTS:
|
||||
|
||||
def support_matrix(arg):
|
||||
port, entry = arg
|
||||
port_dir = get_circuitpython_root_dir() / "ports" / port
|
||||
for entry in (port_dir / "boards").iterdir():
|
||||
if not entry.is_dir():
|
||||
continue
|
||||
board_modules = []
|
||||
settings = get_settings_from_makefile(str(port_dir), entry.name)
|
||||
|
||||
if use_branded_name:
|
||||
with open(entry / "mpconfigboard.h") as get_name:
|
||||
board_contents = get_name.read()
|
||||
board_name_re = re.search(r"(?<=MICROPY_HW_BOARD_NAME)\s+(.+)",
|
||||
board_contents)
|
||||
if board_name_re:
|
||||
board_name = board_name_re.group(1).strip('"')
|
||||
else:
|
||||
board_name = entry.name
|
||||
|
||||
settings = get_settings_from_makefile(str(port_dir), entry.name)
|
||||
board_modules = []
|
||||
for module in base:
|
||||
key = f'CIRCUITPY_{module.upper()}'
|
||||
if int(lookup_setting(settings, key, '0')):
|
||||
board_modules.append(base[module]['name'])
|
||||
|
||||
if use_branded_name:
|
||||
with open(entry / "mpconfigboard.h") as get_name:
|
||||
board_contents = get_name.read()
|
||||
board_name_re = re.search(r"(?<=MICROPY_HW_BOARD_NAME)\s+(.+)",
|
||||
board_contents)
|
||||
if board_name_re:
|
||||
board_name = board_name_re.group(1).strip('"')
|
||||
return (board_name, sorted(board_modules))
|
||||
|
||||
board_modules = []
|
||||
for module in base:
|
||||
key = f'CIRCUITPY_{module.upper()}'
|
||||
if int(lookup_setting(settings, key, '0')):
|
||||
board_modules.append(base[module]['name'])
|
||||
boards[board_name] = sorted(board_modules)
|
||||
executor = ThreadPoolExecutor(max_workers=os.cpu_count())
|
||||
boards = dict(sorted(executor.map(support_matrix, all_ports_all_boards())))
|
||||
|
||||
#print(json.dumps(boards, indent=2))
|
||||
return boards
|
||||
|
@ -17,3 +17,4 @@ is limited.
|
||||
../ports/mimxrt10xx/README
|
||||
../ports/nrf/README
|
||||
../ports/stm/README
|
||||
../ports/esp32s2/README
|
||||
|
@ -13,7 +13,7 @@ When CircuitPython restarts it will create a fresh empty ``CIRCUITPY`` filesyste
|
||||
|
||||
This often happens on Windows when the ``CIRCUITPY`` disk is not safely ejected
|
||||
before being reset by the button or being disconnected from USB. This can also
|
||||
happen on Linux and Mac OSX but its less likely.
|
||||
happen on Linux and Mac OSX but it's less likely.
|
||||
|
||||
.. caution:: To erase and re-create ``CIRCUITPY`` (for example, to correct a corrupted filesystem),
|
||||
follow one of the procedures below. It's important to note that **any files stored on the**
|
||||
@ -43,7 +43,7 @@ ValueError: Incompatible ``.mpy`` file.
|
||||
|
||||
This error occurs when importing a module that is stored as a ``mpy`` binary file
|
||||
(rather than a ``py`` text file) that was generated by a different version of
|
||||
CircuitPython than the one its being loaded into. Most versions are compatible
|
||||
CircuitPython than the one it's being loaded into. Most versions are compatible
|
||||
but, rarely they aren't. In particular, the ``mpy`` binary format changed between
|
||||
CircuitPython versions 1.x and 2.x, and will change again between 2.x and 3.x.
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
STATIC uintptr_t machine_mem_get_addr(mp_obj_t addr_o, uint align) {
|
||||
uintptr_t addr = mp_obj_int_get_truncated(addr_o);
|
||||
if ((addr & (align - 1)) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, translate("address %08x is not aligned to %d bytes"), addr, align));
|
||||
mp_raise_ValueError_varg(translate("address %08x is not aligned to %d bytes"), addr, align);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
|
||||
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, translate("empty heap")));
|
||||
mp_raise_IndexError(translate("empty heap"));
|
||||
}
|
||||
mp_obj_t item = heap->items[0];
|
||||
heap->len -= 1;
|
||||
|
@ -57,6 +57,8 @@ typedef struct _ujson_stream_t {
|
||||
int errcode;
|
||||
mp_obj_t python_readinto[2 + 1];
|
||||
mp_obj_array_t bytearray_obj;
|
||||
size_t start;
|
||||
size_t end;
|
||||
byte cur;
|
||||
} ujson_stream_t;
|
||||
|
||||
@ -77,28 +79,44 @@ STATIC byte ujson_stream_next(ujson_stream_t *s) {
|
||||
return s->cur;
|
||||
}
|
||||
|
||||
// We read from an object's `readinto` method in chunks larger than the json
|
||||
// parser needs to reduce the number of function calls done.
|
||||
|
||||
#define CIRCUITPY_JSON_READ_CHUNK_SIZE 64
|
||||
|
||||
STATIC mp_uint_t ujson_python_readinto(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
|
||||
(void) size; // Ignore size because we know it's always 1.
|
||||
ujson_stream_t* s = obj;
|
||||
s->bytearray_obj.items = buf;
|
||||
s->bytearray_obj.len = size;
|
||||
*errcode = 0;
|
||||
mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
|
||||
if (ret == mp_const_none) {
|
||||
*errcode = MP_EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
|
||||
if (s->start == s->end) {
|
||||
*errcode = 0;
|
||||
mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
|
||||
if (ret == mp_const_none) {
|
||||
*errcode = MP_EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
s->start = 0;
|
||||
s->end = mp_obj_get_int(ret);
|
||||
}
|
||||
return mp_obj_get_int(ret);
|
||||
|
||||
*((uint8_t *)buf) = ((uint8_t*) s->bytearray_obj.items)[s->start];
|
||||
s->start++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
|
||||
const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, stream_obj);
|
||||
ujson_stream_t s;
|
||||
uint8_t character_buffer[CIRCUITPY_JSON_READ_CHUNK_SIZE];
|
||||
if (stream_p == NULL) {
|
||||
s.start = 0;
|
||||
s.end = 0;
|
||||
mp_load_method(stream_obj, MP_QSTR_readinto, s.python_readinto);
|
||||
s.bytearray_obj.base.type = &mp_type_bytearray;
|
||||
s.bytearray_obj.typecode = BYTEARRAY_TYPECODE;
|
||||
s.bytearray_obj.len = CIRCUITPY_JSON_READ_CHUNK_SIZE;
|
||||
s.bytearray_obj.free = 0;
|
||||
// len and items are set at read time
|
||||
s.bytearray_obj.items = character_buffer;
|
||||
s.python_readinto[2] = MP_OBJ_FROM_PTR(&s.bytearray_obj);
|
||||
s.stream_obj = &s;
|
||||
s.read = ujson_python_readinto;
|
||||
|
@ -43,7 +43,7 @@ STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
|
||||
mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t no = mp_obj_get_int(no_in);
|
||||
if (no < 0 || no >= self->num_matches) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in));
|
||||
mp_raise_arg1(&mp_type_IndexError, no_in);
|
||||
}
|
||||
|
||||
const char *start = self->caps[no * 2];
|
||||
@ -82,7 +82,7 @@ STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span
|
||||
if (n_args == 2) {
|
||||
no = mp_obj_get_int(args[1]);
|
||||
if (no < 0 || no >= self->num_matches) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, args[1]));
|
||||
mp_raise_arg1(&mp_type_IndexError, args[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,7 +326,7 @@ STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *a
|
||||
}
|
||||
|
||||
if (match_no >= (unsigned int)match->num_matches) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no)));
|
||||
mp_raise_arg1(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
|
||||
}
|
||||
|
||||
const char *start_match = match->caps[match_no * 2];
|
||||
|
@ -179,7 +179,7 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
|
||||
return res;
|
||||
|
||||
error:
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
|
||||
mp_raise_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
|
||||
|
||||
|
@ -22,6 +22,7 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n
|
||||
case Char:
|
||||
if(*sp != *pc++)
|
||||
return 0;
|
||||
/* FALLTHROUGH */
|
||||
case Any:
|
||||
sp++;
|
||||
continue;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 11a7ecff6d76a02644ff23a734b792afaa615e44
|
||||
Subproject commit c4b06e419f3d515478b05bb8ce03ebdb29cddec4
|
@ -123,7 +123,7 @@ DRESULT disk_write (
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
bdev_t pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
@ -133,7 +133,7 @@ DRESULT disk_ioctl (
|
||||
}
|
||||
|
||||
// First part: call the relevant method of the underlying block device
|
||||
mp_obj_t ret = mp_const_none;
|
||||
mp_int_t out_value = 0;
|
||||
if (vfs->flags & FSUSER_HAVE_IOCTL) {
|
||||
// new protocol with ioctl
|
||||
static const uint8_t op_map[8] = {
|
||||
@ -144,9 +144,19 @@ DRESULT disk_ioctl (
|
||||
};
|
||||
uint8_t bp_op = op_map[cmd & 7];
|
||||
if (bp_op != 0) {
|
||||
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op);
|
||||
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
|
||||
ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
|
||||
if (vfs->flags & FSUSER_NATIVE) {
|
||||
bool (*f)(size_t, mp_int_t*) = (void*)(uintptr_t)vfs->u.ioctl[2];
|
||||
if (!f(bp_op, (mp_int_t*) &out_value)) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
} else {
|
||||
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op);
|
||||
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
|
||||
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
|
||||
if (ret != mp_const_none) {
|
||||
out_value = mp_obj_get_int(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// old protocol with sync and count
|
||||
@ -157,10 +167,13 @@ DRESULT disk_ioctl (
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_SECTOR_COUNT:
|
||||
ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
|
||||
case GET_SECTOR_COUNT: {
|
||||
mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
|
||||
if (ret != mp_const_none) {
|
||||
out_value = mp_obj_get_int(ret);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case GET_SECTOR_SIZE:
|
||||
// old protocol has fixed sector size of 512 bytes
|
||||
break;
|
||||
@ -177,16 +190,16 @@ DRESULT disk_ioctl (
|
||||
return RES_OK;
|
||||
|
||||
case GET_SECTOR_COUNT: {
|
||||
*((DWORD*)buff) = mp_obj_get_int(ret);
|
||||
*((DWORD*)buff) = out_value;
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
case GET_SECTOR_SIZE: {
|
||||
if (ret == mp_const_none) {
|
||||
if (out_value == 0) {
|
||||
// Default sector size
|
||||
*((WORD*)buff) = 512;
|
||||
} else {
|
||||
*((WORD*)buff) = mp_obj_get_int(ret);
|
||||
*((WORD*)buff) = out_value;
|
||||
}
|
||||
#if _MAX_SS != _MIN_SS
|
||||
// need to store ssize because we use it in disk_read/disk_write
|
||||
@ -202,7 +215,7 @@ DRESULT disk_ioctl (
|
||||
case IOCTL_INIT:
|
||||
case IOCTL_STATUS: {
|
||||
DSTATUS stat;
|
||||
if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
|
||||
if (out_value != 0) {
|
||||
// error initialising
|
||||
stat = STA_NOINIT;
|
||||
} else if (vfs->writeblocks[0] == MP_OBJ_NULL) {
|
||||
|
@ -24,7 +24,7 @@ typedef struct _mp_obj_vfs_posix_file_t {
|
||||
#ifdef MICROPY_CPYTHON_COMPAT
|
||||
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
|
||||
if (o->fd < 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, translate("I/O operation on closed file")));
|
||||
mp_raise_ValueError(translate("I/O operation on closed file"));
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 41f7a3530d4cacdbf668399d3a015ea29c7e169b
|
||||
Subproject commit 8bb1210eebed4846dae7e76ff1db86a010b132bc
|
@ -1 +1 @@
|
||||
Subproject commit 209edd164eb640a8ced561a54505792fc99a67b9
|
||||
Subproject commit ce30b04a3c8e557d48a0607ddcb25272b196a433
|
@ -1 +1 @@
|
||||
Subproject commit 5d81a9ea822a85e46be4a512ac44abf21e77d816
|
||||
Subproject commit 4f5dc66d50e43ca8d413ab0d86c125a7a13d394f
|
@ -1 +1 @@
|
||||
Subproject commit 01f3f6674b4493ba29b857e0f43deb69975736ec
|
||||
Subproject commit fce466bd2bb70ca86b79e5cb36bbaca00afacfd1
|
@ -1 +1 @@
|
||||
Subproject commit 9fe8f314c032cee89b9ad7697d61e9cba76431ff
|
||||
Subproject commit bea5d4a347aeece71a421ee292551264e3bf7ae2
|
@ -1 +1 @@
|
||||
Subproject commit f1cc47f024b27e670b9bf2a51c89e32f93c1b957
|
||||
Subproject commit fee951908cc5f1ba7db5edd2537fade09d626730
|
@ -1 +1 @@
|
||||
Subproject commit 434e5b5346cb0a1a9eb15989b00278be87cb2ff1
|
||||
Subproject commit 608291801ce7112b280d32518de79993cc80963a
|
1
frozen/Adafruit_CircuitPython_RFM69
Submodule
1
frozen/Adafruit_CircuitPython_RFM69
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c0b9bdf22997552396abb514a6304d33460c2912
|
1
frozen/Adafruit_CircuitPython_RFM9x
Submodule
1
frozen/Adafruit_CircuitPython_RFM9x
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 4696e07638eff28392b57162d2a70e20473e97b7
|
@ -1 +1 @@
|
||||
Subproject commit 6143ec2a96a6d218041e9cab5968de26702d7bbf
|
||||
Subproject commit dd7cc167c528a94a9feed81f9c52b5d372f68258
|
@ -1 +1 @@
|
||||
Subproject commit 43017e30a1e772b67ac68293a944e863c031e389
|
||||
Subproject commit c070f6e8dbc37757cbcb444269c6cd6a4b676647
|
@ -1 +1 @@
|
||||
Subproject commit 88738da275a83acabb14b7140d1c79b33cdc7b02
|
||||
Subproject commit 9d91ec849efb5fbc3d26d350a75a61f15d19bc48
|
@ -1 +1 @@
|
||||
Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223
|
||||
Subproject commit 40d8a03b4569d566faa62fcb0f798178118f2954
|
@ -1 +1 @@
|
||||
Subproject commit 87755e088150cc9bce42f4104cbd74d91b923c6f
|
||||
Subproject commit a14da2e1ced1010a0da65f758199ff08eedd0bd5
|
@ -144,7 +144,7 @@ int readline_process_char(int c) {
|
||||
goto right_arrow_key;
|
||||
} else if (c == CHAR_CTRL_K) {
|
||||
// CTRL-K is kill from cursor to end-of-line, inclusive
|
||||
vstr_cut_tail_bytes(rl.line, last_line_len - rl.cursor_pos);
|
||||
vstr_cut_tail_bytes(rl.line, rl.line->len - rl.cursor_pos);
|
||||
// set redraw parameters
|
||||
redraw_from_cursor = true;
|
||||
} else if (c == CHAR_CTRL_N) {
|
||||
@ -155,6 +155,7 @@ int readline_process_char(int c) {
|
||||
goto up_arrow_key;
|
||||
} else if (c == CHAR_CTRL_U) {
|
||||
// CTRL-U is kill from beginning-of-line up to cursor
|
||||
cont_chars = count_cont_bytes(rl.line->buf+rl.orig_line_len, rl.line->buf+rl.cursor_pos);
|
||||
vstr_cut_out_bytes(rl.line, rl.orig_line_len, rl.cursor_pos - rl.orig_line_len);
|
||||
// set redraw parameters
|
||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||
@ -342,6 +343,7 @@ left_arrow_key:
|
||||
if (c == '~') {
|
||||
if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') {
|
||||
home_key:
|
||||
cont_chars = count_cont_bytes(rl.line->buf+rl.orig_line_len, rl.line->buf+rl.cursor_pos);
|
||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||
} else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') {
|
||||
end_key:
|
||||
@ -352,7 +354,12 @@ end_key:
|
||||
delete_key:
|
||||
#endif
|
||||
if (rl.cursor_pos < rl.line->len) {
|
||||
vstr_cut_out_bytes(rl.line, rl.cursor_pos, 1);
|
||||
size_t len = 1;
|
||||
while (UTF8_IS_CONT(rl.line->buf[rl.cursor_pos+len]) &&
|
||||
rl.cursor_pos+len < rl.line->len) {
|
||||
len++;
|
||||
}
|
||||
vstr_cut_out_bytes(rl.line, rl.cursor_pos, len);
|
||||
redraw_from_cursor = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164
|
||||
Subproject commit 902c16f49197a8baf5e71ec924a812a86e733a74
|
@ -1 +1 @@
|
||||
Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9
|
||||
Subproject commit 218b80e63ab6ff87c1851e403f08b3d716d68f5e
|
@ -101,7 +101,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
#endif
|
||||
}
|
||||
|
||||
// If the code was loaded from a file its likely to be running for a while so we'll long
|
||||
// If the code was loaded from a file it's likely to be running for a while so we'll long
|
||||
// live it and collect any garbage before running.
|
||||
if (input_kind == MP_PARSE_FILE_INPUT) {
|
||||
module_fun = make_obj_long_lived(module_fun, 6);
|
||||
@ -113,6 +113,8 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
start = mp_hal_ticks_ms();
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||
// Handle any ctrl-c interrupt that arrived just in time
|
||||
mp_handle_pending();
|
||||
nlr_pop();
|
||||
ret = 0;
|
||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||
@ -130,6 +132,10 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
|
||||
// at the moment, the value of SystemExit is unused
|
||||
ret = pyexec_system_exit;
|
||||
#if CIRCUITPY_ALARM
|
||||
} else if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_DeepSleepRequest)) {
|
||||
ret = PYEXEC_DEEP_SLEEP;
|
||||
#endif
|
||||
} else {
|
||||
if ((mp_obj_t) nlr.ret_val != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
|
@ -49,6 +49,7 @@ extern int pyexec_system_exit;
|
||||
#define PYEXEC_FORCED_EXIT (0x100)
|
||||
#define PYEXEC_SWITCH_MODE (0x200)
|
||||
#define PYEXEC_EXCEPTION (0x400)
|
||||
#define PYEXEC_DEEP_SLEEP (0x800)
|
||||
|
||||
int pyexec_raw_repl(void);
|
||||
int pyexec_friendly_repl(void);
|
||||
|
960
locale/ID.po
960
locale/ID.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
818
locale/cs.po
818
locale/cs.po
File diff suppressed because it is too large
Load Diff
941
locale/de_DE.po
941
locale/de_DE.po
File diff suppressed because it is too large
Load Diff
3870
locale/el.po
Normal file
3870
locale/el.po
Normal file
File diff suppressed because it is too large
Load Diff
1054
locale/es.po
1054
locale/es.po
File diff suppressed because it is too large
Load Diff
760
locale/fil.po
760
locale/fil.po
File diff suppressed because it is too large
Load Diff
1275
locale/fr.po
1275
locale/fr.po
File diff suppressed because it is too large
Load Diff
742
locale/hi.po
742
locale/hi.po
File diff suppressed because it is too large
Load Diff
758
locale/it_IT.po
758
locale/it_IT.po
File diff suppressed because it is too large
Load Diff
1611
locale/ja.po
1611
locale/ja.po
File diff suppressed because it is too large
Load Diff
757
locale/ko.po
757
locale/ko.po
File diff suppressed because it is too large
Load Diff
907
locale/nl.po
907
locale/nl.po
File diff suppressed because it is too large
Load Diff
1044
locale/pl.po
1044
locale/pl.po
File diff suppressed because it is too large
Load Diff
918
locale/pt_BR.po
918
locale/pt_BR.po
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user