# Copyright 2021-2022 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 __future__ import annotations import collections import dataclasses from dataclasses import field import enum import functools import logging import secrets import struct from collections.abc import Sequence from typing import Any, Callable, Iterable, Optional, Union, TypeVar, ClassVar, cast from typing_extensions import Self from bumble import crypto from bumble.colors import color from bumble.core import ( DeviceClass, InvalidArgumentError, InvalidPacketError, PhysicalTransport, ProtocolError, bit_flags_to_strings, name_or_number, padded_bytes, ) from bumble import utils # ----------------------------------------------------------------------------- # Logging # ----------------------------------------------------------------------------- logger = logging.getLogger(__name__) # ----------------------------------------------------------------------------- # Utils # ----------------------------------------------------------------------------- def hci_command_op_code(ogf, ocf): return ogf << 10 | ocf def hci_vendor_command_op_code(ocf): return hci_command_op_code(HCI_VENDOR_OGF, ocf) def key_with_value(dictionary, target_value): for key, value in dictionary.items(): if value == target_value: return key return None def indent_lines(string): return '\n'.join([' ' + line for line in string.split('\n')]) def map_null_terminated_utf8_string(utf8_bytes): try: terminator = utf8_bytes.find(0) if terminator < 0: terminator = len(utf8_bytes) return utf8_bytes[0:terminator].decode('utf8') except UnicodeDecodeError: return utf8_bytes def map_class_of_device(class_of_device): ( service_classes, major_device_class, minor_device_class, ) = DeviceClass.split_class_of_device(class_of_device) return ( f'[{class_of_device:06X}] Services(' f'{",".join(DeviceClass.service_class_labels(service_classes))}),' f'Class({DeviceClass.major_device_class_name(major_device_class)}|' f'{DeviceClass.minor_device_class_name(major_device_class, minor_device_class)}' ')' ) def phy_list_to_bits(phys: Optional[Iterable[Phy]]) -> int: if phys is None: return 0 phy_bits = 0 for phy in phys: if phy not in HCI_LE_PHY_TYPE_TO_BIT: raise InvalidArgumentError('invalid PHY') phy_bits |= 1 << HCI_LE_PHY_TYPE_TO_BIT[phy] return phy_bits class SpecableEnum(utils.OpenIntEnum): @classmethod def type_spec(cls, size: int): return {'size': size, 'mapper': lambda x: cls(x).name} @classmethod def type_metadata(cls, size: int, list_begin: bool = False, list_end: bool = False): return metadata(cls.type_spec(size), list_begin=list_begin, list_end=list_end) class SpecableFlag(enum.IntFlag): @classmethod def type_spec(cls, size: int): return {'size': size, 'mapper': lambda x: cls(x).name} @classmethod def type_metadata(cls, size: int, list_begin: bool = False, list_end: bool = False): return metadata(cls.type_spec(size), list_begin=list_begin, list_end=list_end) # ----------------------------------------------------------------------------- # Field Metadata # ----------------------------------------------------------------------------- # Field specification can be: # - a dict with "serializer", "parser", "size", "mapper" keys # - a callable that takes (packet, offset) and returns (new_offset, value) (deserialize only) # - a string of # - ">2" and ">4" for 2-byte and 4-byte big-endian integers # - "*" for all remaining bytes in the packet # - "v" for variable length bytes with a leading length byte # - an integer [1, 4] for 1-byte, 2-byte or 4-byte unsigned little-endian integers # - an integer [-2, -1] for 1-byte, 2-byte signed little-endian integers FieldSpec = Union[dict[str, Any], Callable[[bytes, int], tuple[int, Any]], str, int] Fields = Sequence[Union[tuple[str, FieldSpec], 'Fields']] @dataclasses.dataclass class FieldMetadata: spec: FieldSpec list_begin: bool = False list_end: bool = False def metadata( spec: FieldSpec, list_begin: bool = False, list_end: bool = False ) -> dict[str, Any]: return { "bumble.hci": FieldMetadata(spec=spec, list_begin=list_begin, list_end=list_end) } # ----------------------------------------------------------------------------- # Constants # ----------------------------------------------------------------------------- # fmt: off # pylint: disable=line-too-long HCI_VENDOR_OGF = 0x3F # HCI Version HCI_VERSION_BLUETOOTH_CORE_1_0B = 0 HCI_VERSION_BLUETOOTH_CORE_1_1 = 1 HCI_VERSION_BLUETOOTH_CORE_1_2 = 2 HCI_VERSION_BLUETOOTH_CORE_2_0_EDR = 3 HCI_VERSION_BLUETOOTH_CORE_2_1_EDR = 4 HCI_VERSION_BLUETOOTH_CORE_3_0_HS = 5 HCI_VERSION_BLUETOOTH_CORE_4_0 = 6 HCI_VERSION_BLUETOOTH_CORE_4_1 = 7 HCI_VERSION_BLUETOOTH_CORE_4_2 = 8 HCI_VERSION_BLUETOOTH_CORE_5_0 = 9 HCI_VERSION_BLUETOOTH_CORE_5_1 = 10 HCI_VERSION_BLUETOOTH_CORE_5_2 = 11 HCI_VERSION_BLUETOOTH_CORE_5_3 = 12 HCI_VERSION_BLUETOOTH_CORE_5_4 = 13 HCI_VERSION_BLUETOOTH_CORE_6_0 = 14 HCI_VERSION_NAMES = { HCI_VERSION_BLUETOOTH_CORE_1_0B: 'HCI_VERSION_BLUETOOTH_CORE_1_0B', HCI_VERSION_BLUETOOTH_CORE_1_1: 'HCI_VERSION_BLUETOOTH_CORE_1_1', HCI_VERSION_BLUETOOTH_CORE_1_2: 'HCI_VERSION_BLUETOOTH_CORE_1_2', HCI_VERSION_BLUETOOTH_CORE_2_0_EDR: 'HCI_VERSION_BLUETOOTH_CORE_2_0_EDR', HCI_VERSION_BLUETOOTH_CORE_2_1_EDR: 'HCI_VERSION_BLUETOOTH_CORE_2_1_EDR', HCI_VERSION_BLUETOOTH_CORE_3_0_HS: 'HCI_VERSION_BLUETOOTH_CORE_3_0_HS', HCI_VERSION_BLUETOOTH_CORE_4_0: 'HCI_VERSION_BLUETOOTH_CORE_4_0', HCI_VERSION_BLUETOOTH_CORE_4_1: 'HCI_VERSION_BLUETOOTH_CORE_4_1', HCI_VERSION_BLUETOOTH_CORE_4_2: 'HCI_VERSION_BLUETOOTH_CORE_4_2', HCI_VERSION_BLUETOOTH_CORE_5_0: 'HCI_VERSION_BLUETOOTH_CORE_5_0', HCI_VERSION_BLUETOOTH_CORE_5_1: 'HCI_VERSION_BLUETOOTH_CORE_5_1', HCI_VERSION_BLUETOOTH_CORE_5_2: 'HCI_VERSION_BLUETOOTH_CORE_5_2', HCI_VERSION_BLUETOOTH_CORE_5_3: 'HCI_VERSION_BLUETOOTH_CORE_5_3', HCI_VERSION_BLUETOOTH_CORE_5_4: 'HCI_VERSION_BLUETOOTH_CORE_5_4', HCI_VERSION_BLUETOOTH_CORE_6_0: 'HCI_VERSION_BLUETOOTH_CORE_6_0', } # LMP Version LMP_VERSION_NAMES = HCI_VERSION_NAMES # HCI Packet types HCI_COMMAND_PACKET = 0x01 HCI_ACL_DATA_PACKET = 0x02 HCI_SYNCHRONOUS_DATA_PACKET = 0x03 HCI_EVENT_PACKET = 0x04 HCI_ISO_DATA_PACKET = 0x05 # HCI Event Codes HCI_INQUIRY_COMPLETE_EVENT = 0x01 HCI_INQUIRY_RESULT_EVENT = 0x02 HCI_CONNECTION_COMPLETE_EVENT = 0x03 HCI_CONNECTION_REQUEST_EVENT = 0x04 HCI_DISCONNECTION_COMPLETE_EVENT = 0x05 HCI_AUTHENTICATION_COMPLETE_EVENT = 0x06 HCI_REMOTE_NAME_REQUEST_COMPLETE_EVENT = 0x07 HCI_ENCRYPTION_CHANGE_EVENT = 0x08 HCI_CHANGE_CONNECTION_LINK_KEY_COMPLETE_EVENT = 0x09 HCI_LINK_KEY_TYPE_CHANGED_EVENT = 0x0A HCI_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE_EVENT = 0x0B HCI_READ_REMOTE_VERSION_INFORMATION_COMPLETE_EVENT = 0x0C HCI_QOS_SETUP_COMPLETE_EVENT = 0x0D HCI_COMMAND_COMPLETE_EVENT = 0x0E HCI_COMMAND_STATUS_EVENT = 0x0F HCI_HARDWARE_ERROR_EVENT = 0x10 HCI_FLUSH_OCCURRED_EVENT = 0x11 HCI_ROLE_CHANGE_EVENT = 0x12 HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT = 0x13 HCI_MODE_CHANGE_EVENT = 0x14 HCI_RETURN_LINK_KEYS_EVENT = 0x15 HCI_PIN_CODE_REQUEST_EVENT = 0x16 HCI_LINK_KEY_REQUEST_EVENT = 0x17 HCI_LINK_KEY_NOTIFICATION_EVENT = 0x18 HCI_LOOPBACK_COMMAND_EVENT = 0x19 HCI_DATA_BUFFER_OVERFLOW_EVENT = 0x1A HCI_MAX_SLOTS_CHANGE_EVENT = 0x1B HCI_READ_CLOCK_OFFSET_COMPLETE_EVENT = 0x1C HCI_CONNECTION_PACKET_TYPE_CHANGED_EVENT = 0x1D HCI_QOS_VIOLATION_EVENT = 0x1E HCI_PAGE_SCAN_REPETITION_MODE_CHANGE_EVENT = 0x20 HCI_FLOW_SPECIFICATION_COMPLETE_EVENT = 0x21 HCI_INQUIRY_RESULT_WITH_RSSI_EVENT = 0x22 HCI_READ_REMOTE_EXTENDED_FEATURES_COMPLETE_EVENT = 0x23 HCI_SYNCHRONOUS_CONNECTION_COMPLETE_EVENT = 0x2C HCI_SYNCHRONOUS_CONNECTION_CHANGED_EVENT = 0x2D HCI_SNIFF_SUBRATING_EVENT = 0x2E HCI_EXTENDED_INQUIRY_RESULT_EVENT = 0x2F HCI_ENCRYPTION_KEY_REFRESH_COMPLETE_EVENT = 0x30 HCI_IO_CAPABILITY_REQUEST_EVENT = 0x31 HCI_IO_CAPABILITY_RESPONSE_EVENT = 0x32 HCI_USER_CONFIRMATION_REQUEST_EVENT = 0x33 HCI_USER_PASSKEY_REQUEST_EVENT = 0x34 HCI_REMOTE_OOB_DATA_REQUEST_EVENT = 0x35 HCI_SIMPLE_PAIRING_COMPLETE_EVENT = 0x36 HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT = 0x38 HCI_ENHANCED_FLUSH_COMPLETE_EVENT = 0x39 HCI_USER_PASSKEY_NOTIFICATION_EVENT = 0x3B HCI_KEYPRESS_NOTIFICATION_EVENT = 0x3C HCI_REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION_EVENT = 0x3D HCI_LE_META_EVENT = 0x3E HCI_NUMBER_OF_COMPLETED_DATA_BLOCKS_EVENT = 0x48 HCI_TRIGGERED_CLOCK_CAPTURE_EVENT = 0X4E HCI_SYNCHRONIZATION_TRAIN_COMPLETE_EVENT = 0X4F HCI_SYNCHRONIZATION_TRAIN_RECEIVED_EVENT = 0X50 HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_EVENT = 0X51 HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_TIMEOUT_EVENT = 0X52 HCI_TRUNCATED_PAGE_COMPLETE_EVENT = 0X53 HCI_PERIPHERAL_PAGE_RESPONSE_TIMEOUT_EVENT = 0X54 HCI_CONNECTIONLESS_PERIPHERAL_BROADCAST_CHANNEL_MAP_CHANGE_EVENT = 0X55 HCI_INQUIRY_RESPONSE_NOTIFICATION_EVENT = 0X56 HCI_AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED_EVENT = 0X57 HCI_SAM_STATUS_CHANGE_EVENT = 0X58 HCI_ENCRYPTION_CHANGE_V2_EVENT = 0x59 HCI_VENDOR_EVENT = 0xFF # HCI Subevent Codes HCI_LE_CONNECTION_COMPLETE_EVENT = 0x01 HCI_LE_ADVERTISING_REPORT_EVENT = 0x02 HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT = 0x03 HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT = 0x04 HCI_LE_LONG_TERM_KEY_REQUEST_EVENT = 0x05 HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT = 0x06 HCI_LE_DATA_LENGTH_CHANGE_EVENT = 0x07 HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT = 0x08 HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT = 0x09 HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT = 0x0A HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT = 0x0B HCI_LE_PHY_UPDATE_COMPLETE_EVENT = 0x0C HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT = 0x0D HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT = 0x0E HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT = 0x0F HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT = 0x10 HCI_LE_SCAN_TIMEOUT_EVENT = 0x11 HCI_LE_ADVERTISING_SET_TERMINATED_EVENT = 0x12 HCI_LE_SCAN_REQUEST_RECEIVED_EVENT = 0x13 HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT = 0x14 HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT = 0X15 HCI_LE_CONNECTION_IQ_REPORT_EVENT = 0X16 HCI_LE_CTE_REQUEST_FAILED_EVENT = 0X17 HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED_EVENT = 0X18 HCI_LE_CIS_ESTABLISHED_EVENT = 0X19 HCI_LE_CIS_REQUEST_EVENT = 0X1A HCI_LE_CREATE_BIG_COMPLETE_EVENT = 0X1B HCI_LE_TERMINATE_BIG_COMPLETE_EVENT = 0X1C HCI_LE_BIG_SYNC_ESTABLISHED_EVENT = 0X1D HCI_LE_BIG_SYNC_LOST_EVENT = 0X1E HCI_LE_REQUEST_PEER_SCA_COMPLETE_EVENT = 0X1F HCI_LE_PATH_LOSS_THRESHOLD_EVENT = 0X20 HCI_LE_TRANSMIT_POWER_REPORTING_EVENT = 0X21 HCI_LE_BIGINFO_ADVERTISING_REPORT_EVENT = 0X22 HCI_LE_SUBRATE_CHANGE_EVENT = 0X23 HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_V2_EVENT = 0X24 HCI_LE_PERIODIC_ADVERTISING_REPORT_V2_EVENT = 0X25 HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED_V2_EVENT = 0X26 HCI_LE_PERIODIC_ADVERTISING_SUBEVENT_DATA_REQUEST_EVENT = 0X27 HCI_LE_PERIODIC_ADVERTISING_RESPONSE_REPORT_EVENT = 0X28 HCI_LE_ENHANCED_CONNECTION_COMPLETE_V2_EVENT = 0X29 HCI_LE_READ_ALL_REMOTE_FEATURES_COMPLETE_EVENT = 0x2A HCI_LE_CIS_ESTABLISHED_V2_EVENT = 0x2B HCI_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE_EVENT = 0x2C HCI_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE_EVENT = 0x2D HCI_LE_CS_SECURITY_ENABLE_COMPLETE_EVENT = 0x2E HCI_LE_CS_CONFIG_COMPLETE_EVENT = 0x2F HCI_LE_CS_PROCEDURE_ENABLE_COMPLETE_EVENT = 0x30 HCI_LE_CS_SUBEVENT_RESULT_EVENT = 0x31 HCI_LE_CS_SUBEVENT_RESULT_CONTINUE_EVENT = 0x32 HCI_LE_CS_TEST_END_COMPLETE_EVENT = 0x33 HCI_LE_MONITORED_ADVERTISERS_REPORT_EVENT = 0x34 HCI_LE_FRAME_SPACE_UPDATE_EVENT = 0x35 # HCI Command HCI_INQUIRY_COMMAND = hci_command_op_code(0x01, 0x0001) HCI_INQUIRY_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0002) HCI_PERIODIC_INQUIRY_MODE_COMMAND = hci_command_op_code(0x01, 0x0003) HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND = hci_command_op_code(0x01, 0x0004) HCI_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x0005) HCI_DISCONNECT_COMMAND = hci_command_op_code(0x01, 0x0006) HCI_CREATE_CONNECTION_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0008) HCI_ACCEPT_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0009) HCI_REJECT_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x000A) HCI_LINK_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x000B) HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000C) HCI_PIN_CODE_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x000D) HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x000E) HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND = hci_command_op_code(0x01, 0x000F) HCI_AUTHENTICATION_REQUESTED_COMMAND = hci_command_op_code(0x01, 0x0011) HCI_SET_CONNECTION_ENCRYPTION_COMMAND = hci_command_op_code(0x01, 0x0013) HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND = hci_command_op_code(0x01, 0x0015) HCI_LINK_KEY_SELECTION_COMMAND = hci_command_op_code(0x01, 0x0017) HCI_REMOTE_NAME_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0019) HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND = hci_command_op_code(0x01, 0x001A) HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001B) HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x01, 0x001C) HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x01, 0x001D) HCI_READ_CLOCK_OFFSET_COMMAND = hci_command_op_code(0x01, 0x001F) HCI_READ_LMP_HANDLE_COMMAND = hci_command_op_code(0x01, 0x0020) HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x0028) HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x0029) HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x002A) HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002B) HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002C) HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002D) HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x002E) HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x002F) HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x0030) HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x0033) HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x01, 0x0034) HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND = hci_command_op_code(0x01, 0x003D) HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND = hci_command_op_code(0x01, 0x003E) HCI_TRUNCATED_PAGE_COMMAND = hci_command_op_code(0x01, 0x003F) HCI_TRUNCATED_PAGE_CANCEL_COMMAND = hci_command_op_code(0x01, 0x0040) HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND = hci_command_op_code(0x01, 0x0041) HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND = hci_command_op_code(0x01, 0x0042) HCI_START_SYNCHRONIZATION_TRAIN_COMMAND = hci_command_op_code(0x01, 0x0043) HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND = hci_command_op_code(0x01, 0x0044) HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND = hci_command_op_code(0x01, 0x0045) HCI_HOLD_MODE_COMMAND = hci_command_op_code(0x02, 0x0001) HCI_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0003) HCI_EXIT_SNIFF_MODE_COMMAND = hci_command_op_code(0x02, 0x0004) HCI_QOS_SETUP_COMMAND = hci_command_op_code(0x02, 0x0007) HCI_ROLE_DISCOVERY_COMMAND = hci_command_op_code(0x02, 0x0009) HCI_SWITCH_ROLE_COMMAND = hci_command_op_code(0x02, 0x000B) HCI_READ_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000C) HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000D) HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000E) HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND = hci_command_op_code(0x02, 0x000F) HCI_FLOW_SPECIFICATION_COMMAND = hci_command_op_code(0x02, 0x0010) HCI_SNIFF_SUBRATING_COMMAND = hci_command_op_code(0x02, 0x0011) HCI_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x03, 0x0001) HCI_RESET_COMMAND = hci_command_op_code(0x03, 0x0003) HCI_SET_EVENT_FILTER_COMMAND = hci_command_op_code(0x03, 0x0005) HCI_FLUSH_COMMAND = hci_command_op_code(0x03, 0x0008) HCI_READ_PIN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0009) HCI_WRITE_PIN_TYPE_COMMAND = hci_command_op_code(0x03, 0x000A) HCI_READ_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x000D) HCI_WRITE_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x0011) HCI_DELETE_STORED_LINK_KEY_COMMAND = hci_command_op_code(0x03, 0x0012) HCI_WRITE_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0013) HCI_READ_LOCAL_NAME_COMMAND = hci_command_op_code(0x03, 0x0014) HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0015) HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0016) HCI_READ_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0017) HCI_WRITE_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0018) HCI_READ_SCAN_ENABLE_COMMAND = hci_command_op_code(0x03, 0x0019) HCI_WRITE_SCAN_ENABLE_COMMAND = hci_command_op_code(0x03, 0x001A) HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001B) HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001C) HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001D) HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x001E) HCI_READ_AUTHENTICATION_ENABLE_COMMAND = hci_command_op_code(0x03, 0x001F) HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND = hci_command_op_code(0x03, 0x0020) HCI_READ_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0023) HCI_WRITE_CLASS_OF_DEVICE_COMMAND = hci_command_op_code(0x03, 0x0024) HCI_READ_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0025) HCI_WRITE_VOICE_SETTING_COMMAND = hci_command_op_code(0x03, 0x0026) HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0027) HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0028) HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND = hci_command_op_code(0x03, 0x0029) HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND = hci_command_op_code(0x03, 0x002A) HCI_READ_HOLD_MODE_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x002B) HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND = hci_command_op_code(0x03, 0x002C) HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x002D) HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002E) HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND = hci_command_op_code(0x03, 0x002F) HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND = hci_command_op_code(0x03, 0x0031) HCI_HOST_BUFFER_SIZE_COMMAND = hci_command_op_code(0x03, 0x0033) HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND = hci_command_op_code(0x03, 0x0035) HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0036) HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x0037) HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND = hci_command_op_code(0x03, 0x0038) HCI_READ_CURRENT_IAC_LAP_COMMAND = hci_command_op_code(0x03, 0x0039) HCI_WRITE_CURRENT_IAC_LAP_COMMAND = hci_command_op_code(0x03, 0x003A) HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x03, 0x003F) HCI_READ_INQUIRY_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0042) HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0043) HCI_READ_INQUIRY_MODE_COMMAND = hci_command_op_code(0x03, 0x0044) HCI_WRITE_INQUIRY_MODE_COMMAND = hci_command_op_code(0x03, 0x0045) HCI_READ_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0046) HCI_WRITE_PAGE_SCAN_TYPE_COMMAND = hci_command_op_code(0x03, 0x0047) HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND = hci_command_op_code(0x03, 0x0048) HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND = hci_command_op_code(0x03, 0x0049) HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND = hci_command_op_code(0x03, 0x0051) HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND = hci_command_op_code(0x03, 0x0052) HCI_REFRESH_ENCRYPTION_KEY_COMMAND = hci_command_op_code(0x03, 0x0053) HCI_READ_SIMPLE_PAIRING_MODE_COMMAND = hci_command_op_code(0x03, 0x0055) HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND = hci_command_op_code(0x03, 0x0056) HCI_READ_LOCAL_OOB_DATA_COMMAND = hci_command_op_code(0x03, 0x0057) HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0058) HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0059) HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND = hci_command_op_code(0x03, 0x005A) HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND = hci_command_op_code(0x03, 0x005B) HCI_ENHANCED_FLUSH_COMMAND = hci_command_op_code(0x03, 0x005F) HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND = hci_command_op_code(0x03, 0x0060) HCI_SET_EVENT_MASK_PAGE_2_COMMAND = hci_command_op_code(0x03, 0x0063) HCI_READ_FLOW_CONTROL_MODE_COMMAND = hci_command_op_code(0x03, 0x0066) HCI_WRITE_FLOW_CONTROL_MODE_COMMAND = hci_command_op_code(0x03, 0x0067) HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x03, 0x0068) HCI_READ_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006C) HCI_WRITE_LE_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x006D) HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x006E) HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND = hci_command_op_code(0x03, 0x006F) HCI_SET_MWS_SIGNALING_COMMAND = hci_command_op_code(0x03, 0x0070) HCI_SET_MWS_TRANSPORT_LAYER_COMMAND = hci_command_op_code(0x03, 0x0071) HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND = hci_command_op_code(0x03, 0x0072) HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND = hci_command_op_code(0x03, 0x0073) HCI_SET_RESERVED_LT_ADDR_COMMAND = hci_command_op_code(0x03, 0x0074) HCI_DELETE_RESERVED_LT_ADDR_COMMAND = hci_command_op_code(0x03, 0x0075) HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND = hci_command_op_code(0x03, 0x0076) HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x0077) HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND = hci_command_op_code(0x03, 0x0078) HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x0079) HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND = hci_command_op_code(0x03, 0x007A) HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007B) HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007C) HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND = hci_command_op_code(0x03, 0x007D) HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007E) HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND = hci_command_op_code(0x03, 0x007F) HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND = hci_command_op_code(0x03, 0x0080) HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND = hci_command_op_code(0x03, 0x0081) HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND = hci_command_op_code(0x03, 0x0082) HCI_CONFIGURE_DATA_PATH_COMMAND = hci_command_op_code(0x03, 0x0083) HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND = hci_command_op_code(0x03, 0x0084) HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND = hci_command_op_code(0x04, 0x0001) HCI_READ_LOCAL_SUPPORTED_COMMANDS_COMMAND = hci_command_op_code(0x04, 0x0002) HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0003) HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND = hci_command_op_code(0x04, 0x0004) HCI_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x04, 0x0005) HCI_READ_BD_ADDR_COMMAND = hci_command_op_code(0x04, 0x0009) HCI_READ_DATA_BLOCK_SIZE_COMMAND = hci_command_op_code(0x04, 0x000A) HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND = hci_command_op_code(0x04, 0x000B) HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND = hci_command_op_code(0x04, 0x000C) HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND = hci_command_op_code(0x04, 0x000D) HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND = hci_command_op_code(0x04, 0x000E) HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND = hci_command_op_code(0x04, 0x000F) HCI_READ_FAILED_CONTACT_COUNTER_COMMAND = hci_command_op_code(0x05, 0x0001) HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND = hci_command_op_code(0x05, 0x0002) HCI_READ_LINK_QUALITY_COMMAND = hci_command_op_code(0x05, 0x0003) HCI_READ_RSSI_COMMAND = hci_command_op_code(0x05, 0x0005) HCI_READ_AFH_CHANNEL_MAP_COMMAND = hci_command_op_code(0x05, 0x0006) HCI_READ_CLOCK_COMMAND = hci_command_op_code(0x05, 0x0007) HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND = hci_command_op_code(0x05, 0x0008) HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND = hci_command_op_code(0x05, 0x000C) HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND = hci_command_op_code(0x05, 0x000D) HCI_READ_LOOPBACK_MODE_COMMAND = hci_command_op_code(0x06, 0x0001) HCI_WRITE_LOOPBACK_MODE_COMMAND = hci_command_op_code(0x06, 0x0002) HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND = hci_command_op_code(0x06, 0x0003) HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND = hci_command_op_code(0x06, 0x0004) HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND = hci_command_op_code(0x06, 0x000A) HCI_LE_SET_EVENT_MASK_COMMAND = hci_command_op_code(0x08, 0x0001) HCI_LE_READ_BUFFER_SIZE_COMMAND = hci_command_op_code(0x08, 0x0002) HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0003) HCI_LE_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0005) HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0006) HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND = hci_command_op_code(0x08, 0x0007) HCI_LE_SET_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0008) HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0009) HCI_LE_SET_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000A) HCI_LE_SET_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x000B) HCI_LE_SET_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x000C) HCI_LE_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x000D) HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND = hci_command_op_code(0x08, 0x000E) HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x000F) HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0010) HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0011) HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND = hci_command_op_code(0x08, 0x0012) HCI_LE_CONNECTION_UPDATE_COMMAND = hci_command_op_code(0x08, 0x0013) HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x08, 0x0014) HCI_LE_READ_CHANNEL_MAP_COMMAND = hci_command_op_code(0x08, 0x0015) HCI_LE_READ_REMOTE_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0016) HCI_LE_ENCRYPT_COMMAND = hci_command_op_code(0x08, 0x0017) HCI_LE_RAND_COMMAND = hci_command_op_code(0x08, 0x0018) HCI_LE_ENABLE_ENCRYPTION_COMMAND = hci_command_op_code(0x08, 0x0019) HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x001A) HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x001B) HCI_LE_READ_SUPPORTED_STATES_COMMAND = hci_command_op_code(0x08, 0x001C) HCI_LE_RECEIVER_TEST_COMMAND = hci_command_op_code(0x08, 0x001D) HCI_LE_TRANSMITTER_TEST_COMMAND = hci_command_op_code(0x08, 0x001E) HCI_LE_TEST_END_COMMAND = hci_command_op_code(0x08, 0x001F) HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND = hci_command_op_code(0x08, 0x0020) HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND = hci_command_op_code(0x08, 0x0021) HCI_LE_SET_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0022) HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0023) HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x0024) HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = hci_command_op_code(0x08, 0x0025) HCI_LE_GENERATE_DHKEY_COMMAND = hci_command_op_code(0x08, 0x0026) HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0027) HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0028) HCI_LE_CLEAR_RESOLVING_LIST_COMMAND = hci_command_op_code(0x08, 0x0029) HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x002A) HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002B) HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x002C) HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND = hci_command_op_code(0x08, 0x002D) HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND = hci_command_op_code(0x08, 0x002E) HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x002F) HCI_LE_READ_PHY_COMMAND = hci_command_op_code(0x08, 0x0030) HCI_LE_SET_DEFAULT_PHY_COMMAND = hci_command_op_code(0x08, 0x0031) HCI_LE_SET_PHY_COMMAND = hci_command_op_code(0x08, 0x0032) HCI_LE_RECEIVER_TEST_V2_COMMAND = hci_command_op_code(0x08, 0x0033) HCI_LE_TRANSMITTER_TEST_V2_COMMAND = hci_command_op_code(0x08, 0x0034) HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND = hci_command_op_code(0x08, 0x0035) HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0036) HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x0037) HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0038) HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0039) HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND = hci_command_op_code(0x08, 0x003A) HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003B) HCI_LE_REMOVE_ADVERTISING_SET_COMMAND = hci_command_op_code(0x08, 0x003C) HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND = hci_command_op_code(0x08, 0x003D) HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x003E) HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND = hci_command_op_code(0x08, 0x003F) HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0040) HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0041) HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0042) HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND = hci_command_op_code(0x08, 0x0043) HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0044) HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND = hci_command_op_code(0x08, 0x0045) HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x0046) HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0047) HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0048) HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND = hci_command_op_code(0x08, 0x0049) HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x004A) HCI_LE_READ_TRANSMIT_POWER_COMMAND = hci_command_op_code(0x08, 0x004B) HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004C) HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND = hci_command_op_code(0x08, 0x004D) HCI_LE_SET_PRIVACY_MODE_COMMAND = hci_command_op_code(0x08, 0x004E) HCI_LE_RECEIVER_TEST_V3_COMMAND = hci_command_op_code(0x08, 0x004F) HCI_LE_TRANSMITTER_TEST_V3_COMMAND = hci_command_op_code(0x08, 0x0050) HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0051) HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0052) HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0053) HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0054) HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0055) HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0056) HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0057) HCI_LE_READ_ANTENNA_INFORMATION_COMMAND = hci_command_op_code(0x08, 0x0058) HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0059) HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND = hci_command_op_code(0x08, 0x005A) HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND = hci_command_op_code(0x08, 0x005B) HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x005C) HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x005D) HCI_LE_GENERATE_DHKEY_V2_COMMAND = hci_command_op_code(0x08, 0x005E) HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND = hci_command_op_code(0x08, 0x005F) HCI_LE_READ_BUFFER_SIZE_V2_COMMAND = hci_command_op_code(0x08, 0x0060) HCI_LE_READ_ISO_TX_SYNC_COMMAND = hci_command_op_code(0x08, 0x0061) HCI_LE_SET_CIG_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0062) HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND = hci_command_op_code(0x08, 0x0063) HCI_LE_CREATE_CIS_COMMAND = hci_command_op_code(0x08, 0x0064) HCI_LE_REMOVE_CIG_COMMAND = hci_command_op_code(0x08, 0x0065) HCI_LE_ACCEPT_CIS_REQUEST_COMMAND = hci_command_op_code(0x08, 0x0066) HCI_LE_REJECT_CIS_REQUEST_COMMAND = hci_command_op_code(0x08, 0x0067) HCI_LE_CREATE_BIG_COMMAND = hci_command_op_code(0x08, 0x0068) HCI_LE_CREATE_BIG_TEST_COMMAND = hci_command_op_code(0x08, 0x0069) HCI_LE_TERMINATE_BIG_COMMAND = hci_command_op_code(0x08, 0x006A) HCI_LE_BIG_CREATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x006B) HCI_LE_BIG_TERMINATE_SYNC_COMMAND = hci_command_op_code(0x08, 0x006C) HCI_LE_REQUEST_PEER_SCA_COMMAND = hci_command_op_code(0x08, 0x006D) HCI_LE_SETUP_ISO_DATA_PATH_COMMAND = hci_command_op_code(0x08, 0x006E) HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND = hci_command_op_code(0x08, 0x006F) HCI_LE_ISO_TRANSMIT_TEST_COMMAND = hci_command_op_code(0x08, 0x0070) HCI_LE_ISO_RECEIVE_TEST_COMMAND = hci_command_op_code(0x08, 0x0071) HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND = hci_command_op_code(0x08, 0x0072) HCI_LE_ISO_TEST_END_COMMAND = hci_command_op_code(0x08, 0x0073) HCI_LE_SET_HOST_FEATURE_COMMAND = hci_command_op_code(0x08, 0x0074) HCI_LE_READ_ISO_LINK_QUALITY_COMMAND = hci_command_op_code(0x08, 0x0075) HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x08, 0x0076) HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND = hci_command_op_code(0x08, 0x0077) HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0078) HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0079) HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND = hci_command_op_code(0x08, 0x007A) HCI_LE_TRANSMITTER_TEST_V4_COMMAND = hci_command_op_code(0x08, 0x007B) HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND = hci_command_op_code(0x08, 0x007C) HCI_LE_SET_DEFAULT_SUBRATE_COMMAND = hci_command_op_code(0x08, 0x007D) HCI_LE_SUBRATE_REQUEST_COMMAND = hci_command_op_code(0x08, 0x007E) HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V2_COMMAND = hci_command_op_code(0x08, 0x007F) HCI_LE_SET_DECISION_DATA_COMMAND = hci_command_op_code(0x08, 0x0080) HCI_LE_SET_DECISION_INSTRUCTIONS_COMMAND = hci_command_op_code(0x08, 0x0081) HCI_LE_SET_PERIODIC_ADVERTISING_SUBEVENT_DATA_COMMAND = hci_command_op_code(0x08, 0x0082) HCI_LE_SET_PERIODIC_ADVERTISING_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0083) HCI_LE_SET_PERIODIC_SYNC_SUBEVENT_COMMAND = hci_command_op_code(0x08, 0x0084) HCI_LE_EXTENDED_CREATE_CONNECTION_V2_COMMAND = hci_command_op_code(0x08, 0x0085) HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V2_COMMAND = hci_command_op_code(0x08, 0x0086) HCI_LE_READ_ALL_LOCAL_SUPPORTED_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0087) HCI_LE_READ_ALL_REMOTE_FEATURES_COMMAND = hci_command_op_code(0x08, 0x0088) HCI_LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES_COMMAND = hci_command_op_code(0x08, 0x0089) HCI_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMMAND = hci_command_op_code(0x08, 0x008A) HCI_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES_COMMAND = hci_command_op_code(0x08, 0x008B) HCI_LE_CS_SECURITY_ENABLE_COMMAND = hci_command_op_code(0x08, 0x008C) HCI_LE_CS_SET_DEFAULT_SETTINGS_COMMAND = hci_command_op_code(0x08, 0x008D) HCI_LE_CS_READ_REMOTE_FAE_TABLE_COMMAND = hci_command_op_code(0x08, 0x008E) HCI_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE_COMMAND = hci_command_op_code(0x08, 0x008F) HCI_LE_CS_CREATE_CONFIG_COMMAND = hci_command_op_code(0x08, 0x0090) HCI_LE_CS_REMOVE_CONFIG_COMMAND = hci_command_op_code(0x08, 0x0091) HCI_LE_CS_SET_CHANNEL_CLASSIFICATION_COMMAND = hci_command_op_code(0x08, 0x0092) HCI_LE_CS_SET_PROCEDURE_PARAMETERS_COMMAND = hci_command_op_code(0x08, 0x0093) HCI_LE_CS_PROCEDURE_ENABLE_COMMAND = hci_command_op_code(0x08, 0x0094) HCI_LE_CS_TEST_COMMAND = hci_command_op_code(0x08, 0x0095) HCI_LE_CS_TEST_END_COMMAND = hci_command_op_code(0x08, 0x0096) HCI_LE_SET_HOST_FEATURE_V2_COMMAND = hci_command_op_code(0x08, 0x0097) HCI_LE_ADD_DEVICE_TO_MONITORED_ADVERTISERS_LIST_COMMAND = hci_command_op_code(0x08, 0x0098) HCI_LE_REMOVE_DEVICE_FROM_MONITORED_ADVERTISERS_LIST_COMMAND = hci_command_op_code(0x08, 0x0099) HCI_LE_CLEAR_MONITORED_ADVERTISERS_LIST_COMMAND = hci_command_op_code(0x08, 0x009A) HCI_LE_READ_MONITORED_ADVERTISERS_LIST_SIZE_COMMAND = hci_command_op_code(0x08, 0x009B) HCI_LE_ENABLE_MONITORING_ADVERTISERS_COMMAND = hci_command_op_code(0x08, 0x009C) HCI_LE_FRAME_SPACE_UPDATE_COMMAND = hci_command_op_code(0x08, 0x009D) # HCI Error Codes # See Bluetooth spec Vol 2, Part D - 1.3 LIST OF ERROR CODES HCI_SUCCESS = 0x00 HCI_UNKNOWN_HCI_COMMAND_ERROR = 0x01 HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR = 0x02 HCI_HARDWARE_FAILURE_ERROR = 0x03 HCI_PAGE_TIMEOUT_ERROR = 0x04 HCI_AUTHENTICATION_FAILURE_ERROR = 0x05 HCI_PIN_OR_KEY_MISSING_ERROR = 0x06 HCI_MEMORY_CAPACITY_EXCEEDED_ERROR = 0x07 HCI_CONNECTION_TIMEOUT_ERROR = 0x08 HCI_CONNECTION_LIMIT_EXCEEDED_ERROR = 0x09 HCI_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED_ERROR = 0x0A HCI_CONNECTION_ALREADY_EXISTS_ERROR = 0x0B HCI_COMMAND_DISALLOWED_ERROR = 0x0C HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR = 0x0D HCI_CONNECTION_REJECTED_DUE_TO_SECURITY_REASONS_ERROR = 0x0E HCI_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR_ERROR = 0x0F HCI_CONNECTION_ACCEPT_TIMEOUT_ERROR = 0x10 HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE_ERROR = 0x11 HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR = 0x12 HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR = 0x13 HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_LOW_RESOURCES_ERROR = 0x14 HCI_REMOTE_DEVICE_TERMINATED_CONNECTION_DUE_TO_POWER_OFF_ERROR = 0x15 HCI_CONNECTION_TERMINATED_BY_LOCAL_HOST_ERROR = 0x16 HCI_REPEATED_ATTEMPTS_ERROR = 0X17 HCI_PAIRING_NOT_ALLOWED_ERROR = 0X18 HCI_UNKNOWN_LMP_PDU_ERROR = 0X19 HCI_UNSUPPORTED_REMOTE_FEATURE_ERROR = 0X1A HCI_SCO_OFFSET_REJECTED_ERROR = 0X1B HCI_SCO_INTERVAL_REJECTED_ERROR = 0X1C HCI_SCO_AIR_MODE_REJECTED_ERROR = 0X1D HCI_INVALID_LMP_OR_LL_PARAMETERS_ERROR = 0X1E HCI_UNSPECIFIED_ERROR_ERROR = 0X1F HCI_UNSUPPORTED_LMP_OR_LL_PARAMETER_VALUE_ERROR = 0X20 HCI_ROLE_CHANGE_NOT_ALLOWED_ERROR = 0X21 HCI_LMP_OR_LL_RESPONSE_TIMEOUT_ERROR = 0X22 HCI_LMP_ERROR_TRANSACTION_COLLISION_OR_LL_PROCEDURE_COLLISION_ERROR = 0X23 HCI_LMP_PDU_NOT_ALLOWED_ERROR = 0X24 HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE_ERROR = 0X25 HCI_LINK_KEY_CANNOT_BE_CHANGED_ERROR = 0X26 HCI_REQUESTED_QOS_NOT_SUPPORTED_ERROR = 0X27 HCI_INSTANT_PASSED_ERROR = 0X28 HCI_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED_ERROR = 0X29 HCI_DIFFERENT_TRANSACTION_COLLISION_ERROR = 0X2A HCI_RESERVED_FOR_FUTURE_USE = 0X2B HCI_QOS_UNACCEPTABLE_PARAMETER_ERROR = 0X2C HCI_QOS_REJECTED_ERROR = 0X2D HCI_CHANNEL_CLASSIFICATION_NOT_SUPPORTED_ERROR = 0X2E HCI_INSUFFICIENT_SECURITY_ERROR = 0X2F HCI_PARAMETER_OUT_OF_MANDATORY_RANGE_ERROR = 0X30 HCI_ROLE_SWITCH_PENDING_ERROR = 0X32 HCI_RESERVED_SLOT_VIOLATION_ERROR = 0X34 HCI_ROLE_SWITCH_FAILED_ERROR = 0X35 HCI_EXTENDED_INQUIRY_RESPONSE_TOO_LARGE_ERROR = 0X36 HCI_SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST_ERROR = 0X37 HCI_HOST_BUSY_PAIRING_ERROR = 0X38 HCI_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND_ERROR = 0X39 HCI_CONTROLLER_BUSY_ERROR = 0X3A HCI_UNACCEPTABLE_CONNECTION_PARAMETERS_ERROR = 0X3B HCI_ADVERTISING_TIMEOUT_ERROR = 0X3C HCI_CONNECTION_TERMINATED_DUE_TO_MIC_FAILURE_ERROR = 0X3D HCI_CONNECTION_FAILED_TO_BE_ESTABLISHED_ERROR = 0X3E HCI_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING_ERROR = 0X40 HCI_TYPE0_SUBMAP_NOT_DEFINED_ERROR = 0X41 HCI_UNKNOWN_ADVERTISING_IDENTIFIER_ERROR = 0X42 HCI_LIMIT_REACHED_ERROR = 0X43 HCI_OPERATION_CANCELLED_BY_HOST_ERROR = 0X44 HCI_PACKET_TOO_LONG_ERROR = 0X45 HCI_ERROR_NAMES = { error_code: error_name for (error_name, error_code) in globals().items() if error_name.startswith('HCI_') and error_name.endswith('_ERROR') } HCI_ERROR_NAMES[HCI_SUCCESS] = 'HCI_SUCCESS' # Command Status codes HCI_COMMAND_STATUS_PENDING = 0 class Phy(SpecableEnum): LE_1M = 1 LE_2M = 2 LE_CODED = 3 # ACL HCI_ACL_PB_FIRST_NON_FLUSHABLE = 0 HCI_ACL_PB_CONTINUATION = 1 HCI_ACL_PB_FIRST_FLUSHABLE = 2 HCI_ACK_PB_COMPLETE_L2CAP = 3 HCI_LE_PHY_NAMES: dict[int,str] = { Phy.LE_1M: 'LE 1M', Phy.LE_2M: 'LE 2M', Phy.LE_CODED: 'LE Coded' } HCI_LE_1M_PHY_BIT = 0 HCI_LE_2M_PHY_BIT = 1 HCI_LE_CODED_PHY_BIT = 2 HCI_LE_PHY_BIT_NAMES = ['LE_1M_PHY', 'LE_2M_PHY', 'LE_CODED_PHY'] HCI_LE_PHY_TYPE_TO_BIT: dict[Phy, int] = { Phy.LE_1M: HCI_LE_1M_PHY_BIT, Phy.LE_2M: HCI_LE_2M_PHY_BIT, Phy.LE_CODED: HCI_LE_CODED_PHY_BIT, } class PhyBit(SpecableFlag): LE_1M = 1 << HCI_LE_1M_PHY_BIT LE_2M = 1 << HCI_LE_2M_PHY_BIT LE_CODED = 1 << HCI_LE_CODED_PHY_BIT class CsRole(SpecableEnum): INITIATOR = 0x00 REFLECTOR = 0x01 class CsRoleMask(enum.IntFlag): INITIATOR = 0x01 REFLECTOR = 0x02 class CsSyncPhy(SpecableEnum): LE_1M = 1 LE_2M = 2 LE_2M_2BT = 3 class CsSyncPhySupported(enum.IntFlag): LE_2M = 0x01 LE_2M_2BT = 0x02 class RttType(SpecableEnum): AA_ONLY = 0x00 SOUNDING_SEQUENCE_32_BIT = 0x01 SOUNDING_SEQUENCE_96_BIT = 0x02 RANDOM_SEQUENCE_32_BIT = 0x03 RANDOM_SEQUENCE_64_BIT = 0x04 RANDOM_SEQUENCE_96_BIT = 0x05 RANDOM_SEQUENCE_128_BIT = 0x06 class CsSnr(SpecableEnum): SNR_18_DB = 0x00 SNR_21_DB = 0x01 SNR_24_DB = 0x02 SNR_27_DB = 0x03 SNR_30_DB = 0x04 NOT_APPLIED = 0xFF class CsDoneStatus(SpecableEnum): ALL_RESULTS_COMPLETED = 0x00 PARTIAL = 0x01 ABORTED = 0x0F class CsProcedureAbortReason(SpecableEnum): NO_ABORT = 0x00 LOCAL_HOST_OR_REMOTE_REQUEST = 0x01 CHANNEL_MAP_UPDATE_INSTANT_PASSED = 0x02 UNSPECIFIED = 0x0F class CsSubeventAbortReason(SpecableEnum): NO_ABORT = 0x00 LOCAL_HOST_OR_REMOTE_REQUEST = 0x01 NO_CS_SYNC_RECEIVED = 0x02 SCHEDULING_CONFLICT_OR_LIMITED_RESOURCES = 0x03 UNSPECIFIED = 0x0F class Role(SpecableEnum): CENTRAL = 0 PERIPHERAL = 1 # For Backward Compatibility. HCI_CENTRAL_ROLE = Role.CENTRAL HCI_PERIPHERAL_ROLE = Role.PERIPHERAL HCI_LE_1M_PHY = Phy.LE_1M HCI_LE_2M_PHY = Phy.LE_2M HCI_LE_CODED_PHY = Phy.LE_CODED # Connection Parameters HCI_CONNECTION_INTERVAL_MS_PER_UNIT = 1.25 HCI_CONNECTION_LATENCY_MS_PER_UNIT = 1.25 HCI_SUPERVISION_TIMEOUT_MS_PER_UNIT = 10 # Inquiry LAP HCI_LIMITED_DEDICATED_INQUIRY_LAP = 0x9E8B00 HCI_GENERAL_INQUIRY_LAP = 0x9E8B33 HCI_INQUIRY_LAP_NAMES = { HCI_LIMITED_DEDICATED_INQUIRY_LAP: 'Limited Dedicated Inquiry', HCI_GENERAL_INQUIRY_LAP: 'General Inquiry' } # Inquiry Mode HCI_STANDARD_INQUIRY_MODE = 0x00 HCI_INQUIRY_WITH_RSSI_MODE = 0x01 HCI_EXTENDED_INQUIRY_MODE = 0x02 # Page Scan Repetition Mode HCI_R0_PAGE_SCAN_REPETITION_MODE = 0x00 HCI_R1_PAGE_SCAN_REPETITION_MODE = 0x01 HCI_R2_PAGE_SCAN_REPETITION_MODE = 0x02 # IO Capability class IoCapability(SpecableEnum): DISPLAY_ONLY = 0x00 DISPLAY_YES_NO = 0x01 KEYBOARD_ONLY = 0x02 NO_INPUT_NO_OUTPUT = 0x03 # Authentication Requirements class AuthenticationRequirements(SpecableEnum): MITM_NOT_REQUIRED_NO_BONDING = 0x00 MITM_REQUIRED_NO_BONDING = 0x01 MITM_NOT_REQUIRED_DEDICATED_BONDING = 0x02 MITM_REQUIRED_DEDICATED_BONDING = 0x03 MITM_NOT_REQUIRED_GENERAL_BONDING = 0x04 MITM_REQUIRED_GENERAL_BONDING = 0x05 # Link Key Types class LinkKeyType(SpecableEnum): COMBINATION_KEY = 0X00 LOCAL_UNIT_KEY = 0X01 REMOTE_UNIT_KEY = 0X02 DEBUG_COMBINATION_KEY = 0X03 UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192 = 0X04 AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192 = 0X05 CHANGED_COMBINATION_KEY = 0X06 UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256 = 0X07 AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256 = 0X08 # Address types class AddressType(SpecableEnum): PUBLIC_DEVICE = 0x00 RANDOM_DEVICE = 0x01 PUBLIC_IDENTITY = 0x02 RANDOM_IDENTITY = 0x03 # (Directed Only) Address is RPA, but controller cannot resolve. UNABLE_TO_RESOLVE = 0xFE # (Extended Only) No address. ANONYMOUS = 0xFF # Supported Commands Masks # See Bluetooth spec @ 6.27 SUPPORTED COMMANDS 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_LE_CS_READ_REMOTE_FAE_TABLE_COMMAND : 1 << (12*8+2), HCI_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE_COMMAND : 1 << (12*8+3), 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_LE_CS_CREATE_CONFIG_COMMAND : 1 << (16*8+6), HCI_LE_CS_REMOVE_CONFIG_COMMAND : 1 << (16*8+7), 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_LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES_COMMAND : 1 << (20*8+5), HCI_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMMAND : 1 << (20*8+6), HCI_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES_COMMAND : 1 << (20*8+7), 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_LE_CS_TEST_COMMAND : 1 << (23*8+3), HCI_LE_CS_TEST_END_COMMAND : 1 << (23*8+4), HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND : 1 << (24*8+0), HCI_LE_CS_SECURITY_ENABLE_COMMAND : 1 << (24*8+1), HCI_READ_LE_HOST_SUPPORT_COMMAND : 1 << (24*8+5), HCI_WRITE_LE_HOST_SUPPORT_COMMAND : 1 << (24*8+6), HCI_LE_CS_SET_DEFAULT_SETTINGS_COMMAND : 1 << (24*8+7), 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_LE_ENABLE_MONITORING_ADVERTISERS_COMMAND : 1 << (28*8+7), HCI_LE_CS_SET_CHANNEL_CLASSIFICATION_COMMAND : 1 << (29*8+0), HCI_LE_CS_SET_PROCEDURE_PARAMETERS_COMMAND : 1 << (29*8+1), HCI_LE_CS_PROCEDURE_ENABLE_COMMAND : 1 << (29*8+2), 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_DECISION_DATA_COMMAND : 1 << (46*8+3), HCI_LE_SET_DECISION_INSTRUCTIONS_COMMAND : 1 << (46*8+4), 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), HCI_LE_READ_ALL_LOCAL_SUPPORTED_FEATURES_COMMAND : 1 << (47*8+2), HCI_LE_READ_ALL_REMOTE_FEATURES_COMMAND : 1 << (47*8+3), HCI_LE_SET_HOST_FEATURE_V2_COMMAND : 1 << (47*8+4), HCI_LE_ADD_DEVICE_TO_MONITORED_ADVERTISERS_LIST_COMMAND : 1 << (47*8+5), HCI_LE_REMOVE_DEVICE_FROM_MONITORED_ADVERTISERS_LIST_COMMAND : 1 << (47*8+6), HCI_LE_CLEAR_MONITORED_ADVERTISERS_LIST_COMMAND : 1 << (47*8+7), HCI_LE_READ_MONITORED_ADVERTISERS_LIST_SIZE_COMMAND : 1 << (48*8+0), HCI_LE_FRAME_SPACE_UPDATE_COMMAND : 1 << (48*8+1), } # LE Supported Features # See Bluetooth spec @ Vol 6, Part B, 4.6 FEATURE SUPPORT class LeFeature(SpecableEnum): LE_ENCRYPTION = 0 CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 EXTENDED_REJECT_INDICATION = 2 PERIPHERAL_INITIATED_FEATURE_EXCHANGE = 3 LE_PING = 4 LE_DATA_PACKET_LENGTH_EXTENSION = 5 LL_PRIVACY = 6 EXTENDED_SCANNER_FILTER_POLICIES = 7 LE_2M_PHY = 8 STABLE_MODULATION_INDEX_TRANSMITTER = 9 STABLE_MODULATION_INDEX_RECEIVER = 10 LE_CODED_PHY = 11 LE_EXTENDED_ADVERTISING = 12 LE_PERIODIC_ADVERTISING = 13 CHANNEL_SELECTION_ALGORITHM_2 = 14 LE_POWER_CLASS_1 = 15 MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE = 16 CONNECTION_CTE_REQUEST = 17 CONNECTION_CTE_RESPONSE = 18 CONNECTIONLESS_CTE_TRANSMITTER = 19 CONNECTIONLESS_CTR_RECEIVER = 20 ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION = 21 ANTENNA_SWITCHING_DURING_CTE_RECEPTION = 22 RECEIVING_CONSTANT_TONE_EXTENSIONS = 23 PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER = 24 PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT = 25 SLEEP_CLOCK_ACCURACY_UPDATES = 26 REMOTE_PUBLIC_KEY_VALIDATION = 27 CONNECTED_ISOCHRONOUS_STREAM_CENTRAL = 28 CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL = 29 ISOCHRONOUS_BROADCASTER = 30 SYNCHRONIZED_RECEIVER = 31 CONNECTED_ISOCHRONOUS_STREAM = 32 LE_POWER_CONTROL_REQUEST = 33 LE_POWER_CONTROL_REQUEST_DUP = 34 LE_PATH_LOSS_MONITORING = 35 PERIODIC_ADVERTISING_ADI_SUPPORT = 36 CONNECTION_SUBRATING = 37 CONNECTION_SUBRATING_HOST_SUPPORT = 38 CHANNEL_CLASSIFICATION = 39 ADVERTISING_CODING_SELECTION = 40 ADVERTISING_CODING_SELECTION_HOST_SUPPORT = 41 DECISION_BASED_ADVERTISING_FILTERING = 42 PERIODIC_ADVERTISING_WITH_RESPONSES_ADVERTISER = 43 PERIODIC_ADVERTISING_WITH_RESPONSES_SCANNER = 44 UNSEGMENTED_FRAMED_MODE = 45 CHANNEL_SOUNDING = 46 CHANNEL_SOUNDING_HOST_SUPPORT = 47 CHANNEL_SOUNDING_TONE_QUALITY_INDICATION = 48 LL_EXTENDED_FEATURE_SET = 63 MONITORING_ADVERTISERS = 64 FRAME_SPACE_UPDATE = 65 class LeFeatureMask(enum.IntFlag): LE_ENCRYPTION = 1 << LeFeature.LE_ENCRYPTION CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1 << LeFeature.CONNECTION_PARAMETERS_REQUEST_PROCEDURE EXTENDED_REJECT_INDICATION = 1 << LeFeature.EXTENDED_REJECT_INDICATION PERIPHERAL_INITIATED_FEATURE_EXCHANGE = 1 << LeFeature.PERIPHERAL_INITIATED_FEATURE_EXCHANGE LE_PING = 1 << LeFeature.LE_PING LE_DATA_PACKET_LENGTH_EXTENSION = 1 << LeFeature.LE_DATA_PACKET_LENGTH_EXTENSION LL_PRIVACY = 1 << LeFeature.LL_PRIVACY EXTENDED_SCANNER_FILTER_POLICIES = 1 << LeFeature.EXTENDED_SCANNER_FILTER_POLICIES LE_2M_PHY = 1 << LeFeature.LE_2M_PHY STABLE_MODULATION_INDEX_TRANSMITTER = 1 << LeFeature.STABLE_MODULATION_INDEX_TRANSMITTER STABLE_MODULATION_INDEX_RECEIVER = 1 << LeFeature.STABLE_MODULATION_INDEX_RECEIVER LE_CODED_PHY = 1 << LeFeature.LE_CODED_PHY LE_EXTENDED_ADVERTISING = 1 << LeFeature.LE_EXTENDED_ADVERTISING LE_PERIODIC_ADVERTISING = 1 << LeFeature.LE_PERIODIC_ADVERTISING CHANNEL_SELECTION_ALGORITHM_2 = 1 << LeFeature.CHANNEL_SELECTION_ALGORITHM_2 LE_POWER_CLASS_1 = 1 << LeFeature.LE_POWER_CLASS_1 MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE = 1 << LeFeature.MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE CONNECTION_CTE_REQUEST = 1 << LeFeature.CONNECTION_CTE_REQUEST CONNECTION_CTE_RESPONSE = 1 << LeFeature.CONNECTION_CTE_RESPONSE CONNECTIONLESS_CTE_TRANSMITTER = 1 << LeFeature.CONNECTIONLESS_CTE_TRANSMITTER CONNECTIONLESS_CTR_RECEIVER = 1 << LeFeature.CONNECTIONLESS_CTR_RECEIVER ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION = 1 << LeFeature.ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION ANTENNA_SWITCHING_DURING_CTE_RECEPTION = 1 << LeFeature.ANTENNA_SWITCHING_DURING_CTE_RECEPTION RECEIVING_CONSTANT_TONE_EXTENSIONS = 1 << LeFeature.RECEIVING_CONSTANT_TONE_EXTENSIONS PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER = 1 << LeFeature.PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT = 1 << LeFeature.PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT SLEEP_CLOCK_ACCURACY_UPDATES = 1 << LeFeature.SLEEP_CLOCK_ACCURACY_UPDATES REMOTE_PUBLIC_KEY_VALIDATION = 1 << LeFeature.REMOTE_PUBLIC_KEY_VALIDATION CONNECTED_ISOCHRONOUS_STREAM_CENTRAL = 1 << LeFeature.CONNECTED_ISOCHRONOUS_STREAM_CENTRAL CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL = 1 << LeFeature.CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL ISOCHRONOUS_BROADCASTER = 1 << LeFeature.ISOCHRONOUS_BROADCASTER SYNCHRONIZED_RECEIVER = 1 << LeFeature.SYNCHRONIZED_RECEIVER CONNECTED_ISOCHRONOUS_STREAM = 1 << LeFeature.CONNECTED_ISOCHRONOUS_STREAM LE_POWER_CONTROL_REQUEST = 1 << LeFeature.LE_POWER_CONTROL_REQUEST LE_POWER_CONTROL_REQUEST_DUP = 1 << LeFeature.LE_POWER_CONTROL_REQUEST_DUP LE_PATH_LOSS_MONITORING = 1 << LeFeature.LE_PATH_LOSS_MONITORING PERIODIC_ADVERTISING_ADI_SUPPORT = 1 << LeFeature.PERIODIC_ADVERTISING_ADI_SUPPORT CONNECTION_SUBRATING = 1 << LeFeature.CONNECTION_SUBRATING CONNECTION_SUBRATING_HOST_SUPPORT = 1 << LeFeature.CONNECTION_SUBRATING_HOST_SUPPORT CHANNEL_CLASSIFICATION = 1 << LeFeature.CHANNEL_CLASSIFICATION ADVERTISING_CODING_SELECTION = 1 << LeFeature.ADVERTISING_CODING_SELECTION ADVERTISING_CODING_SELECTION_HOST_SUPPORT = 1 << LeFeature.ADVERTISING_CODING_SELECTION_HOST_SUPPORT DECISION_BASED_ADVERTISING_FILTERING = 1 << LeFeature.DECISION_BASED_ADVERTISING_FILTERING PERIODIC_ADVERTISING_WITH_RESPONSES_ADVERTISER = 1 << LeFeature.PERIODIC_ADVERTISING_WITH_RESPONSES_ADVERTISER PERIODIC_ADVERTISING_WITH_RESPONSES_SCANNER = 1 << LeFeature.PERIODIC_ADVERTISING_WITH_RESPONSES_SCANNER UNSEGMENTED_FRAMED_MODE = 1 << LeFeature.UNSEGMENTED_FRAMED_MODE CHANNEL_SOUNDING = 1 << LeFeature.CHANNEL_SOUNDING CHANNEL_SOUNDING_HOST_SUPPORT = 1 << LeFeature.CHANNEL_SOUNDING_HOST_SUPPORT CHANNEL_SOUNDING_TONE_QUALITY_INDICATION = 1 << LeFeature.CHANNEL_SOUNDING_TONE_QUALITY_INDICATION LL_EXTENDED_FEATURE_SET = 1 << LeFeature.LL_EXTENDED_FEATURE_SET MONITORING_ADVERTISERS = 1 << LeFeature.MONITORING_ADVERTISERS FRAME_SPACE_UPDATE = 1 << LeFeature.FRAME_SPACE_UPDATE class LmpFeature(SpecableEnum): # Page 0 (Legacy LMP features) LMP_3_SLOT_PACKETS = 0 LMP_5_SLOT_PACKETS = 1 ENCRYPTION = 2 SLOT_OFFSET = 3 TIMING_ACCURACY = 4 ROLE_SWITCH = 5 HOLD_MODE = 6 SNIFF_MODE = 7 # PREVIOUSLY_USED = 8 POWER_CONTROL_REQUESTS = 9 CHANNEL_QUALITY_DRIVEN_DATA_RATE_CQDDR = 10 SCO_LINK = 11 HV2_PACKETS = 12 HV3_PACKETS = 13 U_LAW_LOG_SYNCHRONOUS_DATA = 14 A_LAW_LOG_SYNCHRONOUS_DATA = 15 CVSD_SYNCHRONOUS_DATA = 16 PAGING_PARAMETER_NEGOTIATION = 17 POWER_CONTROL = 18 TRANSPARENT_SYNCHRONOUS_DATA = 19 FLOW_CONTROL_LAG_LEAST_SIGNIFICANT_BIT = 20 FLOW_CONTROL_LAG_MIDDLE_BIT = 21 FLOW_CONTROL_LAG_MOST_SIGNIFICANT_BIT = 22 BROADCAST_ENCRYPTION = 23 # RESERVED_FOR_FUTURE_USE = 24 ENHANCED_DATA_RATE_ACL_2_MBPS_MODE = 25 ENHANCED_DATA_RATE_ACL_3_MBPS_MODE = 26 ENHANCED_INQUIRY_SCAN = 27 INTERLACED_INQUIRY_SCAN = 28 INTERLACED_PAGE_SCAN = 29 RSSI_WITH_INQUIRY_RESULTS = 30 EXTENDED_SCO_LINK_EV3_PACKETS = 31 EV4_PACKETS = 32 EV5_PACKETS = 33 # RESERVED_FOR_FUTURE_USE = 34 AFH_CAPABLE_PERIPHERAL = 35 AFH_CLASSIFICATION_PERIPHERAL = 36 BR_EDR_NOT_SUPPORTED = 37 LE_SUPPORTED_CONTROLLER = 38 LMP_3_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS = 39 LMP_5_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS = 40 SNIFF_SUBRATING = 41 PAUSE_ENCRYPTION = 42 AFH_CAPABLE_CENTRAL = 43 AFH_CLASSIFICATION_CENTRAL = 44 ENHANCED_DATA_RATE_ESCO_2_MBPS_MODE = 45 ENHANCED_DATA_RATE_ESCO_3_MBPS_MODE = 46 LMP_3_SLOT_ENHANCED_DATA_RATE_ESCO_PACKETS = 47 EXTENDED_INQUIRY_RESPONSE = 48 SIMULTANEOUS_LE_AND_BR_EDR_TO_SAME_DEVICE_CAPABLE_CONTROLLER = 49 # RESERVED_FOR_FUTURE_USE = 50 SECURE_SIMPLE_PAIRING_CONTROLLER_SUPPORT = 51 ENCAPSULATED_PDU = 52 ERRONEOUS_DATA_REPORTING = 53 NON_FLUSHABLE_PACKET_BOUNDARY_FLAG = 54 # RESERVED_FOR_FUTURE_USE = 55 HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT = 56 VARIABLE_INQUIRY_TX_POWER_LEVEL = 57 ENHANCED_POWER_CONTROL = 58 # RESERVED_FOR_FUTURE_USE = 59 # RESERVED_FOR_FUTURE_USE = 60 # RESERVED_FOR_FUTURE_USE = 61 # RESERVED_FOR_FUTURE_USE = 62 EXTENDED_FEATURES = 63 # Page 1 SECURE_SIMPLE_PAIRING_HOST_SUPPORT = 64 LE_SUPPORTED_HOST = 65 # PREVIOUSLY_USED = 66 SECURE_CONNECTIONS_HOST_SUPPORT = 67 # Page 2 CONNECTIONLESS_PERIPHERAL_BROADCAST_TRANSMITTER_OPERATION = 128 CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVER_OPERATION = 129 SYNCHRONIZATION_TRAIN = 130 SYNCHRONIZATION_SCAN = 131 HCI_INQUIRY_RESPONSE_NOTIFICATION_EVENT = 132 GENERALIZED_INTERLACED_SCAN = 133 COARSE_CLOCK_ADJUSTMENT = 134 RESERVED_FOR_FUTURE_USE = 135 SECURE_CONNECTIONS_CONTROLLER_SUPPORT = 136 PING = 137 SLOT_AVAILABILITY_MASK = 138 TRAIN_NUDGING = 139 class LmpFeatureMask(enum.IntFlag): # Page 0 (Legacy LMP features) LMP_3_SLOT_PACKETS = (1 << LmpFeature.LMP_3_SLOT_PACKETS) LMP_5_SLOT_PACKETS = (1 << LmpFeature.LMP_5_SLOT_PACKETS) ENCRYPTION = (1 << LmpFeature.ENCRYPTION) SLOT_OFFSET = (1 << LmpFeature.SLOT_OFFSET) TIMING_ACCURACY = (1 << LmpFeature.TIMING_ACCURACY) ROLE_SWITCH = (1 << LmpFeature.ROLE_SWITCH) HOLD_MODE = (1 << LmpFeature.HOLD_MODE) SNIFF_MODE = (1 << LmpFeature.SNIFF_MODE) # PREVIOUSLY_USED = (1 << LmpFeature.PREVIOUSLY_USED) POWER_CONTROL_REQUESTS = (1 << LmpFeature.POWER_CONTROL_REQUESTS) CHANNEL_QUALITY_DRIVEN_DATA_RATE_CQDDR = (1 << LmpFeature.CHANNEL_QUALITY_DRIVEN_DATA_RATE_CQDDR) SCO_LINK = (1 << LmpFeature.SCO_LINK) HV2_PACKETS = (1 << LmpFeature.HV2_PACKETS) HV3_PACKETS = (1 << LmpFeature.HV3_PACKETS) U_LAW_LOG_SYNCHRONOUS_DATA = (1 << LmpFeature.U_LAW_LOG_SYNCHRONOUS_DATA) A_LAW_LOG_SYNCHRONOUS_DATA = (1 << LmpFeature.A_LAW_LOG_SYNCHRONOUS_DATA) CVSD_SYNCHRONOUS_DATA = (1 << LmpFeature.CVSD_SYNCHRONOUS_DATA) PAGING_PARAMETER_NEGOTIATION = (1 << LmpFeature.PAGING_PARAMETER_NEGOTIATION) POWER_CONTROL = (1 << LmpFeature.POWER_CONTROL) TRANSPARENT_SYNCHRONOUS_DATA = (1 << LmpFeature.TRANSPARENT_SYNCHRONOUS_DATA) FLOW_CONTROL_LAG_LEAST_SIGNIFICANT_BIT = (1 << LmpFeature.FLOW_CONTROL_LAG_LEAST_SIGNIFICANT_BIT) FLOW_CONTROL_LAG_MIDDLE_BIT = (1 << LmpFeature.FLOW_CONTROL_LAG_MIDDLE_BIT) FLOW_CONTROL_LAG_MOST_SIGNIFICANT_BIT = (1 << LmpFeature.FLOW_CONTROL_LAG_MOST_SIGNIFICANT_BIT) BROADCAST_ENCRYPTION = (1 << LmpFeature.BROADCAST_ENCRYPTION) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) ENHANCED_DATA_RATE_ACL_2_MBPS_MODE = (1 << LmpFeature.ENHANCED_DATA_RATE_ACL_2_MBPS_MODE) ENHANCED_DATA_RATE_ACL_3_MBPS_MODE = (1 << LmpFeature.ENHANCED_DATA_RATE_ACL_3_MBPS_MODE) ENHANCED_INQUIRY_SCAN = (1 << LmpFeature.ENHANCED_INQUIRY_SCAN) INTERLACED_INQUIRY_SCAN = (1 << LmpFeature.INTERLACED_INQUIRY_SCAN) INTERLACED_PAGE_SCAN = (1 << LmpFeature.INTERLACED_PAGE_SCAN) RSSI_WITH_INQUIRY_RESULTS = (1 << LmpFeature.RSSI_WITH_INQUIRY_RESULTS) EXTENDED_SCO_LINK_EV3_PACKETS = (1 << LmpFeature.EXTENDED_SCO_LINK_EV3_PACKETS) EV4_PACKETS = (1 << LmpFeature.EV4_PACKETS) EV5_PACKETS = (1 << LmpFeature.EV5_PACKETS) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) AFH_CAPABLE_PERIPHERAL = (1 << LmpFeature.AFH_CAPABLE_PERIPHERAL) AFH_CLASSIFICATION_PERIPHERAL = (1 << LmpFeature.AFH_CLASSIFICATION_PERIPHERAL) BR_EDR_NOT_SUPPORTED = (1 << LmpFeature.BR_EDR_NOT_SUPPORTED) LE_SUPPORTED_CONTROLLER = (1 << LmpFeature.LE_SUPPORTED_CONTROLLER) LMP_3_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS = (1 << LmpFeature.LMP_3_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS) LMP_5_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS = (1 << LmpFeature.LMP_5_SLOT_ENHANCED_DATA_RATE_ACL_PACKETS) SNIFF_SUBRATING = (1 << LmpFeature.SNIFF_SUBRATING) PAUSE_ENCRYPTION = (1 << LmpFeature.PAUSE_ENCRYPTION) AFH_CAPABLE_CENTRAL = (1 << LmpFeature.AFH_CAPABLE_CENTRAL) AFH_CLASSIFICATION_CENTRAL = (1 << LmpFeature.AFH_CLASSIFICATION_CENTRAL) ENHANCED_DATA_RATE_ESCO_2_MBPS_MODE = (1 << LmpFeature.ENHANCED_DATA_RATE_ESCO_2_MBPS_MODE) ENHANCED_DATA_RATE_ESCO_3_MBPS_MODE = (1 << LmpFeature.ENHANCED_DATA_RATE_ESCO_3_MBPS_MODE) LMP_3_SLOT_ENHANCED_DATA_RATE_ESCO_PACKETS = (1 << LmpFeature.LMP_3_SLOT_ENHANCED_DATA_RATE_ESCO_PACKETS) EXTENDED_INQUIRY_RESPONSE = (1 << LmpFeature.EXTENDED_INQUIRY_RESPONSE) SIMULTANEOUS_LE_AND_BR_EDR_TO_SAME_DEVICE_CAPABLE_CONTROLLER = (1 << LmpFeature.SIMULTANEOUS_LE_AND_BR_EDR_TO_SAME_DEVICE_CAPABLE_CONTROLLER) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) SECURE_SIMPLE_PAIRING_CONTROLLER_SUPPORT = (1 << LmpFeature.SECURE_SIMPLE_PAIRING_CONTROLLER_SUPPORT) ENCAPSULATED_PDU = (1 << LmpFeature.ENCAPSULATED_PDU) ERRONEOUS_DATA_REPORTING = (1 << LmpFeature.ERRONEOUS_DATA_REPORTING) NON_FLUSHABLE_PACKET_BOUNDARY_FLAG = (1 << LmpFeature.NON_FLUSHABLE_PACKET_BOUNDARY_FLAG) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT = (1 << LmpFeature.HCI_LINK_SUPERVISION_TIMEOUT_CHANGED_EVENT) VARIABLE_INQUIRY_TX_POWER_LEVEL = (1 << LmpFeature.VARIABLE_INQUIRY_TX_POWER_LEVEL) ENHANCED_POWER_CONTROL = (1 << LmpFeature.ENHANCED_POWER_CONTROL) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) # RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) EXTENDED_FEATURES = (1 << LmpFeature.EXTENDED_FEATURES) # Page 1 SECURE_SIMPLE_PAIRING_HOST_SUPPORT = (1 << LmpFeature.SECURE_SIMPLE_PAIRING_HOST_SUPPORT) LE_SUPPORTED_HOST = (1 << LmpFeature.LE_SUPPORTED_HOST) # PREVIOUSLY_USED = (1 << LmpFeature.PREVIOUSLY_USED) SECURE_CONNECTIONS_HOST_SUPPORT = (1 << LmpFeature.SECURE_CONNECTIONS_HOST_SUPPORT) # Page 2 CONNECTIONLESS_PERIPHERAL_BROADCAST_TRANSMITTER_OPERATION = (1 << LmpFeature.CONNECTIONLESS_PERIPHERAL_BROADCAST_TRANSMITTER_OPERATION) CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVER_OPERATION = (1 << LmpFeature.CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVER_OPERATION) SYNCHRONIZATION_TRAIN = (1 << LmpFeature.SYNCHRONIZATION_TRAIN) SYNCHRONIZATION_SCAN = (1 << LmpFeature.SYNCHRONIZATION_SCAN) HCI_INQUIRY_RESPONSE_NOTIFICATION_EVENT = (1 << LmpFeature.HCI_INQUIRY_RESPONSE_NOTIFICATION_EVENT) GENERALIZED_INTERLACED_SCAN = (1 << LmpFeature.GENERALIZED_INTERLACED_SCAN) COARSE_CLOCK_ADJUSTMENT = (1 << LmpFeature.COARSE_CLOCK_ADJUSTMENT) RESERVED_FOR_FUTURE_USE = (1 << LmpFeature.RESERVED_FOR_FUTURE_USE) SECURE_CONNECTIONS_CONTROLLER_SUPPORT = (1 << LmpFeature.SECURE_CONNECTIONS_CONTROLLER_SUPPORT) PING = (1 << LmpFeature.PING) SLOT_AVAILABILITY_MASK = (1 << LmpFeature.SLOT_AVAILABILITY_MASK) TRAIN_NUDGING = (1 << LmpFeature.TRAIN_NUDGING) # fmt: on # pylint: enable=line-too-long # pylint: disable=invalid-name # ----------------------------------------------------------------------------- # pylint: disable-next=unnecessary-lambda STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)} CS_ROLE_SPEC = {'size': 1, 'mapper': lambda x: CsRole(x).name} CS_ROLE_MASK_SPEC = {'size': 1, 'mapper': lambda x: CsRoleMask(x).name} CS_SYNC_PHY_SPEC = {'size': 1, 'mapper': lambda x: CsSyncPhy(x).name} CS_SYNC_PHY_SUPPORTED_SPEC = {'size': 1, 'mapper': lambda x: CsSyncPhySupported(x).name} RTT_TYPE_SPEC = {'size': 1, 'mapper': lambda x: RttType(x).name} CS_SNR_SPEC = {'size': 1, 'mapper': lambda x: CsSnr(x).name} COD_SPEC = {'size': 3, 'mapper': map_class_of_device} class CodecID(SpecableEnum): # fmt: off U_LOG = 0x00 A_LOG = 0x01 CVSD = 0x02 TRANSPARENT = 0x03 LINEAR_PCM = 0x04 MSBC = 0x05 LC3 = 0x06 G729A = 0x07 VENDOR_SPECIFIC = 0xFF @dataclasses.dataclass(frozen=True) class CodingFormat: codec_id: CodecID company_id: int = 0 vendor_specific_codec_id: int = 0 @classmethod def parse_from_bytes(cls, data: bytes, offset: int) -> tuple[int, CodingFormat]: (codec_id, company_id, vendor_specific_codec_id) = struct.unpack_from( ' CodingFormat: return cls.parse_from_bytes(data, 0)[1] def __bytes__(self) -> bytes: return struct.pack( ' str: return Role(role).name @staticmethod def le_phy_name(phy): return HCI_LE_PHY_NAMES.get(phy, str(phy)) @staticmethod def inquiry_lap_name(lap): return HCI_INQUIRY_LAP_NAMES.get(lap, f'0x{lap:06X}') @staticmethod def io_capability_name(io_capability: int) -> str: return IoCapability(io_capability).name @staticmethod def authentication_requirements_name(authentication_requirements: int) -> str: return AuthenticationRequirements(authentication_requirements).name @staticmethod def link_key_type_name(link_key_type: int) -> str: return LinkKeyType(link_key_type).name # ----------------------------------------------------------------------------- class HCI_Error(ProtocolError): def __init__(self, error_code): super().__init__( error_code, error_namespace='hci', error_name=HCI_Constant.error_name(error_code), ) # ----------------------------------------------------------------------------- class HCI_StatusError(ProtocolError): def __init__(self, response): super().__init__( response.status, error_namespace=HCI_Command.command_name(response.command_opcode), error_name=HCI_Constant.status_name(response.status), ) # ----------------------------------------------------------------------------- # Generic HCI object # ----------------------------------------------------------------------------- class HCI_Object: @staticmethod def init_from_fields(hci_object, fields, values): if isinstance(values, dict): for field in fields: if isinstance(field, list): # The field is an array, up-level the array field names for sub_field_name, _ in field: setattr(hci_object, sub_field_name, values[sub_field_name]) else: field_name = field[0] setattr(hci_object, field_name, values[field_name]) else: for field_name, field_value in zip(fields, values): setattr(hci_object, field_name, field_value) @staticmethod def init_from_bytes(hci_object, data, offset, fields): parsed = HCI_Object.dict_from_bytes(data, offset, fields) HCI_Object.init_from_fields(hci_object, parsed.keys(), parsed.values()) @staticmethod def parse_field(data: bytes, offset: int, field_type: FieldSpec): # The field_type may be a dictionary with a mapper, parser, and/or size if isinstance(field_type, dict): if 'size' in field_type: field_type = field_type['size'] elif 'parser' in field_type: field_type = field_type['parser'] # Parse the field if field_type == '*': # The rest of the bytes field_value = data[offset:] return (field_value, len(field_value)) if field_type == 'v': # Variable-length bytes field, with 1-byte length at the beginning field_length = data[offset] offset += 1 field_value = data[offset : offset + field_length] return (field_value, field_length + 1) if field_type == 1: # 8-bit unsigned return (data[offset], 1) if field_type == -1: # 8-bit signed return (struct.unpack_from('b', data, offset)[0], 1) if field_type == 2: # 16-bit unsigned return (struct.unpack_from('2': # 16-bit unsigned big-endian return (struct.unpack_from('>H', data, offset)[0], 2) if field_type == -2: # 16-bit signed return (struct.unpack_from('4': # 32-bit unsigned big-endian return (struct.unpack_from('>I', data, offset)[0], 4) if isinstance(field_type, int) and 4 < field_type <= 256: # Byte array (from 5 up to 256 bytes) return (data[offset : offset + field_type], field_type) if callable(field_type): new_offset, field_value = field_type(data, offset) return (field_value, new_offset - offset) raise InvalidArgumentError(f'unknown field type {field_type}') @classmethod def dict_and_offset_from_bytes( cls, data: bytes, offset: int, fields: Fields ) -> tuple[int, collections.OrderedDict[str, Any]]: result = collections.OrderedDict[str, Any]() for field in fields: if isinstance(field, list): # This is an array field, starting with a 1-byte item count. item_count = data[offset] offset += 1 # Set fields first, because item_count might be 0. for sub_field_name, _ in field: result[sub_field_name] = [] for _ in range(item_count): for sub_field_name, sub_field_type in field: value, size = HCI_Object.parse_field( data, offset, sub_field_type ) result[sub_field_name].append(value) offset += size continue field_name, field_type = field assert isinstance(field_name, str) field_value, field_size = HCI_Object.parse_field( data, offset, cast(FieldSpec, field_type) ) result[field_name] = field_value offset += field_size return (offset, result) @staticmethod def dict_from_bytes(data, offset, fields): return HCI_Object.dict_and_offset_from_bytes(data, offset, fields)[1] @staticmethod def serialize_field(field_value: Any, field_type: FieldSpec) -> bytes: # The field_type may be a dictionary with a mapper, parser, serializer, # and/or size serializer = None if isinstance(field_type, dict): if 'serializer' in field_type: serializer = field_type['serializer'] if 'size' in field_type: field_type = field_type['size'] # Serialize the field if serializer: field_bytes = serializer(field_value) elif field_type == 1: # 8-bit unsigned field_bytes = bytes([field_value]) elif field_type == -1: # 8-bit signed field_bytes = struct.pack('b', field_value) elif field_type == 2: # 16-bit unsigned field_bytes = struct.pack('2': # 16-bit unsigned big-endian field_bytes = struct.pack('>H', field_value) elif field_type == -2: # 16-bit signed field_bytes = struct.pack('4': # 32-bit unsigned big-endian field_bytes = struct.pack('>I', field_value) elif field_type == '*': if isinstance(field_value, int): if 0 <= field_value <= 255: field_bytes = bytes([field_value]) else: raise InvalidArgumentError('value too large for *-typed field') else: field_bytes = bytes(field_value) elif field_type == 'v': # Variable-length bytes field, with 1-byte length at the beginning field_bytes = bytes(field_value) field_length = len(field_bytes) field_bytes = bytes([field_length]) + field_bytes elif isinstance(field_value, (bytes, bytearray)) or hasattr( field_value, '__bytes__' ): field_bytes = bytes(field_value) if isinstance(field_type, int) and 4 < field_type <= 256: # Truncate or pad with zeros if the field is too long or too short if len(field_bytes) < field_type: field_bytes += bytes(field_type - len(field_bytes)) elif len(field_bytes) > field_type: field_bytes = field_bytes[:field_type] else: raise InvalidArgumentError( f"don't know how to serialize type {type(field_value)}" ) return field_bytes @staticmethod def dict_to_bytes(hci_object, fields): result = bytearray() for field in fields: if isinstance(field, list): # The field is an array. The serialized form starts with a 1-byte # item count. We use the length of the first array field as the # array count, since all array fields have the same number of items. item_count = len(hci_object[field[0][0]]) result += bytes([item_count]) + b''.join( b''.join( HCI_Object.serialize_field( hci_object[sub_field_name][i], sub_field_type ) for sub_field_name, sub_field_type in field ) for i in range(item_count) ) continue (field_name, field_type) = field result += HCI_Object.serialize_field(hci_object[field_name], field_type) return bytes(result) @classmethod def from_bytes(cls, data, offset, fields): return cls(fields, **cls.dict_from_bytes(data, offset, fields)) def __bytes__(self): return HCI_Object.dict_to_bytes(self.__dict__, self.fields) @staticmethod def parse_length_prefixed_bytes(data, offset): length = data[offset] return offset + 1 + length, data[offset + 1 : offset + 1 + length] @staticmethod def serialize_length_prefixed_bytes(data, padded_size=0): prefixed_size = 1 + len(data) padding = ( bytes(padded_size - prefixed_size) if prefixed_size < padded_size else b'' ) return bytes([len(data)]) + data + padding @staticmethod def format_field_value(value, indentation): if isinstance(value, bytes): return value.hex() if isinstance(value, HCI_Object): return '\n' + value.to_string(indentation) return str(value) @staticmethod def stringify_field( field_name, field_type, field_value, indentation, value_mappers ): value_mapper = None if isinstance(field_type, dict): # Get the value mapper from the specifier value_mapper = field_type.get('mapper') # Check if there's a matching mapper passed if value_mappers: value_mapper = value_mappers.get(field_name, value_mapper) # Map the value if we have a mapper if value_mapper is not None: field_value = value_mapper(field_value) # Get the string representation of the value return HCI_Object.format_field_value( field_value, indentation=indentation + ' ' ) @staticmethod def format_fields(hci_object, fields, indentation='', value_mappers=None): if not fields: return '' # Build array of formatted key:value pairs field_strings = [] for field in fields: if isinstance(field, list): for sub_field in field: sub_field_name, sub_field_type = sub_field item_count = len(hci_object[sub_field_name]) for i in range(item_count): field_strings.append( ( f'{sub_field_name}[{i}]', HCI_Object.stringify_field( sub_field_name, sub_field_type, hci_object[sub_field_name][i], indentation, value_mappers, ), ), ) continue field_name, field_type = field field_value = hci_object[field_name] field_strings.append( ( field_name, HCI_Object.stringify_field( field_name, field_type, field_value, indentation, value_mappers ), ), ) # Measure the widest field name max_field_name_length = max(len(s[0]) for s in field_strings) sep = ':' return '\n'.join( f'{indentation}' f'{color(f"{field_name + sep:{1 + max_field_name_length}}", "cyan")} {field_value}' for field_name, field_value in field_strings ) @classmethod def fields_from_dataclass(cls, obj: Any) -> list[Any]: stack: list[list[Any]] = [[]] for field in dataclasses.fields(obj): # Fields without metadata should be ignored. if not isinstance( (metadata := field.metadata.get("bumble.hci")), FieldMetadata ): continue if metadata.list_begin: stack.append([]) if metadata.spec: stack[-1].append((field.name, metadata.spec)) if metadata.list_end: top = stack.pop() stack[-1].append(top) return stack[0] def __init__(self, fields, **kwargs): self.fields = fields self.init_from_fields(self, fields, kwargs) def to_string(self, indentation='', value_mappers=None): return HCI_Object.format_fields( self.__dict__, self.fields, indentation, value_mappers ) def __str__(self): return self.to_string() # ----------------------------------------------------------------------------- @dataclasses.dataclass class HCI_Dataclass_Object(HCI_Object): def __post_init__(self) -> None: self.fields = HCI_Object.fields_from_dataclass(self) @classmethod def parse_from_bytes(cls, data: bytes, offset: int) -> tuple[int, Self]: fields = HCI_Object.fields_from_dataclass(cls) offset, kwargs = HCI_Object.dict_and_offset_from_bytes(data, offset, fields) return offset, cls(**kwargs) # ----------------------------------------------------------------------------- # Bluetooth Address # ----------------------------------------------------------------------------- class Address: ''' Bluetooth Address (see Bluetooth spec Vol 6, Part B - 1.3 DEVICE ADDRESS) NOTE: the address bytes are stored in little-endian byte order here, so address[0] is the LSB of the address, address[5] is the MSB. ''' PUBLIC_DEVICE_ADDRESS = AddressType.PUBLIC_DEVICE RANDOM_DEVICE_ADDRESS = AddressType.RANDOM_DEVICE PUBLIC_IDENTITY_ADDRESS = AddressType.PUBLIC_IDENTITY RANDOM_IDENTITY_ADDRESS = AddressType.RANDOM_IDENTITY # Type declarations NIL: Address ANY: Address ANY_RANDOM: Address # pylint: disable-next=unnecessary-lambda ADDRESS_TYPE_SPEC = {'size': 1, 'mapper': lambda x: Address.address_type_name(x)} @classmethod def address_type_name(cls: type[Self], address_type: int) -> str: return AddressType(address_type).name @classmethod def from_string_for_transport( cls: type[Self], string: str, transport: PhysicalTransport ) -> Self: if transport == PhysicalTransport.BR_EDR: address_type = Address.PUBLIC_DEVICE_ADDRESS else: address_type = Address.RANDOM_DEVICE_ADDRESS return cls(string, address_type) @classmethod def parse_address(cls: type[Self], data: bytes, offset: int) -> tuple[int, Self]: # Fix the type to a default value. This is used for parsing type-less Classic # addresses return cls.parse_address_with_type(data, offset, Address.PUBLIC_DEVICE_ADDRESS) @classmethod def parse_random_address( cls: type[Self], data: bytes, offset: int ) -> tuple[int, Self]: return cls.parse_address_with_type(data, offset, Address.RANDOM_DEVICE_ADDRESS) @classmethod def parse_address_with_type( cls: type[Self], data: bytes, offset: int, address_type: AddressType ) -> tuple[int, Self]: return offset + 6, cls(data[offset : offset + 6], address_type) @classmethod def parse_address_preceded_by_type( cls: type[Self], data: bytes, offset: int ) -> tuple[int, Self]: address_type = AddressType(data[offset - 1]) return cls.parse_address_with_type(data, offset, address_type) @classmethod def generate_static_address(cls) -> Address: '''Generates Random Static Address, with the 2 most significant bits of 0b11. See Bluetooth spec, Vol 6, Part B - Table 1.2. ''' address_bytes = secrets.token_bytes(6) address_bytes = address_bytes[:5] + bytes([address_bytes[5] | 0b11000000]) return Address( address=address_bytes, address_type=Address.RANDOM_DEVICE_ADDRESS ) @classmethod def generate_private_address(cls, irk: bytes = b'') -> Address: '''Generates Random Private MAC Address. If IRK is present, a Resolvable Private Address, with the 2 most significant bits of 0b01 will be generated. Otherwise, a Non-resolvable Private Address, with the 2 most significant bits of 0b00 will be generated. See Bluetooth spec, Vol 6, Part B - Table 1.2. Args: irk: Local Identity Resolving Key(IRK), in little-endian. If not set, a non-resolvable address will be generated. ''' if irk: prand = crypto.generate_prand() address_bytes = crypto.ah(irk, prand) + prand else: address_bytes = secrets.token_bytes(6) address_bytes = address_bytes[:5] + bytes([address_bytes[5] & 0b00111111]) return Address( address=address_bytes, address_type=Address.RANDOM_DEVICE_ADDRESS ) def __init__( self, address: Union[bytes, str], address_type: AddressType = RANDOM_DEVICE_ADDRESS, ) -> None: ''' 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. ''' if isinstance(address, bytes): self.address_bytes = address else: # Check if there's a '/P' type specifier if address.endswith('P'): address_type = Address.PUBLIC_DEVICE_ADDRESS address = address[:-2] if len(address) == 12 + 5: # Form with ':' separators address = address.replace(':', '') self.address_bytes = bytes(reversed(bytes.fromhex(address))) if len(self.address_bytes) != 6: raise InvalidArgumentError('invalid address length') self.address_type = address_type def clone(self): return Address(self.address_bytes, self.address_type) @property def is_public(self): return self.address_type in ( self.PUBLIC_DEVICE_ADDRESS, self.PUBLIC_IDENTITY_ADDRESS, ) @property def is_random(self): return not self.is_public @property def is_resolved(self): return self.address_type in ( self.PUBLIC_IDENTITY_ADDRESS, self.RANDOM_IDENTITY_ADDRESS, ) @property def is_resolvable(self): return self.address_type == self.RANDOM_DEVICE_ADDRESS and ( self.address_bytes[5] >> 6 == 1 ) @property def is_static(self): return self.is_random and (self.address_bytes[5] >> 6 == 3) def to_string(self, with_type_qualifier=True): ''' String representation of the address, MSB first, with an optional type qualifier. ''' result = ':'.join([f'{x:02X}' for x in reversed(self.address_bytes)]) if not with_type_qualifier or not self.is_public: return result return result + '/P' def __bytes__(self): return self.address_bytes def __hash__(self): return hash(self.address_bytes) def __eq__(self, other): return ( isinstance(other, Address) and self.address_bytes == other.address_bytes and self.is_public == other.is_public ) def __str__(self): return self.to_string() def __repr__(self): return f'Address({self.to_string(False)}/{self.address_type_name(self.address_type)})' # Predefined address values Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS) Address.ANY = Address(b"\x00\x00\x00\x00\x00\x00", Address.PUBLIC_DEVICE_ADDRESS) Address.ANY_RANDOM = Address(b"\x00\x00\x00\x00\x00\x00", Address.RANDOM_DEVICE_ADDRESS) # ----------------------------------------------------------------------------- class OwnAddressType(SpecableEnum): PUBLIC = 0 RANDOM = 1 RESOLVABLE_OR_PUBLIC = 2 RESOLVABLE_OR_RANDOM = 3 # ----------------------------------------------------------------------------- class LoopbackMode(SpecableEnum): DISABLED = 0 LOCAL = 1 REMOTE = 2 # ----------------------------------------------------------------------------- class CteType(SpecableEnum): AOA_CONSTANT_TONE_EXTENSION = 0x00 AOD_CONSTANT_TONE_EXTENSION_1US = 0x01 AOD_CONSTANT_TONE_EXTENSION_2US = 0x02 NO_CONSTANT_TONE_EXTENSION = 0xFF # ----------------------------------------------------------------------------- class HCI_Packet: ''' Abstract Base class for HCI packets ''' hci_packet_type: ClassVar[int] @staticmethod def from_bytes(packet: bytes) -> HCI_Packet: packet_type = packet[0] if packet_type == HCI_COMMAND_PACKET: return HCI_Command.from_bytes(packet) if packet_type == HCI_ACL_DATA_PACKET: return HCI_AclDataPacket.from_bytes(packet) if packet_type == HCI_SYNCHRONOUS_DATA_PACKET: return HCI_SynchronousDataPacket.from_bytes(packet) if packet_type == HCI_EVENT_PACKET: return HCI_Event.from_bytes(packet) if packet_type == HCI_ISO_DATA_PACKET: return HCI_IsoDataPacket.from_bytes(packet) return HCI_CustomPacket(packet) def __init__(self, name): self.name = name def __bytes__(self) -> bytes: raise NotImplementedError def __repr__(self) -> str: return self.name # ----------------------------------------------------------------------------- class HCI_CustomPacket(HCI_Packet): def __init__(self, payload): super().__init__('HCI_CUSTOM_PACKET') self.hci_packet_type = payload[0] self.payload = payload def __bytes__(self) -> bytes: return self.payload # ----------------------------------------------------------------------------- class HCI_Command(HCI_Packet): ''' See Bluetooth spec @ Vol 2, Part E - 5.4.1 HCI Command Packet ''' hci_packet_type = HCI_COMMAND_PACKET command_names: dict[int, str] = {} command_classes: dict[int, type[HCI_Command]] = {} op_code: int = -1 fields: Fields = () return_parameters_fields: Fields = () _parameters: bytes = b'' _Command = TypeVar("_Command", bound="HCI_Command") @classmethod def command(cls, subclass: type[_Command]) -> type[_Command]: ''' Decorator used to declare and register subclasses ''' subclass.name = subclass.__name__.upper() subclass.op_code = key_with_value(subclass.command_names, subclass.name) if subclass.op_code is None: raise KeyError(f'command {subclass.name} not found in command_names') if dataclasses.is_dataclass(subclass): subclass.fields = HCI_Object.fields_from_dataclass(subclass) # Register a factory for this class cls.command_classes[subclass.op_code] = subclass return subclass @staticmethod def command_map(symbols: dict[str, Any]) -> dict[int, str]: return { command_code: command_name for (command_name, command_code) in symbols.items() if command_name.startswith('HCI_') and command_name.endswith('_COMMAND') } @classmethod def register_commands(cls, symbols: dict[str, Any]) -> None: cls.command_names.update(cls.command_map(symbols)) @staticmethod def from_bytes(packet: bytes) -> HCI_Command: op_code, length = struct.unpack_from(' HCI_Command: command = cls(**HCI_Object.dict_from_bytes(parameters, 0, cls.fields)) command.parameters = parameters return command @staticmethod def command_name(op_code): name = HCI_Command.command_names.get(op_code) if name is not None: return name return f'[OGF=0x{op_code >> 10:02x}, OCF=0x{op_code & 0x3FF:04x}]' @classmethod def create_return_parameters(cls, **kwargs): return HCI_Object(cls.return_parameters_fields, **kwargs) @classmethod def parse_return_parameters(cls, parameters): if not cls.return_parameters_fields: return None return_parameters = HCI_Object.from_bytes( parameters, 0, cls.return_parameters_fields ) return_parameters.fields = cls.return_parameters_fields return return_parameters def __init__( self, parameters: Optional[bytes] = None, *, op_code: Optional[int] = None, **kwargs, ) -> None: # op_code should be set in cls. if op_code is not None: self.op_code = op_code super().__init__(HCI_Command.command_name(self.op_code)) if self.fields and kwargs: HCI_Object.init_from_fields(self, self.fields, kwargs) if parameters is None: parameters = HCI_Object.dict_to_bytes(kwargs, self.fields) self.parameters = parameters or b'' @property def parameters(self) -> bytes: if not self._parameters: self._parameters = HCI_Object.dict_to_bytes(self.__dict__, self.fields) return self._parameters @parameters.setter def parameters(self, parameters: bytes): self._parameters = parameters def __bytes__(self) -> bytes: parameters = b'' if self.parameters is None else self.parameters return ( struct.pack(' bytes: ''' Compute the event mask value for a list of events. ''' # NOTE: this implementation takes advantage of the fact that as of version 5.4 # of the core specification, the bit number for each event code is equal to one # less than the event code. # If future versions of the specification deviate from that, a different # implementation would be needed. return sum((1 << event_code - 1) for event_code in event_codes).to_bytes( 8, 'little' ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Reset_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.2 Reset Command ''' # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Set_Event_Filter_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.3 Set Event Filter Command ''' filter_type: int = field(metadata=metadata(1)) filter_condition: bytes = field(metadata=metadata("*")) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Stored_Link_Key_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.8 Read Stored Link Key Command ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) read_all_flag: int = field(metadata=metadata(1)) return_parameters_fields = [ ('status', STATUS_SPEC), ('max_num_keys', 2), ('num_keys_read', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Delete_Stored_Link_Key_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.10 Delete Stored Link Key Command ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) delete_all_flag: int = field(metadata=metadata(1)) return_parameters_fields = [('status', STATUS_SPEC), ('num_keys_deleted', 2)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Local_Name_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.11 Write Local Name Command ''' local_name: bytes = field( metadata=metadata({'size': 248, 'mapper': map_null_terminated_utf8_string}) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Name_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.12 Read Local Name Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string}), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Connection_Accept_Timeout_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.14 Write Connection Accept Timeout Command ''' connection_accept_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Page_Timeout_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.16 Write Page Timeout Command ''' page_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Scan_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.18 Write Scan Enable Command ''' scan_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Page_Scan_Activity_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.19 Read Page Scan Activity Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('page_scan_interval', 2), ('page_scan_window', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Page_Scan_Activity_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.20 Write Page Scan Activity Command ''' page_scan_interval: int = field(metadata=metadata(2)) page_scan_window: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Inquiry_Scan_Activity_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.22 Write Inquiry Scan Activity Command ''' inquiry_scan_interval: int = field(metadata=metadata(2)) inquiry_scan_window: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Authentication_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.23 Read Authentication Enable Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('authentication_enable', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Authentication_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.24 Write Authentication Enable Command ''' authentication_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Class_Of_Device_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.25 Read Class of Device Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('class_of_device', COD_SPEC), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Class_Of_Device_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.26 Write Class of Device Command ''' class_of_device: int = field(metadata=metadata(COD_SPEC)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Voice_Setting_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.27 Read Voice Setting Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('voice_setting', 2)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Voice_Setting_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.28 Write Voice Setting Command ''' voice_setting: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Synchronous_Flow_Control_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.36 Read Synchronous Flow Control Enable Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('synchronous_flow_control_enable', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Synchronous_Flow_Control_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.37 Write Synchronous Flow Control Enable Command ''' synchronous_flow_control_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Host_Buffer_Size_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.39 Host Buffer Size Command ''' host_acl_data_packet_length: int = field(metadata=metadata(2)) host_synchronous_data_packet_length: int = field(metadata=metadata(1)) host_total_num_acl_data_packets: int = field(metadata=metadata(2)) host_total_num_synchronous_data_packets: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Link_Supervision_Timeout_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.42 Write Link Supervision Timeout Command ''' handle: int = field(metadata=metadata(2)) link_supervision_timeout: int = field(metadata=metadata(2)) return_parameters_fields = [ ('status', STATUS_SPEC), ('handle', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Number_Of_Supported_IAC_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.43 Read Number Of Supported IAC Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('num_support_iac', 1)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Current_IAC_LAP_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.44 Read Current IAC LAP Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('num_current_iac', 1), ('iac_lap', '*'), # TODO: this should be parsed as an array ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Inquiry_Scan_Type_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.48 Write Inquiry Scan Type Command ''' scan_type: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Inquiry_Mode_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.50 Write Inquiry Mode Command ''' inquiry_mode: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Page_Scan_Type_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.51 Read Page Scan Type Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('page_scan_type', 1)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Page_Scan_Type_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.52 Write Page Scan Type Command ''' page_scan_type: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Extended_Inquiry_Response_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.56 Write Extended Inquiry Response Command ''' fec_required: int = field(metadata=metadata(1)) extended_inquiry_response: int = field( metadata=metadata({'size': 240, 'serializer': lambda x: padded_bytes(x, 240)}) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Simple_Pairing_Mode_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.59 Write Simple Pairing Mode Command ''' simple_pairing_mode: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_OOB_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.60 Read Local OOB Data Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('c', 16), ('r', 16), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Inquiry_Response_Transmit_Power_Level_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.61 Read Inquiry Response Transmit Power Level Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('tx_power', -1)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Default_Erroneous_Data_Reporting_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.64 Read Default Erroneous Data Reporting Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('erroneous_data_reporting', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Set_Event_Mask_Page_2_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.69 Set Event Mask Page 2 Command ''' event_mask_page_2: bytes = field(metadata=metadata(8)) @staticmethod def mask(event_codes: Iterable[int]) -> bytes: ''' Compute the event mask value for a list of events. ''' # NOTE: this implementation takes advantage of the fact that as of version 6.0 # of the core specification, the bit number for each event code is equal to 64 # less than the event code. # If future versions of the specification deviate from that, a different # implementation would be needed. return sum((1 << event_code - 64) for event_code in event_codes).to_bytes( 8, 'little' ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_LE_Host_Support_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.78 Read LE Host Support Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('le_supported_host', 1), ('unused', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_LE_Host_Support_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.79 Write LE Host Support Command ''' le_supported_host: int = field(metadata=metadata(1)) simultaneous_le_host: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Secure_Connections_Host_Support_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.92 Write Secure Connections Host Support Command ''' secure_connections_host_support: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Authenticated_Payload_Timeout_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.94 Write Authenticated Payload Timeout Command ''' connection_handle: int = field(metadata=metadata(2)) authenticated_payload_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_OOB_Extended_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.3.95 Read Local OOB Extended Data Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('c_192', 16), ('r_192', 16), ('c_256', 16), ('r_256', 16), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Version_Information_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.1 Read Local Version Information Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('hci_version', 1), ('hci_subversion', 2), ('lmp_version', 1), ('company_identifier', 2), ('lmp_subversion', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Supported_Commands_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.2 Read Local Supported Commands Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('supported_commands', 64)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Supported_Features_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.3 Read Local Supported Features Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('lmp_features', 8), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Extended_Features_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.4 Read Local Extended Features Command ''' page_number: int = field(metadata=metadata(1)) return_parameters_fields = [ ('status', STATUS_SPEC), ('page_number', 1), ('maximum_page_number', 1), ('extended_lmp_features', 8), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Buffer_Size_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.5 Read Buffer Size Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('hc_acl_data_packet_length', 2), ('hc_synchronous_data_packet_length', 1), ('hc_total_num_acl_data_packets', 2), ('hc_total_num_synchronous_data_packets', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_BD_ADDR_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.6 Read BD_ADDR Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('bd_addr', Address.parse_address), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Supported_Codecs_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.8 Read Local Supported Codecs Command ''' return_parameters_fields = [ ("status", STATUS_SPEC), [("standard_codec_ids", 1)], [("vendor_specific_codec_ids", 4)], ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Local_Supported_Codecs_V2_Command(HCI_Command): ''' See Bluetooth spec @ 7.4.8 Read Local Supported Codecs Command ''' return_parameters_fields = [ ("status", STATUS_SPEC), [("standard_codec_ids", 1), ("standard_codec_transports", 1)], [("vendor_specific_codec_ids", 4), ("vendor_specific_codec_transports", 1)], ] class Transport(SpecableFlag): BR_EDR_ACL = 1 << 0 BR_EDR_SCO = 1 << 1 LE_CIS = 1 << 2 LE_BIS = 1 << 3 # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_RSSI_Command(HCI_Command): ''' See Bluetooth spec @ 7.5.4 Read RSSI Command ''' handle: int = field(metadata=metadata(2)) return_parameters_fields = [('status', STATUS_SPEC), ('handle', 2), ('rssi', -1)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Encryption_Key_Size_Command(HCI_Command): ''' See Bluetooth spec @ 7.5.7 Read Encryption Key Size Command ''' connection_handle: int = field(metadata=metadata(2)) return_parameters_fields = [ ('status', STATUS_SPEC), ('connection_handle', 2), ('key_size', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Read_Loopback_Mode_Command(HCI_Command): ''' See Bluetooth spec @ 7.6.1 Read Loopback Mode Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('loopback_mode', LoopbackMode.type_spec(1)), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_Write_Loopback_Mode_Command(HCI_Command): ''' See Bluetooth spec @ 7.6.2 Write Loopback Mode Command ''' loopback_mode: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Event_Mask_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.1 LE Set Event Mask Command ''' le_event_mask: bytes = field(metadata=metadata(8)) @staticmethod def mask(event_codes: Iterable[int]) -> bytes: ''' Compute the event mask value for a list of events. ''' # NOTE: this implementation takes advantage of the fact that as of version 5.4 # of the core specification, the bit number for each event code is equal to one # less than the event code. # If future versions of the specification deviate from that, a different # implementation would be needed. return sum((1 << event_code - 1) for event_code in event_codes).to_bytes( 8, 'little' ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Buffer_Size_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.2 LE Read Buffer Size Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('le_acl_data_packet_length', 2), ('total_num_le_acl_data_packets', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Buffer_Size_V2_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.2 LE Read Buffer Size V2 Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('le_acl_data_packet_length', 2), ('total_num_le_acl_data_packets', 1), ('iso_data_packet_length', 2), ('total_num_iso_data_packets', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Local_Supported_Features_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.3 LE Read Local Supported Features Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('le_features', 8)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Random_Address_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.4 LE Set Random Address Command ''' random_address: Address = field( metadata=metadata( lambda data, offset: Address.parse_address_with_type( data, offset, Address.RANDOM_DEVICE_ADDRESS ) ) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Advertising_Parameters_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.5 LE Set Advertising Parameters Command ''' class AdvertisingType(SpecableEnum): ADV_IND = 0x00 ADV_DIRECT_IND = 0x01 ADV_SCAN_IND = 0x02 ADV_NONCONN_IND = 0x03 ADV_DIRECT_IND_LOW_DUTY = 0x04 advertising_interval_min: int = field(metadata=metadata(2)) advertising_interval_max: int = field(metadata=metadata(2)) advertising_type: int = field(metadata=AdvertisingType.type_metadata(1)) own_address_type: int = field(metadata=OwnAddressType.type_metadata(1)) peer_address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertising_channel_map: int = field(metadata=metadata(1)) advertising_filter_policy: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Advertising_Physical_Channel_Tx_Power_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.6 LE Read Advertising Physical Channel Tx Power Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('tx_power_level', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Advertising_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.7 LE Set Advertising Data Command ''' advertising_data: bytes = field( metadata=metadata( { 'parser': HCI_Object.parse_length_prefixed_bytes, 'serializer': functools.partial( HCI_Object.serialize_length_prefixed_bytes, padded_size=32 ), } ) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Scan_Response_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.8 LE Set Scan Response Data Command ''' scan_response_data: bytes = field( metadata=metadata( { 'parser': HCI_Object.parse_length_prefixed_bytes, 'serializer': functools.partial( HCI_Object.serialize_length_prefixed_bytes, padded_size=32 ), } ) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Advertising_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.9 LE Set Advertising Enable Command ''' advertising_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Scan_Parameters_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.10 LE Set Scan Parameters Command ''' le_scan_type: int = field(metadata=metadata(1)) le_scan_interval: int = field(metadata=metadata(2)) le_scan_window: int = field(metadata=metadata(2)) own_address_type: int = field(metadata=OwnAddressType.type_metadata(1)) scanning_filter_policy: int = field(metadata=metadata(1)) PASSIVE_SCANNING = 0 ACTIVE_SCANNING = 1 BASIC_UNFILTERED_POLICY = 0x00 BASIC_FILTERED_POLICY = 0x01 EXTENDED_UNFILTERED_POLICY = 0x02 EXTENDED_FILTERED_POLICY = 0x03 # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Scan_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.11 LE Set Scan Enable Command ''' le_scan_enable: int = field(metadata=metadata(1)) filter_duplicates: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Create_Connection_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.12 LE Create Connection Command ''' le_scan_interval: int = field(metadata=metadata(2)) le_scan_window: int = field(metadata=metadata(2)) initiator_filter_policy: int = field(metadata=metadata(1)) peer_address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) own_address_type: int = field(metadata=OwnAddressType.type_metadata(1)) connection_interval_min: int = field(metadata=metadata(2)) connection_interval_max: int = field(metadata=metadata(2)) max_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) min_ce_length: int = field(metadata=metadata(2)) max_ce_length: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Create_Connection_Cancel_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.13 LE Create Connection Cancel Command ''' # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Filter_Accept_List_Size_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.14 LE Read Filter Accept List Size Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('filter_accept_list_size', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Clear_Filter_Accept_List_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.15 LE Clear Filter Accept List Command ''' # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Add_Device_To_Filter_Accept_List_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.16 LE Add Device To Filter Accept List Command ''' address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) address: Address = field(metadata=metadata(Address.parse_address_preceded_by_type)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Remove_Device_From_Filter_Accept_List_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.17 LE Remove Device From Filter Accept List Command ''' address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) address: Address = field(metadata=metadata(Address.parse_address_preceded_by_type)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Connection_Update_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.18 LE Connection Update Command ''' connection_handle: int = field(metadata=metadata(2)) connection_interval_min: int = field(metadata=metadata(2)) connection_interval_max: int = field(metadata=metadata(2)) max_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) min_ce_length: int = field(metadata=metadata(2)) max_ce_length: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Remote_Features_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.21 LE Read Remote Features Command ''' connection_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Rand_Command(HCI_Command): """ See Bluetooth spec @ 7.8.23 LE Rand Command """ return_parameters_fields = [("status", STATUS_SPEC), ("random_number", 8)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Enable_Encryption_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.24 LE Enable Encryption Command (renamed from "LE Start Encryption Command" in version prior to 5.2 of the specification) ''' connection_handle: int = field(metadata=metadata(2)) random_number: bytes = field(metadata=metadata(8)) encrypted_diversifier: int = field(metadata=metadata(2)) long_term_key: bytes = field(metadata=metadata(16)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Long_Term_Key_Request_Reply_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.25 LE Long Term Key Request Reply Command ''' connection_handle: int = field(metadata=metadata(2)) long_term_key: bytes = field(metadata=metadata(16)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Long_Term_Key_Request_Negative_Reply_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.26 LE Long Term Key Request Negative Reply Command ''' connection_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Supported_States_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.27 LE Read Supported States Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('le_states', 8), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Remote_Connection_Parameter_Request_Reply_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.31 LE Remote Connection Parameter Request Reply Command ''' connection_handle: int = field(metadata=metadata(2)) interval_min: int = field(metadata=metadata(2)) interval_max: int = field(metadata=metadata(2)) max_latency: int = field(metadata=metadata(2)) timeout: int = field(metadata=metadata(2)) min_ce_length: int = field(metadata=metadata(2)) max_ce_length: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Remote_Connection_Parameter_Request_Negative_Reply_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.32 LE Remote Connection Parameter Request Negative Reply Command ''' connection_handle: int = field(metadata=metadata(2)) reason: int = field(metadata=metadata(STATUS_SPEC)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Data_Length_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.33 LE Set Data Length Command ''' connection_handle: int = field(metadata=metadata(2)) tx_octets: int = field(metadata=metadata(2)) tx_time: int = field(metadata=metadata(2)) return_parameters_fields = [('status', STATUS_SPEC), ('connection_handle', 2)] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Suggested_Default_Data_Length_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.34 LE Read Suggested Default Data Length Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('suggested_max_tx_octets', 2), ('suggested_max_tx_time', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Write_Suggested_Default_Data_Length_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.35 LE Write Suggested Default Data Length Command ''' suggested_max_tx_octets: int = field(metadata=metadata(2)) suggested_max_tx_time: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Add_Device_To_Resolving_List_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.38 LE Add Device To Resolving List Command ''' peer_identity_address_type: int = field( metadata=metadata(Address.ADDRESS_TYPE_SPEC) ) peer_identity_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) peer_irk: bytes = field(metadata=metadata(16)) local_irk: bytes = field(metadata=metadata(16)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Clear_Resolving_List_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.40 LE Clear Resolving List Command ''' # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Address_Resolution_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.44 LE Set Address Resolution Enable Command ''' address_resolution_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Resolvable_Private_Address_Timeout_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.45 LE Set Resolvable Private Address Timeout Command ''' rpa_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Maximum_Data_Length_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.46 LE Read Maximum Data Length Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('supported_max_tx_octets', 2), ('supported_max_tx_time', 2), ('supported_max_rx_octets', 2), ('supported_max_rx_time', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_PHY_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.47 LE Read PHY Command ''' connection_handle: int = field(metadata=metadata(2)) return_parameters_fields = [ ('status', STATUS_SPEC), ('connection_handle', 2), ('tx_phy', Phy.type_spec(1)), ('rx_phy', Phy.type_spec(1)), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Default_PHY_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.48 LE Set Default PHY Command ''' class AnyPhy(SpecableFlag): ANY_TX = 0 ANY_RX = 1 all_phys: int = field(metadata=AnyPhy.type_metadata(1)) tx_phys: int = field(metadata=PhyBit.type_metadata(1)) rx_phys: int = field(metadata=PhyBit.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_PHY_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.49 LE Set PHY Command ''' connection_handle: int = field(metadata=metadata(2)) all_phys: int = field( metadata=HCI_LE_Set_Default_PHY_Command.AnyPhy.type_metadata(1) ) tx_phys: int = field(metadata=PhyBit.type_metadata(1)) rx_phys: int = field(metadata=PhyBit.type_metadata(1)) phy_options: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Advertising_Set_Random_Address_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.52 LE Set Advertising Set Random Address Command ''' advertising_handle: int = field(metadata=metadata(1)) random_address: Address = field( metadata=metadata( lambda data, offset: Address.parse_address_with_type( data, offset, Address.RANDOM_DEVICE_ADDRESS ) ) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Extended_Advertising_Parameters_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.53 LE Set Extended Advertising Parameters Command ''' return_parameters_fields = [('status', STATUS_SPEC), ('selected_tx_power', 1)] TX_POWER_NO_PREFERENCE = 0x7F SHOULD_NOT_FRAGMENT = 0x01 class AdvertisingProperties(SpecableFlag): CONNECTABLE_ADVERTISING = 1 << 0 SCANNABLE_ADVERTISING = 1 << 1 DIRECTED_ADVERTISING = 1 << 2 HIGH_DUTY_CYCLE_DIRECTED_CONNECTABLE_ADVERTISING = 1 << 3 USE_LEGACY_ADVERTISING_PDUS = 1 << 4 ANONYMOUS_ADVERTISING = 1 << 5 INCLUDE_TX_POWER = 1 << 6 def __str__(self) -> str: return '|'.join( flag.name for flag in HCI_LE_Set_Extended_Advertising_Parameters_Command.AdvertisingProperties if self.value & flag.value and flag.name is not None ) class ChannelMap(SpecableFlag): CHANNEL_37 = 1 << 0 CHANNEL_38 = 1 << 1 CHANNEL_39 = 1 << 2 def __str__(self) -> str: return '|'.join( flag.name for flag in HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap if self.value & flag.value and flag.name is not None ) advertising_handle: int = field(metadata=metadata(1)) advertising_event_properties: int = field( metadata=AdvertisingProperties.type_metadata(2) ) primary_advertising_interval_min: int = field(metadata=metadata(3)) primary_advertising_interval_max: int = field(metadata=metadata(3)) primary_advertising_channel_map: int = field(metadata=ChannelMap.type_metadata(1)) own_address_type: int = field(metadata=OwnAddressType.type_metadata(1)) peer_address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertising_filter_policy: int = field(metadata=metadata(1)) advertising_tx_power: int = field(metadata=metadata(1)) primary_advertising_phy: int = field(metadata=Phy.type_metadata(1)) secondary_advertising_max_skip: int = field(metadata=metadata(1)) secondary_advertising_phy: int = field(metadata=Phy.type_metadata(1)) advertising_sid: int = field(metadata=metadata(1)) scan_request_notification_enable: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Extended_Advertising_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.54 LE Set Extended Advertising Data Command ''' class Operation(SpecableEnum): INTERMEDIATE_FRAGMENT = 0x00 FIRST_FRAGMENT = 0x01 LAST_FRAGMENT = 0x02 COMPLETE_DATA = 0x03 UNCHANGED_DATA = 0x04 advertising_handle: int = field(metadata=metadata(1)) operation: int = field(metadata=Operation.type_metadata(1)) fragment_preference: int = field(metadata=metadata(1)) advertising_data: bytes = field(metadata=metadata("v")) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Extended_Scan_Response_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.55 LE Set Extended Scan Response Data Command ''' advertising_handle: int = field(metadata=metadata(1)) operation: int = field( metadata=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.type_metadata(1) ) fragment_preference: int = field(metadata=metadata(1)) scan_response_data: bytes = field(metadata=metadata("v")) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Extended_Advertising_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.56 LE Set Extended Advertising Enable Command ''' enable: int = field(metadata=metadata(1)) advertising_handles: Sequence[int] = field(metadata=metadata(1, list_begin=True)) durations: Sequence[int] = field(metadata=metadata(2)) max_extended_advertising_events: Sequence[int] = field( metadata=metadata(1, list_end=True) ) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Maximum_Advertising_Data_Length_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.57 LE Read Maximum Advertising Data Length Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('max_advertising_data_length', 2), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.58 LE Read Number of Supported Advertising Sets Command ''' return_parameters_fields = [ ('status', STATUS_SPEC), ('num_supported_advertising_sets', 1), ] # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Remove_Advertising_Set_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.59 LE Remove Advertising Set Command ''' advertising_handle: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Clear_Advertising_Sets_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.60 LE Clear Advertising Sets Command ''' # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Periodic_Advertising_Parameters_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.61 LE Set Periodic Advertising Parameters command ''' advertising_handle: int = field(metadata=metadata(1)) periodic_advertising_interval_min: int = field(metadata=metadata(2)) periodic_advertising_interval_max: int = field(metadata=metadata(2)) periodic_advertising_properties: int = field(metadata=metadata(2)) class Properties(SpecableFlag): INCLUDE_TX_POWER = 1 << 6 # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Periodic_Advertising_Data_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.62 LE Set Periodic Advertising Data command ''' advertising_handle: int = field(metadata=metadata(1)) operation: int = field( metadata=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.type_metadata(1) ) advertising_data: bytes = field(metadata=metadata("v")) # ----------------------------------------------------------------------------- @HCI_Command.command @dataclasses.dataclass class HCI_LE_Set_Periodic_Advertising_Enable_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.63 LE Set Periodic Advertising Enable Command ''' enable: int = field(metadata=metadata(1)) advertising_handle: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Command.command class HCI_LE_Set_Extended_Scan_Parameters_Command(HCI_Command): ''' See Bluetooth spec @ 7.8.64 LE Set Extended Scan Parameters Command ''' PASSIVE_SCANNING = 0 ACTIVE_SCANNING = 1 BASIC_UNFILTERED_POLICY = 0x00 BASIC_FILTERED_POLICY = 0x01 EXTENDED_UNFILTERED_POLICY = 0x02 EXTENDED_FILTERED_POLICY = 0x03 op_code = HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND @classmethod def from_parameters(cls, parameters: bytes) -> Self: own_address_type = parameters[0] scanning_filter_policy = parameters[1] scanning_phys = parameters[2] phy_bits_set = bin(scanning_phys).count('1') scan_types = [] scan_intervals = [] scan_windows = [] for i in range(phy_bits_set): scan_types.append(parameters[3 + (5 * i)]) scan_intervals.append( struct.unpack_from(' None: super().__init__() self.own_address_type = own_address_type self.scanning_filter_policy = scanning_filter_policy self.scanning_phys = scanning_phys self.scan_types = list(scan_types) self.scan_intervals = list(scan_intervals) self.scan_windows = list(scan_windows) self.parameters = bytes( [own_address_type, scanning_filter_policy, scanning_phys] ) phy_bits_set = bin(scanning_phys).count('1') for i in range(phy_bits_set): self.parameters += struct.pack( ' Self: initiator_filter_policy = parameters[0] own_address_type = parameters[1] peer_address_type = parameters[2] peer_address = Address.parse_address_preceded_by_type(parameters, 3)[1] initiating_phys = parameters[9] phy_bits_set = bin(initiating_phys).count('1') def read_parameter_list(offset): return [ struct.unpack_from(' type[_Event]: ''' Decorator used to declare and register subclasses ''' subclass.name = subclass.__name__.upper() subclass.event_code = key_with_value(subclass.event_names, subclass.name) subclass.fields = HCI_Object.fields_from_dataclass(subclass) if subclass.event_code is None: raise KeyError(f'event {subclass.name} not found in event_names') # Register a factory for this class cls.event_classes[subclass.event_code] = subclass return subclass @staticmethod def event_map(symbols: dict[str, Any]) -> dict[int, str]: return { event_code: event_name for (event_name, event_code) in symbols.items() if event_name.startswith('HCI_') and not event_name.startswith('HCI_LE_') and event_name.endswith('_EVENT') } @staticmethod def event_name(event_code): return name_or_number(HCI_Event.event_names, event_code) @staticmethod def register_events(symbols: dict[str, Any]) -> None: HCI_Event.event_names.update(HCI_Event.event_map(symbols)) @staticmethod def registered(event_class): event_class.name = event_class.__name__.upper() event_class.event_code = key_with_value(HCI_Event.event_names, event_class.name) if event_class.event_code is None: raise KeyError(f'event {event_class.name} not found in event_names') # Register a factory for this class HCI_Event.event_classes[event_class.event_code] = event_class return event_class @classmethod def add_vendor_factory( cls, factory: Callable[[bytes], Optional[HCI_Event]] ) -> None: cls.vendor_factories.append(factory) @classmethod def remove_vendor_factory( cls, factory: Callable[[bytes], Optional[HCI_Event]] ) -> None: if factory in cls.vendor_factories: cls.vendor_factories.remove(factory) @classmethod def from_bytes(cls, packet: bytes) -> HCI_Event: event_code = packet[1] length = packet[2] parameters = packet[3:] if len(parameters) != length: raise InvalidPacketError('invalid packet length') subclass: Optional[type[HCI_Event]] if event_code == HCI_LE_META_EVENT: # We do this dispatch here and not in the subclass in order to avoid call # loops subevent_code = parameters[0] subclass = HCI_LE_Meta_Event.subevent_classes.get(subevent_code) if subclass is None: # No class registered, just use a generic class instance return HCI_LE_Meta_Event( subevent_code=subevent_code, parameters=parameters ) elif event_code == HCI_VENDOR_EVENT: # Invoke all the registered factories to see if any of them can handle # the event for vendor_factory in cls.vendor_factories: if event := vendor_factory(parameters): return event # No factory, or the factory could not create an instance, # return a generic vendor event return HCI_Vendor_Event(data=parameters) else: subclass = HCI_Event.event_classes.get(event_code) if subclass is None: # No class registered, just use a generic class instance return HCI_Event(event_code=event_code, parameters=parameters) # Invoke the factory to create a new instance return subclass.from_parameters(parameters) @classmethod def from_parameters(cls, parameters: bytes) -> Self: event = cls(**HCI_Object.dict_from_bytes(parameters, 0, cls.fields)) event.parameters = parameters return event def __init__( self, parameters: Optional[bytes] = None, *, event_code: Optional[int] = None, **kwargs, ): if event_code is not None: self.event_code = event_code super().__init__(HCI_Event.event_name(self.event_code)) if self.fields and kwargs: HCI_Object.init_from_fields(self, self.fields, kwargs) if parameters is None: parameters = HCI_Object.dict_to_bytes(kwargs, self.fields) self.parameters = parameters or b'' @property def parameters(self) -> bytes: if not self._parameters: self._parameters = HCI_Object.dict_to_bytes(self.__dict__, self.fields) return self._parameters @parameters.setter def parameters(self, parameters: bytes): self._parameters = parameters def __bytes__(self) -> bytes: parameters = self.parameters return bytes([HCI_EVENT_PACKET, self.event_code, len(parameters)]) + parameters def __str__(self): result = color(self.name, 'magenta') if self.fields: result += ':\n' + HCI_Object.format_fields(self.__dict__, self.fields, ' ') else: if self.parameters: result += f': {self.parameters.hex()}' return result HCI_Event.register_events(globals()) # ----------------------------------------------------------------------------- class HCI_Extended_Event(HCI_Event): ''' HCI_Event subclass for events that have a subevent code. ''' subevent_names: dict[int, str] = {} subevent_classes: dict[int, type[HCI_Extended_Event]] = {} subevent_code: int = -1 _parameters: bytes = b'' _ExtendedEvent = TypeVar("_ExtendedEvent", bound="HCI_Extended_Event") # TODO: Remove type ignore after migrating HCI_Event. @classmethod def event(cls, subclass: type[_ExtendedEvent]) -> type[_ExtendedEvent]: # type: ignore[override] ''' Decorator used to declare and register subclasses ''' subclass.name = subclass.__name__.upper() subclass.subevent_code = key_with_value(subclass.subevent_names, subclass.name) if subclass.subevent_code is None: raise KeyError(f'subevent {subclass.name} not found in subevent_names') # Register a factory for this class cls.subevent_classes[subclass.subevent_code] = subclass subclass.fields = HCI_Object.fields_from_dataclass(subclass) return subclass @property def parameters(self) -> bytes: if not self._parameters: self._parameters = bytes([self.subevent_code]) + HCI_Object.dict_to_bytes( self.__dict__, self.fields ) return self._parameters @parameters.setter def parameters(self, parameters: bytes): self._parameters = parameters @classmethod def subevent_name(cls, subevent_code): subevent_name = cls.subevent_names.get(subevent_code) if subevent_name is not None: return subevent_name return f'{cls.__name__.upper()}[0x{subevent_code:02X}]' @staticmethod def subevent_map(symbols: dict[str, Any]) -> dict[int, str]: return { subevent_code: subevent_name for (subevent_name, subevent_code) in symbols.items() if subevent_name.startswith('HCI_') and subevent_name.endswith('_EVENT') } @classmethod def register_subevents(cls, symbols: dict[str, Any]) -> None: cls.subevent_names.update(cls.subevent_map(symbols)) @classmethod def subclass_from_parameters( cls, parameters: bytes ) -> Optional[HCI_Extended_Event]: """ Factory method that parses the subevent code, finds a registered subclass, and creates an instance if found. """ subevent_code = parameters[0] if subclass := cls.subevent_classes.get(subevent_code): return subclass.from_parameters(parameters) return None @classmethod def from_parameters(cls, parameters: bytes) -> Self: """Factory method for subclasses (the subevent code has already been parsed)""" event = cls(**HCI_Object.dict_from_bytes(parameters, 1, cls.fields)) event.parameters = parameters return event def __init__( self, parameters: Optional[bytes] = None, *, subevent_code: Optional[int] = None, **kwargs, ) -> None: if subevent_code is not None: self.subevent_code = subevent_code if parameters is None and self.fields and kwargs: parameters = bytes([self.subevent_code]) + HCI_Object.dict_to_bytes( kwargs, self.fields ) super().__init__(parameters, **kwargs) # Override the name in order to adopt the subevent name instead self.name = self.subevent_name(self.subevent_code) # ----------------------------------------------------------------------------- class HCI_LE_Meta_Event(HCI_Extended_Event): ''' See Bluetooth spec @ 7.7.65 LE Meta Event ''' event_code: int = HCI_LE_META_EVENT subevent_classes = {} @staticmethod def subevent_map(symbols: dict[str, Any]) -> dict[int, str]: return { subevent_code: subevent_name for (subevent_name, subevent_code) in symbols.items() if subevent_name.startswith('HCI_LE_') and subevent_name.endswith('_EVENT') } HCI_LE_Meta_Event.register_subevents(globals()) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Connection_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.1 LE Connection Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) role: int = field(metadata=Role.type_metadata(1)) peer_address_type: int = field(metadata=AddressType.type_metadata(1)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) connection_interval: int = field(metadata=metadata(2)) peripheral_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) central_clock_accuracy: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Advertising_Report_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.2 LE Advertising Report Event ''' class EventType(SpecableEnum): ADV_IND = 0x00 ADV_DIRECT_IND = 0x01 ADV_SCAN_IND = 0x02 ADV_NONCONN_IND = 0x03 SCAN_RSP = 0x04 @dataclasses.dataclass class Report(HCI_Dataclass_Object): event_type: int = field( metadata=metadata( { 'size': 1, 'mapper': lambda x: HCI_LE_Advertising_Report_Event.EventType( x ).name, } ) ) address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) data: bytes = field(metadata=metadata('v')) rssi: int = field(metadata=metadata(-1)) reports: Sequence[Report] = field( metadata=metadata(Report.parse_from_bytes, list_begin=True, list_end=True) ) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Connection_Update_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.3 LE Connection Update Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) connection_interval: int = field(metadata=metadata(2)) peripheral_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Read_Remote_Features_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.4 LE Read Remote Features Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) le_features: bytes = field(metadata=metadata(8)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Long_Term_Key_Request_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.5 LE Long Term Key Request Event ''' connection_handle: int = field(metadata=metadata(2)) random_number: bytes = field(metadata=metadata(8)) encryption_diversifier: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Remote_Connection_Parameter_Request_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.6 LE Remote Connection Parameter Request Event ''' connection_handle: int = field(metadata=metadata(2)) interval_min: int = field(metadata=metadata(2)) interval_max: int = field(metadata=metadata(2)) max_latency: int = field(metadata=metadata(2)) timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Data_Length_Change_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.7 LE Data Length Change Event ''' connection_handle: int = field(metadata=metadata(2)) max_tx_octets: int = field(metadata=metadata(2)) max_tx_time: int = field(metadata=metadata(2)) max_rx_octets: int = field(metadata=metadata(2)) max_rx_time: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Enhanced_Connection_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.10 LE Enhanced Connection Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) role: int = field(metadata=Role.type_metadata(1)) peer_address_type: int = field(metadata=AddressType.type_metadata(1)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) local_resolvable_private_address: Address = field( metadata=metadata(Address.parse_random_address) ) peer_resolvable_private_address: Address = field( metadata=metadata(Address.parse_random_address) ) connection_interval: int = field(metadata=metadata(2)) peripheral_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) central_clock_accuracy: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Enhanced_Connection_Complete_V2_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.10 LE Enhanced Connection Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) role: int = field(metadata=Role.type_metadata(1)) peer_address_type: int = field(metadata=AddressType.type_metadata(1)) peer_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) local_resolvable_private_address: Address = field( metadata=metadata(Address.parse_random_address) ) peer_resolvable_private_address: Address = field( metadata=metadata(Address.parse_random_address) ) connection_interval: int = field(metadata=metadata(2)) peripheral_latency: int = field(metadata=metadata(2)) supervision_timeout: int = field(metadata=metadata(2)) central_clock_accuracy: int = field(metadata=metadata(1)) advertising_handle: int = field(metadata=metadata(1)) sync_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_PHY_Update_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.12 LE PHY Update Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) tx_phy: int = field(metadata=Phy.type_metadata(1)) rx_phy: int = field(metadata=Phy.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Extended_Advertising_Report_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.13 LE Extended Advertising Report Event ''' class EventType(enum.IntFlag): CONNECTABLE_ADVERTISING = 1 << 0 SCANNABLE_ADVERTISING = 1 << 1 DIRECTED_ADVERTISING = 1 << 2 SCAN_RESPONSE = 1 << 3 LEGACY_ADVERTISING_PDU_USED = 1 << 4 DATA_COMPLETE = 0x00 DATA_INCOMPLETE_MORE_TO_COME = 0x01 DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02 LEGACY_PDU_TYPE_MAP = { 0b0011: HCI_LE_Advertising_Report_Event.EventType.ADV_IND, 0b0101: HCI_LE_Advertising_Report_Event.EventType.ADV_DIRECT_IND, 0b0010: HCI_LE_Advertising_Report_Event.EventType.ADV_SCAN_IND, 0b0000: HCI_LE_Advertising_Report_Event.EventType.ADV_NONCONN_IND, 0b1011: HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP, 0b1010: HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP, } NO_ADI_FIELD_PROVIDED = 0xFF TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F RSSI_NOT_AVAILABLE = 0x7F ANONYMOUS_ADDRESS_TYPE = 0xFF UNRESOLVED_RESOLVABLE_ADDRESS_TYPE = 0xFE @dataclasses.dataclass class Report(HCI_Dataclass_Object): event_type: int = field( metadata=metadata( { 'size': 2, 'mapper': lambda x: HCI_LE_Extended_Advertising_Report_Event.EventType( x ).name, } ) ) address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) primary_phy: int = field(metadata=metadata(Phy.type_spec(1))) secondary_phy: int = field(metadata=metadata(Phy.type_spec(1))) advertising_sid: int = field(metadata=metadata(1)) tx_power: int = field(metadata=metadata(1)) rssi: int = field(metadata=metadata(-1)) periodic_advertising_interval: int = field(metadata=metadata(2)) direct_address_type: int = field(metadata=metadata(Address.ADDRESS_TYPE_SPEC)) direct_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) data: bytes = field(metadata=metadata('v')) reports: Sequence[Report] = field( metadata=metadata(Report.parse_from_bytes, list_begin=True, list_end=True) ) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Sync_Established_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) sync_handle: int = field(metadata=metadata(2)) advertising_sid: int = field(metadata=metadata(1)) advertiser_address_type: int = field(metadata=AddressType.type_metadata(1)) advertiser_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertiser_phy: int = field(metadata=Phy.type_metadata(1)) periodic_advertising_interval: int = field(metadata=metadata(2)) advertiser_clock_accuracy: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Sync_Established_V2_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) sync_handle: int = field(metadata=metadata(2)) advertising_sid: int = field(metadata=metadata(1)) advertiser_address_type: int = field(metadata=AddressType.type_metadata(1)) advertiser_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertiser_phy: int = field(metadata=Phy.type_metadata(1)) periodic_advertising_interval: int = field(metadata=metadata(2)) advertiser_clock_accuracy: int = field(metadata=metadata(1)) num_subevents: int = field(metadata=metadata(1)) subevent_interval: int = field(metadata=metadata(1)) response_slot_delay: int = field(metadata=metadata(1)) response_slot_spacing: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Report_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event ''' class DataStatus(SpecableEnum): DATA_COMPLETE = 0x00 DATA_INCOMPLETE_MORE_TO_COME = 0x01 DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02 TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F RSSI_NOT_AVAILABLE = 0x7F sync_handle: int = field(metadata=metadata(2)) tx_power: int = field(metadata=metadata(-1)) rssi: int = field(metadata=metadata(-1)) cte_type: int = field(metadata=CteType.type_metadata(1)) data_status: int = field(metadata=DataStatus.type_metadata(1)) data: bytes = field(metadata=metadata("v")) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Report_V2_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event ''' sync_handle: int = field(metadata=metadata(2)) tx_power: int = field(metadata=metadata(-1)) rssi: int = field(metadata=metadata(-1)) cte_type: int = field(metadata=CteType.type_metadata(1)) periodic_event_counter: int = field(metadata=metadata(2)) subevent: int = field(metadata=metadata(1)) data_status: int = field(metadata=CteType.type_metadata(1)) data: bytes = field(metadata=metadata("v")) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Sync_Lost_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.16 LE Periodic Advertising Sync Lost Event ''' sync_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Advertising_Set_Terminated_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.18 LE Advertising Set Terminated Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) advertising_handle: int = field(metadata=metadata(1)) connection_handle: int = field(metadata=metadata(2)) num_completed_extended_advertising_events: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Channel_Selection_Algorithm_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.20 LE Channel Selection Algorithm Event ''' connection_handle: int = field(metadata=metadata(2)) channel_selection_algorithm: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Sync_Transfer_Received_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.24 LE Periodic Advertising Sync Transfer Received Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) service_data: int = field(metadata=metadata(2)) sync_handle: int = field(metadata=metadata(2)) advertising_sid: int = field(metadata=metadata(1)) advertiser_address_type: int = field(metadata=AddressType.type_metadata(1)) advertiser_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertiser_phy: int = field(metadata=metadata(1)) periodic_advertising_interval: int = field(metadata=metadata(2)) advertiser_clock_accuracy: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Periodic_Advertising_Sync_Transfer_Received_V2_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.24 LE Periodic Advertising Sync Transfer Received Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) service_data: int = field(metadata=metadata(2)) sync_handle: int = field(metadata=metadata(2)) advertising_sid: int = field(metadata=metadata(1)) advertiser_address_type: int = field(metadata=AddressType.type_metadata(1)) advertiser_address: Address = field( metadata=metadata(Address.parse_address_preceded_by_type) ) advertiser_phy: int = field(metadata=metadata(1)) periodic_advertising_interval: int = field(metadata=metadata(2)) advertiser_clock_accuracy: int = field(metadata=metadata(1)) num_subevents: int = field(metadata=metadata(1)) subevent_interval: int = field(metadata=metadata(1)) response_slot_delay: int = field(metadata=metadata(1)) response_slot_spacing: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CIS_Established_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.25 LE CIS Established Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) cig_sync_delay: int = field(metadata=metadata(3)) cis_sync_delay: int = field(metadata=metadata(3)) transport_latency_c_to_p: int = field(metadata=metadata(3)) transport_latency_p_to_c: int = field(metadata=metadata(3)) phy_c_to_p: int = field(metadata=metadata(1)) phy_p_to_c: int = field(metadata=metadata(1)) nse: int = field(metadata=metadata(1)) bn_c_to_p: int = field(metadata=metadata(1)) bn_p_to_c: int = field(metadata=metadata(1)) ft_c_to_p: int = field(metadata=metadata(1)) ft_p_to_c: int = field(metadata=metadata(1)) max_pdu_c_to_p: int = field(metadata=metadata(2)) max_pdu_p_to_c: int = field(metadata=metadata(2)) iso_interval: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CIS_Request_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.26 LE CIS Request Event ''' acl_connection_handle: int = field(metadata=metadata(2)) cis_connection_handle: int = field(metadata=metadata(2)) cig_id: int = field(metadata=metadata(1)) cis_id: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Create_BIG_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.27 LE Create BIG Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) big_handle: int = field(metadata=metadata(1)) big_sync_delay: int = field(metadata=metadata(3)) transport_latency_big: int = field(metadata=metadata(3)) phy: int = field(metadata=metadata(1)) nse: int = field(metadata=metadata(1)) bn: int = field(metadata=metadata(1)) pto: int = field(metadata=metadata(1)) irc: int = field(metadata=metadata(1)) max_pdu: int = field(metadata=metadata(2)) iso_interval: int = field(metadata=metadata(2)) connection_handle: int = field(metadata=metadata(2, list_begin=True, list_end=True)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_Terminate_BIG_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.28 LE Terminate BIG Complete Event ''' big_handle: int = field(metadata=metadata(1)) reason: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_BIG_Sync_Established_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.29 LE BIG Sync Established event ''' status: int = field(metadata=metadata(STATUS_SPEC)) big_handle: int = field(metadata=metadata(1)) transport_latency_big: int = field(metadata=metadata(3)) nse: int = field(metadata=metadata(1)) bn: int = field(metadata=metadata(1)) pto: int = field(metadata=metadata(1)) irc: int = field(metadata=metadata(1)) max_pdu: int = field(metadata=metadata(2)) iso_interval: int = field(metadata=metadata(2)) connection_handle: int = field(metadata=metadata(2, list_begin=True, list_end=True)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_BIG_Sync_Lost_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.30 LE BIG Sync Lost event ''' big_handle: int = field(metadata=metadata(1)) reason: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_BIGInfo_Advertising_Report_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.34 LE BIGInfo Advertising Report Event ''' sync_handle: int = field(metadata=metadata(2)) num_bis: int = field(metadata=metadata(1)) nse: int = field(metadata=metadata(1)) iso_interval: int = field(metadata=metadata(2)) bn: int = field(metadata=metadata(1)) pto: int = field(metadata=metadata(1)) irc: int = field(metadata=metadata(1)) max_pdu: int = field(metadata=metadata(2)) sdu_interval: int = field(metadata=metadata(3)) max_sdu: int = field(metadata=metadata(2)) phy: int = field(metadata=Phy.type_metadata(1)) framing: int = field(metadata=metadata(1)) encryption: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Read_Remote_Supported_Capabilities_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.39 LE CS Read Remote Supported Capabilities Complete event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) num_config_supported: int = field(metadata=metadata(1)) max_consecutive_procedures_supported: int = field(metadata=metadata(2)) num_antennas_supported: int = field(metadata=metadata(1)) max_antenna_paths_supported: int = field(metadata=metadata(1)) roles_supported: int = field(metadata=metadata(1)) modes_supported: int = field(metadata=metadata(1)) rtt_capability: int = field(metadata=metadata(1)) rtt_aa_only_n: int = field(metadata=metadata(1)) rtt_sounding_n: int = field(metadata=metadata(1)) rtt_random_payload_n: int = field(metadata=metadata(1)) nadm_sounding_capability: int = field(metadata=metadata(2)) nadm_random_capability: int = field(metadata=metadata(2)) cs_sync_phys_supported: int = field(metadata=metadata(CS_SYNC_PHY_SUPPORTED_SPEC)) subfeatures_supported: int = field(metadata=metadata(2)) t_ip1_times_supported: int = field(metadata=metadata(2)) t_ip2_times_supported: int = field(metadata=metadata(2)) t_fcs_times_supported: int = field(metadata=metadata(2)) t_pm_times_supported: int = field(metadata=metadata(2)) t_sw_time_supported: int = field(metadata=metadata(1)) tx_snr_capability: int = field(metadata=metadata(CS_SNR_SPEC)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Read_Remote_FAE_Table_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.40 LE CS Read Remote FAE Table Complete event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) remote_fae_table: bytes = field(metadata=metadata(72)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Security_Enable_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.41 LE CS Security Enable Complete event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Config_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.42 LE CS Config Complete event ''' class Action(SpecableEnum): REMOVED = 0 CREATED = 1 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) config_id: int = field(metadata=metadata(1)) action: int = field(metadata=Action.type_metadata(1)) main_mode_type: int = field(metadata=metadata(1)) sub_mode_type: int = field(metadata=metadata(1)) min_main_mode_steps: int = field(metadata=metadata(1)) max_main_mode_steps: int = field(metadata=metadata(1)) main_mode_repetition: int = field(metadata=metadata(1)) mode_0_steps: int = field(metadata=metadata(1)) role: int = field(metadata=metadata(CS_ROLE_SPEC)) rtt_type: int = field(metadata=metadata(RTT_TYPE_SPEC)) cs_sync_phy: int = field(metadata=metadata(CS_SYNC_PHY_SPEC)) channel_map: bytes = field(metadata=metadata(10)) channel_map_repetition: int = field(metadata=metadata(1)) channel_selection_type: int = field(metadata=metadata(1)) ch3c_shape: int = field(metadata=metadata(1)) ch3c_jump: int = field(metadata=metadata(1)) reserved: int = field(metadata=metadata(1)) t_ip1_time: int = field(metadata=metadata(1)) t_ip2_time: int = field(metadata=metadata(1)) t_fcs_time: int = field(metadata=metadata(1)) t_pm_time: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Procedure_Enable_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.43 LE CS Procedure Enable Complete event ''' class State(SpecableEnum): DISABLED = 0 ENABLED = 1 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) config_id: int = field(metadata=metadata(1)) state: int = field(metadata=State.type_metadata(1)) tone_antenna_config_selection: int = field(metadata=metadata(1)) selected_tx_power: int = field(metadata=metadata(-1)) subevent_len: int = field(metadata=metadata(3)) subevents_per_event: int = field(metadata=metadata(1)) subevent_interval: int = field(metadata=metadata(2)) event_interval: int = field(metadata=metadata(2)) procedure_interval: int = field(metadata=metadata(2)) procedure_count: int = field(metadata=metadata(2)) max_procedure_len: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Subevent_Result_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.44 LE CS Subevent Result event ''' connection_handle: int = field(metadata=metadata(2)) config_id: int = field(metadata=metadata(1)) start_acl_conn_event_counter: int = field(metadata=metadata(2)) procedure_counter: int = field(metadata=metadata(2)) frequency_compensation: int = field(metadata=metadata(2)) reference_power_level: int = field(metadata=metadata(-1)) procedure_done_status: int = field(metadata=metadata(1)) subevent_done_status: int = field(metadata=metadata(1)) abort_reason: int = field(metadata=metadata(1)) num_antenna_paths: int = field(metadata=metadata(1)) step_mode: Sequence[int] = field(metadata=metadata(1, list_begin=True)) step_channel: Sequence[int] = field(metadata=metadata(1)) step_data: Sequence[bytes] = field(metadata=metadata("v", list_end=True)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Subevent_Result_Continue_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.45 LE CS Subevent Result Continue event ''' connection_handle: int = field(metadata=metadata(2)) config_id: int = field(metadata=metadata(1)) procedure_done_status: int = field(metadata=metadata(1)) subevent_done_status: int = field(metadata=metadata(1)) abort_reason: int = field(metadata=metadata(1)) num_antenna_paths: int = field(metadata=metadata(1)) step_mode: Sequence[int] = field(metadata=metadata(1, list_begin=True)) step_channel: Sequence[int] = field(metadata=metadata(1)) step_data: Sequence[bytes] = field(metadata=metadata("v", list_end=True)) # ----------------------------------------------------------------------------- @HCI_LE_Meta_Event.event @dataclasses.dataclass class HCI_LE_CS_Test_End_Complete_Event(HCI_LE_Meta_Event): ''' See Bluetooth spec @ 7.7.65.46 LE CS Test End Complete event ''' connection_handle: int = field(metadata=metadata(2)) status: int = field(metadata=metadata(STATUS_SPEC)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Inquiry_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.1 Inquiry Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Inquiry_Result_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.2 Inquiry Result Event ''' bd_addr: Sequence[Address] = field( metadata=metadata(Address.parse_address, list_begin=True) ) page_scan_repetition_mode: Sequence[int] = field(metadata=metadata(1)) reserved_0: Sequence[int] = field(metadata=metadata(1)) reserved_1: Sequence[int] = field(metadata=metadata(1)) class_of_device: Sequence[int] = field(metadata=metadata(COD_SPEC)) clock_offset: Sequence[int] = field(metadata=metadata(2, list_end=True)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Connection_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.3 Connection Complete Event ''' class LinkType(SpecableEnum): SCO = 0x00 ACL = 0x01 ESCO = 0x02 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) link_type: int = field(metadata=LinkType.type_metadata(1)) encryption_enabled: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Connection_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.4 Connection Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) class_of_device: int = field(metadata=metadata(3)) link_type: int = field( metadata=HCI_Connection_Complete_Event.LinkType.type_metadata(1) ) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Disconnection_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.5 Disconnection Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) reason: int = field(metadata=metadata(STATUS_SPEC)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Authentication_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.6 Authentication Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Remote_Name_Request_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.7 Remote Name Request Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) remote_name: bytes = field( metadata=metadata({'size': 248, 'mapper': map_null_terminated_utf8_string}) ) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Encryption_Change_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.8 Encryption Change Event ''' class Enabled(SpecableEnum): OFF = 0x00 E0_OR_AES_CCM = 0x01 AES_CCM = 0x02 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) encryption_enabled: int = field(metadata=Enabled.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Encryption_Change_V2_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.8 Encryption Change Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) encryption_enabled: int = field( metadata=HCI_Encryption_Change_Event.Enabled.type_metadata(1) ) encryption_key_size: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Read_Remote_Supported_Features_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.11 Read Remote Supported Features Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) lmp_features: bytes = field(metadata=metadata(8)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Read_Remote_Version_Information_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.12 Read Remote Version Information Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) version: int = field(metadata=metadata(1)) manufacturer_name: int = field(metadata=metadata(2)) subversion: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_QOS_Setup_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.13 QoS Setup Complete Event ''' class ServiceType(SpecableEnum): NO_TRAFFIC_AVAILABLE = 0x00 BEST_EFFORT_AVAILABLE = 0x01 GUARANTEED_AVAILABLE = 0x02 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) unused: int = field(metadata=metadata(1)) service_type: int = field(metadata=ServiceType.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Command_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.14 Command Complete Event ''' num_hci_command_packets: int = field(metadata=metadata(1)) command_opcode: int = field( metadata=metadata({'size': 2, 'mapper': HCI_Command.command_name}) ) return_parameters: Union[bytes, HCI_Object, int] = field(metadata=metadata("*")) def map_return_parameters(self, return_parameters): '''Map simple 'status' return parameters to their named constant form''' if isinstance(return_parameters, bytes) and len(return_parameters) == 1: # Byte-array form return HCI_Constant.status_name(return_parameters[0]) if isinstance(return_parameters, int): # Already converted to an integer status code return HCI_Constant.status_name(return_parameters) return return_parameters @classmethod def from_parameters(cls, parameters: bytes) -> Self: event = cls(**HCI_Object.dict_from_bytes(parameters, 0, cls.fields)) event.parameters = parameters # Parse the return parameters if ( isinstance(event.return_parameters, bytes) and len(event.return_parameters) == 1 ): # All commands with 1-byte return parameters return a 'status' field, # convert it to an integer event.return_parameters = event.return_parameters[0] else: subclass = HCI_Command.command_classes.get(event.command_opcode) if subclass: # Try to parse the return parameters bytes into an object. return_parameters = subclass.parse_return_parameters( event.return_parameters ) if return_parameters is not None: event.return_parameters = return_parameters return event def __str__(self): return f'{color(self.name, "magenta")}:\n' + HCI_Object.format_fields( self.__dict__, self.fields, ' ', {'return_parameters': self.map_return_parameters}, ) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Command_Status_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.15 Command Complete Event ''' PENDING = 0 @staticmethod def status_name(status): if status == HCI_Command_Status_Event.PENDING: return 'PENDING' return HCI_Constant.error_name(status) status: int = field( metadata=metadata( {'size': 1, 'mapper': lambda x: HCI_Command_Status_Event.status_name(x)} ) ) num_hci_command_packets: int = field(metadata=metadata(1)) command_opcode: int = field( metadata=metadata({'size': 2, 'mapper': HCI_Command.command_name}) ) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Role_Change_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.18 Role Change Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) new_role: int = field(metadata=Role.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Number_Of_Completed_Packets_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.19 Number Of Completed Packets Event ''' connection_handles: Sequence[int] = field(metadata=metadata(2, list_begin=True)) num_completed_packets: Sequence[int] = field(metadata=metadata(2, list_end=True)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Mode_Change_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.20 Mode Change Event ''' class Mode(SpecableEnum): ACTIVE = 0x00 HOLD = 0x01 SNIFF = 0x02 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) current_mode: int = field(metadata=Mode.type_metadata(1)) interval: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_PIN_Code_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.22 PIN Code Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Link_Key_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.24 7.7.23 Link Key Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Link_Key_Notification_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.24 Link Key Notification Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) link_key: bytes = field(metadata=metadata(16)) key_type: int = field(metadata=LinkKeyType.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Max_Slots_Change_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.27 Max Slots Change Event ''' connection_handle: int = field(metadata=metadata(2)) lmp_max_slots: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Read_Clock_Offset_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.28 Read Clock Offset Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) clock_offset: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Connection_Packet_Type_Changed_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.29 Connection Packet Type Changed Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) packet_type: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Page_Scan_Repetition_Mode_Change_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.31 Page Scan Repetition Mode Change Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) page_scan_repetition_mode: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Inquiry_Result_With_RSSI_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.33 Inquiry Result with RSSI Event ''' bd_addr: Sequence[Address] = field( metadata=metadata(Address.parse_address, list_begin=True) ) page_scan_repetition_mode: Sequence[int] = field(metadata=metadata(1)) reserved: Sequence[int] = field(metadata=metadata(1)) class_of_device: Sequence[int] = field(metadata=metadata(COD_SPEC)) clock_offset: Sequence[int] = field(metadata=metadata(2)) rssi: Sequence[int] = field(metadata=metadata(-1, list_end=True)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Read_Remote_Extended_Features_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.34 Read Remote Extended Features Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) page_number: int = field(metadata=metadata(1)) maximum_page_number: int = field(metadata=metadata(1)) extended_lmp_features: bytes = field(metadata=metadata(8)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Synchronous_Connection_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.35 Synchronous Connection Complete Event ''' class LinkType(SpecableEnum): SCO = 0x00 ESCO = 0x02 class AirMode(SpecableEnum): U_LAW_LOG = 0x00 A_LAW_LOG_AIR_MORE = 0x01 CVSD = 0x02 TRANSPARENT_DATA = 0x03 status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) link_type: int = field(metadata=LinkType.type_metadata(1)) transmission_interval: int = field(metadata=metadata(1)) retransmission_window: int = field(metadata=metadata(1)) rx_packet_length: int = field(metadata=metadata(2)) tx_packet_length: int = field(metadata=metadata(2)) air_mode: int = field(metadata=AirMode.type_metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Synchronous_Connection_Changed_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.36 Synchronous Connection Changed Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) transmission_interval: int = field(metadata=metadata(1)) retransmission_window: int = field(metadata=metadata(1)) rx_packet_length: int = field(metadata=metadata(2)) tx_packet_length: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Sniff_Subrating_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.37 Sniff Subrating Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) max_tx_latency: int = field(metadata=metadata(2)) max_rx_latency: int = field(metadata=metadata(2)) min_remote_timeout: int = field(metadata=metadata(2)) min_local_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Extended_Inquiry_Result_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.38 Extended Inquiry Result Event ''' num_responses: int = field(metadata=metadata(1)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) page_scan_repetition_mode: int = field(metadata=metadata(1)) reserved: int = field(metadata=metadata(1)) class_of_device: int = field(metadata=metadata(COD_SPEC)) clock_offset: int = field(metadata=metadata(2)) rssi: int = field(metadata=metadata(-1)) extended_inquiry_response: bytes = field(metadata=metadata(240)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Encryption_Key_Refresh_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.39 Encryption Key Refresh Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) connection_handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_IO_Capability_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.40 IO Capability Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_IO_Capability_Response_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.41 IO Capability Response Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) io_capability: int = field(metadata=IoCapability.type_metadata(1)) oob_data_present: int = field(metadata=metadata(1)) authentication_requirements: int = field( metadata=AuthenticationRequirements.type_metadata(1) ) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_User_Confirmation_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.42 User Confirmation Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) numeric_value: int = field(metadata=metadata(4)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_User_Passkey_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.43 User Passkey Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Remote_OOB_Data_Request_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.44 Remote OOB Data Request Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Simple_Pairing_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.45 Simple Pairing Complete Event ''' status: int = field(metadata=metadata(STATUS_SPEC)) bd_addr: Address = field(metadata=metadata(Address.parse_address)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Link_Supervision_Timeout_Changed_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.46 Link Supervision Timeout Changed Event ''' connection_handle: int = field(metadata=metadata(2)) link_supervision_timeout: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Enhanced_Flush_Complete_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.47 Enhanced Flush Complete Event ''' handle: int = field(metadata=metadata(2)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_User_Passkey_Notification_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.48 User Passkey Notification Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) passkey: int = field(metadata=metadata(4)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Keypress_Notification_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.49 Keypress Notification Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) notification_type: int = field(metadata=metadata(1)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Remote_Host_Supported_Features_Notification_Event(HCI_Event): ''' See Bluetooth spec @ 7.7.50 Remote Host Supported Features Notification Event ''' bd_addr: Address = field(metadata=metadata(Address.parse_address)) host_supported_features: bytes = field(metadata=metadata(8)) # ----------------------------------------------------------------------------- @HCI_Event.event @dataclasses.dataclass class HCI_Vendor_Event(HCI_Event): ''' See Bluetooth spec @ 5.4.4 HCI Event packet ''' data: bytes = field(metadata=metadata("*")) # ----------------------------------------------------------------------------- class HCI_AclDataPacket(HCI_Packet): ''' See Bluetooth spec @ 5.4.2 HCI ACL Data Packets ''' hci_packet_type = HCI_ACL_DATA_PACKET @staticmethod def from_bytes(packet: bytes) -> HCI_AclDataPacket: # Read the header h, data_total_length = struct.unpack_from('> 12) & 3 bc_flag = (h >> 14) & 3 data = packet[5:] if len(data) != data_total_length: raise InvalidPacketError('invalid packet length') return HCI_AclDataPacket( connection_handle, pb_flag, bc_flag, data_total_length, data ) def __bytes__(self): h = (self.pb_flag << 12) | (self.bc_flag << 14) | self.connection_handle return ( struct.pack(' HCI_SynchronousDataPacket: # Read the header h, data_total_length = struct.unpack_from('> 12) & 0b11 data = packet[4:] if len(data) != data_total_length: raise InvalidPacketError( f'invalid packet length {len(data)} != {data_total_length}' ) return HCI_SynchronousDataPacket( connection_handle, packet_status, data_total_length, data ) def __bytes__(self) -> bytes: h = (self.packet_status << 12) | self.connection_handle return ( struct.pack(' None: self.connection_handle = connection_handle self.packet_status = packet_status self.data_total_length = data_total_length self.data = data def __str__(self) -> str: return ( f'{color("SCO", "blue")}: ' f'handle=0x{self.connection_handle:04x}, ' f'ps={self.packet_status}, ' f'data_total_length={self.data_total_length}, ' f'data={self.data.hex()}' ) # ----------------------------------------------------------------------------- @dataclasses.dataclass class HCI_IsoDataPacket(HCI_Packet): ''' See Bluetooth spec @ 5.4.5 HCI ISO Data Packets ''' hci_packet_type: ClassVar[int] = HCI_ISO_DATA_PACKET connection_handle: int data_total_length: int iso_sdu_fragment: bytes pb_flag: int ts_flag: int = 0 time_stamp: Optional[int] = None packet_sequence_number: Optional[int] = None iso_sdu_length: Optional[int] = None packet_status_flag: Optional[int] = None def __post_init__(self) -> None: self.ts_flag = self.time_stamp is not None @staticmethod def from_bytes(packet: bytes) -> HCI_IsoDataPacket: time_stamp: Optional[int] = None packet_sequence_number: Optional[int] = None iso_sdu_length: Optional[int] = None packet_status_flag: Optional[int] = None pos = 1 pdu_info, data_total_length = struct.unpack_from('> 12) & 0b11 ts_flag = (pdu_info >> 14) & 0b01 pos += 4 # pb_flag in (0b00, 0b10) but faster should_include_sdu_info = not (pb_flag & 0b01) if ts_flag: if not should_include_sdu_info: logger.warning(f'Timestamp included when pb_flag={bin(pb_flag)}') time_stamp, *_ = struct.unpack_from('> 15) & 1 pos += 4 iso_sdu_fragment = packet[pos:] return HCI_IsoDataPacket( connection_handle=connection_handle, pb_flag=pb_flag, ts_flag=ts_flag, data_total_length=data_total_length, time_stamp=time_stamp, packet_sequence_number=packet_sequence_number, iso_sdu_length=iso_sdu_length, packet_status_flag=packet_status_flag, iso_sdu_fragment=iso_sdu_fragment, ) def __bytes__(self) -> bytes: fmt = ' str: result = ( f'{color("ISO", "blue")}: ' f'handle=0x{self.connection_handle:04x}, ' f'pb={self.pb_flag}, ' f'data_total_length={self.data_total_length}' ) if self.ts_flag: result += f', time_stamp={self.time_stamp}' if self.pb_flag in (0b00, 0b10): result += ( ', ' f'packet_sequence_number={self.packet_sequence_number}, ' f'ps={self.packet_status_flag}, ' f'sdu_fragment={self.iso_sdu_fragment.hex()}' ) return result # ----------------------------------------------------------------------------- class HCI_AclDataPacketAssembler: current_data: Optional[bytes] def __init__(self, callback: Callable[[bytes], Any]) -> None: self.callback = callback self.current_data = None self.l2cap_pdu_length = 0 def feed_packet(self, packet: HCI_AclDataPacket) -> None: if packet.pb_flag in ( HCI_ACL_PB_FIRST_NON_FLUSHABLE, HCI_ACL_PB_FIRST_FLUSHABLE, ): (l2cap_pdu_length,) = struct.unpack_from(' self.l2cap_pdu_length + 4: logger.warning('!!! ACL data exceeds L2CAP PDU') self.current_data = None self.l2cap_pdu_length = 0