diff --git a/apps/show.py b/apps/show.py index 5cd2309e..f849e3a7 100644 --- a/apps/show.py +++ b/apps/show.py @@ -104,7 +104,7 @@ class SnoopPacketReader: ) @click.option( '--vendors', - type=click.Choice(['android']), + type=click.Choice(['android', 'zephyr']), multiple=True, help='Support vendor-specific commands (list one or more)', ) @@ -114,6 +114,8 @@ def main(format, vendors, filename): for vendor in vendors: if vendor == 'android': import bumble.vendor.android.hci + elif vendor == 'zephyr': + import bumble.vendor.zephyr.hci input = open(filename, 'rb') if format == 'h4': diff --git a/bumble/vendor/zephyr/__init__.py b/bumble/vendor/zephyr/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bumble/vendor/zephyr/hci.py b/bumble/vendor/zephyr/hci.py new file mode 100644 index 00000000..9ffb3c35 --- /dev/null +++ b/bumble/vendor/zephyr/hci.py @@ -0,0 +1,88 @@ +# Copyright 2021-2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ----------------------------------------------------------------------------- +# Imports +# ----------------------------------------------------------------------------- +from bumble.hci import ( + hci_vendor_command_op_code, + HCI_Command, + STATUS_SPEC, +) + + +# ----------------------------------------------------------------------------- +# Constants +# ----------------------------------------------------------------------------- + +# Zephyr RTOS Vendor Specific Commands and Events. +# Only a subset of the commands are implemented here currently. +# +# pylint: disable-next=line-too-long +# See https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/bluetooth/hci_vs.h +HCI_WRITE_TX_POWER_LEVEL_COMMAND = hci_vendor_command_op_code(0x000E) +HCI_READ_TX_POWER_LEVEL_COMMAND = hci_vendor_command_op_code(0x000F) + +HCI_Command.register_commands(globals()) + + +# ----------------------------------------------------------------------------- +class TX_Power_Level_Command: + ''' + Base class for read and write TX power level HCI commands + ''' + + TX_POWER_HANDLE_TYPE_ADV = 0x00 + TX_POWER_HANDLE_TYPE_SCAN = 0x01 + TX_POWER_HANDLE_TYPE_CONN = 0x02 + + +# ----------------------------------------------------------------------------- +@HCI_Command.command( + fields=[('handle_type', 1), ('connection_handle', 2), ('tx_power_level', -1)], + return_parameters_fields=[ + ('status', STATUS_SPEC), + ('handle_type', 1), + ('connection_handle', 2), + ('selected_tx_power_level', -1), + ], +) +class HCI_Write_Tx_Power_Level_Command(HCI_Command, TX_Power_Level_Command): + ''' + Write TX power level. See BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL in + https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/bluetooth/hci_vs.h + + Power level is in dB. Connection handle for TX_POWER_HANDLE_TYPE_ADV and + TX_POWER_HANDLE_TYPE_SCAN should be zero. + ''' + + +# ----------------------------------------------------------------------------- +@HCI_Command.command( + fields=[('handle_type', 1), ('connection_handle', 2)], + return_parameters_fields=[ + ('status', STATUS_SPEC), + ('handle_type', 1), + ('connection_handle', 2), + ('tx_power_level', -1), + ], +) +class HCI_Read_Tx_Power_Level_Command(HCI_Command, TX_Power_Level_Command): + ''' + Read TX power level. See BT_HCI_OP_VS_READ_TX_POWER_LEVEL in + https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/bluetooth/hci_vs.h + + Power level is in dB. Connection handle for TX_POWER_HANDLE_TYPE_ADV and + TX_POWER_HANDLE_TYPE_SCAN should be zero. + ''' diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 0cf65f11..82a6f419 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -64,6 +64,7 @@ nav: - Linux: platforms/linux.md - Windows: platforms/windows.md - Android: platforms/android.md + - Zephyr: platforms/zephyr.md - Examples: - Overview: examples/index.md diff --git a/docs/mkdocs/src/platforms/index.md b/docs/mkdocs/src/platforms/index.md index a93e947a..858785f1 100644 --- a/docs/mkdocs/src/platforms/index.md +++ b/docs/mkdocs/src/platforms/index.md @@ -9,3 +9,4 @@ For platform-specific information, see the following pages: * :material-linux: Linux - see the [Linux platform page](linux.md) * :material-microsoft-windows: Windows - see the [Windows platform page](windows.md) * :material-android: Android - see the [Android platform page](android.md) + * :material-memory: Zephyr - see the [Zephyr platform page](zephyr.md) diff --git a/docs/mkdocs/src/platforms/zephyr.md b/docs/mkdocs/src/platforms/zephyr.md new file mode 100644 index 00000000..0e68247f --- /dev/null +++ b/docs/mkdocs/src/platforms/zephyr.md @@ -0,0 +1,51 @@ +:material-memory: ZEPHYR PLATFORM +================================= + +Set TX Power on nRF52840 +------------------------ + +The Nordic nRF52840 supports Zephyr's vendor specific HCI command for setting TX +power during advertising, connection, or scanning. With the example [HCI +USB](https://docs.zephyrproject.org/latest/samples/bluetooth/hci_usb/README.html) +application, an [nRF52840 +dongle](https://www.nordicsemi.com/Products/Development- +hardware/nRF52840-Dongle) can be used as a Bumble controller. + +To add dynamic TX power support to the HCI USB application, add the following to +`zephyr/samples/bluetooth/hci_usb/prj.conf` and build. + +``` +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_CONN_RSSI=y +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y +``` + +Alternatively, a prebuilt firmware application can be downloaded here: +[hci_usb.zip](../downloads/zephyr/hci_usb.zip). + +Put the nRF52840 dongle into bootloader mode by pressing the RESET button. The +LED should pulse red. Load the firmware application with the `nrfutil` tool: + +``` +nrfutil dfu usb-serial -pkg hci_usb.zip -p /dev/ttyACM0 +``` + +The vendor specific HCI commands to read and write TX power are defined in +`bumble/vendor/zephyr/hci.py` and may be used as such: + +```python +from bumble.vendor.zephyr.hci import HCI_Write_Tx_Power_Level_Command + +# set advertising power to -4 dB +response = await host.send_command( + HCI_Write_Tx_Power_Level_Command( + handle_type=HCI_Write_Tx_Power_Level_Command.TX_POWER_HANDLE_TYPE_ADV, + connection_handle=0, + tx_power_level=-4, + ) +) + +if response.return_parameters.status == HCI_SUCCESS: + print(f"TX power set to {response.return_parameters.selected_tx_power_level}") + +```