Compare commits

...

20 Commits

Author SHA1 Message Date
Gilles Boccon-Gibod
4a60df108a Merge pull request #447 from BenjaminLawson/bump-rootcanal
Bump rootcanal to 1.9.0
2024-03-14 14:00:36 -07:00
Ben Lawson
ad48109748 Bump rootcanal to 1.9.0 2024-03-14 13:15:02 -07:00
Gilles Boccon-Gibod
44c51c13ac Merge pull request #445 from google/gbg/driver-probe-fix
fix intel driver probe
2024-03-12 12:51:08 -07:00
Gilles Boccon-Gibod
7507be1eab update metadata when setting the host controller directly 2024-03-12 11:50:47 -07:00
Gilles Boccon-Gibod
cbe9446dcf fix intel driver probe 2024-03-12 09:54:20 -07:00
Charlie Boutier
174930399a intel: send vsc INTEL_DDC_CONFIG_WRITE
This VSC enable host-initiated role-switching after connection.

Implement this VSC in a driver fashion.

Test: avatar security_test with the Bluetooth Dongle Intel BE200
2024-03-11 09:15:18 -07:00
Gilles Boccon-Gibod
1f3aee5566 Merge pull request #438 from BenjaminLawson/pandora-extended-advertising
Implement Pandora extended advertising
2024-03-07 20:36:56 -08:00
Ben Lawson
256044a789 Implement Pandora extended advertising
Support setting the PHY of Pandora scans.
2024-03-07 16:18:49 -08:00
Gilles Boccon-Gibod
e554bd1033 Merge pull request #434 from google/gbg/show-timestamps
show timestamps from snoop logs
2024-02-29 11:44:23 -08:00
Gilles Boccon-Gibod
38981cefa1 pad index field 2024-02-28 11:46:35 -08:00
Gilles Boccon-Gibod
f2d601f411 show timestamps from snoop logs 2024-02-27 16:40:37 -08:00
zxzxwu
6e7c64c1de Merge pull request #431 from zxzxwu/rust
Bump Rust to 1.76.0
2024-02-23 15:14:30 +08:00
Josh Wu
565d51f4db Bump Rust to 1.76.0
```
error: failed to compile `cargo-all-features v1.10.0`, intermediate artifacts can be found at `/tmp/cargo-installshCmAG`

Caused by:
  package `clap v4.5.1` cannot be built because it requires rustc 1.74 or newer, while the currently active rustc version is 1.70.0
  Try re-running cargo install with `--locked`

```
2024-02-22 15:22:20 +08:00
Gilles Boccon-Gibod
de8f3d9c1e Merge pull request #426 from akuker/patch-1
Add clarification to short circuit list feature
2024-02-12 21:22:14 -08:00
Tony Kuker
cde6d48690 Add clarification to short circuit list feature 2024-02-12 12:22:36 -06:00
zxzxwu
02180088b3 Merge pull request #425 from zxzxwu/command
Refactor command supporting list
2024-02-07 21:45:52 +08:00
zxzxwu
90f49267d1 Merge pull request #424 from zxzxwu/adv
Fix double-disable legacy advertising set
2024-02-06 16:13:51 +08:00
Josh Wu
0e6d69cd7b Refactor command supporting list 2024-02-06 12:06:00 +08:00
Josh Wu
9eccc583d5 Fix double-disable legacy advertising set
When legacy advertising set is disabled passively(by set termination),
the legacy advertising set won't be released, and the next
stop_advertising() call will try to disable it again and cause an error.
2024-02-06 12:00:30 +08:00
Gilles Boccon-Gibod
f4aeaa6eb3 Merge pull request #422 from google/gbg/bench-rfcomm-params
add rfcomm options and fix l2cap mtu negotiation
2024-02-05 09:14:16 -08:00
15 changed files with 671 additions and 604 deletions

View File

@@ -47,7 +47,7 @@ jobs:
strategy:
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11" ]
rust-version: [ "1.70.0", "stable" ]
rust-version: [ "1.76.0", "stable" ]
fail-fast: false
steps:
- name: Check out from Git

3
.gitignore vendored
View File

@@ -9,6 +9,9 @@ __pycache__
# generated by setuptools_scm
bumble/_version.py
.vscode/launch.json
.vscode/settings.json
/.idea
venv/
.venv/
# snoop logs
out/

View File

@@ -15,7 +15,11 @@
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import datetime
import logging
import os
import struct
import click
from bumble.colors import color
@@ -24,6 +28,14 @@ from bumble.transport.common import PacketReader
from bumble.helpers import PacketTracer
# -----------------------------------------------------------------------------
# Logging
# -----------------------------------------------------------------------------
logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# Classes
# -----------------------------------------------------------------------------
class SnoopPacketReader:
'''
@@ -36,12 +48,18 @@ class SnoopPacketReader:
DATALINK_BSCP = 1003
DATALINK_H5 = 1004
IDENTIFICATION_PATTERN = b'btsnoop\0'
TIMESTAMP_ANCHOR = datetime.datetime(2000, 1, 1)
TIMESTAMP_DELTA = 0x00E03AB44A676000
ONE_MICROSECOND = datetime.timedelta(microseconds=1)
def __init__(self, source):
self.source = source
self.at_end = False
# Read the header
identification_pattern = source.read(8)
if identification_pattern.hex().lower() != '6274736e6f6f7000':
if identification_pattern != self.IDENTIFICATION_PATTERN:
raise ValueError(
'not a valid snoop file, unexpected identification pattern'
)
@@ -55,19 +73,32 @@ class SnoopPacketReader:
# Read the record header
header = self.source.read(24)
if len(header) < 24:
return (0, None)
self.at_end = True
return (None, 0, None)
# Parse the header
(
original_length,
included_length,
packet_flags,
_cumulative_drops,
_timestamp_seconds,
_timestamp_microsecond,
) = struct.unpack('>IIIIII', header)
timestamp,
) = struct.unpack('>IIIIQ', header)
# Abort on truncated packets
# Skip truncated packets
if original_length != included_length:
return (0, None)
print(
color(
f"!!! truncated packet ({included_length}/{original_length})", "red"
)
)
self.source.read(included_length)
return (None, 0, None)
# Convert the timestamp to a datetime object.
ts_dt = self.TIMESTAMP_ANCHOR + datetime.timedelta(
microseconds=timestamp - self.TIMESTAMP_DELTA
)
if self.data_link_type == self.DATALINK_H1:
# The packet is un-encapsulated, look at the flags to figure out its type
@@ -89,7 +120,17 @@ class SnoopPacketReader:
bytes([packet_type]) + self.source.read(included_length),
)
return (packet_flags & 1, self.source.read(included_length))
return (ts_dt, packet_flags & 1, self.source.read(included_length))
# -----------------------------------------------------------------------------
class Printer:
def __init__(self):
self.index = 0
def print(self, message: str) -> None:
self.index += 1
print(f"[{self.index:8}]{message}")
# -----------------------------------------------------------------------------
@@ -122,24 +163,28 @@ def main(format, vendors, filename):
packet_reader = PacketReader(input)
def read_next_packet():
return (0, packet_reader.next_packet())
return (None, 0, packet_reader.next_packet())
else:
packet_reader = SnoopPacketReader(input)
read_next_packet = packet_reader.next_packet
tracer = PacketTracer(emit_message=print)
printer = Printer()
tracer = PacketTracer(emit_message=printer.print)
while True:
while not packet_reader.at_end:
try:
(direction, packet) = read_next_packet()
if packet is None:
break
tracer.trace(hci.HCI_Packet.from_bytes(packet), direction)
(timestamp, direction, packet) = read_next_packet()
if packet:
tracer.trace(hci.HCI_Packet.from_bytes(packet), direction, timestamp)
else:
printer.print(color("[TRUNCATED]", "red"))
except Exception as error:
logger.exception()
print(color(f'!!! {error}', 'red'))
# -----------------------------------------------------------------------------
if __name__ == '__main__':
logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'WARNING').upper())
main() # pylint: disable=no-value-for-parameter

View File

@@ -2065,7 +2065,9 @@ class Device(CompositeEventEmitter):
"""Stop legacy advertising."""
# Disable advertising
if self.legacy_advertising_set:
await self.legacy_advertising_set.stop()
if self.legacy_advertising_set.enabled:
await self.legacy_advertising_set.stop()
await self.legacy_advertising_set.remove()
self.legacy_advertising_set = None
elif self.legacy_advertiser:
await self.legacy_advertiser.stop()
@@ -2110,6 +2112,20 @@ class Device(CompositeEventEmitter):
Returns:
An AdvertisingSet instance.
"""
# Instantiate default values
if advertising_parameters is None:
advertising_parameters = AdvertisingParameters()
if (
not advertising_parameters.advertising_event_properties.is_legacy
and advertising_data
and scan_response_data
):
raise ValueError(
"Extended advertisements can't have both data and scan \
response data"
)
# Allocate a new handle
try:
advertising_handle = next(
@@ -2123,10 +2139,6 @@ class Device(CompositeEventEmitter):
except StopIteration as exc:
raise RuntimeError("all valid advertising handles already in use") from exc
# Instantiate default values
if advertising_parameters is None:
advertising_parameters = AdvertisingParameters()
# Use the device's random address if a random address is needed but none was
# provided.
if (
@@ -2207,9 +2219,6 @@ class Device(CompositeEventEmitter):
if self.legacy_advertiser:
return True
if self.legacy_advertising_set and self.legacy_advertising_set.enabled:
return True
return any(
advertising_set.enabled
for advertising_set in self.extended_advertising_sets.values()
@@ -2223,7 +2232,7 @@ class Device(CompositeEventEmitter):
scan_window: int = DEVICE_DEFAULT_SCAN_WINDOW, # Scan window in ms
own_address_type: int = OwnAddressType.RANDOM,
filter_duplicates: bool = False,
scanning_phys: Tuple[int, int] = (HCI_LE_1M_PHY, HCI_LE_CODED_PHY),
scanning_phys: List[int] = [HCI_LE_1M_PHY, HCI_LE_CODED_PHY],
) -> None:
# Check that the arguments are legal
if scan_interval < scan_window:
@@ -3541,11 +3550,9 @@ class Device(CompositeEventEmitter):
connection_handle,
number_of_completed_extended_advertising_events,
):
# Legacy advertising set is also one of extended advertising sets.
if not (
advertising_set := (
self.extended_advertising_sets.get(advertising_handle)
or self.legacy_advertising_set
)
advertising_set := self.extended_advertising_sets.get(advertising_handle)
):
logger.warning(f'advertising set {advertising_handle} not found')
return

View File

@@ -25,7 +25,7 @@ import pathlib
import platform
from typing import Dict, Iterable, Optional, Type, TYPE_CHECKING
from . import rtk
from . import rtk, intel
from .common import Driver
if TYPE_CHECKING:
@@ -45,7 +45,7 @@ async def get_driver_for_host(host: Host) -> Optional[Driver]:
found.
If a "driver" HCI metadata entry is present, only that driver class will be probed.
"""
driver_classes: Dict[str, Type[Driver]] = {"rtk": rtk.Driver}
driver_classes: Dict[str, Type[Driver]] = {"rtk": rtk.Driver, "intel": intel.Driver}
probe_list: Iterable[str]
if driver_name := host.hci_metadata.get("driver"):
# Only probe a single driver

70
bumble/drivers/intel.py Normal file
View File

@@ -0,0 +1,70 @@
# Copyright 2024 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
# -----------------------------------------------------------------------------
import logging
from bumble.drivers import common
from bumble.hci import (
hci_vendor_command_op_code, # type: ignore
HCI_Command,
HCI_Reset_Command,
)
# -----------------------------------------------------------------------------
# Logging
# -----------------------------------------------------------------------------
logger = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# HCI Commands
# -----------------------------------------------------------------------------
HCI_INTEL_DDC_CONFIG_WRITE_COMMAND = hci_vendor_command_op_code(0xFC8B) # type: ignore
HCI_INTEL_DDC_CONFIG_WRITE_PAYLOAD = [0x03, 0xE4, 0x02, 0x00]
HCI_Command.register_commands(globals())
@HCI_Command.command( # type: ignore
fields=[("params", "*")],
return_parameters_fields=[
("params", "*"),
],
)
class Hci_Intel_DDC_Config_Write_Command(HCI_Command):
pass
class Driver(common.Driver):
def __init__(self, host):
self.host = host
@classmethod
async def for_host(cls, host): # type: ignore
# Only instantiate this driver if explicitly selected
if host.hci_metadata.get("driver") == "intel":
return cls(host)
return None
async def init_controller(self):
self.host.ready = True
await self.host.send_command(HCI_Reset_Command(), check_result=True)
await self.host.send_command(
Hci_Intel_DDC_Config_Write_Command(
params=HCI_INTEL_DDC_CONFIG_WRITE_PAYLOAD
)
)

View File

@@ -790,538 +790,317 @@ HCI_RANDOM_DEVICE_ADDRESS_TYPE = 0x01
HCI_PUBLIC_IDENTITY_ADDRESS_TYPE = 0x02
HCI_RANDOM_IDENTITY_ADDRESS_TYPE = 0x03
# Supported Commands Flags
# Supported Commands Masks
# See Bluetooth spec @ 6.27 SUPPORTED COMMANDS
HCI_SUPPORTED_COMMANDS_FLAGS = (
# Octet 0
(
HCI_INQUIRY_COMMAND,
HCI_INQUIRY_CANCEL_COMMAND,
HCI_PERIODIC_INQUIRY_MODE_COMMAND,
HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND,
HCI_CREATE_CONNECTION_COMMAND,
HCI_DISCONNECT_COMMAND,
None,
HCI_CREATE_CONNECTION_CANCEL_COMMAND
),
# Octet 1
(
HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
HCI_REJECT_CONNECTION_REQUEST_COMMAND,
HCI_LINK_KEY_REQUEST_REPLY_COMMAND,
HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_PIN_CODE_REQUEST_REPLY_COMMAND,
HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND,
HCI_AUTHENTICATION_REQUESTED_COMMAND
),
# Octet 2
(
HCI_SET_CONNECTION_ENCRYPTION_COMMAND,
HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND,
HCI_LINK_KEY_SELECTION_COMMAND,
HCI_REMOTE_NAME_REQUEST_COMMAND,
HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND,
HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND,
HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND,
HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND
),
# Octet 3
(
HCI_READ_CLOCK_OFFSET_COMMAND,
HCI_READ_LMP_HANDLE_COMMAND,
None,
None,
None,
None,
None,
None
),
# Octet 4
(
None,
HCI_HOLD_MODE_COMMAND,
HCI_SNIFF_MODE_COMMAND,
HCI_EXIT_SNIFF_MODE_COMMAND,
None,
None,
HCI_QOS_SETUP_COMMAND,
HCI_ROLE_DISCOVERY_COMMAND
),
# Octet 5
(
HCI_SWITCH_ROLE_COMMAND,
HCI_READ_LINK_POLICY_SETTINGS_COMMAND,
HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND,
HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
HCI_FLOW_SPECIFICATION_COMMAND,
HCI_SET_EVENT_MASK_COMMAND,
HCI_RESET_COMMAND
),
# Octet 6
(
HCI_SET_EVENT_FILTER_COMMAND,
HCI_FLUSH_COMMAND,
HCI_READ_PIN_TYPE_COMMAND,
HCI_WRITE_PIN_TYPE_COMMAND,
None,
HCI_READ_STORED_LINK_KEY_COMMAND,
HCI_WRITE_STORED_LINK_KEY_COMMAND,
HCI_DELETE_STORED_LINK_KEY_COMMAND
),
# Octet 7
(
HCI_WRITE_LOCAL_NAME_COMMAND,
HCI_READ_LOCAL_NAME_COMMAND,
HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
HCI_READ_PAGE_TIMEOUT_COMMAND,
HCI_WRITE_PAGE_TIMEOUT_COMMAND,
HCI_READ_SCAN_ENABLE_COMMAND,
HCI_WRITE_SCAN_ENABLE_COMMAND
),
# Octet 8
(
HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND,
HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND,
HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND,
HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND,
HCI_READ_AUTHENTICATION_ENABLE_COMMAND,
HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND,
None,
None
),
# Octet 9
(
HCI_READ_CLASS_OF_DEVICE_COMMAND,
HCI_WRITE_CLASS_OF_DEVICE_COMMAND,
HCI_READ_VOICE_SETTING_COMMAND,
HCI_WRITE_VOICE_SETTING_COMMAND,
HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND,
HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND
),
# Octet 10
(
HCI_READ_HOLD_MODE_ACTIVITY_COMMAND,
HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND,
HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND,
HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND,
HCI_HOST_BUFFER_SIZE_COMMAND,
HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND
),
# Octet 11
(
HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND,
HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND,
HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND,
HCI_READ_CURRENT_IAC_LAP_COMMAND,
HCI_WRITE_CURRENT_IAC_LAP_COMMAND,
None,
None,
None
),
# Octet 12
(
None,
HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND,
None,
None,
HCI_READ_INQUIRY_SCAN_TYPE_COMMAND,
HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND,
HCI_READ_INQUIRY_MODE_COMMAND,
HCI_WRITE_INQUIRY_MODE_COMMAND
),
# Octet 13
(
HCI_READ_PAGE_SCAN_TYPE_COMMAND,
HCI_WRITE_PAGE_SCAN_TYPE_COMMAND,
HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
None,
None,
None,
None,
),
# Octet 14
(
None,
None,
None,
HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND,
None,
HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND,
HCI_READ_BUFFER_SIZE_COMMAND
),
# Octet 15
(
None,
HCI_READ_BD_ADDR_COMMAND,
HCI_READ_FAILED_CONTACT_COUNTER_COMMAND,
HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND,
HCI_READ_LINK_QUALITY_COMMAND,
HCI_READ_RSSI_COMMAND,
HCI_READ_AFH_CHANNEL_MAP_COMMAND,
HCI_READ_CLOCK_COMMAND
),
# Octet 16
(
HCI_READ_LOOPBACK_MODE_COMMAND,
HCI_WRITE_LOOPBACK_MODE_COMMAND,
HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND,
HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
None,
None,
),
# Octet 17
(
HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND,
HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND,
HCI_REFRESH_ENCRYPTION_KEY_COMMAND,
None,
HCI_SNIFF_SUBRATING_COMMAND,
HCI_READ_SIMPLE_PAIRING_MODE_COMMAND,
HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND,
HCI_READ_LOCAL_OOB_DATA_COMMAND
),
# Octet 18
(
HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND,
HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND,
HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
None,
None,
None,
HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND
),
# Octet 19
(
HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND,
HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND,
HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND,
HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND,
HCI_ENHANCED_FLUSH_COMMAND,
HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND
),
# Octet 20
(
None,
None,
HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND,
HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND,
None,
None,
None,
),
# Octet 21
(
None,
None,
None,
None,
None,
None,
None,
None,
),
# Octet 22
(
None,
None,
HCI_SET_EVENT_MASK_PAGE_2_COMMAND,
None,
None,
None,
None,
None,
),
# Octet 23
(
HCI_READ_FLOW_CONTROL_MODE_COMMAND,
HCI_WRITE_FLOW_CONTROL_MODE_COMMAND,
HCI_READ_DATA_BLOCK_SIZE_COMMAND,
None,
None,
None,
None,
None,
),
# Octet 24
(
HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND,
None,
None,
None,
None,
HCI_READ_LE_HOST_SUPPORT_COMMAND,
HCI_WRITE_LE_HOST_SUPPORT_COMMAND,
None,
),
# Octet 25
(
HCI_LE_SET_EVENT_MASK_COMMAND,
HCI_LE_READ_BUFFER_SIZE_COMMAND,
HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
None,
HCI_LE_SET_RANDOM_ADDRESS_COMMAND,
HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND,
HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND,
HCI_LE_SET_ADVERTISING_DATA_COMMAND,
),
# Octet 26
(
HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND,
HCI_LE_SET_ADVERTISING_ENABLE_COMMAND,
HCI_LE_SET_SCAN_PARAMETERS_COMMAND,
HCI_LE_SET_SCAN_ENABLE_COMMAND,
HCI_LE_CREATE_CONNECTION_COMMAND,
HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND,
HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND,
HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND
),
# Octet 27
(
HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND,
HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND,
HCI_LE_CONNECTION_UPDATE_COMMAND,
HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND,
HCI_LE_READ_CHANNEL_MAP_COMMAND,
HCI_LE_READ_REMOTE_FEATURES_COMMAND,
HCI_LE_ENCRYPT_COMMAND,
HCI_LE_RAND_COMMAND
),
# Octet 28
(
HCI_LE_ENABLE_ENCRYPTION_COMMAND,
HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND,
HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_LE_READ_SUPPORTED_STATES_COMMAND,
HCI_LE_RECEIVER_TEST_COMMAND,
HCI_LE_TRANSMITTER_TEST_COMMAND,
HCI_LE_TEST_END_COMMAND,
None,
),
# Octet 29
(
None,
None,
None,
HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND,
HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND,
HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND
),
# Octet 30
(
HCI_SET_MWS_SIGNALING_COMMAND,
HCI_SET_MWS_TRANSPORT_LAYER_COMMAND,
HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND,
HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND,
HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND,
HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND,
HCI_TRUNCATED_PAGE_COMMAND,
HCI_TRUNCATED_PAGE_CANCEL_COMMAND
),
# Octet 31
(
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND,
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND,
HCI_START_SYNCHRONIZATION_TRAIN_COMMAND,
HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND,
HCI_SET_RESERVED_LT_ADDR_COMMAND,
HCI_DELETE_RESERVED_LT_ADDR_COMMAND,
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND,
HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND
),
# Octet 32
(
HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND,
HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND,
HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND,
HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND
),
# Octet 33
(
HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND,
HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND,
HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND,
HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND,
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND,
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND,
HCI_LE_SET_DATA_LENGTH_COMMAND,
HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND
),
# Octet 34
(
HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND,
HCI_LE_GENERATE_DHKEY_COMMAND,
HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND,
HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND,
HCI_LE_CLEAR_RESOLVING_LIST_COMMAND,
HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND,
HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND
),
# Octet 35
(
HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND,
HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND,
HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND,
HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND,
HCI_LE_READ_PHY_COMMAND,
HCI_LE_SET_DEFAULT_PHY_COMMAND,
HCI_LE_SET_PHY_COMMAND,
HCI_LE_RECEIVER_TEST_V2_COMMAND
),
# Octet 36
(
HCI_LE_TRANSMITTER_TEST_V2_COMMAND,
HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND,
HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND,
HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND,
HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND,
HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND,
HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND,
HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND,
),
# Octet 37
(
HCI_LE_REMOVE_ADVERTISING_SET_COMMAND,
HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND,
HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND,
HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND,
HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
),
# Octet 38
(
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND,
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND,
HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND,
HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND,
HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND,
HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND,
HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND,
HCI_LE_READ_TRANSMIT_POWER_COMMAND
),
# Octet 39
(
HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND,
HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND,
HCI_LE_SET_PRIVACY_MODE_COMMAND,
HCI_LE_RECEIVER_TEST_V3_COMMAND,
HCI_LE_TRANSMITTER_TEST_V3_COMMAND,
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND,
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND,
HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND,
),
# Octet 40
(
HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND,
HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND,
HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND,
HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND,
HCI_LE_READ_ANTENNA_INFORMATION_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND,
HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND,
HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND
),
# Octet 41
(
HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
HCI_LE_GENERATE_DHKEY_V2_COMMAND,
HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND,
HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND,
HCI_LE_READ_BUFFER_SIZE_V2_COMMAND,
HCI_LE_READ_ISO_TX_SYNC_COMMAND,
HCI_LE_SET_CIG_PARAMETERS_COMMAND
),
# Octet 42
(
HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND,
HCI_LE_CREATE_CIS_COMMAND,
HCI_LE_REMOVE_CIG_COMMAND,
HCI_LE_ACCEPT_CIS_REQUEST_COMMAND,
HCI_LE_REJECT_CIS_REQUEST_COMMAND,
HCI_LE_CREATE_BIG_COMMAND,
HCI_LE_CREATE_BIG_TEST_COMMAND,
HCI_LE_TERMINATE_BIG_COMMAND,
),
# Octet 43
(
HCI_LE_BIG_CREATE_SYNC_COMMAND,
HCI_LE_BIG_TERMINATE_SYNC_COMMAND,
HCI_LE_REQUEST_PEER_SCA_COMMAND,
HCI_LE_SETUP_ISO_DATA_PATH_COMMAND,
HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND,
HCI_LE_ISO_TRANSMIT_TEST_COMMAND,
HCI_LE_ISO_RECEIVE_TEST_COMMAND,
HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND
),
# Octet 44
(
HCI_LE_ISO_TEST_END_COMMAND,
HCI_LE_SET_HOST_FEATURE_COMMAND,
HCI_LE_READ_ISO_LINK_QUALITY_COMMAND,
HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND,
HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND,
HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND,
HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND,
HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND
),
# Octet 45
(
HCI_LE_TRANSMITTER_TEST_V4_COMMAND,
HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND,
HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND,
HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND,
HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND,
HCI_CONFIGURE_DATA_PATH_COMMAND,
HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND,
HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND
),
# Octet 46
(
HCI_LE_SET_DEFAULT_SUBRATE_COMMAND,
HCI_LE_SUBRATE_REQUEST_COMMAND,
HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V2_COMMAND,
None,
None,
HCI_LE_SET_PERIODIC_ADVERTISING_SUBEVENT_DATA_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_RESPONSE_DATA_COMMAND,
HCI_LE_SET_PERIODIC_SYNC_SUBEVENT_COMMAND
),
# Octet 47
(
HCI_LE_EXTENDED_CREATE_CONNECTION_V2_COMMAND,
HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V2_COMMAND,
None,
None,
None,
None,
None,
None,
)
)
HCI_SUPPORTED_COMMANDS_MASKS = {
HCI_INQUIRY_COMMAND : 1 << (0*8+0),
HCI_INQUIRY_CANCEL_COMMAND : 1 << (0*8+1),
HCI_PERIODIC_INQUIRY_MODE_COMMAND : 1 << (0*8+2),
HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND : 1 << (0*8+3),
HCI_CREATE_CONNECTION_COMMAND : 1 << (0*8+4),
HCI_DISCONNECT_COMMAND : 1 << (0*8+5),
HCI_CREATE_CONNECTION_CANCEL_COMMAND : 1 << (0*8+7),
HCI_ACCEPT_CONNECTION_REQUEST_COMMAND : 1 << (1*8+0),
HCI_REJECT_CONNECTION_REQUEST_COMMAND : 1 << (1*8+1),
HCI_LINK_KEY_REQUEST_REPLY_COMMAND : 1 << (1*8+2),
HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (1*8+3),
HCI_PIN_CODE_REQUEST_REPLY_COMMAND : 1 << (1*8+4),
HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (1*8+5),
HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND : 1 << (1*8+6),
HCI_AUTHENTICATION_REQUESTED_COMMAND : 1 << (1*8+7),
HCI_SET_CONNECTION_ENCRYPTION_COMMAND : 1 << (2*8+0),
HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND : 1 << (2*8+1),
HCI_LINK_KEY_SELECTION_COMMAND : 1 << (2*8+2),
HCI_REMOTE_NAME_REQUEST_COMMAND : 1 << (2*8+3),
HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND : 1 << (2*8+4),
HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND : 1 << (2*8+5),
HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND : 1 << (2*8+6),
HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND : 1 << (2*8+7),
HCI_READ_CLOCK_OFFSET_COMMAND : 1 << (3*8+0),
HCI_READ_LMP_HANDLE_COMMAND : 1 << (3*8+1),
HCI_HOLD_MODE_COMMAND : 1 << (4*8+1),
HCI_SNIFF_MODE_COMMAND : 1 << (4*8+2),
HCI_EXIT_SNIFF_MODE_COMMAND : 1 << (4*8+3),
HCI_QOS_SETUP_COMMAND : 1 << (4*8+6),
HCI_ROLE_DISCOVERY_COMMAND : 1 << (4*8+7),
HCI_SWITCH_ROLE_COMMAND : 1 << (5*8+0),
HCI_READ_LINK_POLICY_SETTINGS_COMMAND : 1 << (5*8+1),
HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND : 1 << (5*8+2),
HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND : 1 << (5*8+3),
HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND : 1 << (5*8+4),
HCI_FLOW_SPECIFICATION_COMMAND : 1 << (5*8+5),
HCI_SET_EVENT_MASK_COMMAND : 1 << (5*8+6),
HCI_RESET_COMMAND : 1 << (5*8+7),
HCI_SET_EVENT_FILTER_COMMAND : 1 << (6*8+0),
HCI_FLUSH_COMMAND : 1 << (6*8+1),
HCI_READ_PIN_TYPE_COMMAND : 1 << (6*8+2),
HCI_WRITE_PIN_TYPE_COMMAND : 1 << (6*8+3),
HCI_READ_STORED_LINK_KEY_COMMAND : 1 << (6*8+5),
HCI_WRITE_STORED_LINK_KEY_COMMAND : 1 << (6*8+6),
HCI_DELETE_STORED_LINK_KEY_COMMAND : 1 << (6*8+7),
HCI_WRITE_LOCAL_NAME_COMMAND : 1 << (7*8+0),
HCI_READ_LOCAL_NAME_COMMAND : 1 << (7*8+1),
HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND : 1 << (7*8+2),
HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND : 1 << (7*8+3),
HCI_READ_PAGE_TIMEOUT_COMMAND : 1 << (7*8+4),
HCI_WRITE_PAGE_TIMEOUT_COMMAND : 1 << (7*8+5),
HCI_READ_SCAN_ENABLE_COMMAND : 1 << (7*8+6),
HCI_WRITE_SCAN_ENABLE_COMMAND : 1 << (7*8+7),
HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND : 1 << (8*8+0),
HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND : 1 << (8*8+1),
HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND : 1 << (8*8+2),
HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND : 1 << (8*8+3),
HCI_READ_AUTHENTICATION_ENABLE_COMMAND : 1 << (8*8+4),
HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND : 1 << (8*8+5),
HCI_READ_CLASS_OF_DEVICE_COMMAND : 1 << (9*8+0),
HCI_WRITE_CLASS_OF_DEVICE_COMMAND : 1 << (9*8+1),
HCI_READ_VOICE_SETTING_COMMAND : 1 << (9*8+2),
HCI_WRITE_VOICE_SETTING_COMMAND : 1 << (9*8+3),
HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND : 1 << (9*8+4),
HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND : 1 << (9*8+5),
HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND : 1 << (9*8+6),
HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND : 1 << (9*8+7),
HCI_READ_HOLD_MODE_ACTIVITY_COMMAND : 1 << (10*8+0),
HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND : 1 << (10*8+1),
HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (10*8+2),
HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND : 1 << (10*8+3),
HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND : 1 << (10*8+4),
HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND : 1 << (10*8+5),
HCI_HOST_BUFFER_SIZE_COMMAND : 1 << (10*8+6),
HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND : 1 << (10*8+7),
HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND : 1 << (11*8+0),
HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND : 1 << (11*8+1),
HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND : 1 << (11*8+2),
HCI_READ_CURRENT_IAC_LAP_COMMAND : 1 << (11*8+3),
HCI_WRITE_CURRENT_IAC_LAP_COMMAND : 1 << (11*8+4),
HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND : 1 << (12*8+1),
HCI_READ_INQUIRY_SCAN_TYPE_COMMAND : 1 << (12*8+4),
HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND : 1 << (12*8+5),
HCI_READ_INQUIRY_MODE_COMMAND : 1 << (12*8+6),
HCI_WRITE_INQUIRY_MODE_COMMAND : 1 << (12*8+7),
HCI_READ_PAGE_SCAN_TYPE_COMMAND : 1 << (13*8+0),
HCI_WRITE_PAGE_SCAN_TYPE_COMMAND : 1 << (13*8+1),
HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND : 1 << (13*8+2),
HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND : 1 << (13*8+3),
HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND : 1 << (14*8+3),
HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND : 1 << (14*8+5),
HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND : 1 << (14*8+6),
HCI_READ_BUFFER_SIZE_COMMAND : 1 << (14*8+7),
HCI_READ_BD_ADDR_COMMAND : 1 << (15*8+1),
HCI_READ_FAILED_CONTACT_COUNTER_COMMAND : 1 << (15*8+2),
HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND : 1 << (15*8+3),
HCI_READ_LINK_QUALITY_COMMAND : 1 << (15*8+4),
HCI_READ_RSSI_COMMAND : 1 << (15*8+5),
HCI_READ_AFH_CHANNEL_MAP_COMMAND : 1 << (15*8+6),
HCI_READ_CLOCK_COMMAND : 1 << (15*8+7),
HCI_READ_LOOPBACK_MODE_COMMAND : 1 << (16*8+0),
HCI_WRITE_LOOPBACK_MODE_COMMAND : 1 << (16*8+1),
HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND : 1 << (16*8+2),
HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND : 1 << (16*8+3),
HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND : 1 << (16*8+4),
HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND : 1 << (16*8+5),
HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND : 1 << (17*8+0),
HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND : 1 << (17*8+1),
HCI_REFRESH_ENCRYPTION_KEY_COMMAND : 1 << (17*8+2),
HCI_SNIFF_SUBRATING_COMMAND : 1 << (17*8+4),
HCI_READ_SIMPLE_PAIRING_MODE_COMMAND : 1 << (17*8+5),
HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND : 1 << (17*8+6),
HCI_READ_LOCAL_OOB_DATA_COMMAND : 1 << (17*8+7),
HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (18*8+0),
HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (18*8+1),
HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND : 1 << (18*8+2),
HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND : 1 << (18*8+3),
HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND : 1 << (18*8+7),
HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND : 1 << (19*8+0),
HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (19*8+1),
HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND : 1 << (19*8+2),
HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (19*8+3),
HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND : 1 << (19*8+4),
HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND : 1 << (19*8+5),
HCI_ENHANCED_FLUSH_COMMAND : 1 << (19*8+6),
HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (19*8+7),
HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND : 1 << (20*8+2),
HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (20*8+3),
HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND : 1 << (20*8+4),
HCI_SET_EVENT_MASK_PAGE_2_COMMAND : 1 << (22*8+2),
HCI_READ_FLOW_CONTROL_MODE_COMMAND : 1 << (23*8+0),
HCI_WRITE_FLOW_CONTROL_MODE_COMMAND : 1 << (23*8+1),
HCI_READ_DATA_BLOCK_SIZE_COMMAND : 1 << (23*8+2),
HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (24*8+0),
HCI_READ_LE_HOST_SUPPORT_COMMAND : 1 << (24*8+5),
HCI_WRITE_LE_HOST_SUPPORT_COMMAND : 1 << (24*8+6),
HCI_LE_SET_EVENT_MASK_COMMAND : 1 << (25*8+0),
HCI_LE_READ_BUFFER_SIZE_COMMAND : 1 << (25*8+1),
HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND : 1 << (25*8+2),
HCI_LE_SET_RANDOM_ADDRESS_COMMAND : 1 << (25*8+4),
HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND : 1 << (25*8+5),
HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND : 1 << (25*8+6),
HCI_LE_SET_ADVERTISING_DATA_COMMAND : 1 << (25*8+7),
HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND : 1 << (26*8+0),
HCI_LE_SET_ADVERTISING_ENABLE_COMMAND : 1 << (26*8+1),
HCI_LE_SET_SCAN_PARAMETERS_COMMAND : 1 << (26*8+2),
HCI_LE_SET_SCAN_ENABLE_COMMAND : 1 << (26*8+3),
HCI_LE_CREATE_CONNECTION_COMMAND : 1 << (26*8+4),
HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND : 1 << (26*8+5),
HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND : 1 << (26*8+6),
HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND : 1 << (26*8+7),
HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND : 1 << (27*8+0),
HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND : 1 << (27*8+1),
HCI_LE_CONNECTION_UPDATE_COMMAND : 1 << (27*8+2),
HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND : 1 << (27*8+3),
HCI_LE_READ_CHANNEL_MAP_COMMAND : 1 << (27*8+4),
HCI_LE_READ_REMOTE_FEATURES_COMMAND : 1 << (27*8+5),
HCI_LE_ENCRYPT_COMMAND : 1 << (27*8+6),
HCI_LE_RAND_COMMAND : 1 << (27*8+7),
HCI_LE_ENABLE_ENCRYPTION_COMMAND : 1 << (28*8+0),
HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND : 1 << (28*8+1),
HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (28*8+2),
HCI_LE_READ_SUPPORTED_STATES_COMMAND : 1 << (28*8+3),
HCI_LE_RECEIVER_TEST_COMMAND : 1 << (28*8+4),
HCI_LE_TRANSMITTER_TEST_COMMAND : 1 << (28*8+5),
HCI_LE_TEST_END_COMMAND : 1 << (28*8+6),
HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND : 1 << (29*8+3),
HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND : 1 << (29*8+4),
HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND : 1 << (29*8+5),
HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND : 1 << (29*8+6),
HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND : 1 << (29*8+7),
HCI_SET_MWS_SIGNALING_COMMAND : 1 << (30*8+0),
HCI_SET_MWS_TRANSPORT_LAYER_COMMAND : 1 << (30*8+1),
HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND : 1 << (30*8+2),
HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND : 1 << (30*8+3),
HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND : 1 << (30*8+4),
HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND : 1 << (30*8+5),
HCI_TRUNCATED_PAGE_COMMAND : 1 << (30*8+6),
HCI_TRUNCATED_PAGE_CANCEL_COMMAND : 1 << (30*8+7),
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND : 1 << (31*8+0),
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND : 1 << (31*8+1),
HCI_START_SYNCHRONIZATION_TRAIN_COMMAND : 1 << (31*8+2),
HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND : 1 << (31*8+3),
HCI_SET_RESERVED_LT_ADDR_COMMAND : 1 << (31*8+4),
HCI_DELETE_RESERVED_LT_ADDR_COMMAND : 1 << (31*8+5),
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND : 1 << (31*8+6),
HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND : 1 << (31*8+7),
HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND : 1 << (32*8+0),
HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND : 1 << (32*8+1),
HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND : 1 << (32*8+2),
HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND : 1 << (32*8+3),
HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND : 1 << (32*8+4),
HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND : 1 << (32*8+5),
HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND : 1 << (32*8+6),
HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND : 1 << (32*8+7),
HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND : 1 << (33*8+0),
HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND : 1 << (33*8+1),
HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND : 1 << (33*8+2),
HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND : 1 << (33*8+3),
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND : 1 << (33*8+4),
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND : 1 << (33*8+5),
HCI_LE_SET_DATA_LENGTH_COMMAND : 1 << (33*8+6),
HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND : 1 << (33*8+7),
HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND : 1 << (34*8+0),
HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND : 1 << (34*8+1),
HCI_LE_GENERATE_DHKEY_COMMAND : 1 << (34*8+2),
HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND : 1 << (34*8+3),
HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND : 1 << (34*8+4),
HCI_LE_CLEAR_RESOLVING_LIST_COMMAND : 1 << (34*8+5),
HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND : 1 << (34*8+6),
HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND : 1 << (34*8+7),
HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND : 1 << (35*8+0),
HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND : 1 << (35*8+1),
HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND : 1 << (35*8+2),
HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND : 1 << (35*8+3),
HCI_LE_READ_PHY_COMMAND : 1 << (35*8+4),
HCI_LE_SET_DEFAULT_PHY_COMMAND : 1 << (35*8+5),
HCI_LE_SET_PHY_COMMAND : 1 << (35*8+6),
HCI_LE_RECEIVER_TEST_V2_COMMAND : 1 << (35*8+7),
HCI_LE_TRANSMITTER_TEST_V2_COMMAND : 1 << (36*8+0),
HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND : 1 << (36*8+1),
HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND : 1 << (36*8+2),
HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND : 1 << (36*8+3),
HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND : 1 << (36*8+4),
HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND : 1 << (36*8+5),
HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND : 1 << (36*8+6),
HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND : 1 << (36*8+7),
HCI_LE_REMOVE_ADVERTISING_SET_COMMAND : 1 << (37*8+0),
HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND : 1 << (37*8+1),
HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND : 1 << (37*8+2),
HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND : 1 << (37*8+3),
HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND : 1 << (37*8+4),
HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND : 1 << (37*8+5),
HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND : 1 << (37*8+6),
HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND : 1 << (37*8+7),
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND : 1 << (38*8+0),
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND : 1 << (38*8+1),
HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND : 1 << (38*8+2),
HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND : 1 << (38*8+3),
HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND : 1 << (38*8+4),
HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND : 1 << (38*8+5),
HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND : 1 << (38*8+6),
HCI_LE_READ_TRANSMIT_POWER_COMMAND : 1 << (38*8+7),
HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND : 1 << (39*8+0),
HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND : 1 << (39*8+1),
HCI_LE_SET_PRIVACY_MODE_COMMAND : 1 << (39*8+2),
HCI_LE_RECEIVER_TEST_V3_COMMAND : 1 << (39*8+3),
HCI_LE_TRANSMITTER_TEST_V3_COMMAND : 1 << (39*8+4),
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND : 1 << (39*8+5),
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND : 1 << (39*8+6),
HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND : 1 << (39*8+7),
HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND : 1 << (40*8+0),
HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND : 1 << (40*8+1),
HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND : 1 << (40*8+2),
HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND : 1 << (40*8+3),
HCI_LE_READ_ANTENNA_INFORMATION_COMMAND : 1 << (40*8+4),
HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND : 1 << (40*8+5),
HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND : 1 << (40*8+6),
HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND : 1 << (40*8+7),
HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND : 1 << (41*8+0),
HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND : 1 << (41*8+1),
HCI_LE_GENERATE_DHKEY_V2_COMMAND : 1 << (41*8+2),
HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND : 1 << (41*8+3),
HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND : 1 << (41*8+4),
HCI_LE_READ_BUFFER_SIZE_V2_COMMAND : 1 << (41*8+5),
HCI_LE_READ_ISO_TX_SYNC_COMMAND : 1 << (41*8+6),
HCI_LE_SET_CIG_PARAMETERS_COMMAND : 1 << (41*8+7),
HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND : 1 << (42*8+0),
HCI_LE_CREATE_CIS_COMMAND : 1 << (42*8+1),
HCI_LE_REMOVE_CIG_COMMAND : 1 << (42*8+2),
HCI_LE_ACCEPT_CIS_REQUEST_COMMAND : 1 << (42*8+3),
HCI_LE_REJECT_CIS_REQUEST_COMMAND : 1 << (42*8+4),
HCI_LE_CREATE_BIG_COMMAND : 1 << (42*8+5),
HCI_LE_CREATE_BIG_TEST_COMMAND : 1 << (42*8+6),
HCI_LE_TERMINATE_BIG_COMMAND : 1 << (42*8+7),
HCI_LE_BIG_CREATE_SYNC_COMMAND : 1 << (43*8+0),
HCI_LE_BIG_TERMINATE_SYNC_COMMAND : 1 << (43*8+1),
HCI_LE_REQUEST_PEER_SCA_COMMAND : 1 << (43*8+2),
HCI_LE_SETUP_ISO_DATA_PATH_COMMAND : 1 << (43*8+3),
HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND : 1 << (43*8+4),
HCI_LE_ISO_TRANSMIT_TEST_COMMAND : 1 << (43*8+5),
HCI_LE_ISO_RECEIVE_TEST_COMMAND : 1 << (43*8+6),
HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND : 1 << (43*8+7),
HCI_LE_ISO_TEST_END_COMMAND : 1 << (44*8+0),
HCI_LE_SET_HOST_FEATURE_COMMAND : 1 << (44*8+1),
HCI_LE_READ_ISO_LINK_QUALITY_COMMAND : 1 << (44*8+2),
HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (44*8+3),
HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (44*8+4),
HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND : 1 << (44*8+5),
HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND : 1 << (44*8+6),
HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND : 1 << (44*8+7),
HCI_LE_TRANSMITTER_TEST_V4_COMMAND : 1 << (45*8+0),
HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND : 1 << (45*8+1),
HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND : 1 << (45*8+2),
HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND : 1 << (45*8+3),
HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND : 1 << (45*8+4),
HCI_CONFIGURE_DATA_PATH_COMMAND : 1 << (45*8+5),
HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND : 1 << (45*8+6),
HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND : 1 << (45*8+7),
HCI_LE_SET_DEFAULT_SUBRATE_COMMAND : 1 << (46*8+0),
HCI_LE_SUBRATE_REQUEST_COMMAND : 1 << (46*8+1),
HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V2_COMMAND : 1 << (46*8+2),
HCI_LE_SET_PERIODIC_ADVERTISING_SUBEVENT_DATA_COMMAND : 1 << (46*8+5),
HCI_LE_SET_PERIODIC_ADVERTISING_RESPONSE_DATA_COMMAND : 1 << (46*8+6),
HCI_LE_SET_PERIODIC_SYNC_SUBEVENT_COMMAND : 1 << (46*8+7),
HCI_LE_EXTENDED_CREATE_CONNECTION_V2_COMMAND : 1 << (47*8+0),
HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V2_COMMAND : 1 << (47*8+1),
}
# LE Supported Features
# See Bluetooth spec @ Vol 6, Part B, 4.6 FEATURE SUPPORT

View File

@@ -18,6 +18,7 @@
from __future__ import annotations
from collections.abc import Callable, MutableMapping
import datetime
from typing import cast, Any, Optional
import logging
@@ -66,12 +67,13 @@ PSM_NAMES = {
rfcomm.RFCOMM_PSM: 'RFCOMM',
sdp.SDP_PSM: 'SDP',
avdtp.AVDTP_PSM: 'AVDTP',
avctp.AVCTP_PSM: 'AVCTP'
avctp.AVCTP_PSM: 'AVCTP',
# TODO: add more PSM values
}
AVCTP_PID_NAMES = {avrcp.AVRCP_PID: 'AVRCP'}
# -----------------------------------------------------------------------------
class PacketTracer:
class AclStream:
@@ -207,6 +209,7 @@ class PacketTracer:
self.label = label
self.emit_message = emit_message
self.acl_streams = {} # ACL streams, by connection handle
self.packet_timestamp: Optional[datetime.datetime] = None
def start_acl_stream(self, connection_handle: int) -> PacketTracer.AclStream:
logger.info(
@@ -234,7 +237,10 @@ class PacketTracer:
# Let the other forwarder know so it can cleanup its stream as well
self.peer.end_acl_stream(connection_handle)
def on_packet(self, packet: HCI_Packet) -> None:
def on_packet(
self, timestamp: Optional[datetime.datetime], packet: HCI_Packet
) -> None:
self.packet_timestamp = timestamp
self.emit(packet)
if packet.hci_packet_type == HCI_ACL_DATA_PACKET:
@@ -254,13 +260,22 @@ class PacketTracer:
)
def emit(self, message: Any) -> None:
self.emit_message(f'[{self.label}] {message}')
if self.packet_timestamp:
prefix = f"[{self.packet_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')}]"
else:
prefix = ""
self.emit_message(f'{prefix}[{self.label}] {message}')
def trace(self, packet: HCI_Packet, direction: int = 0) -> None:
def trace(
self,
packet: HCI_Packet,
direction: int = 0,
timestamp: Optional[datetime.datetime] = None,
) -> None:
if direction == 0:
self.host_to_controller_analyzer.on_packet(packet)
self.host_to_controller_analyzer.on_packet(timestamp, packet)
else:
self.controller_to_host_analyzer.on_packet(packet)
self.controller_to_host_analyzer.on_packet(timestamp, packet)
def __init__(
self,

View File

@@ -22,7 +22,17 @@ import dataclasses
import logging
import struct
from typing import Any, Awaitable, Callable, Deque, Dict, Optional, cast, TYPE_CHECKING
from typing import (
Any,
Awaitable,
Callable,
Deque,
Dict,
Optional,
Set,
cast,
TYPE_CHECKING,
)
from bumble.colors import color
from bumble.l2cap import L2CAP_PDU
@@ -165,7 +175,7 @@ class Host(AbortableEventEmitter):
self.number_of_supported_advertising_sets = 0
self.maximum_advertising_data_length = 31
self.local_version = None
self.local_supported_commands = bytes(64)
self.local_supported_commands = 0
self.local_le_features = 0
self.local_lmp_features = hci.LmpFeatureMask(0) # Classic LMP features
self.suggested_max_tx_octets = 251 # Max allowed
@@ -232,7 +242,9 @@ class Host(AbortableEventEmitter):
response = await self.send_command(
hci.HCI_Read_Local_Supported_Commands_Command(), check_result=True
)
self.local_supported_commands = response.return_parameters.supported_commands
self.local_supported_commands = int.from_bytes(
response.return_parameters.supported_commands, 'little'
)
if self.supports_command(hci.HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND):
response = await self.send_command(
@@ -486,7 +498,7 @@ class Host(AbortableEventEmitter):
def controller(self, controller) -> None:
self.set_packet_sink(controller)
if controller:
controller.set_packet_sink(self)
self.set_packet_source(controller)
def set_packet_sink(self, sink: Optional[TransportSink]) -> None:
self.hci_sink = sink
@@ -583,31 +595,19 @@ class Host(AbortableEventEmitter):
offset += data_total_length
bytes_remaining -= data_total_length
def supports_command(self, command):
# Find the support flag position for this command
for octet, flags in enumerate(hci.HCI_SUPPORTED_COMMANDS_FLAGS):
for flag_position, value in enumerate(flags):
if value == command:
# Check if the flag is set
if octet < len(self.local_supported_commands) and flag_position < 8:
return (
self.local_supported_commands[octet] & (1 << flag_position)
) != 0
return False
def supports_command(self, op_code: int) -> bool:
return (
self.local_supported_commands
& hci.HCI_SUPPORTED_COMMANDS_MASKS.get(op_code, 0)
) != 0
@property
def supported_commands(self):
commands = []
for octet, flags in enumerate(self.local_supported_commands):
if octet < len(hci.HCI_SUPPORTED_COMMANDS_FLAGS):
for flag in range(8):
if flags & (1 << flag) != 0:
command = hci.HCI_SUPPORTED_COMMANDS_FLAGS[octet][flag]
if command is not None:
commands.append(command)
return commands
def supported_commands(self) -> Set[int]:
return set(
op_code
for op_code, mask in hci.HCI_SUPPORTED_COMMANDS_MASKS.items()
if self.local_supported_commands & mask
)
def supports_le_features(self, feature: hci.LeFeatureMask) -> bool:
return (self.local_le_features & feature) == feature

View File

@@ -34,8 +34,11 @@ from bumble.device import (
DEVICE_DEFAULT_SCAN_INTERVAL,
DEVICE_DEFAULT_SCAN_WINDOW,
Advertisement,
AdvertisingParameters,
AdvertisingEventProperties,
AdvertisingType,
Device,
Phy,
)
from bumble.gatt import Service
from bumble.hci import (
@@ -47,6 +50,7 @@ from bumble.hci import (
from google.protobuf import any_pb2 # pytype: disable=pyi-error
from google.protobuf import empty_pb2 # pytype: disable=pyi-error
from pandora.host_grpc_aio import HostServicer
from pandora import host_pb2
from pandora.host_pb2 import (
NOT_CONNECTABLE,
NOT_DISCOVERABLE,
@@ -94,6 +98,25 @@ SECONDARY_PHY_MAP: Dict[int, SecondaryPhy] = {
3: SECONDARY_CODED,
}
PRIMARY_PHY_TO_BUMBLE_PHY_MAP: Dict[PrimaryPhy, Phy] = {
PRIMARY_1M: Phy.LE_1M,
PRIMARY_CODED: Phy.LE_CODED,
}
SECONDARY_PHY_TO_BUMBLE_PHY_MAP: Dict[SecondaryPhy, Phy] = {
SECONDARY_NONE: Phy.LE_1M,
SECONDARY_1M: Phy.LE_1M,
SECONDARY_2M: Phy.LE_2M,
SECONDARY_CODED: Phy.LE_CODED,
}
OWN_ADDRESS_MAP: Dict[host_pb2.OwnAddressType, bumble.hci.OwnAddressType] = {
host_pb2.PUBLIC: bumble.hci.OwnAddressType.PUBLIC,
host_pb2.RANDOM: bumble.hci.OwnAddressType.RANDOM,
host_pb2.RESOLVABLE_OR_PUBLIC: bumble.hci.OwnAddressType.RESOLVABLE_OR_PUBLIC,
host_pb2.RESOLVABLE_OR_RANDOM: bumble.hci.OwnAddressType.RESOLVABLE_OR_RANDOM,
}
class HostService(HostServicer):
waited_connections: Set[int]
@@ -281,10 +304,113 @@ class HostService(HostServicer):
async def Advertise(
self, request: AdvertiseRequest, context: grpc.ServicerContext
) -> AsyncGenerator[AdvertiseResponse, None]:
if not request.legacy:
raise NotImplementedError(
"TODO: add support for extended advertising in Bumble"
try:
if request.legacy:
async for rsp in self.legacy_advertise(request, context):
yield rsp
else:
async for rsp in self.extended_advertise(request, context):
yield rsp
finally:
pass
async def extended_advertise(
self, request: AdvertiseRequest, context: grpc.ServicerContext
) -> AsyncGenerator[AdvertiseResponse, None]:
advertising_data = bytes(self.unpack_data_types(request.data))
scan_response_data = bytes(self.unpack_data_types(request.scan_response_data))
scannable = len(scan_response_data) != 0
advertising_event_properties = AdvertisingEventProperties(
is_connectable=request.connectable,
is_scannable=scannable,
is_directed=request.target is not None,
is_high_duty_cycle_directed_connectable=False,
is_legacy=False,
is_anonymous=False,
include_tx_power=False,
)
peer_address = Address.ANY
if request.target:
# Need to reverse bytes order since Bumble Address is using MSB.
target_bytes = bytes(reversed(request.target))
if request.target_variant() == "public":
peer_address = Address(target_bytes, Address.PUBLIC_DEVICE_ADDRESS)
else:
peer_address = Address(target_bytes, Address.RANDOM_DEVICE_ADDRESS)
advertising_parameters = AdvertisingParameters(
advertising_event_properties=advertising_event_properties,
own_address_type=OWN_ADDRESS_MAP[request.own_address_type],
peer_address=peer_address,
primary_advertising_phy=PRIMARY_PHY_TO_BUMBLE_PHY_MAP[request.primary_phy],
secondary_advertising_phy=SECONDARY_PHY_TO_BUMBLE_PHY_MAP[
request.secondary_phy
],
)
if advertising_interval := request.interval:
advertising_parameters.primary_advertising_interval_min = int(
advertising_interval
)
advertising_parameters.primary_advertising_interval_max = int(
advertising_interval
)
if interval_range := request.interval_range:
advertising_parameters.primary_advertising_interval_max += int(
interval_range
)
advertising_set = await self.device.create_advertising_set(
advertising_parameters=advertising_parameters,
advertising_data=advertising_data,
scan_response_data=scan_response_data,
)
pending_connection: asyncio.Future[
bumble.device.Connection
] = asyncio.get_running_loop().create_future()
if request.connectable:
def on_connection(connection: bumble.device.Connection) -> None:
if (
connection.transport == BT_LE_TRANSPORT
and connection.role == BT_PERIPHERAL_ROLE
):
pending_connection.set_result(connection)
self.device.on('connection', on_connection)
try:
# Advertise until RPC is canceled
while True:
if not advertising_set.enabled:
self.log.debug('Advertise (extended)')
await advertising_set.start()
if not request.connectable:
await asyncio.sleep(1)
continue
connection = await pending_connection
pending_connection = asyncio.get_running_loop().create_future()
cookie = any_pb2.Any(value=connection.handle.to_bytes(4, 'big'))
yield AdvertiseResponse(connection=Connection(cookie=cookie))
await asyncio.sleep(1)
finally:
try:
self.log.debug('Stop Advertise (extended)')
await advertising_set.stop()
await advertising_set.remove()
except Exception:
pass
async def legacy_advertise(
self, request: AdvertiseRequest, context: grpc.ServicerContext
) -> AsyncGenerator[AdvertiseResponse, None]:
if advertising_interval := request.interval:
self.device.config.advertising_interval_min = int(advertising_interval)
self.device.config.advertising_interval_max = int(advertising_interval)
@@ -422,11 +548,16 @@ class HostService(HostServicer):
self, request: ScanRequest, context: grpc.ServicerContext
) -> AsyncGenerator[ScanningResponse, None]:
# TODO: modify `start_scanning` to accept floats instead of int for ms values
if request.phys:
raise NotImplementedError("TODO: add support for `request.phys`")
self.log.debug('Scan')
scanning_phys = []
if PRIMARY_1M in request.phys:
scanning_phys.append(int(Phy.LE_1M))
if PRIMARY_CODED in request.phys:
scanning_phys.append(int(Phy.LE_CODED))
if not scanning_phys:
scanning_phys = [int(Phy.LE_1M), int(Phy.LE_CODED)]
scan_queue: asyncio.Queue[Advertisement] = asyncio.Queue()
handler = self.device.on('advertisement', scan_queue.put_nowait)
await self.device.start_scanning(
@@ -439,6 +570,7 @@ class HostService(HostServicer):
scan_window=int(request.window)
if request.window
else DEVICE_DEFAULT_SCAN_WINDOW,
scanning_phys=scanning_phys,
)
try:

View File

@@ -168,11 +168,13 @@ class PacketReader:
def __init__(self, source: io.BufferedReader) -> None:
self.source = source
self.at_end = False
def next_packet(self) -> Optional[bytes]:
# Get the packet type
packet_type = self.source.read(1)
if len(packet_type) != 1:
self.at_end = True
return None
# Get the packet info based on its type

View File

@@ -12,12 +12,25 @@ a host that send custom HCI commands that the controller may not understand.
```
python hci_bridge.py <host-transport-spec> <controller-transport-spec> [command-short-circuit-list]
```
The command-short-circuit-list field is specified by a series of comma separated Opcode Group
Field (OGF) : OpCode Command Field (OCF) pairs. The OGF/OCF values are specified in the Blutooth
core specification.
For the commands that are listed in the short-circuit-list, the HCI bridge will always generate
a Command Complete Event for the specified op code. The return parameter will be HCI_SUCCESS.
This feature can only be used for commands that return Command Complete. Other events will not be
generated by the HCI bridge tool.
!!! example "UDP to Serial"
```
python hci_bridge.py udp:0.0.0.0:9000,127.0.0.1:9001 serial:/dev/tty.usbmodem0006839912171,1000000 0x3f:0x0070,0x3f:0x0074,0x3f:0x0077,0x3f:0x0078
```
In this example, the short circuit list is specified to respond to the Vendor-specific Opcode Group
Field (0x3f) commands 0x70, 0x74, 0x77, 0x78 with Command Complete. The short circuit list can be
used where the Host uses some HCI commands that are not supported/implemented by the Controller.
!!! example "PTY to Link Relay"
```
python hci_bridge.py serial:emulated_uart_pty,1000000 link-relay:ws://127.0.0.1:10723/test
@@ -28,3 +41,4 @@ a host that send custom HCI commands that the controller may not understand.
(through which the communication with other virtual controllers will be mediated).
NOTE: this assumes you're running a Link Relay on port `10723`.

View File

@@ -10,7 +10,7 @@ used with particular HCI controller.
When the transport for an HCI controller is instantiated from a transport name,
a driver may also be forced by specifying ``driver=<driver-name>`` in the optional
metadata portion of the transport name. For example,
``usb:[driver=-rtk]0`` indicates that the ``rtk`` driver should be used with the
``usb:[driver=rtk]0`` indicates that the ``rtk`` driver should be used with the
first USB device, even if a normal probe would not have selected it based on the
USB vendor ID and product ID.

View File

@@ -10,7 +10,7 @@ documentation = "https://docs.rs/crate/bumble"
authors = ["Marshall Pierce <marshallpierce@google.com>"]
keywords = ["bluetooth", "ble"]
categories = ["api-bindings", "network-programming"]
rust-version = "1.70.0"
rust-version = "1.76.0"
# https://github.com/frewsxcv/cargo-all-features#options
[package.metadata.cargo-all-features]

View File

@@ -99,7 +99,7 @@ development =
types-protobuf >= 4.21.0
avatar =
pandora-avatar == 0.0.5
rootcanal == 1.7.0 ; python_version>='3.10'
rootcanal == 1.9.0 ; python_version>='3.10'
documentation =
mkdocs >= 1.4.0
mkdocs-material >= 8.5.6