Initialize an instance. address may be a byte array in little-endian
-format, or a hex string in big-endian format (with optional ':'
-separators between the bytes).
-If the address is a string suffixed with '/P', address_type is ignored and the type
-is set to PUBLIC_DEVICE_ADDRESS.
def__init__(self,address,address_type=RANDOM_DEVICE_ADDRESS):
- '''
- Initialize an instance. `address` may be a byte array in little-endian
- format, or a hex string in big-endian format (with optional ':'
- separators between the bytes).
- If the address is a string suffixed with '/P', `address_type` is ignored and the type
- is set to PUBLIC_DEVICE_ADDRESS.
- '''
- iftype(address)isbytes:
- self.address_bytes=address
- else:
- # Check if there's a '/P' type specifier
- ifaddress.endswith('P'):
- address_type=Address.PUBLIC_DEVICE_ADDRESS
- address=address[:-2]
-
- iflen(address)==12+5:
- # Form with ':' separators
- address=address.replace(':','')
- self.address_bytes=bytes(reversed(bytes.fromhex(address)))
-
- iflen(self.address_bytes)!=6:
- raiseValueError('invalid address length')
-
- self.address_type=address_type
-
Initialize an instance. address may be a byte array in little-endian
+format, or a hex string in big-endian format (with optional ':'
+separators between the bytes).
+If the address is a string suffixed with '/P', address_type is ignored and
+the type is set to PUBLIC_DEVICE_ADDRESS.
def__init__(self,address,address_type=RANDOM_DEVICE_ADDRESS):
+ '''
+ Initialize an instance. `address` may be a byte array in little-endian
+ format, or a hex string in big-endian format (with optional ':'
+ separators between the bytes).
+ If the address is a string suffixed with '/P', `address_type` is ignored and
+ the type is set to PUBLIC_DEVICE_ADDRESS.
+ '''
+ ifisinstance(address,bytes):
+ self.address_bytes=address
+ else:
+ # Check if there's a '/P' type specifier
+ ifaddress.endswith('P'):
+ address_type=Address.PUBLIC_DEVICE_ADDRESS
+ address=address[:-2]
+
+ iflen(address)==12+5:
+ # Form with ':' separators
+ address=address.replace(':','')
+ self.address_bytes=bytes(reversed(bytes.fromhex(address)))
+
+ iflen(self.address_bytes)!=6:
+ raiseValueError('invalid address length')
+
+ self.address_type=address_type
+
classHCI_Command(HCI_Packet):''' See Bluetooth spec @ Vol 2, Part E - 5.4.1 HCI Command Packet '''
+
hci_packet_type=HCI_COMMAND_PACKETcommand_classes={}@staticmethod
- defcommand(fields=[],return_parameters_fields=[]):
+ defcommand(fields=(),return_parameters_fields=()):''' Decorator used to declare and register subclasses '''
@@ -1731,8 +1836,10 @@ is set to PUBLIC_DEVICE_ADDRESS.
# Patch the __init__ method to fix the op_codeiffieldsisnotNone:
+
definit(self,parameters=None,**kwargs):returnHCI_Command.__init__(self,cls.op_code,parameters,**kwargs)
+
cls.__init__=init# Register a factory for this class
@@ -1761,8 +1868,8 @@ is set to PUBLIC_DEVICE_ADDRESS.
HCI_Command.__init__(self,op_code,parameters)HCI_Object.init_from_bytes(self,parameters,0,fields)returnself
- else:
- returncls.from_parameters(parameters)
+
+ returncls.from_parameters(parameters)@staticmethoddefcommand_name(op_code):
@@ -1781,12 +1888,15 @@ is set to PUBLIC_DEVICE_ADDRESS.
HCI_Object.init_from_fields(self,fields,kwargs)ifparametersisNone:parameters=HCI_Object.dict_to_bytes(kwargs,fields)
- self.op_code=op_code
+ self.op_code=op_codeself.parameters=parametersdefto_bytes(self):parameters=b''ifself.parametersisNoneelseself.parameters
- returnstruct.pack('<BHB',HCI_COMMAND_PACKET,self.op_code,len(parameters))+parameters
+ return(
+ struct.pack('<BHB',HCI_COMMAND_PACKET,self.op_code,len(parameters))
+ +parameters
+ )def__bytes__(self):returnself.to_bytes()
@@ -1819,7 +1929,7 @@ is set to PUBLIC_DEVICE_ADDRESS.
-command(fields=[],return_parameters_fields=[])
+command(fields=(),return_parameters_fields=())staticmethod
@@ -1834,33 +1944,35 @@ is set to PUBLIC_DEVICE_ADDRESS.
Source code in bumble/hci.py
-
@staticmethod
+defcommand(fields=(),return_parameters_fields=()):''' Decorator used to declare and register subclasses '''
@@ -1875,8 +1987,10 @@ is set to PUBLIC_DEVICE_ADDRESS.
# Patch the __init__ method to fix the op_codeiffieldsisnotNone:
+
definit(self,parameters=None,**kwargs):returnHCI_Command.__init__(self,cls.op_code,parameters,**kwargs)
+
cls.__init__=init# Register a factory for this class
@@ -1914,17 +2028,21 @@ is set to PUBLIC_DEVICE_ADDRESS.
Source code in bumble/hci.py
-
This tool lists all the USB devices, with details about each device.
For each device, the different possible Bumble transport strings that can
-refer to it are listed.
-If the device is known to be a Bluetooth HCI device, its identifier is printed
+refer to it are listed.
+If the device is known to be a Bluetooth HCI device, its identifier is printed
in reverse colors, and the transport names in cyan color.
For other devices, regardless of their type, the transport names are printed
in red. Whether that device is actually a Bluetooth device or not depends on
@@ -1240,12 +1268,12 @@ When installed from PyPI, run as
When running from the source distribution:
$ python3 apps/usb-probe.py
-
or
+
or
$ python3 apps/usb-probe.py --verbose
Example
-
$ python3 apps/usb_probe.py
+
$ python3 apps/usb_probe.py
ID 0A12:0001
Bumble Transport Names: usb:0 or usb:0A12:0001
diff --git a/components/controller.html b/components/controller.html
index 54f9f97e..d6313098 100644
--- a/components/controller.html
+++ b/components/controller.html
@@ -234,6 +234,34 @@
+
+
+
+
+
+
For now, we are configuring the black formatter with the option to leave quotes unchanged.
+The preferred quote style is single quotes, which isn't a configurable option for Black, so we are not enforcing it. This may change in the future.
The adoption of Black as a formatter came in late in the project, with already a large code base. As a result, a large number of files were changed in a single commit, which gets in the way of tracing authorship with git blame. The file git-blame-ignore-revs contains the commit hash of when that mass-formatting event occurred, which you can use to skip it in a git blame analysis:
The project includes a pylint configuration (see the pyproject.toml file for details).
+The pre-commit checks only enforce that there are no errors. But we strongly recommend that you run the linter with warnings enabled at least, and possibly the "Refactor" ('R') and "Convention" ('C') categories as well.
+To run the linter, use the project.lint invoke command.
+
+
Running the linter with default options
+
With the default settings, Errors and Warnings are enabled, but Refactor and Convention categories are not.
+
The project includes a .vscode/settings.json file that specifies the black formatter and enables an editor ruler at 88 columns.
+You may want to configure your own environment to "format on save" with black if you find that useful. We are not making that choice at the workspace level.
To contribute some code to the project, you will need to submit a GitHub Pull Request (a.k.a PR). Please familiarize yourself with how that works (see GitHub Pull Requests)
+
You should follow the project's code style, and pre-check your code before submitting a PR. The GitHub project is set up with some Actions that will check that a PR passes at least the basic tests and complies with the coding style, but it is still recommended to check that for yourself before submitting a PR.
+To run the basic checks (essentially: running the tests, the linter, and the formatter), use the project.pre-commitinvoke command, and address any issues found:
+
$ invoke project.pre-commit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/development/python_environments.html b/development/python_environments.html
index 973c4b82..614d7c8e 100644
--- a/development/python_environments.html
+++ b/development/python_environments.html
@@ -311,6 +311,34 @@
+
+
+
+
+
+
When you don't want to install Bumble in your main/default python environment,
+
When you don't want to install Bumble in your main/default python environment,
using a virtual environment, where the package and its dependencies can be
installed, isolated from the rest, may be useful.
-
There are many flavors of python environments and dependency managers.
+
There are many flavors of python environments and dependency managers.
This page describes a few of the most common ones.
pyenv lets you easily switch between multiple versions of Python. It's simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.
+
pyenv lets you easily switch between multiple versions of Python. It's simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.
Visit the pyenv site for instructions on how to install
and use pyenv
Conda is a convenient package manager and virtual environment.
The file environment.yml is a Conda environment file that you can use to create
a new Conda environment. Once created, you can simply activate this environment when
-working with Bumble.
+working with Bumble.
Visit the Conda site for instructions on how to install
and use Conda.
-A few useful commands:
You need Python 3.8 or above. Python >= 3.9 is recommended, but 3.8 should be sufficient if
necessary (there may be some optional functionality that will not work on some platforms with
-python 3.8).
+python 3.8).
Visit the Python site for instructions on how to install Python
-for your platform.
+for your platform.
Throughout the documentation, when shell commands are shown, it is assumed that you can
invoke Python as
$ python
-If invoking python is different on your platform (it may be python3 for example, or just py or py.exe),
+If invoking python is different on your platform (it may be python3 for example, or just py or py.exe),
adjust accordingly.
-
You may be simply using Bumble as a module for your own application or as a dependency to your own
+
You may be simply using Bumble as a module for your own application or as a dependency to your own
module, or you may be working on modifying or contributing to the Bumble module or example code
itself.
When you work on the Bumble code itself, and run some of the tests or example apps, or import the
-module in your own code, you typically either install the package from source in "development mode" as described above, or you may choose to skip the install phase.
+module in your own code, you typically either install the package from source in "development mode" as described above, or you may choose to skip the install phase.
+
If you plan on contributing to the project, please read the contributing section.
If you prefer not to install the package (even in development mode), you can load the module directly from its location in the project.
+
If you prefer not to install the package (even in development mode), you can load the module directly from its location in the project.
A simple way to do that is to set your PYTHONPATH to
point to the root project directory, where the bumble subdirectory is located. You may set
PYTHONPATH globally, or locally with each command line execution (on Unix-like systems).
-
Example with a global PYTHONPATH, from a unix shell, when the working directory is the root
+
Example with a global PYTHONPATH, from a unix shell, when the working directory is the root
directory of the project.
Once you've installed or downloaded Bumble, you can either start using some of the
+
Once you've installed or downloaded Bumble, you can either start using some of the
Bundled apps and tools, or look at the examples
to get a feel for how to use the APIs, and start writing your own applications.
Depending on the use case you're interested in exploring, you may need to use a physical Bluetooth
controller, like a USB dongle or a board with a Bluetooth radio. Visit the Hardware page
-for more information on using a physical radio, and/or the Transports page for more
+for more information on using a physical radio, and/or the Transports page for more
details on interfacing with either hardware modules or virtual controllers over various transports.
The Bumble Host connects to a controller over an HCI Transport.
-To use a hardware controller attached to the host on which the host application is running, the transport is typically either HCI over UART or HCI over USB.
-On Linux, the VHCI Transport can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the TCP Client transport, the TCP Server transport or the UDP Transport) to an HCI Bridge bridging the network transport to a physical controller on a remote host.
-
In theory, any controller that is compliant with the HCI over UART or HCI over USB protocols can be used.
-
HCI over USB is very common, implemented by a number of commercial Bluetooth dongles.
+
The Bumble Host connects to a controller over an HCI Transport.
+To use a hardware controller attached to the host on which the host application is running, the transport is typically either HCI over UART or HCI over USB.
+On Linux, the VHCI Transport can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the TCP Client transport, the TCP Server transport or the UDP Transport) to an HCI Bridge bridging the network transport to a physical controller on a remote host.
+
In theory, any controller that is compliant with the HCI over UART or HCI over USB protocols can be used.
+
HCI over USB is very common, implemented by a number of commercial Bluetooth dongles.
It is also possible to use an embedded development board, running a specialized application, such as the HCI UART and HCI USB demo applications from the Zephyr project, or the blehci application from mynewt/nimble
Some specific USB dongles and embedded boards that are known to work include:
diff --git a/images/bumble_layers.svg b/images/bumble_layers.svg
index 3da9f583..c0dbca17 100644
--- a/images/bumble_layers.svg
+++ b/images/bumble_layers.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/index.html b/index.html
index e6414431..f0741318 100644
--- a/index.html
+++ b/index.html
@@ -454,6 +454,34 @@
+
+
+
+
+
+
Using Bumble with Android is not about running the Bumble stack on the Android
-OS itself, but rather using Bumble with the Bluetooth support of the Android
+OS itself, but rather using Bumble with the Bluetooth support of the Android
emulator.
The two main use cases are:
Connecting the Bumble host stack to the Android emulator's virtual controller.
-
Using Bumble as an HCI bridge to connect the Android emulator to a physical
+
Using Bumble as an HCI bridge to connect the Android emulator to a physical
Bluetooth controller, such as a USB dongle
@@ -1277,13 +1305,13 @@ be evolving. The information contained here be somewhat out of sync with the
version of the emulator you are using.
You will need version 31.3.8.0 or later.
-
The Android emulator supports Bluetooth in two ways: either by exposing virtual
+
The Android emulator supports Bluetooth in two ways: either by exposing virtual
Bluetooth controllers to which you can connect a virtual Bluetooth host stack, or
by exposing an way to connect your own virtual controller to the Android Bluetooth
stack via a virtual HCI interface.
Both ways are controlled via gRPC requests to the Android emulator.
If the version of the emulator you are running does not yet support enabling
+
If the version of the emulator you are running does not yet support enabling
Bluetooth support by default or automatically, you must launch the emulator from
the command line.
@@ -1299,7 +1327,7 @@ communicate link layer packets between them, thus creating a virtual radio netwo
Configuring a Bumble Device instance to use Root Canal as a virtual controller
allows that virtual device to communicate with the Android Bluetooth stack, and
through it with Android applications as well as system-managed profiles.
-To connect a Bumble host stack to a Root Canal virtual controller instance, use
+To connect a Bumble host stack to a Root Canal virtual controller instance, use
the bumble android-emulator transport in host mode (the default).
Run the example GATT server connected to the emulator
@@ -1330,7 +1358,7 @@ before attaching the virtual controller, then re-enable it once attached.
The show application that's included with Bumble can be used to parse and pretty-print the HCI packets
-from an Android HCI "snoop log" (see this page
+from an Android HCI "snoop log" (see this page
for details on how to obtain HCI snoop logs from an Android device).
Use the --format snoop option to specify that the file is in that specific format.
+
+
+
+
@@ -1432,8 +1460,8 @@ The 3 main types of physical Bluetooth controllers are:
Conflicts with the kernel and BlueZ
If your use a USB dongle that is recognized by your kernel as a supported Bluetooth device, it is
-likely that the kernel driver will claim that USB device and attach it to the BlueZ stack.
-If you want to claim ownership of it to use with Bumble, you will need to set the state of the corresponding HCI interface as DOWN.
+likely that the kernel driver will claim that USB device and attach it to the BlueZ stack.
+If you want to claim ownership of it to use with Bumble, you will need to set the state of the corresponding HCI interface as DOWN.
HCI interfaces are numbered, starting from 0 (i.e hci0, hci1, ...).
For example, to bring hci0 down:
$ sudo hciconfig hci0 down
@@ -1450,7 +1478,7 @@ close it, so you may need to bring the interface back UP before usi
USB Permissions
By default, when running as a regular user, you won't have the permission to use
arbitrary USB devices.
-You can change the permissions for a specific USB device based on its bus number and
+You can change the permissions for a specific USB device based on its bus number and
device number (you can use lsusb to find the Bus and Device numbers for your Bluetooth
dongle).
Example:
@@ -1474,7 +1502,7 @@ You can bring a HCI controller UP or DOWN with h
HCI Socket Permissions
By default, when running as a regular user, you won't have the permission to use
an HCI socket to a Bluetooth controller (you may see an exception like PermissionError: [Errno 1] Operation not permitted).
-
If you want to run without using sudo, you need to manage the capabilities by adding the appropriate entries in /etc/security/capability.conf to grant a user or group the cap_net_admin capability.
+
If you want to run without using sudo, you need to manage the capabilities by adding the appropriate entries in /etc/security/capability.conf to grant a user or group the cap_net_admin capability.
See this manpage for details.
Alternatively, if you are just experimenting temporarily, the capsh command may be useful in order
to execute a single command with enhanced permissions, as in this example:
@@ -1492,20 +1520,20 @@ lists all available HCI controllers and their state.
When the Bluetooth daemon, bluetoothd, is running, it will try to use any HCI controller attached to the BlueZ stack, automatically. This means that whenever an HCI socket transport is released, it is likely that bluetoothd will take it over, so you will get a "device busy" condition (ex: OSError: [Errno 16] Device or resource busy). If that happens, you can always use
+
When the Bluetooth daemon, bluetoothd, is running, it will try to use any HCI controller attached to the BlueZ stack, automatically. This means that whenever an HCI socket transport is released, it is likely that bluetoothd will take it over, so you will get a "device busy" condition (ex: OSError: [Errno 16] Device or resource busy). If that happens, you can always use
$ hciconfig hci0 down
(or hci<X> with <X> being the index of the controller device you want to use), but a simpler solution is to just stop the bluetoothd daemon, with a command like:
@@ -1564,7 +1592,7 @@ In both cases, the controller can run locally on the Linux host, or remotely on
To use a Bluetooth USB dongle on Windows, you need a USB dongle that does not require a vendor Windows driver (the dongle will be used directly through the WinUSB driver rather than through a vendor-supplied Windows driver).
In order to use the dongle, the WinUSB driver must be assigned to the USB device. It is likely that, by default, when you first plug in the dongle, it will be recognized by Windows as a Bluetooth USB device, and Windows will try to use it with its native Bluetooth stack. You will need to switch the driver, which can be done easily with the Zadig tool.
-In the Zadig tool, select your USB dongle device, and associate it with WinUSB.
+In the Zadig tool, select your USB dongle device, and associate it with WinUSB.
Once the WinUSB driver is correctly assigned to your device, you can confirm that by checking the settings with the Windows Device Manager control panel. Your device should appear under "Universal Serial Bus Device" (not under "Bluetooth"), and inspecting the driver details, you should see winusb.sys in the list of driver files.
The Android emulator transport either connects, as a host, to a "Root Canal" virtual controller
("host" mode), or attaches a virtual controller to the Android Bluetooth host stack ("controller" mode).
The moniker syntax for an Android Emulator transport is: android-emulator:[mode=<host|controller>][mode=<host|controller>].
-Both the mode=<host|controller> and mode=<host|controller> parameters are optional (so the moniker android-emulator by itself is a valid moniker, which will create a transport in host mode, connected to localhost on the default gRPC port for the emulator)
+
The moniker syntax for an Android Emulator transport is: android-emulator:[mode=<host|controller>][<hostname>:<port>], where
+the mode parameter can specify running as a host or a controller, and <hostname>:<port> can specify a host name (or IP address) and TCP port number on which to reach the gRPC server for the emulator.
+Both the mode=<host|controller> and <hostname>:<port> parameters are optional (so the moniker android-emulator by itself is a valid moniker, which will create a transport in host mode, connected to localhost on the default gRPC port for the emulator).
Example
-
android-emulator
+
android-emulator
connect as a host to the emulator on localhost:8554
Example
-
android-emulator:mode=controller
+
android-emulator:mode=controller
connect as a controller to the emulator on localhost:8554
Example
-
android-emulator:localhost:8555
+
android-emulator:localhost:8555
connect as a host to the emulator on localhost:8555
The moniker for an HCI Socket transport is either just hci-socket (to use the default/first Bluetooth controller), or hci-socket:<index> where <index> is the 0-based index of a Bluetooth controller device.
Example
-
hci-socket
+
hci-socket
Use an HCI socket to the first Bluetooth controller (hci0 on Linux)
+
+
+
+
@@ -1225,7 +1253,7 @@
Where path, is used, is the path name where a symbolic link to the PTY will be created for convenience (the link will be removed when the transport is closed or when the process exits).
Example
-
pty:virtual_hci
+
pty:virtual_hci
Creates a PTY entry and a symbolic link, named virtual_hci, linking to the PTY
The moniker syntax for a TCP server transport is: tcp-server:<local-host>:<local-port>
-where <local-host> may be the address of a local network interface, or _ to accept
+where <local-host> may be the address of a local network interface, or _ to accept
connections on all local network interfaces.
Example
-
tcp-server:_:9001
+
tcp-server:_:9001
Waits for and accepts connections on port 9001
@@ -1345,9 +1387,9 @@ the first USB interface of the device will be used, regardless of the interface
This may be useful for some devices that use a custom class/subclass but may nonetheless work as-is.
Examples
-
usb:04b4:f901
+
usb:04b4:f901
The USB dongle with <vendor> equal to 04b4 and <product> equal to f901
-
usb:0
+
usb:0
The first Bluetooth HCI dongle that's declared as such by Class/Subclass/Protocol
usb:04b4:f901/0016A45B05D8
The USB dongle with <vendor> equal to 04b4, <product> equal to f901 and <serial> equal to 0016A45B05D8
@@ -1359,6 +1401,9 @@ The BT USB dongle vendor=0B05 and product=17CB, in "forced" mode.
The library includes two different implementations of the USB transport, implemented using different python bindings for libusb.
Using the transport prefix pyusb: instead of usb: selects the implementation based on PyUSB, using the synchronous API of libusb, whereas the default implementation is based on libusb1, using the asynchronous API of libusb. In order to use the alternative PyUSB-based implementation, you need to ensure that you have installed that python module, as it isn't installed by default as a dependency of Bumble.
The libusb-1.0 shared library is required to use both usb and pyusb transports. This library should be installed automatically with Bumble, as part of the libusb_package Python package.
+If your OS or architecture is not supported by libusb_package, you can install a system-wide library with brew install libusb for Mac or apt install libusb-1.0-0 for Linux.
You can use the usb_probe tool to list all the USB devices attached to your host computer.
diff --git a/transports/vhci.html b/transports/vhci.html
index 98135c89..a57e1b32 100644
--- a/transports/vhci.html
+++ b/transports/vhci.html
@@ -234,6 +234,34 @@
+
+
+
+
+
+
The moniker for a VHCI transport is either just vhci (to use the default VHCI device path at /dev/vhci), or vhci:<path> where <path> is the path of a VHCI device.
Example
-
vhci
+
vhci
Attaches a virtual controller transport to /dev/vhci
Connecting an emulated Bluetooth device to a physical controller¶
It can be useful to connect an emulated device (like a phone simulator, or an emulated embedded device) to a physical controller in order to connect to other Bluetooth devices. By doing this via a Bumble HCI bridge, it becomes easy to inspect the HCI packets exchanged with the controller, and possibly filter/change them if needed (for example to support vendor-specific HCI extensions).