mirror of
https://github.com/google/bumble.git
synced 2026-05-08 03:58:01 +00:00
This affect the way security keys are stored. For instance the same key can be used both as public and random, and it need to be stored separately one from each other.
4972 lines
199 KiB
Python
4972 lines
199 KiB
Python
# 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
|
|
# -----------------------------------------------------------------------------
|
|
import struct
|
|
import collections
|
|
import logging
|
|
import functools
|
|
from colors import color
|
|
|
|
from .core import *
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Logging
|
|
# -----------------------------------------------------------------------------
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Utils
|
|
# -----------------------------------------------------------------------------
|
|
def hci_command_op_code(ogf, ocf):
|
|
return (ogf << 10 | 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(str):
|
|
return '\n'.join([' ' + line for line in str.split('\n')])
|
|
|
|
|
|
def map_null_terminated_utf8_string(utf8_bytes):
|
|
try:
|
|
terminator = utf8_bytes.find(0)
|
|
if terminator < 0:
|
|
return 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({",".join(DeviceClass.service_class_labels(service_classes))}),Class({DeviceClass.major_device_class_name(major_device_class)}|{DeviceClass.minor_device_class_name(major_device_class, minor_device_class)})'
|
|
|
|
|
|
def phy_list_to_bits(phys):
|
|
if phys is None:
|
|
return 0
|
|
else:
|
|
phy_bits = 0
|
|
for phy in phys:
|
|
if phy not in HCI_LE_PHY_TYPE_TO_BIT:
|
|
raise ValueError('invalid PHY')
|
|
phy_bits |= (1 << HCI_LE_PHY_TYPE_TO_BIT[phy])
|
|
return phy_bits
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Constants
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# 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_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'
|
|
}
|
|
|
|
# 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 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 = 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_EVENT_NAMES = {
|
|
event_code: event_name for (event_name, event_code) in globals().items()
|
|
if event_name.startswith('HCI_') and event_name.endswith('_EVENT')
|
|
}
|
|
|
|
# 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_SUBEVENT_NAMES = {
|
|
event_code: event_name for (event_name, event_code) in globals().items()
|
|
if event_name.startswith('HCI_LE_') and event_name.endswith('_EVENT') and event_code != HCI_LE_META_EVENT
|
|
}
|
|
|
|
# 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_COMMAND_NAMES = {
|
|
command_code: command_name for (command_name, command_code) in globals().items()
|
|
if command_name.startswith('HCI_') and command_name.endswith('_COMMAND')
|
|
}
|
|
|
|
# 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
|
|
|
|
# LE Event Masks
|
|
HCI_LE_CONNECTION_COMPLETE_EVENT_MASK = (1 << 0)
|
|
HCI_LE_ADVERTISING_REPORT_EVENT_MASK = (1 << 1)
|
|
HCI_LE_CONNECTION_UPDATE_COMPLETE_EVENT_MASK = (1 << 2)
|
|
HCI_LE_READ_REMOTE_FEATURES_COMPLETE_EVENT_MASK = (1 << 3)
|
|
HCI_LE_LONG_TERM_KEY_REQUEST_EVENT_MASK = (1 << 4)
|
|
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_EVENT_MASK = (1 << 5)
|
|
HCI_LE_DATA_LENGTH_CHANGE_EVENT_MASK = (1 << 6)
|
|
HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMPLETE_EVENT_MASK = (1 << 7)
|
|
HCI_LE_GENERATE_DHKEY_COMPLETE_EVENT_MASK = (1 << 8)
|
|
HCI_LE_ENHANCED_CONNECTION_COMPLETE_EVENT_MASK = (1 << 9)
|
|
HCI_LE_DIRECTED_ADVERTISING_REPORT_EVENT_MASK = (1 << 10)
|
|
HCI_LE_PHY_UPDATE_COMPLETE_EVENT_MASK = (1 << 11)
|
|
HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT_MASK = (1 << 12)
|
|
HCI_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHED_EVENT_MASK = (1 << 13)
|
|
HCI_LE_PERIODIC_ADVERTISING_REPORT_EVENT_MASK = (1 << 14)
|
|
HCI_LE_PERIODIC_ADVERTISING_SYNC_LOST_EVENT_MASK = (1 << 15)
|
|
HCI_LE_EXTENDED_SCAN_TIMEOUT_EVENT_MASK = (1 << 16)
|
|
HCI_LE_EXTENDED_ADVERTISING_SET_TERMINATED_EVENT_MASK = (1 << 17)
|
|
HCI_LE_SCAN_REQUEST_RECEIVED_EVENT_MASK = (1 << 18)
|
|
HCI_LE_CHANNEL_SELECTION_ALGORITHM_EVENT_MASK = (1 << 19)
|
|
HCI_LE_CONNECTIONLESS_IQ_REPORT_EVENT_MASK = (1 << 20)
|
|
HCI_LE_CONNECTION_IQ_REPORT_EVENT_MASK = (1 << 21)
|
|
HCI_LE_CTE_REQUEST_FAILED_EVENT_MASK = (1 << 22)
|
|
HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED_EVENT_MASK = (1 << 23)
|
|
HCI_LE_CIS_ESTABLISHED_EVENT_MASK = (1 << 24)
|
|
HCI_LE_CIS_REQUEST_EVENT_MASK = (1 << 25)
|
|
HCI_LE_CREATE_BIG_COMPLETE_EVENT_MASK = (1 << 26)
|
|
HCI_LE_TERMINATE_BIG_COMPLETE_EVENT_MASK = (1 << 27)
|
|
HCI_LE_BIG_SYNC_ESTABLISHED_EVENT_MASK = (1 << 28)
|
|
HCI_LE_BIG_SYNC_LOST_EVENT_MASK = (1 << 29)
|
|
HCI_LE_REQUEST_PEER_SCA_COMPLETE_EVENT_MASK = (1 << 30)
|
|
HCI_LE_PATH_LOSS_THRESHOLD_EVENT_MASK = (1 << 31)
|
|
HCI_LE_TRANSMIT_POWER_REPORTING_EVENT_MASK = (1 << 32)
|
|
HCI_LE_BIGINFO_ADVERTISING_REPORT_EVENT_MASK = (1 << 33)
|
|
HCI_LE_SUBRATE_CHANGE_EVENT_MASK = (1 << 34)
|
|
|
|
HCI_LE_EVENT_MASK_NAMES = {
|
|
mask: mask_name for (mask_name, mask) in globals().items()
|
|
if mask_name.startswith('HCI_LE_') and mask_name.endswith('_EVENT_MASK')
|
|
}
|
|
|
|
# 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
|
|
|
|
# Roles
|
|
HCI_CENTRAL_ROLE = 0
|
|
HCI_PERIPHERAL_ROLE = 1
|
|
|
|
HCI_ROLE_NAMES = {
|
|
HCI_CENTRAL_ROLE: 'CENTRAL',
|
|
HCI_PERIPHERAL_ROLE: 'PERIPHERAL'
|
|
}
|
|
|
|
# LE PHY Types
|
|
HCI_LE_1M_PHY = 1
|
|
HCI_LE_2M_PHY = 2
|
|
HCI_LE_CODED_PHY = 3
|
|
|
|
HCI_LE_PHY_NAMES = {
|
|
HCI_LE_1M_PHY: 'LE 1M',
|
|
HCI_LE_2M_PHY: 'LE 2M',
|
|
HCI_LE_CODED_PHY: '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 = {
|
|
HCI_LE_1M_PHY: HCI_LE_1M_PHY_BIT,
|
|
HCI_LE_2M_PHY: HCI_LE_2M_PHY_BIT,
|
|
HCI_LE_CODED_PHY: HCI_LE_CODED_PHY_BIT
|
|
}
|
|
|
|
# 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
|
|
HCI_DISPLAY_ONLY_IO_CAPABILITY = 0x00
|
|
HCI_DISPLAY_YES_NO_IO_CAPABILITY = 0x01
|
|
HCI_KEYBOARD_ONLY_IO_CAPABILITY = 0x02
|
|
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY = 0x03
|
|
|
|
HCI_IO_CAPABILITY_NAMES = {
|
|
HCI_DISPLAY_ONLY_IO_CAPABILITY: 'HCI_DISPLAY_ONLY_IO_CAPABILITY',
|
|
HCI_DISPLAY_YES_NO_IO_CAPABILITY: 'HCI_DISPLAY_YES_NO_IO_CAPABILITY',
|
|
HCI_KEYBOARD_ONLY_IO_CAPABILITY: 'HCI_KEYBOARD_ONLY_IO_CAPABILITY',
|
|
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: 'HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY'
|
|
}
|
|
|
|
# Authentication Requirements
|
|
HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS = 0x00
|
|
HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS = 0x01
|
|
HCI_MITM_NOT_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS = 0x02
|
|
HCI_MITM_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS = 0x03
|
|
HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS = 0x04
|
|
HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS = 0x05
|
|
|
|
HCI_AUTHENTICATION_REQUIREMENTS_NAMES = {
|
|
HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS',
|
|
HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS',
|
|
HCI_MITM_NOT_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_NOT_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS',
|
|
HCI_MITM_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_REQUIRED_DEDICATED_BONDING_AUTHENTICATION_REQUIREMENTS',
|
|
HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS',
|
|
HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS: 'HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS'
|
|
}
|
|
|
|
# Link Key Types
|
|
HCI_COMBINATION_KEY_TYPE = 0X00
|
|
HCI_LOCAL_UNIT_KEY_TYPE = 0X01
|
|
HCI_REMOTE_UNIT_KEY_TYPE = 0X02
|
|
HCI_DEBUG_COMBINATION_KEY_TYPE = 0X03
|
|
HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE = 0X04
|
|
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE = 0X05
|
|
HCI_CHANGED_COMBINATION_KEY_TYPE = 0X06
|
|
HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE = 0X07
|
|
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE = 0X08
|
|
|
|
HCI_LINK_TYPE_NAMES = {
|
|
HCI_COMBINATION_KEY_TYPE: 'HCI_COMBINATION_KEY_TYPE',
|
|
HCI_LOCAL_UNIT_KEY_TYPE: 'HCI_LOCAL_UNIT_KEY_TYPE',
|
|
HCI_REMOTE_UNIT_KEY_TYPE: 'HCI_REMOTE_UNIT_KEY_TYPE',
|
|
HCI_DEBUG_COMBINATION_KEY_TYPE: 'HCI_DEBUG_COMBINATION_KEY_TYPE',
|
|
HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE: 'HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE',
|
|
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE: 'HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE',
|
|
HCI_CHANGED_COMBINATION_KEY_TYPE: 'HCI_CHANGED_COMBINATION_KEY_TYPE',
|
|
HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE: 'HCI_UNAUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE',
|
|
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE: 'HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE'
|
|
}
|
|
|
|
# Address types
|
|
HCI_PUBLIC_DEVICE_ADDRESS_TYPE = 0x00
|
|
HCI_RANDOM_DEVICE_ADDRESS_TYPE = 0x01
|
|
HCI_PUBLIC_IDENTITY_ADDRESS_TYPE = 0x02
|
|
HCI_RANDOM_IDENTITY_ADDRESS_TYPE = 0x03
|
|
|
|
# Supported Commands Flags
|
|
# See Bluetooth spec @ 6.27 SUPPORTED COMMANDS
|
|
HCI_SUPPORTED_COMMANDS_FLAGS = (
|
|
# Octet 0
|
|
(
|
|
HCI_INQUIRY_COMMAND,
|
|
HCI_INQUIRY_CANCEL_COMMAND,
|
|
HCI_PERIODIC_INQUIRY_MODE_COMMAND,
|
|
HCI_EXIT_PERIODIC_INQUIRY_MODE_COMMAND,
|
|
HCI_CREATE_CONNECTION_COMMAND,
|
|
HCI_DISCONNECT_COMMAND,
|
|
None,
|
|
HCI_CREATE_CONNECTION_CANCEL_COMMAND
|
|
),
|
|
# Octet 1
|
|
(
|
|
HCI_ACCEPT_CONNECTION_REQUEST_COMMAND,
|
|
HCI_REJECT_CONNECTION_REQUEST_COMMAND,
|
|
HCI_LINK_KEY_REQUEST_REPLY_COMMAND,
|
|
HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_PIN_CODE_REQUEST_REPLY_COMMAND,
|
|
HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_CHANGE_CONNECTION_PACKET_TYPE_COMMAND,
|
|
HCI_AUTHENTICATION_REQUESTED_COMMAND
|
|
),
|
|
# Octet 2
|
|
(
|
|
HCI_SET_CONNECTION_ENCRYPTION_COMMAND,
|
|
HCI_CHANGE_CONNECTION_LINK_KEY_COMMAND,
|
|
HCI_LINK_KEY_SELECTION_COMMAND,
|
|
HCI_REMOTE_NAME_REQUEST_COMMAND,
|
|
HCI_REMOTE_NAME_REQUEST_CANCEL_COMMAND,
|
|
HCI_READ_REMOTE_SUPPORTED_FEATURES_COMMAND,
|
|
HCI_READ_REMOTE_EXTENDED_FEATURES_COMMAND,
|
|
HCI_READ_REMOTE_VERSION_INFORMATION_COMMAND
|
|
),
|
|
# Octet 3
|
|
(
|
|
HCI_READ_CLOCK_OFFSET_COMMAND,
|
|
HCI_READ_LMP_HANDLE_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None
|
|
),
|
|
# Octet 4
|
|
(
|
|
None,
|
|
HCI_HOLD_MODE_COMMAND,
|
|
HCI_SNIFF_MODE_COMMAND,
|
|
HCI_EXIT_SNIFF_MODE_COMMAND,
|
|
None,
|
|
None,
|
|
HCI_QOS_SETUP_COMMAND,
|
|
HCI_ROLE_DISCOVERY_COMMAND
|
|
),
|
|
# Octet 5
|
|
(
|
|
HCI_SWITCH_ROLE_COMMAND,
|
|
HCI_READ_LINK_POLICY_SETTINGS_COMMAND,
|
|
HCI_WRITE_LINK_POLICY_SETTINGS_COMMAND,
|
|
HCI_READ_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
|
|
HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS_COMMAND,
|
|
HCI_FLOW_SPECIFICATION_COMMAND,
|
|
HCI_SET_EVENT_MASK_COMMAND,
|
|
HCI_RESET_COMMAND
|
|
),
|
|
# Octet 6
|
|
(
|
|
HCI_SET_EVENT_FILTER_COMMAND,
|
|
HCI_FLUSH_COMMAND,
|
|
HCI_READ_PIN_TYPE_COMMAND,
|
|
HCI_WRITE_PIN_TYPE_COMMAND,
|
|
None,
|
|
HCI_READ_STORED_LINK_KEY_COMMAND,
|
|
HCI_WRITE_STORED_LINK_KEY_COMMAND,
|
|
HCI_DELETE_STORED_LINK_KEY_COMMAND
|
|
),
|
|
# Octet 7
|
|
(
|
|
HCI_WRITE_LOCAL_NAME_COMMAND,
|
|
HCI_READ_LOCAL_NAME_COMMAND,
|
|
HCI_READ_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
|
|
HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT_COMMAND,
|
|
HCI_READ_PAGE_TIMEOUT_COMMAND,
|
|
HCI_WRITE_PAGE_TIMEOUT_COMMAND,
|
|
HCI_READ_SCAN_ENABLE_COMMAND,
|
|
HCI_WRITE_SCAN_ENABLE_COMMAND
|
|
),
|
|
# Octet 8
|
|
(
|
|
HCI_READ_PAGE_SCAN_ACTIVITY_COMMAND,
|
|
HCI_WRITE_PAGE_SCAN_ACTIVITY_COMMAND,
|
|
HCI_READ_INQUIRY_SCAN_ACTIVITY_COMMAND,
|
|
HCI_WRITE_INQUIRY_SCAN_ACTIVITY_COMMAND,
|
|
HCI_READ_AUTHENTICATION_ENABLE_COMMAND,
|
|
HCI_WRITE_AUTHENTICATION_ENABLE_COMMAND,
|
|
None,
|
|
None
|
|
),
|
|
# Octet 9
|
|
(
|
|
HCI_READ_CLASS_OF_DEVICE_COMMAND,
|
|
HCI_WRITE_CLASS_OF_DEVICE_COMMAND,
|
|
HCI_READ_VOICE_SETTING_COMMAND,
|
|
HCI_WRITE_VOICE_SETTING_COMMAND,
|
|
HCI_READ_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
|
|
HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT_COMMAND,
|
|
HCI_READ_NUM_BROADCAST_RETRANSMISSIONS_COMMAND,
|
|
HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS_COMMAND
|
|
),
|
|
# Octet 10
|
|
(
|
|
HCI_READ_HOLD_MODE_ACTIVITY_COMMAND,
|
|
HCI_WRITE_HOLD_MODE_ACTIVITY_COMMAND,
|
|
HCI_READ_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
|
|
HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE_COMMAND,
|
|
HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_COMMAND,
|
|
HCI_HOST_BUFFER_SIZE_COMMAND,
|
|
HCI_HOST_NUMBER_OF_COMPLETED_PACKETS_COMMAND
|
|
),
|
|
# Octet 11
|
|
(
|
|
HCI_READ_LINK_SUPERVISION_TIMEOUT_COMMAND,
|
|
HCI_WRITE_LINK_SUPERVISION_TIMEOUT_COMMAND,
|
|
HCI_READ_NUMBER_OF_SUPPORTED_IAC_COMMAND,
|
|
HCI_READ_CURRENT_IAC_LAP_COMMAND,
|
|
HCI_WRITE_CURRENT_IAC_LAP_COMMAND,
|
|
None,
|
|
None,
|
|
None
|
|
),
|
|
# Octet 12
|
|
(
|
|
None,
|
|
HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION_COMMAND,
|
|
None,
|
|
None,
|
|
HCI_READ_INQUIRY_SCAN_TYPE_COMMAND,
|
|
HCI_WRITE_INQUIRY_SCAN_TYPE_COMMAND,
|
|
HCI_READ_INQUIRY_MODE_COMMAND,
|
|
HCI_WRITE_INQUIRY_MODE_COMMAND
|
|
),
|
|
# Octet 13
|
|
(
|
|
HCI_READ_PAGE_SCAN_TYPE_COMMAND,
|
|
HCI_WRITE_PAGE_SCAN_TYPE_COMMAND,
|
|
HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
|
|
HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 14
|
|
(
|
|
None,
|
|
None,
|
|
None,
|
|
HCI_READ_LOCAL_VERSION_INFORMATION_COMMAND,
|
|
None,
|
|
HCI_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
|
|
HCI_READ_LOCAL_EXTENDED_FEATURES_COMMAND,
|
|
HCI_READ_BUFFER_SIZE_COMMAND
|
|
),
|
|
# Octet 15
|
|
(
|
|
None,
|
|
HCI_READ_BD_ADDR_COMMAND,
|
|
HCI_READ_FAILED_CONTACT_COUNTER_COMMAND,
|
|
HCI_RESET_FAILED_CONTACT_COUNTER_COMMAND,
|
|
HCI_READ_LINK_QUALITY_COMMAND,
|
|
HCI_READ_RSSI_COMMAND,
|
|
HCI_READ_AFH_CHANNEL_MAP_COMMAND,
|
|
HCI_READ_CLOCK_COMMAND
|
|
),
|
|
# Octet 16
|
|
(
|
|
HCI_READ_LOOPBACK_MODE_COMMAND,
|
|
HCI_WRITE_LOOPBACK_MODE_COMMAND,
|
|
HCI_ENABLE_DEVICE_UNDER_TEST_MODE_COMMAND,
|
|
HCI_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
|
|
HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
|
|
HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 17
|
|
(
|
|
HCI_READ_EXTENDED_INQUIRY_RESPONSE_COMMAND,
|
|
HCI_WRITE_EXTENDED_INQUIRY_RESPONSE_COMMAND,
|
|
HCI_REFRESH_ENCRYPTION_KEY_COMMAND,
|
|
None,
|
|
HCI_SNIFF_SUBRATING_COMMAND,
|
|
HCI_READ_SIMPLE_PAIRING_MODE_COMMAND,
|
|
HCI_WRITE_SIMPLE_PAIRING_MODE_COMMAND,
|
|
HCI_READ_LOCAL_OOB_DATA_COMMAND
|
|
),
|
|
# Octet 18
|
|
(
|
|
HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
|
|
HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
HCI_IO_CAPABILITY_REQUEST_REPLY_COMMAND
|
|
),
|
|
# Octet 19
|
|
(
|
|
HCI_USER_CONFIRMATION_REQUEST_REPLY_COMMAND,
|
|
HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_USER_PASSKEY_REQUEST_REPLY_COMMAND,
|
|
HCI_USER_PASSKEY_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_REMOTE_OOB_DATA_REQUEST_REPLY_COMMAND,
|
|
HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE_COMMAND,
|
|
HCI_ENHANCED_FLUSH_COMMAND,
|
|
HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY_COMMAND
|
|
),
|
|
# Octet 20
|
|
(
|
|
None,
|
|
None,
|
|
HCI_SEND_KEYPRESS_NOTIFICATION_COMMAND,
|
|
HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_READ_ENCRYPTION_KEY_SIZE_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 21
|
|
(
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 22
|
|
(
|
|
None,
|
|
None,
|
|
HCI_SET_EVENT_MASK_PAGE_2_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 23
|
|
(
|
|
HCI_READ_FLOW_CONTROL_MODE_COMMAND,
|
|
HCI_WRITE_FLOW_CONTROL_MODE_COMMAND,
|
|
HCI_READ_DATA_BLOCK_SIZE_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
),
|
|
# Octet 24
|
|
(
|
|
HCI_READ_ENHANCED_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
HCI_READ_LE_HOST_SUPPORT_COMMAND,
|
|
HCI_WRITE_LE_HOST_SUPPORT_COMMAND,
|
|
None,
|
|
),
|
|
# Octet 25
|
|
(
|
|
HCI_LE_SET_EVENT_MASK_COMMAND,
|
|
HCI_LE_READ_BUFFER_SIZE_COMMAND,
|
|
HCI_LE_READ_LOCAL_SUPPORTED_FEATURES_COMMAND,
|
|
None,
|
|
HCI_LE_SET_RANDOM_ADDRESS_COMMAND,
|
|
HCI_LE_SET_ADVERTISING_PARAMETERS_COMMAND,
|
|
HCI_LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER_COMMAND,
|
|
HCI_LE_SET_ADVERTISING_DATA_COMMAND,
|
|
),
|
|
# Octet 26
|
|
(
|
|
HCI_LE_SET_SCAN_RESPONSE_DATA_COMMAND,
|
|
HCI_LE_SET_ADVERTISING_ENABLE_COMMAND,
|
|
HCI_LE_SET_SCAN_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_SCAN_ENABLE_COMMAND,
|
|
HCI_LE_CREATE_CONNECTION_COMMAND,
|
|
HCI_LE_CREATE_CONNECTION_CANCEL_COMMAND,
|
|
HCI_LE_READ_FILTER_ACCEPT_LIST_SIZE_COMMAND,
|
|
HCI_LE_CLEAR_FILTER_ACCEPT_LIST_COMMAND
|
|
),
|
|
# Octet 27
|
|
(
|
|
HCI_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_COMMAND,
|
|
HCI_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_COMMAND,
|
|
HCI_LE_CONNECTION_UPDATE_COMMAND,
|
|
HCI_LE_SET_HOST_CHANNEL_CLASSIFICATION_COMMAND,
|
|
HCI_LE_READ_CHANNEL_MAP_COMMAND,
|
|
HCI_LE_READ_REMOTE_FEATURES_COMMAND,
|
|
HCI_LE_ENCRYPT_COMMAND,
|
|
HCI_LE_RAND_COMMAND
|
|
),
|
|
# Octet 28
|
|
(
|
|
HCI_LE_ENABLE_ENCRYPTION_COMMAND,
|
|
HCI_LE_LONG_TERM_KEY_REQUEST_REPLY_COMMAND,
|
|
HCI_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_LE_READ_SUPPORTED_STATES_COMMAND,
|
|
HCI_LE_RECEIVER_TEST_COMMAND,
|
|
HCI_LE_TRANSMITTER_TEST_COMMAND,
|
|
HCI_LE_TEST_END_COMMAND,
|
|
None,
|
|
),
|
|
# Octet 29
|
|
(
|
|
None,
|
|
None,
|
|
None,
|
|
HCI_ENHANCED_SETUP_SYNCHRONOUS_CONNECTION_COMMAND,
|
|
HCI_ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST_COMMAND,
|
|
HCI_READ_LOCAL_SUPPORTED_CODECS_COMMAND,
|
|
HCI_SET_MWS_CHANNEL_PARAMETERS_COMMAND,
|
|
HCI_SET_EXTERNAL_FRAME_CONFIGURATION_COMMAND
|
|
),
|
|
# Octet 30
|
|
(
|
|
HCI_SET_MWS_SIGNALING_COMMAND,
|
|
HCI_SET_MWS_TRANSPORT_LAYER_COMMAND,
|
|
HCI_SET_MWS_SCAN_FREQUENCY_TABLE_COMMAND,
|
|
HCI_GET_MWS_TRANSPORT_LAYER_CONFIGURATION_COMMAND,
|
|
HCI_SET_MWS_PATTERN_CONFIGURATION_COMMAND,
|
|
HCI_SET_TRIGGERED_CLOCK_CAPTURE_COMMAND,
|
|
HCI_TRUNCATED_PAGE_COMMAND,
|
|
HCI_TRUNCATED_PAGE_CANCEL_COMMAND
|
|
),
|
|
# Octet 31
|
|
(
|
|
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_COMMAND,
|
|
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE_COMMAND,
|
|
HCI_START_SYNCHRONIZATION_TRAIN_COMMAND,
|
|
HCI_RECEIVE_SYNCHRONIZATION_TRAIN_COMMAND,
|
|
HCI_SET_RESERVED_LT_ADDR_COMMAND,
|
|
HCI_DELETE_RESERVED_LT_ADDR_COMMAND,
|
|
HCI_SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA_COMMAND,
|
|
HCI_READ_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND
|
|
),
|
|
# Octet 32
|
|
(
|
|
HCI_WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS_COMMAND,
|
|
HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_COMMAND,
|
|
HCI_READ_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
|
|
HCI_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT_COMMAND,
|
|
HCI_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
|
|
HCI_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_COMMAND,
|
|
HCI_READ_LOCAL_OOB_EXTENDED_DATA_COMMAND,
|
|
HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_COMMAND
|
|
),
|
|
# Octet 33
|
|
(
|
|
HCI_READ_EXTENDED_PAGE_TIMEOUT_COMMAND,
|
|
HCI_WRITE_EXTENDED_PAGE_TIMEOUT_COMMAND,
|
|
HCI_READ_EXTENDED_INQUIRY_LENGTH_COMMAND,
|
|
HCI_WRITE_EXTENDED_INQUIRY_LENGTH_COMMAND,
|
|
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_COMMAND,
|
|
HCI_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_COMMAND,
|
|
HCI_LE_SET_DATA_LENGTH_COMMAND,
|
|
HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND
|
|
),
|
|
# Octet 34
|
|
(
|
|
HCI_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
|
|
HCI_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND,
|
|
HCI_LE_GENERATE_DHKEY_COMMAND,
|
|
HCI_LE_ADD_DEVICE_TO_RESOLVING_LIST_COMMAND,
|
|
HCI_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_COMMAND,
|
|
HCI_LE_CLEAR_RESOLVING_LIST_COMMAND,
|
|
HCI_LE_READ_RESOLVING_LIST_SIZE_COMMAND,
|
|
HCI_LE_READ_PEER_RESOLVABLE_ADDRESS_COMMAND
|
|
),
|
|
# Octet 35
|
|
(
|
|
HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS_COMMAND,
|
|
HCI_LE_SET_ADDRESS_RESOLUTION_ENABLE_COMMAND,
|
|
HCI_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_COMMAND,
|
|
HCI_LE_READ_MAXIMUM_DATA_LENGTH_COMMAND,
|
|
HCI_LE_READ_PHY_COMMAND,
|
|
HCI_LE_SET_DEFAULT_PHY_COMMAND,
|
|
HCI_LE_SET_PHY_COMMAND,
|
|
HCI_LE_RECEIVER_TEST_V2_COMMAND
|
|
),
|
|
# Octet 36
|
|
(
|
|
HCI_LE_TRANSMITTER_TEST_V2_COMMAND,
|
|
HCI_LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_COMMAND,
|
|
HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_EXTENDED_ADVERTISING_DATA_COMMAND,
|
|
HCI_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_COMMAND,
|
|
HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND,
|
|
HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_COMMAND,
|
|
HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_COMMAND,
|
|
),
|
|
# Octet 37
|
|
(
|
|
HCI_LE_REMOVE_ADVERTISING_SET_COMMAND,
|
|
HCI_LE_CLEAR_ADVERTISING_SETS_COMMAND,
|
|
HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_PERIODIC_ADVERTISING_DATA_COMMAND,
|
|
HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE_COMMAND,
|
|
HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_EXTENDED_SCAN_ENABLE_COMMAND,
|
|
HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
|
|
),
|
|
# Octet 38
|
|
(
|
|
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_COMMAND,
|
|
HCI_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_COMMAND,
|
|
HCI_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_COMMAND,
|
|
HCI_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_COMMAND,
|
|
HCI_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_COMMAND,
|
|
HCI_LE_CLEAR_PERIODIC_ADVERTISER_LIST_COMMAND,
|
|
HCI_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_COMMAND,
|
|
HCI_LE_READ_TRANSMIT_POWER_COMMAND
|
|
),
|
|
# Octet 39
|
|
(
|
|
HCI_LE_READ_RF_PATH_COMPENSATION_COMMAND,
|
|
HCI_LE_WRITE_RF_PATH_COMPENSATION_COMMAND,
|
|
HCI_LE_SET_PRIVACY_MODE_COMMAND,
|
|
HCI_LE_RECEIVER_TEST_V3_COMMAND,
|
|
HCI_LE_TRANSMITTER_TEST_V3_COMMAND,
|
|
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE_COMMAND,
|
|
HCI_LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE_COMMAND,
|
|
),
|
|
# Octet 40
|
|
(
|
|
HCI_LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS_COMMAND,
|
|
HCI_LE_CONNECTION_CTE_REQUEST_ENABLE_COMMAND,
|
|
HCI_LE_CONNECTION_CTE_RESPONSE_ENABLE_COMMAND,
|
|
HCI_LE_READ_ANTENNA_INFORMATION_COMMAND,
|
|
HCI_LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE_COMMAND,
|
|
HCI_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_COMMAND,
|
|
HCI_LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER_COMMAND
|
|
),
|
|
# Octet 41
|
|
(
|
|
HCI_LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS_COMMAND,
|
|
HCI_LE_GENERATE_DHKEY_V2_COMMAND,
|
|
HCI_READ_LOCAL_SIMPLE_PAIRING_OPTIONS_COMMAND,
|
|
HCI_LE_MODIFY_SLEEP_CLOCK_ACCURACY_COMMAND,
|
|
HCI_LE_READ_BUFFER_SIZE_V2_COMMAND,
|
|
HCI_LE_READ_ISO_TX_SYNC_COMMAND,
|
|
HCI_LE_SET_CIG_PARAMETERS_COMMAND
|
|
),
|
|
# Octet 42
|
|
(
|
|
HCI_LE_SET_CIG_PARAMETERS_TEST_COMMAND,
|
|
HCI_LE_CREATE_CIS_COMMAND,
|
|
HCI_LE_REMOVE_CIG_COMMAND,
|
|
HCI_LE_ACCEPT_CIS_REQUEST_COMMAND,
|
|
HCI_LE_REJECT_CIS_REQUEST_COMMAND,
|
|
HCI_LE_CREATE_BIG_COMMAND,
|
|
HCI_LE_CREATE_BIG_TEST_COMMAND,
|
|
HCI_LE_TERMINATE_BIG_COMMAND,
|
|
),
|
|
# Octet 43
|
|
(
|
|
HCI_LE_BIG_CREATE_SYNC_COMMAND,
|
|
HCI_LE_BIG_TERMINATE_SYNC_COMMAND,
|
|
HCI_LE_REQUEST_PEER_SCA_COMMAND,
|
|
HCI_LE_SETUP_ISO_DATA_PATH_COMMAND,
|
|
HCI_LE_REMOVE_ISO_DATA_PATH_COMMAND,
|
|
HCI_LE_ISO_TRANSMIT_TEST_COMMAND,
|
|
HCI_LE_ISO_RECEIVE_TEST_COMMAND,
|
|
HCI_LE_ISO_READ_TEST_COUNTERS_COMMAND
|
|
),
|
|
# Octet 44
|
|
(
|
|
HCI_LE_ISO_TEST_END_COMMAND,
|
|
HCI_LE_SET_HOST_FEATURE_COMMAND,
|
|
HCI_LE_READ_ISO_LINK_QUALITY_COMMAND,
|
|
HCI_LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
HCI_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL_COMMAND,
|
|
HCI_LE_SET_PATH_LOSS_REPORTING_PARAMETERS_COMMAND,
|
|
HCI_LE_SET_PATH_LOSS_REPORTING_ENABLE_COMMAND,
|
|
HCI_LE_SET_TRANSMIT_POWER_REPORTING_ENABLE_COMMAND
|
|
),
|
|
# Octet 45
|
|
(
|
|
HCI_LE_TRANSMITTER_TEST_V4_COMMAND,
|
|
HCI_SET_ECOSYSTEM_BASE_INTERVAL_COMMAND,
|
|
HCI_READ_LOCAL_SUPPORTED_CODECS_V2_COMMAND,
|
|
HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES_COMMAND,
|
|
HCI_READ_LOCAL_SUPPORTED_CONTROLLER_DELAY_COMMAND,
|
|
HCI_CONFIGURE_DATA_PATH_COMMAND,
|
|
HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND,
|
|
HCI_SET_MIN_ENCRYPTION_KEY_SIZE_COMMAND
|
|
),
|
|
# Octet 46
|
|
(
|
|
HCI_LE_SET_DEFAULT_SUBRATE_COMMAND,
|
|
HCI_LE_SUBRATE_REQUEST_COMMAND,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None
|
|
)
|
|
)
|
|
|
|
# LE Supported Features
|
|
HCI_LE_ENCRYPTION_LE_SUPPORTED_FEATURE = 0
|
|
HCI_CONNECTION_PARAMETERS_REQUEST_PROCEDURE_LE_SUPPORTED_FEATURE = 1
|
|
HCI_EXTENDED_REJECT_INDICATION_LE_SUPPORTED_FEATURE = 2
|
|
HCI_PERIPHERAL_INITIATED_FEATURE_EXCHANGE_LE_SUPPORTED_FEATURE = 3
|
|
HCI_LE_PING_LE_SUPPORTED_FEATURE = 4
|
|
HCI_LE_DATA_PACKET_LENGTH_EXTENSION_LE_SUPPORTED_FEATURE = 5
|
|
HCI_LL_PRIVACY_LE_SUPPORTED_FEATURE = 6
|
|
HCI_EXTENDED_SCANNER_FILTER_POLICIES_LE_SUPPORTED_FEATURE = 7
|
|
HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE = 8
|
|
HCI_STABLE_MODULATION_INDEX_TRANSMITTER_LE_SUPPORTED_FEATURE = 9
|
|
HCI_STABLE_MODULATION_INDEX_RECEIVER_LE_SUPPORTED_FEATURE = 10
|
|
HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE = 11
|
|
HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE = 12
|
|
HCI_LE_PERIODIC_ADVERTISING_LE_SUPPORTED_FEATURE = 13
|
|
HCI_CHANNEL_SELECTION_ALGORITHM_2_LE_SUPPORTED_FEATURE = 14
|
|
HCI_LE_POWER_CLASS_1_LE_SUPPORTED_FEATURE = 15
|
|
HCI_MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE_LE_SUPPORTED_FEATURE = 16
|
|
HCI_CONNECTION_CTE_REQUEST_LE_SUPPORTED_FEATURE = 17
|
|
HCI_CONNECTION_CTE_RESPONSE_LE_SUPPORTED_FEATURE = 18
|
|
HCI_CONNECTIONLESS_CTE_TRANSMITTER_LE_SUPPORTED_FEATURE = 19
|
|
HCI_CONNECTIONLESS_CTR_RECEIVER_LE_SUPPORTED_FEATURE = 20
|
|
HCI_ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION_LE_SUPPORTED_FEATURE = 21
|
|
HCI_ANTENNA_SWITCHING_DURING_CTE_RECEPTION_LE_SUPPORTED_FEATURE = 22
|
|
HCI_RECEIVING_CONSTANT_TONE_EXTENSIONS_LE_SUPPORTED_FEATURE = 23
|
|
HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER_LE_SUPPORTED_FEATURE = 24
|
|
HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT_LE_SUPPORTED_FEATURE = 25
|
|
HCI_SLEEP_CLOCK_ACCURACY_UPDATES_LE_SUPPORTED_FEATURE = 26
|
|
HCI_REMOTE_PUBLIC_KEY_VALIDATION_LE_SUPPORTED_FEATURE = 27
|
|
HCI_CONNECTED_ISOCHRONOUS_STREAM_CENTRAL_LE_SUPPORTED_FEATURE = 28
|
|
HCI_CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL_LE_SUPPORTED_FEATURE = 29
|
|
HCI_ISOCHRONOUS_BROADCASTER_LE_SUPPORTED_FEATURE = 30
|
|
HCI_SYNCHRONIZED_RECEIVER_LE_SUPPORTED_FEATURE = 31
|
|
HCI_CONNECTED_ISOCHRONOUS_STREAM_LE_SUPPORTED_FEATURE = 32
|
|
HCI_LE_POWER_CONTROL_REQUEST_LE_SUPPORTED_FEATURE = 33
|
|
HCI_LE_POWER_CONTROL_REQUEST_DUP_LE_SUPPORTED_FEATURE = 34
|
|
HCI_LE_PATH_LOSS_MONITORING_LE_SUPPORTED_FEATURE = 35
|
|
HCI_PERIODIC_ADVERTISING_ADI_SUPPORT_LE_SUPPORTED_FEATURE = 36
|
|
HCI_CONNECTION_SUBRATING_LE_SUPPORTED_FEATURE = 37
|
|
HCI_CONNECTION_SUBRATING_HOST_SUPPORT_LE_SUPPORTED_FEATURE = 38
|
|
HCI_CHANNEL_CLASSIFICATION_LE_SUPPORTED_FEATURE = 39
|
|
|
|
HCI_LE_SUPPORTED_FEATURES_NAMES = {
|
|
flag: feature_name for (feature_name, flag) in globals().items()
|
|
if feature_name.startswith('HCI_') and feature_name.endswith('_LE_SUPPORTED_FEATURE')
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)}
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_Constant:
|
|
@staticmethod
|
|
def status_name(status):
|
|
return HCI_ERROR_NAMES.get(status, f'0x{status:02X}')
|
|
|
|
@staticmethod
|
|
def error_name(status):
|
|
return HCI_ERROR_NAMES.get(status, f'0x{status:02X}')
|
|
|
|
@staticmethod
|
|
def role_name(role):
|
|
return HCI_ROLE_NAMES.get(role, str(role))
|
|
|
|
@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):
|
|
return HCI_IO_CAPABILITY_NAMES.get(io_capability, f'0x{io_capability:02X}')
|
|
|
|
@staticmethod
|
|
def authentication_requirements_name(authentication_requirements):
|
|
return HCI_AUTHENTICATION_REQUIREMENTS_NAMES.get(
|
|
authentication_requirements,
|
|
f'0x{authentication_requirements:02X}'
|
|
)
|
|
|
|
@staticmethod
|
|
def link_key_type_name(link_key_type):
|
|
return HCI_LINK_TYPE_NAMES.get(link_key_type, f'0x{link_key_type:02X}')
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_Error(ProtocolError):
|
|
def __init__(self, error_code):
|
|
super().__init__(error_code, 'hci', 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(object, fields, values):
|
|
if type(values) is dict:
|
|
for field_name, _ in fields:
|
|
setattr(object, field_name, values[field_name])
|
|
else:
|
|
for field_name, field_value in zip(fields, values):
|
|
setattr(object, field_name, field_value)
|
|
|
|
@staticmethod
|
|
def init_from_bytes(object, data, offset, fields):
|
|
parsed = HCI_Object.dict_from_bytes(data, offset, fields)
|
|
HCI_Object.init_from_fields(object, parsed.keys(), parsed.values())
|
|
|
|
@staticmethod
|
|
def dict_from_bytes(data, offset, fields):
|
|
result = collections.OrderedDict()
|
|
for (field_name, field_type) in fields:
|
|
# The field_type may be a dictionary with a mapper, parser, and/or size
|
|
if type(field_type) is 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:]
|
|
offset += len(field_value)
|
|
elif field_type == 1:
|
|
# 8-bit unsigned
|
|
field_value = data[offset]
|
|
offset += 1
|
|
elif field_type == -1:
|
|
# 8-bit signed
|
|
field_value = struct.unpack_from('b', data, offset)[0]
|
|
offset += 1
|
|
elif field_type == 2:
|
|
# 16-bit unsigned
|
|
field_value = struct.unpack_from('<H', data, offset)[0]
|
|
offset += 2
|
|
elif field_type == '>2':
|
|
# 16-bit unsigned big-endian
|
|
field_value = struct.unpack_from('>H', data, offset)[0]
|
|
offset += 2
|
|
elif field_type == -2:
|
|
# 16-bit signed
|
|
field_value = struct.unpack_from('<h', data, offset)[0]
|
|
offset += 1
|
|
elif field_type == 3:
|
|
# 24-bit unsigned
|
|
padded = data[offset:offset + 3] + bytes([0])
|
|
field_value = struct.unpack('<I', padded)[0]
|
|
offset += 3
|
|
elif field_type == 4:
|
|
# 32-bit unsigned
|
|
field_value = struct.unpack_from('<I', data, offset)[0]
|
|
offset += 4
|
|
elif field_type == '>4':
|
|
# 32-bit unsigned big-endian
|
|
field_value = struct.unpack_from('>I', data, offset)[0]
|
|
offset += 4
|
|
elif type(field_type) is int and field_type > 4 and field_type <= 256:
|
|
# Byte array (from 5 up to 256 bytes)
|
|
field_value = data[offset:offset + field_type]
|
|
offset += field_type
|
|
elif callable(field_type):
|
|
offset, field_value = field_type(data, offset)
|
|
else:
|
|
raise ValueError(f'unknown field type {field_type}')
|
|
|
|
result[field_name] = field_value
|
|
|
|
return result
|
|
|
|
@staticmethod
|
|
def dict_to_bytes(object, fields):
|
|
result = bytearray()
|
|
for (field_name, field_type) in fields:
|
|
# The field_type may be a dictionary with a mapper, parser, serializer, and/or size
|
|
serializer = None
|
|
if type(field_type) is dict:
|
|
if 'serializer' in field_type:
|
|
serializer = field_type['serializer']
|
|
if 'size' in field_type:
|
|
field_type = field_type['size']
|
|
|
|
# Serialize the field
|
|
field_value = object[field_name]
|
|
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('<H', field_value)
|
|
elif field_type == '>2':
|
|
# 16-bit unsigned big-endian
|
|
field_bytes = struct.pack('>H', field_value)
|
|
elif field_type == -2:
|
|
# 16-bit signed
|
|
field_bytes = struct.pack('<h', field_value)
|
|
elif field_type == 3:
|
|
# 24-bit unsigned
|
|
field_bytes = struct.pack('<I', field_value)[0:3]
|
|
elif field_type == 4:
|
|
# 32-bit unsigned
|
|
field_bytes = struct.pack('<I', field_value)
|
|
elif field_type == '>4':
|
|
# 32-bit unsigned big-endian
|
|
field_bytes = struct.pack('>I', field_value)
|
|
elif field_type == '*':
|
|
if type(field_value) is int:
|
|
if field_value >= 0 and field_value <= 255:
|
|
field_bytes = bytes([field_value])
|
|
else:
|
|
raise ValueError('value too large for *-typed field')
|
|
else:
|
|
field_bytes = bytes(field_value)
|
|
elif type(field_value) is bytes or type(field_value) is bytearray or hasattr(field_value, 'to_bytes'):
|
|
field_bytes = bytes(field_value)
|
|
if type(field_type) is int and field_type > 4 and 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 ValueError(f"don't know how to serialize type {type(field_value)}")
|
|
|
|
result += field_bytes
|
|
|
|
return bytes(result)
|
|
|
|
@classmethod
|
|
def from_bytes(cls, data, offset, fields):
|
|
return cls(fields, **cls.dict_from_bytes(data, offset, fields))
|
|
|
|
def to_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 type(value) is bytes:
|
|
return value.hex()
|
|
elif isinstance(value, HCI_Object):
|
|
return '\n' + value.to_string(indentation)
|
|
else:
|
|
return str(value)
|
|
|
|
@staticmethod
|
|
def format_fields(object, keys, indentation='', value_mappers={}):
|
|
if not keys:
|
|
return ''
|
|
|
|
# Measure the widest field name
|
|
max_field_name_length = max([len(key[0] if type(key) is tuple else key) for key in keys])
|
|
|
|
# Build array of formatted key:value pairs
|
|
fields = []
|
|
for key in keys:
|
|
value_mapper = None
|
|
if type(key) is tuple:
|
|
# The key has an associated specifier
|
|
key, specifier = key
|
|
|
|
# Get the value mapper from the specifier
|
|
if type(specifier) is dict:
|
|
value_mapper = specifier.get('mapper')
|
|
|
|
# Get the value for the field
|
|
value = object[key]
|
|
|
|
# Map the value if needed
|
|
value_mapper = value_mappers.get(key, value_mapper)
|
|
if value_mapper is not None:
|
|
value = value_mapper(value)
|
|
|
|
# Get the string representation of the value
|
|
value_str = HCI_Object.format_field_value(value, indentation = indentation + ' ')
|
|
|
|
# Add the field to the formatted result
|
|
key_str = color(f'{key + ":":{1 + max_field_name_length}}', 'cyan')
|
|
fields.append(f'{indentation}{key_str} {value_str}')
|
|
|
|
return '\n'.join(fields)
|
|
|
|
def __bytes__(self):
|
|
return self.to_bytes()
|
|
|
|
def __init__(self, fields, **kwargs):
|
|
self.fields = fields
|
|
self.init_from_fields(self, fields, kwargs)
|
|
|
|
def to_string(self, indentation='', value_mappers={}):
|
|
return HCI_Object.format_fields(self.__dict__, self.fields, indentation, value_mappers)
|
|
|
|
def __str__(self):
|
|
return self.to_string()
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 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 = 0x00
|
|
RANDOM_DEVICE_ADDRESS = 0x01
|
|
PUBLIC_IDENTITY_ADDRESS = 0x02
|
|
RANDOM_IDENTITY_ADDRESS = 0x03
|
|
|
|
ADDRESS_TYPE_NAMES = {
|
|
PUBLIC_DEVICE_ADDRESS: 'PUBLIC_DEVICE_ADDRESS',
|
|
RANDOM_DEVICE_ADDRESS: 'RANDOM_DEVICE_ADDRESS',
|
|
PUBLIC_IDENTITY_ADDRESS: 'PUBLIC_IDENTITY_ADDRESS',
|
|
RANDOM_IDENTITY_ADDRESS: 'RANDOM_IDENTITY_ADDRESS'
|
|
}
|
|
|
|
ADDRESS_TYPE_SPEC = {'size': 1, 'mapper': lambda x: Address.address_type_name(x)}
|
|
|
|
@classmethod
|
|
@property
|
|
def ANY(cls):
|
|
return cls(b"\xff\xff\xff\xff\xff\xff", cls.PUBLIC_DEVICE_ADDRESS)
|
|
|
|
@classmethod
|
|
@property
|
|
def NIL(cls):
|
|
return cls(b"\x00\x00\x00\x00\x00\x00", cls.PUBLIC_DEVICE_ADDRESS)
|
|
|
|
@staticmethod
|
|
def address_type_name(address_type):
|
|
return name_or_number(Address.ADDRESS_TYPE_NAMES, address_type)
|
|
|
|
@staticmethod
|
|
def from_string_for_transport(string, transport):
|
|
if transport == BT_BR_EDR_TRANSPORT:
|
|
address_type = Address.PUBLIC_DEVICE_ADDRESS
|
|
else:
|
|
address_type = Address.RANDOM_DEVICE_ADDRESS
|
|
return Address(string, address_type)
|
|
|
|
@staticmethod
|
|
def parse_address(data, offset):
|
|
# Fix the type to a default value. This is used for parsing type-less Classic addresses
|
|
return Address.parse_address_with_type(data, offset, Address.PUBLIC_DEVICE_ADDRESS)
|
|
|
|
@staticmethod
|
|
def parse_address_with_type(data, offset, address_type):
|
|
return offset + 6, Address(data[offset:offset + 6], address_type)
|
|
|
|
@staticmethod
|
|
def parse_address_preceded_by_type(data, offset):
|
|
address_type = data[offset - 1]
|
|
return Address.parse_address_with_type(data, offset, address_type)
|
|
|
|
def __init__(self, address, address_type = RANDOM_DEVICE_ADDRESS):
|
|
'''
|
|
Initialize an instance. `address` may be a byte array in little-endian
|
|
format, or a hex string in big-endian format (with optional ':'
|
|
separators between the bytes).
|
|
If the address is a string suffixed with '/P', `address_type` is ignored and the type
|
|
is set to PUBLIC_DEVICE_ADDRESS.
|
|
'''
|
|
if type(address) is 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 ValueError('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 == self.PUBLIC_DEVICE_ADDRESS or self.address_type == self.PUBLIC_IDENTITY_ADDRESS
|
|
|
|
@property
|
|
def is_random(self):
|
|
return not self.is_public
|
|
|
|
@property
|
|
def is_resolved(self):
|
|
return self.address_type == self.PUBLIC_IDENTITY_ADDRESS or self.address_type == 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_bytes(self):
|
|
return self.address_bytes
|
|
|
|
def __bytes__(self):
|
|
return self.to_bytes()
|
|
|
|
def __hash__(self):
|
|
return hash(self.address_bytes)
|
|
|
|
def __eq__(self, other):
|
|
return self.address_bytes == other.address_bytes and self.is_public == other.is_public
|
|
|
|
def __str__(self):
|
|
'''
|
|
String representation of the address, MSB first
|
|
'''
|
|
str = ':'.join([f'{x:02X}' for x in reversed(self.address_bytes)])
|
|
if not self.is_public:
|
|
return str
|
|
return str + '/P'
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class OwnAddressType:
|
|
PUBLIC = 0
|
|
RANDOM = 1
|
|
RESOLVABLE_OR_PUBLIC = 2
|
|
RESOLVABLE_OR_RANDOM = 3
|
|
|
|
TYPE_NAMES = {
|
|
PUBLIC: 'PUBLIC',
|
|
RANDOM: 'RANDOM',
|
|
RESOLVABLE_OR_PUBLIC: 'RESOLVABLE_OR_PUBLIC',
|
|
RESOLVABLE_OR_RANDOM: 'RESOLVABLE_OR_RANDOM'
|
|
}
|
|
|
|
@staticmethod
|
|
def type_name(type):
|
|
return name_or_number(OwnAddressType.TYPE_NAMES, type)
|
|
|
|
TYPE_SPEC = {'size': 1, 'mapper': lambda x: OwnAddressType.type_name(x)}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_Packet:
|
|
'''
|
|
Abstract Base class for HCI packets
|
|
'''
|
|
|
|
@staticmethod
|
|
def from_bytes(packet):
|
|
packet_type = packet[0]
|
|
if packet_type == HCI_COMMAND_PACKET:
|
|
return HCI_Command.from_bytes(packet)
|
|
elif packet_type == HCI_ACL_DATA_PACKET:
|
|
return HCI_AclDataPacket.from_bytes(packet)
|
|
elif packet_type == HCI_EVENT_PACKET:
|
|
return HCI_Event.from_bytes(packet)
|
|
else:
|
|
return HCI_CustomPacket(packet)
|
|
|
|
def __init__(self, name):
|
|
self.name = name
|
|
|
|
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
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
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_classes = {}
|
|
|
|
@staticmethod
|
|
def command(fields=[], return_parameters_fields=[]):
|
|
'''
|
|
Decorator used to declare and register subclasses
|
|
'''
|
|
|
|
def inner(cls):
|
|
cls.name = cls.__name__.upper()
|
|
cls.op_code = key_with_value(HCI_COMMAND_NAMES, cls.name)
|
|
if cls.op_code is None:
|
|
raise KeyError(f'command {cls.name} not found in HCI_COMMAND_NAMES')
|
|
cls.fields = fields
|
|
cls.return_parameters_fields = return_parameters_fields
|
|
|
|
# Patch the __init__ method to fix the op_code
|
|
if fields is not None:
|
|
def init(self, parameters=None, **kwargs):
|
|
return HCI_Command.__init__(self, cls.op_code, parameters, **kwargs)
|
|
cls.__init__ = init
|
|
|
|
# Register a factory for this class
|
|
HCI_Command.command_classes[cls.op_code] = cls
|
|
|
|
return cls
|
|
|
|
return inner
|
|
|
|
@staticmethod
|
|
def from_bytes(packet):
|
|
op_code, length = struct.unpack_from('<HB', packet, 1)
|
|
parameters = packet[4:]
|
|
if len(parameters) != length:
|
|
raise ValueError('invalid packet length')
|
|
|
|
# Look for a registered class
|
|
cls = HCI_Command.command_classes.get(op_code)
|
|
if cls is None:
|
|
# No class registered, just use a generic instance
|
|
return HCI_Command(op_code, parameters)
|
|
|
|
# Create a new instance
|
|
if (fields := getattr(cls, 'fields', None)) is not None:
|
|
self = cls.__new__(cls)
|
|
HCI_Command.__init__(self, op_code, parameters)
|
|
HCI_Object.init_from_bytes(self, parameters, 0, fields)
|
|
return self
|
|
else:
|
|
return cls.from_parameters(parameters)
|
|
|
|
@staticmethod
|
|
def command_name(op_code):
|
|
name = HCI_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)
|
|
|
|
def __init__(self, op_code, parameters=None, **kwargs):
|
|
super().__init__(HCI_Command.command_name(op_code))
|
|
if (fields := getattr(self, 'fields', None)) and kwargs:
|
|
HCI_Object.init_from_fields(self, fields, kwargs)
|
|
if parameters is None:
|
|
parameters = HCI_Object.dict_to_bytes(kwargs, fields)
|
|
self.op_code = op_code
|
|
self.parameters = parameters
|
|
|
|
def to_bytes(self):
|
|
parameters = b'' if self.parameters is None else self.parameters
|
|
return struct.pack('<BHB', HCI_COMMAND_PACKET, self.op_code, len(parameters)) + parameters
|
|
|
|
def __bytes__(self):
|
|
return self.to_bytes()
|
|
|
|
def __str__(self):
|
|
result = color(self.name, 'green')
|
|
if fields := getattr(self, 'fields', None):
|
|
result += ':\n' + HCI_Object.format_fields(self.__dict__, fields, ' ')
|
|
else:
|
|
if self.parameters:
|
|
result += f': {self.parameters.hex()}'
|
|
return result
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('lap', {'size': 3, 'mapper': HCI_Constant.inquiry_lap_name}),
|
|
('inquiry_length', 1),
|
|
('num_responses', 1)
|
|
])
|
|
class HCI_Inquiry_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.1 Inquiry Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Inquiry_Cancel_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.2 Inquiry Cancel Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('packet_type', 2),
|
|
('page_scan_repetition_mode', 1),
|
|
('reserved', 1),
|
|
('clock_offset', 2),
|
|
('allow_role_switch', 1)
|
|
])
|
|
class HCI_Create_Connection_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.5 Create Connection Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
|
|
])
|
|
class HCI_Disconnect_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.6 Disconnect Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_Create_Connection_Cancel_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.7 Create Connection Cancel Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('role', 1)
|
|
])
|
|
class HCI_Accept_Connection_Request_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.8 Accept Connection Request Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
|
|
])
|
|
class HCI_Reject_Connection_Request_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.9 Reject Connection Request Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('link_key', 16)
|
|
])
|
|
class HCI_Link_Key_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.10 Link Key Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_Link_Key_Request_Negative_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.11 Link Key Request Negative Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_PIN_Code_Request_Negative_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.13 PIN Code Request Negative Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('packet_type', 2)
|
|
])
|
|
class HCI_Change_Connection_Packet_Type_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.14 Change Connection Packet Type Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Authentication_Requested_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.15 Authentication Requested Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('encryption_enable', 1)
|
|
])
|
|
class HCI_Set_Connection_Encryption_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.16 Set Connection Encryption Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('page_scan_repetition_mode', 1),
|
|
('reserved', 1),
|
|
('clock_offset', 2)
|
|
])
|
|
class HCI_Remote_Name_Request_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.19 Remote Name Request Command
|
|
'''
|
|
R0 = 0x00
|
|
R1 = 0x01
|
|
R2 = 0x02
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Read_Remote_Supported_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.21 Read Remote Supported Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('page_number', 1)
|
|
])
|
|
class HCI_Read_Remote_Extended_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.22 Read Remote Extended Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Read_Remote_Version_Information_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.23 Read Remote Version Information Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Read_Clock_Offset_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.23 Read Clock Offset Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address),
|
|
('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
|
|
('oob_data_present', 1),
|
|
('authentication_requirements', {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name})
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_IO_Capability_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.29 IO Capability Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_User_Confirmation_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.30 User Confirmation Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_User_Confirmation_Request_Negative_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.31 User Confirmation Request Negative Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address),
|
|
('numeric_value', 4)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_User_Passkey_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.32 User Passkey Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
]
|
|
)
|
|
class HCI_User_Passkey_Request_Negative_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.33 User Passkey Request Negative Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('transmit_bandwidth', 4),
|
|
('receive_bandwidth', 4),
|
|
('transmit_coding_format', 5),
|
|
('receive_coding_format', 5),
|
|
('transmit_codec_frame_size', 2),
|
|
('receive_codec_frame_size', 2),
|
|
('input_bandwidth', 4),
|
|
('output_bandwidth', 4),
|
|
('input_coding_format', 5),
|
|
('output_coding_format', 5),
|
|
('input_coded_data_size', 2),
|
|
('output_coded_data_size', 2),
|
|
('input_pcm_data_format', 1),
|
|
('output_pcm_data_format', 1),
|
|
('input_pcm_sample_payload_msb_position', 1),
|
|
('output_pcm_sample_payload_msb_position', 1),
|
|
('input_data_path', 1),
|
|
('output_data_path', 1),
|
|
('input_transport_unit_size', 1),
|
|
('output_transport_unit_size', 1),
|
|
('max_latency', 2),
|
|
('packet_type', 2),
|
|
('retransmission_effort', 1)
|
|
])
|
|
class HCI_Enhanced_Setup_Synchronous_Connection_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.1.45 Enhanced Setup Synchronous Connection Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('sniff_max_interval', 2),
|
|
('sniff_min_interval', 2),
|
|
('sniff_attempt', 2),
|
|
('sniff_timeout', 2)
|
|
])
|
|
class HCI_Sniff_Mode_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.2 Sniff Mode Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Exit_Sniff_Mode_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.3 Exit Sniff Mode Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bd_addr', Address.parse_address),
|
|
('role', {'size': 1, 'mapper': HCI_Constant.role_name})
|
|
])
|
|
class HCI_Switch_Role_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.8 Switch Role Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('link_policy_settings', 2)
|
|
])
|
|
class HCI_Write_Link_Policy_Settings_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.10 Write Link Policy Settings Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('default_link_policy_settings', 2)
|
|
])
|
|
class HCI_Write_Default_Link_Policy_Settings_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.12 Write Default Link Policy Settings Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('maximum_latency', 2),
|
|
('minimum_remote_timeout', 2),
|
|
('minimum_local_timeout', 2)
|
|
])
|
|
class HCI_Sniff_Subrating_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.2.14 Sniff Subrating Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('event_mask', 8)
|
|
])
|
|
class HCI_Set_Event_Mask_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.1 Set Event Mask Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Reset_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.2 Reset Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('filter_type', 1),
|
|
('filter_condition', '*'),
|
|
])
|
|
class HCI_Set_Event_Filter_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.3 Set Event Filter Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address),
|
|
('read_all_flag', 1)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('max_num_keys', 2),
|
|
('num_keys_read', 2)
|
|
]
|
|
)
|
|
class HCI_Read_Stored_Link_Key_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.8 Read Stored Link Key Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('bd_addr', Address.parse_address),
|
|
('delete_all_flag', 1)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('num_keys_deleted', 2)
|
|
]
|
|
)
|
|
class HCI_Delete_Stored_Link_Key_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.10 Delete Stored Link Key Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
|
|
])
|
|
class HCI_Write_Local_Name_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.11 Write Local Name Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('local_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
|
|
])
|
|
class HCI_Read_Local_Name_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.12 Read Local Name Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_accept_timeout', 2)
|
|
])
|
|
class HCI_Write_Connection_Accept_Timeout_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.14 Write Connection Accept Timeout Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('page_timeout', 2)
|
|
])
|
|
class HCI_Write_Page_Timeout_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.16 Write Page Timeout Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('scan_enable', 1)
|
|
])
|
|
class HCI_Write_Scan_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.18 Write Scan Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('page_scan_interval', 2),
|
|
('page_scan_window', 2)
|
|
])
|
|
class HCI_Read_Page_Scan_Activity_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.19 Read Page Scan Activity Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('page_scan_interval', 2),
|
|
('page_scan_window', 2)
|
|
])
|
|
class HCI_Write_Page_Scan_Activity_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.20 Write Page Scan Activity Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('inquiry_scan_interval', 2),
|
|
('inquiry_scan_window', 2)
|
|
])
|
|
class HCI_Write_Inquiry_Scan_Activity_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.22 Write Inquiry Scan Activity Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('class_of_device', {'size': 3, 'mapper': map_class_of_device})
|
|
])
|
|
class HCI_Read_Class_Of_Device_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.25 Read Class of Device Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('class_of_device', {'size': 3, 'mapper': map_class_of_device})
|
|
])
|
|
class HCI_Write_Class_Of_Device_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.26 Write Class of Device Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('voice_setting', 2)
|
|
])
|
|
class HCI_Read_Voice_Setting_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.27 Read Voice Setting Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('voice_setting', 2)
|
|
])
|
|
class HCI_Write_Voice_Setting_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.28 Write Voice Setting Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Read_Synchronous_Flow_Control_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.36 Read Synchronous Flow Control Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('synchronous_flow_control_enable', 1)
|
|
])
|
|
class HCI_Write_Synchronous_Flow_Control_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.37 Write Synchronous Flow Control Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('host_acl_data_packet_length', 2),
|
|
('host_synchronous_data_packet_length', 1),
|
|
('host_total_num_acl_data_packets', 2),
|
|
('host_total_num_synchronous_data_packets', 2)
|
|
])
|
|
class HCI_Host_Buffer_Size_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.39 Host Buffer Size Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('handle', 2),
|
|
('link_supervision_timeout', 2)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('handle', 2),
|
|
]
|
|
)
|
|
class HCI_Write_Link_Supervision_Timeout_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.42 Write Link Supervision Timeout Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('num_support_iac', 1)
|
|
])
|
|
class HCI_Read_Number_Of_Supported_IAC_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.43 Read Number Of Supported IAC Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('num_current_iac', 1),
|
|
('iac_lap', '*') # TODO: this should be parsed as an array
|
|
])
|
|
class HCI_Read_Current_IAC_LAP_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.44 Read Current IAC LAP Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('scan_type', 1)
|
|
])
|
|
class HCI_Write_Inquiry_Scan_Type_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.48 Write Inquiry Scan Type Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('inquiry_mode', 1)
|
|
])
|
|
class HCI_Write_Inquiry_Mode_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.50 Write Inquiry Mode Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('page_scan_type', 1)
|
|
])
|
|
class HCI_Read_Page_Scan_Type_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.51 Read Page Scan Type Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('page_scan_type', 1)
|
|
])
|
|
class HCI_Write_Page_Scan_Type_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.52 Write Page Scan Type Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('fec_required', 1),
|
|
('extended_inquiry_response', {'size': 240, 'serializer': lambda x: padded_bytes(x, 240)})
|
|
])
|
|
class HCI_Write_Extended_Inquiry_Response_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.56 Write Extended Inquiry Response Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('simple_pairing_mode', 1)
|
|
])
|
|
class HCI_Write_Simple_Pairing_Mode_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.59 Write Simple Pairing Mode Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('tx_power', -1)
|
|
])
|
|
class HCI_Read_Inquiry_Response_Transmit_Power_Level_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.61 Read Inquiry Response Transmit Power Level Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('erroneous_data_reporting', 1)
|
|
])
|
|
class HCI_Read_Default_Erroneous_Data_Reporting_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.64 Read Default Erroneous Data Reporting Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('event_mask_page_2', 8)
|
|
])
|
|
class HCI_Set_Event_Mask_Page_2_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.69 Set Event Mask Page 2 Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Read_LE_Host_Support_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.78 Read LE Host Support Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('le_supported_host', 1),
|
|
('simultaneous_le_host', 1)
|
|
])
|
|
class HCI_Write_LE_Host_Support_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.79 Write LE Host Support Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('secure_connections_host_support', 1)
|
|
])
|
|
class HCI_Write_Secure_Connections_Host_Support_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.92 Write Secure Connections Host Support Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('authenticated_payload_timeout', 2)
|
|
])
|
|
class HCI_Write_Authenticated_Payload_Timeout_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.3.94 Write Authenticated Payload Timeout Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('hci_version', 1),
|
|
('hci_subversion', 2),
|
|
('lmp_version', 1),
|
|
('company_identifier', 2),
|
|
('lmp_subversion', 2)
|
|
])
|
|
class HCI_Read_Local_Version_Information_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.1 Read Local Version Information Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('supported_commands', 64)
|
|
])
|
|
class HCI_Read_Local_Supported_Commands_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.2 Read Local Supported Commands Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Read_Local_Supported_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.3 Read Local Supported Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('page_number', 1)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('page_number', 1),
|
|
('maximum_page_number', 1),
|
|
('extended_lmp_features', 8)
|
|
]
|
|
)
|
|
class HCI_Read_Local_Extended_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.4 Read Local Extended Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.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)
|
|
])
|
|
class HCI_Read_Buffer_Size_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.5 Read Buffer Size Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_Read_BD_ADDR_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.6 Read BD_ADDR Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_Read_Local_Supported_Codecs_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.4.8 Read Local Supported Codecs Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('handle', 2)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('handle', 2),
|
|
('rssi', -1)
|
|
]
|
|
)
|
|
class HCI_Read_RSSI_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.5.4 Read RSSI Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('connection_handle', 2)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('key_size', 1)
|
|
]
|
|
)
|
|
class HCI_Read_Encryption_Key_Size_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.5.7 Read Encryption Key Size Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('le_event_mask', 8)
|
|
])
|
|
class HCI_LE_Set_Event_Mask_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.1 LE Set Event Mask Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('hc_le_acl_data_packet_length', 2),
|
|
('hc_total_num_le_acl_data_packets', 1)
|
|
])
|
|
class HCI_LE_Read_Buffer_Size_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.2 LE Read Buffer Size Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('le_features', 8)
|
|
])
|
|
class HCI_LE_Read_Local_Supported_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.3 LE Read Local Supported Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('random_address', lambda data, offset: Address.parse_address_with_type(data, offset, Address.RANDOM_DEVICE_ADDRESS))
|
|
])
|
|
class HCI_LE_Set_Random_Address_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.4 LE Set Random Address Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_interval_min', 2),
|
|
('advertising_interval_max', 2),
|
|
('advertising_type', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Advertising_Parameters_Command.advertising_type_name(x)}),
|
|
('own_address_type', OwnAddressType.TYPE_SPEC),
|
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
('advertising_channel_map', 1),
|
|
('advertising_filter_policy', 1),
|
|
])
|
|
class HCI_LE_Set_Advertising_Parameters_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.5 LE Set Advertising Parameters Command
|
|
'''
|
|
|
|
ADV_IND = 0x00
|
|
ADV_DIRECT_IND = 0x01
|
|
ADV_SCAN_IND = 0x02
|
|
ADV_NONCONN_IND = 0x03
|
|
ADV_DIRECT_IND_LOW_DUTY = 0x04
|
|
|
|
ADVERTISING_TYPE_NAMES = {
|
|
ADV_IND: 'ADV_IND',
|
|
ADV_DIRECT_IND: 'ADV_DIRECT_IND',
|
|
ADV_SCAN_IND: 'ADV_SCAN_IND',
|
|
ADV_NONCONN_IND: 'ADV_NONCONN_IND',
|
|
ADV_DIRECT_IND_LOW_DUTY: 'ADV_DIRECT_IND_LOW_DUTY'
|
|
}
|
|
|
|
@classmethod
|
|
def advertising_type_name(cls, advertising_type):
|
|
return name_or_number(cls.ADVERTISING_TYPE_NAMES, advertising_type)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_data', {
|
|
'parser': HCI_Object.parse_length_prefixed_bytes,
|
|
'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes, padded_size=32)
|
|
})
|
|
])
|
|
class HCI_LE_Set_Advertising_Data_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.7 LE Set Advertising Data Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('scan_response_data', {
|
|
'parser': HCI_Object.parse_length_prefixed_bytes,
|
|
'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes, padded_size=32)
|
|
})
|
|
])
|
|
class HCI_LE_Set_Scan_Response_Data_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.8 LE Set Scan Response Data Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_enable', 1)
|
|
])
|
|
class HCI_LE_Set_Advertising_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.9 LE Set Advertising Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('le_scan_type', 1),
|
|
('le_scan_interval', 2),
|
|
('le_scan_window', 2),
|
|
('own_address_type', OwnAddressType.TYPE_SPEC),
|
|
('scanning_filter_policy', 1)
|
|
])
|
|
class HCI_LE_Set_Scan_Parameters_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.10 LE Set 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
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('le_scan_enable', 1),
|
|
('filter_duplicates', 1),
|
|
])
|
|
class HCI_LE_Set_Scan_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.11 LE Set Scan Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('le_scan_interval', 2),
|
|
('le_scan_window', 2),
|
|
('initiator_filter_policy', 1),
|
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
('own_address_type', OwnAddressType.TYPE_SPEC),
|
|
('connection_interval_min', 2),
|
|
('connection_interval_max', 2),
|
|
('max_latency', 2),
|
|
('supervision_timeout', 2),
|
|
('min_ce_length', 2),
|
|
('max_ce_length', 2)
|
|
])
|
|
class HCI_LE_Create_Connection_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.12 LE Create Connection Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_LE_Create_Connection_Cancel_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.13 LE Create Connection Cancel Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_LE_Read_Filter_Accept_List_Size_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.14 LE Read Filter Accept List Size Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
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([
|
|
('address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('address', Address.parse_address_preceded_by_type)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('address', Address.parse_address_preceded_by_type)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('connection_interval_min', 2),
|
|
('connection_interval_max', 2),
|
|
('max_latency', 2),
|
|
('supervision_timeout', 2),
|
|
('min_ce_length', 2),
|
|
('max_ce_length', 2)
|
|
])
|
|
class HCI_LE_Connection_Update_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.18 LE Connection Update Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_LE_Read_Remote_Features_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.21 LE Read Remote Features Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('random_number', 8),
|
|
('encrypted_diversifier', 2),
|
|
('long_term_key', 16)
|
|
])
|
|
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)
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('long_term_key', 16)
|
|
])
|
|
class HCI_LE_Long_Term_Key_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.25 LE Long Term Key Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_LE_Read_Supported_States_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.27 LE Read Supported States Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('interval_min', 2),
|
|
('interval_max', 2),
|
|
('max_latency', 2),
|
|
('timeout', 2),
|
|
('min_ce_length', 2),
|
|
('max_ce_length', 2)
|
|
])
|
|
class HCI_LE_Remote_Connection_Parameter_Request_Reply_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.31 LE Remote Connection Parameter Request Reply Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('connection_handle', 2),
|
|
('tx_octets', 2),
|
|
('tx_time', 2),
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2)
|
|
]
|
|
)
|
|
class HCI_LE_Set_Data_Length_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.33 LE Set Data Length Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('suggested_max_tx_octets', 2),
|
|
('suggested_max_tx_time', 2),
|
|
])
|
|
class HCI_LE_Read_Suggested_Default_Data_Length_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.34 LE Read Suggested Default Data Length Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('suggested_max_tx_octets', 2),
|
|
('suggested_max_tx_time', 2)
|
|
])
|
|
class HCI_LE_Write_Suggested_Default_Data_Length_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.35 LE Write Suggested Default Data Length Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('peer_identity_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_identity_address', Address.parse_address_preceded_by_type),
|
|
('peer_irk', 16),
|
|
('local_irk', 16),
|
|
])
|
|
class HCI_LE_Add_Device_To_Resolving_List_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.38 LE Add Device To Resolving List Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_LE_Clear_Resolving_List_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.40 LE Clear Resolving List Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('address_resolution_enable', 1)
|
|
])
|
|
class HCI_LE_Set_Address_Resolution_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.44 LE Set Address Resolution Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('rpa_timeout', 2)
|
|
])
|
|
class HCI_LE_Set_Resolvable_Private_Address_Timeout_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.45 LE Set Resolvable Private Address Timeout Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.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)
|
|
])
|
|
class HCI_LE_Read_Maximum_Data_Length_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.46 LE Read Maximum Data Length Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('connection_handle', 2)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('tx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('rx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name})
|
|
])
|
|
class HCI_LE_Read_PHY_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.47 LE Read PHY Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('all_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_Set_Default_PHY_Command.ANY_PHY_BIT_NAMES)}),
|
|
('tx_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES)}),
|
|
('rx_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES)})
|
|
])
|
|
class HCI_LE_Set_Default_PHY_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.48 LE Set Default PHY Command
|
|
'''
|
|
ANY_TX_PHY_BIT = 0
|
|
ANY_RX_PHY_BIT = 1
|
|
|
|
ANY_PHY_BIT_NAMES = ['Any TX', 'Any RX']
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('connection_handle', 2),
|
|
('all_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_Set_PHY_Command.ANY_PHY_BIT_NAMES)}),
|
|
('tx_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES)}),
|
|
('rx_phys', {'size': 1, 'mapper': lambda x: bit_flags_to_strings(x, HCI_LE_PHY_BIT_NAMES)}),
|
|
('phy_options', 2)
|
|
])
|
|
class HCI_LE_Set_PHY_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.49 LE Set PHY Command
|
|
'''
|
|
ANY_TX_PHY_BIT = 0
|
|
ANY_RX_PHY_BIT = 1
|
|
|
|
ANY_PHY_BIT_NAMES = ['Any TX', 'Any RX']
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_handle', 1),
|
|
('random_address', lambda data, offset: Address.parse_address_with_type(data, offset, Address.RANDOM_DEVICE_ADDRESS))
|
|
])
|
|
class HCI_LE_Set_Advertising_Set_Random_Address_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.52 LE Set Advertising Set Random Address Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(
|
|
fields=[
|
|
('advertising_handle', 1),
|
|
('advertising_event_properties', {'size': 2, 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Parameters_Command.advertising_properties_string(x)}),
|
|
('primary_advertising_interval_min', 3),
|
|
('primary_advertising_interval_max', 3),
|
|
('primary_advertising_channel_map', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Parameters_Command.channel_map_string(x)}),
|
|
('own_address_type', OwnAddressType.TYPE_SPEC),
|
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
('advertising_filter_policy', 1),
|
|
('advertising_tx_power', 1),
|
|
('primary_advertising_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('secondary_advertising_max_skip', 1),
|
|
('secondary_advertising_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('advertising_sid', 1),
|
|
('scan_request_notification_enable', 1)
|
|
],
|
|
return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('selected_tx__power', 1)
|
|
]
|
|
)
|
|
class HCI_LE_Set_Extended_Advertising_Parameters_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.53 LE Set Extended Advertising Parameters Command
|
|
'''
|
|
|
|
CONNECTABLE_ADVERTISING = 0
|
|
SCANNABLE_ADVERTISING = 1
|
|
DIRECTED_ADVERTISING = 2
|
|
HIGH_DUTY_CYCLE_DIRECTED_CONNECTABLE_ADVERTISING = 3
|
|
USE_LEGACY_ADVERTISING_PDUS = 4
|
|
ANONYMOUS_ADVERTISING = 5
|
|
INCLUDE_TX_POWER = 6
|
|
|
|
ADVERTISING_PROPERTIES_NAMES = (
|
|
'CONNECTABLE_ADVERTISING',
|
|
'SCANNABLE_ADVERTISING',
|
|
'DIRECTED_ADVERTISING',
|
|
'HIGH_DUTY_CYCLE_DIRECTED_CONNECTABLE_ADVERTISING',
|
|
'USE_LEGACY_ADVERTISING_PDUS',
|
|
'ANONYMOUS_ADVERTISING',
|
|
'INCLUDE_TX_POWER'
|
|
)
|
|
|
|
CHANNEL_37 = 0
|
|
CHANNEL_38 = 1
|
|
CHANNEL_39 = 2
|
|
|
|
CHANNEL_NAMES = ('37', '38', '39')
|
|
|
|
@classmethod
|
|
def advertising_properties_string(cls, properties):
|
|
return f'[{",".join(bit_flags_to_strings(properties, cls.ADVERTISING_PROPERTIES_NAMES))}]'
|
|
|
|
@classmethod
|
|
def channel_map_string(cls, channel_map):
|
|
return f'[{",".join(bit_flags_to_strings(channel_map, cls.CHANNEL_NAMES))}]'
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_handle', 1),
|
|
('operation', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Data_Command.operation_name(x)}),
|
|
('fragment_preference', 1),
|
|
('advertising_data', {
|
|
'parser': HCI_Object.parse_length_prefixed_bytes,
|
|
'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes)
|
|
})
|
|
])
|
|
class HCI_LE_Set_Extended_Advertising_Data_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.54 LE Set Extended Advertising Data Command
|
|
'''
|
|
|
|
INTERMEDIATE_FRAGMENT = 0x00
|
|
FIRST_FRAGMENT = 0x01
|
|
LAST_FRAGMENT = 0x02
|
|
COMPLETE_DATA = 0x03
|
|
UNCHANGED_DATA = 0x04
|
|
|
|
OPERATION_NAMES = {
|
|
INTERMEDIATE_FRAGMENT: 'INTERMEDIATE_FRAGMENT',
|
|
FIRST_FRAGMENT: 'FIRST_FRAGMENT',
|
|
LAST_FRAGMENT: 'LAST_FRAGMENT',
|
|
COMPLETE_DATA: 'COMPLETE_DATA',
|
|
UNCHANGED_DATA: 'UNCHANGED_DATA'
|
|
}
|
|
|
|
@classmethod
|
|
def operation_name(cls, operation):
|
|
return name_or_number(cls.OPERATION_NAMES, operation)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_handle', 1),
|
|
('operation', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Extended_Advertising_Data_Command.operation_name(x)}),
|
|
('fragment_preference', 1),
|
|
('scan_response_data', {
|
|
'parser': HCI_Object.parse_length_prefixed_bytes,
|
|
'serializer': functools.partial(HCI_Object.serialize_length_prefixed_bytes)
|
|
})
|
|
])
|
|
class HCI_LE_Set_Extended_Scan_Response_Data_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.55 LE Set Extended Scan Response Data Command
|
|
'''
|
|
|
|
INTERMEDIATE_FRAGMENT = 0x00
|
|
FIRST_FRAGMENT = 0x01
|
|
LAST_FRAGMENT = 0x02
|
|
COMPLETE_DATA = 0x03
|
|
|
|
OPERATION_NAMES = {
|
|
INTERMEDIATE_FRAGMENT: 'INTERMEDIATE_FRAGMENT',
|
|
FIRST_FRAGMENT: 'FIRST_FRAGMENT',
|
|
LAST_FRAGMENT: 'LAST_FRAGMENT',
|
|
COMPLETE_DATA: 'COMPLETE_DATA'
|
|
}
|
|
|
|
@classmethod
|
|
def operation_name(cls, operation):
|
|
return name_or_number(cls.OPERATION_NAMES, operation)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(fields=None)
|
|
class HCI_LE_Set_Extended_Advertising_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.56 LE Set Extended Advertising Enable Command
|
|
'''
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
enable = parameters[0]
|
|
num_sets = parameters[1]
|
|
advertising_handles = []
|
|
durations = []
|
|
max_extended_advertising_events = []
|
|
offset = 2
|
|
for _ in range(num_sets):
|
|
advertising_handles.append(parameters[offset])
|
|
durations.append(struct.unpack_from('<H', parameters, offset + 1)[0])
|
|
max_extended_advertising_events.append(parameters[offset + 3])
|
|
offset += 4
|
|
|
|
return cls(enable, advertising_handles, durations, max_extended_advertising_events)
|
|
|
|
def __init__(self, enable, advertising_handles, durations, max_extended_advertising_events):
|
|
super().__init__(HCI_LE_SET_EXTENDED_ADVERTISING_ENABLE_COMMAND)
|
|
self.enable = enable
|
|
self.advertising_handles = advertising_handles
|
|
self.durations = durations
|
|
self.max_extended_advertising_events = max_extended_advertising_events
|
|
|
|
self.parameters = bytes([enable, len(advertising_handles)]) + b''.join([
|
|
struct.pack(
|
|
'<BHB',
|
|
advertising_handles[i],
|
|
durations[i],
|
|
max_extended_advertising_events[i]
|
|
)
|
|
for i in range(len(advertising_handles))
|
|
])
|
|
|
|
def __str__(self):
|
|
fields = [('enable:', self.enable)]
|
|
for i in range(len(self.advertising_handles)):
|
|
fields.append((f'advertising_handle[{i}]: ', self.advertising_handles[i]))
|
|
fields.append((f'duration[{i}]: ', self.durations[i]))
|
|
fields.append((f'max_extended_advertising_events[{i}]:', self.max_extended_advertising_events[i]))
|
|
|
|
return color(self.name, 'green') + ':\n' + '\n'.join(
|
|
[color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
|
|
)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('max_advertising_data_length', 2)
|
|
])
|
|
class HCI_LE_Read_Maximum_Advertising_Data_Length_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.57 LE Read Maximum Advertising Data Length Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(return_parameters_fields=[
|
|
('status', STATUS_SPEC),
|
|
('num_supported_advertising_sets', 1)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('advertising_handle', 1)
|
|
])
|
|
class HCI_LE_Remove_Advertising_Set_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.59 LE Remove Advertising Set Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command()
|
|
class HCI_LE_Clear_Advertising_Sets_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.60 LE Clear Advertising Sets Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('enable', 1),
|
|
('advertising_handle', 1)
|
|
])
|
|
class HCI_LE_Set_Periodic_Advertising_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.63 LE Set Periodic Advertising Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(fields=None)
|
|
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
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
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('<H', parameters, 3 + (5 * i) + 1)[0])
|
|
scan_windows.append(struct.unpack_from('<H', parameters, 3 + (5 * i) + 3)[0])
|
|
|
|
return cls(
|
|
own_address_type = own_address_type,
|
|
scanning_filter_policy = scanning_filter_policy,
|
|
scanning_phys = scanning_phys,
|
|
scan_types = scan_types,
|
|
scan_intervals = scan_intervals,
|
|
scan_windows = scan_windows
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
own_address_type,
|
|
scanning_filter_policy,
|
|
scanning_phys,
|
|
scan_types,
|
|
scan_intervals,
|
|
scan_windows
|
|
):
|
|
super().__init__(HCI_LE_SET_EXTENDED_SCAN_PARAMETERS_COMMAND)
|
|
self.own_address_type = own_address_type
|
|
self.scanning_filter_policy = scanning_filter_policy
|
|
self.scanning_phys = scanning_phys
|
|
self.scan_types = scan_types
|
|
self.scan_intervals = scan_intervals
|
|
self.scan_windows = 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('<BHH', scan_types[i], scan_intervals[i], scan_windows[i])
|
|
|
|
def __str__(self):
|
|
scanning_phys_strs = bit_flags_to_strings(self.scanning_phys, HCI_LE_PHY_BIT_NAMES)
|
|
fields = [
|
|
('own_address_type: ', Address.address_type_name(self.own_address_type)),
|
|
('scanning_filter_policy:', self.scanning_filter_policy),
|
|
('scanning_phys: ', ','.join(scanning_phys_strs)),
|
|
]
|
|
for (i, scanning_phy_str) in enumerate(scanning_phys_strs):
|
|
fields.append((f'{scanning_phy_str}.scan_type: ', 'PASSIVE' if self.scan_types[i] == self.PASSIVE_SCANNING else 'ACTIVE'))
|
|
fields.append((f'{scanning_phy_str}.scan_interval:', self.scan_intervals[i])),
|
|
fields.append((f'{scanning_phy_str}.scan_window: ', self.scan_windows[i]))
|
|
|
|
return color(self.name, 'green') + ':\n' + '\n'.join(
|
|
[color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
|
|
)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('enable', 1),
|
|
('filter_duplicates', 1),
|
|
('duration', 2),
|
|
('period', 2)
|
|
])
|
|
class HCI_LE_Set_Extended_Scan_Enable_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.65 LE Set Extended Scan Enable Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command(fields=None)
|
|
class HCI_LE_Extended_Create_Connection_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.66 LE Extended Create Connection Command
|
|
'''
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
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('<H', parameters, offset + 16 * i)[0] for i in range(phy_bits_set)]
|
|
|
|
return cls(
|
|
initiator_filter_policy = initiator_filter_policy,
|
|
own_address_type = own_address_type,
|
|
peer_address_type = peer_address_type,
|
|
peer_address = peer_address,
|
|
initiating_phys = initiating_phys,
|
|
scan_intervals = read_parameter_list(10),
|
|
scan_windows = read_parameter_list(12),
|
|
connection_interval_mins = read_parameter_list(14),
|
|
connection_interval_maxs = read_parameter_list(16),
|
|
max_latencies = read_parameter_list(18),
|
|
supervision_timeouts = read_parameter_list(20),
|
|
min_ce_lengths = read_parameter_list(22),
|
|
max_ce_lengths = read_parameter_list(24)
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
initiator_filter_policy,
|
|
own_address_type,
|
|
peer_address_type,
|
|
peer_address,
|
|
initiating_phys,
|
|
scan_intervals,
|
|
scan_windows,
|
|
connection_interval_mins,
|
|
connection_interval_maxs,
|
|
max_latencies,
|
|
supervision_timeouts,
|
|
min_ce_lengths,
|
|
max_ce_lengths
|
|
):
|
|
super().__init__(HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND)
|
|
self.initiator_filter_policy = initiator_filter_policy
|
|
self.own_address_type = own_address_type
|
|
self.peer_address_type = peer_address_type
|
|
self.peer_address = peer_address
|
|
self.initiating_phys = initiating_phys
|
|
self.scan_intervals = scan_intervals
|
|
self.scan_windows = scan_windows
|
|
self.connection_interval_mins = connection_interval_mins
|
|
self.connection_interval_maxs = connection_interval_maxs
|
|
self.max_latencies = max_latencies
|
|
self.supervision_timeouts = supervision_timeouts
|
|
self.min_ce_lengths = min_ce_lengths
|
|
self.max_ce_lengths = max_ce_lengths
|
|
|
|
self.parameters = bytes([
|
|
initiator_filter_policy,
|
|
own_address_type,
|
|
peer_address_type
|
|
]) + bytes(peer_address) + bytes([initiating_phys])
|
|
|
|
phy_bits_set = bin(initiating_phys).count('1')
|
|
for i in range(phy_bits_set):
|
|
self.parameters += struct.pack(
|
|
'<HHHHHHHH',
|
|
scan_intervals[i],
|
|
scan_windows[i],
|
|
connection_interval_mins[i],
|
|
connection_interval_maxs[i],
|
|
max_latencies[i],
|
|
supervision_timeouts[i],
|
|
min_ce_lengths[i],
|
|
max_ce_lengths[i]
|
|
)
|
|
|
|
def __str__(self):
|
|
initiating_phys_strs = bit_flags_to_strings(self.initiating_phys, HCI_LE_PHY_BIT_NAMES)
|
|
fields = [
|
|
('initiator_filter_policy:', self.initiator_filter_policy),
|
|
('own_address_type: ', OwnAddressType.type_name(self.own_address_type)),
|
|
('peer_address_type: ', Address.address_type_name(self.peer_address_type)),
|
|
('peer_address: ', str(self.peer_address)),
|
|
('initiating_phys: ', ','.join(initiating_phys_strs)),
|
|
]
|
|
for (i, initiating_phys_str) in enumerate(initiating_phys_strs):
|
|
fields.append((f'{initiating_phys_str}.scan_interval: ', self.scan_intervals[i])),
|
|
fields.append((f'{initiating_phys_str}.scan_window: ', self.scan_windows[i])),
|
|
fields.append((f'{initiating_phys_str}.connection_interval_min:', self.connection_interval_mins[i])),
|
|
fields.append((f'{initiating_phys_str}.connection_interval_max:', self.connection_interval_maxs[i])),
|
|
fields.append((f'{initiating_phys_str}.max_latency: ', self.max_latencies[i])),
|
|
fields.append((f'{initiating_phys_str}.supervision_timeout: ', self.supervision_timeouts[i])),
|
|
fields.append((f'{initiating_phys_str}.min_ce_length: ', self.min_ce_lengths[i])),
|
|
fields.append((f'{initiating_phys_str}.max_ce_length: ', self.max_ce_lengths[i]))
|
|
|
|
return color(self.name, 'green') + ':\n' + '\n'.join(
|
|
[color(field[0], 'cyan') + ' ' + str(field[1]) for field in fields]
|
|
)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('peer_identity_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_identity_address', Address.parse_address_preceded_by_type),
|
|
('privacy_mode', {'size': 1, 'mapper': lambda x: HCI_LE_Set_Privacy_Mode_Command.privacy_mode_name(x)})
|
|
])
|
|
class HCI_LE_Set_Privacy_Mode_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.77 LE Set Privacy Mode Command
|
|
'''
|
|
|
|
NETWORK_PRIVACY_MODE = 0x00
|
|
DEVICE_PRIVACY_MODE = 0x01
|
|
|
|
PRIVACY_MODE_NAMES = {
|
|
NETWORK_PRIVACY_MODE: 'NETWORK_PRIVACY_MODE',
|
|
DEVICE_PRIVACY_MODE: 'DEVICE_PRIVACY_MODE'
|
|
}
|
|
|
|
@classmethod
|
|
def privacy_mode_name(cls, privacy_mode):
|
|
return name_or_number(cls.PRIVACY_MODE_NAMES, privacy_mode)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Command.command([
|
|
('bit_number', 1),
|
|
('bit_value', 1)
|
|
])
|
|
class HCI_LE_Set_Host_Feature_Command(HCI_Command):
|
|
'''
|
|
See Bluetooth spec @ 7.8.115 LE Set Host Feature Command
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# HCI Events
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_Event(HCI_Packet):
|
|
'''
|
|
See Bluetooth spec @ Vol 2, Part E - 5.4.4 HCI Event Packet
|
|
'''
|
|
hci_packet_type = HCI_EVENT_PACKET
|
|
event_classes = {}
|
|
meta_event_classes = {}
|
|
|
|
@staticmethod
|
|
def event(fields=[]):
|
|
'''
|
|
Decorator used to declare and register subclasses
|
|
'''
|
|
|
|
def inner(cls):
|
|
cls.name = cls.__name__.upper()
|
|
cls.event_code = key_with_value(HCI_EVENT_NAMES, cls.name)
|
|
if cls.event_code is None:
|
|
raise KeyError('event not found in HCI_EVENT_NAMES')
|
|
cls.fields = fields
|
|
|
|
# Patch the __init__ method to fix the event_code
|
|
def init(self, parameters=None, **kwargs):
|
|
return HCI_Event.__init__(self, cls.event_code, parameters, **kwargs)
|
|
cls.__init__ = init
|
|
|
|
# Register a factory for this class
|
|
HCI_Event.event_classes[cls.event_code] = cls
|
|
|
|
return cls
|
|
|
|
return inner
|
|
|
|
@staticmethod
|
|
def registered(cls):
|
|
cls.name = cls.__name__.upper()
|
|
cls.event_code = key_with_value(HCI_EVENT_NAMES, cls.name)
|
|
if cls.event_code is None:
|
|
raise KeyError('event not found in HCI_EVENT_NAMES')
|
|
|
|
# Register a factory for this class
|
|
HCI_Event.event_classes[cls.event_code] = cls
|
|
|
|
return cls
|
|
|
|
@staticmethod
|
|
def from_bytes(packet):
|
|
event_code = packet[1]
|
|
length = packet[2]
|
|
parameters = packet[3:]
|
|
if len(parameters) != length:
|
|
raise ValueError('invalid packet length')
|
|
|
|
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]
|
|
cls = HCI_Event.meta_event_classes.get(subevent_code)
|
|
if cls is None:
|
|
# No class registered, just use a generic class instance
|
|
return HCI_LE_Meta_Event(subevent_code, parameters)
|
|
|
|
else:
|
|
cls = HCI_Event.event_classes.get(event_code)
|
|
if cls is None:
|
|
# No class registered, just use a generic class instance
|
|
return HCI_Event(event_code, parameters)
|
|
|
|
# Invoke the factory to create a new instance
|
|
return cls.from_parameters(parameters)
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
self = cls.__new__(cls)
|
|
HCI_Event.__init__(self, self.event_code, parameters)
|
|
if fields := getattr(self, 'fields', None):
|
|
HCI_Object.init_from_bytes(self, parameters, 0, fields)
|
|
return self
|
|
|
|
@staticmethod
|
|
def event_name(event_code):
|
|
return name_or_number(HCI_EVENT_NAMES, event_code)
|
|
|
|
def __init__(self, event_code, parameters=None, **kwargs):
|
|
super().__init__(HCI_Event.event_name(event_code))
|
|
if (fields := getattr(self, 'fields', None)) and kwargs:
|
|
HCI_Object.init_from_fields(self, fields, kwargs)
|
|
if parameters is None:
|
|
parameters = HCI_Object.dict_to_bytes(kwargs, fields)
|
|
self.event_code = event_code
|
|
self.parameters = parameters
|
|
|
|
def to_bytes(self):
|
|
parameters = b'' if self.parameters is None else self.parameters
|
|
return bytes([HCI_EVENT_PACKET, self.event_code, len(parameters)]) + parameters
|
|
|
|
def __bytes__(self):
|
|
return self.to_bytes()
|
|
|
|
def __str__(self):
|
|
result = color(self.name, 'magenta')
|
|
if fields := getattr(self, 'fields', None):
|
|
result += ':\n' + HCI_Object.format_fields(self.__dict__, fields, ' ')
|
|
else:
|
|
if self.parameters:
|
|
result += f': {self.parameters.hex()}'
|
|
return result
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_LE_Meta_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65 LE Meta Event
|
|
'''
|
|
|
|
@staticmethod
|
|
def event(fields=[]):
|
|
'''
|
|
Decorator used to declare and register subclasses
|
|
'''
|
|
|
|
def inner(cls):
|
|
cls.name = cls.__name__.upper()
|
|
cls.subevent_code = key_with_value(HCI_SUBEVENT_NAMES, cls.name)
|
|
if cls.subevent_code is None:
|
|
raise KeyError('subevent not found in HCI_SUBEVENT_NAMES')
|
|
cls.fields = fields
|
|
|
|
# Patch the __init__ method to fix the subevent_code
|
|
def init(self, parameters=None, **kwargs):
|
|
return HCI_LE_Meta_Event.__init__(self, cls.subevent_code, parameters, **kwargs)
|
|
cls.__init__ = init
|
|
|
|
# Register a factory for this class
|
|
HCI_Event.meta_event_classes[cls.subevent_code] = cls
|
|
|
|
return cls
|
|
|
|
return inner
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
self = cls.__new__(cls)
|
|
HCI_LE_Meta_Event.__init__(self, self.subevent_code, parameters)
|
|
if fields := getattr(self, 'fields', None):
|
|
HCI_Object.init_from_bytes(self, parameters, 1, fields)
|
|
return self
|
|
|
|
@staticmethod
|
|
def subevent_name(subevent_code):
|
|
return name_or_number(HCI_SUBEVENT_NAMES, subevent_code)
|
|
|
|
def __init__(self, subevent_code, parameters, **kwargs):
|
|
self.subevent_code = subevent_code
|
|
if parameters is None and (fields := getattr(self, 'fields', None)) and kwargs:
|
|
parameters = bytes([subevent_code]) + HCI_Object.dict_to_bytes(kwargs, fields)
|
|
super().__init__(HCI_LE_META_EVENT, parameters, **kwargs)
|
|
|
|
# Override the name in order to adopt the subevent name instead
|
|
self.name = self.subevent_name(subevent_code)
|
|
|
|
def __str__(self):
|
|
result = color(self.subevent_name(self.subevent_code), 'magenta')
|
|
if fields := getattr(self, 'fields', None):
|
|
result += ':\n' + HCI_Object.format_fields(self.__dict__, fields, ' ')
|
|
else:
|
|
if self.parameters:
|
|
result += f': {self.parameters.hex()}'
|
|
return result
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('role', {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'}),
|
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
('connection_interval', 2),
|
|
('peripheral_latency', 2),
|
|
('supervision_timeout', 2),
|
|
('central_clock_accuracy', 1)
|
|
])
|
|
class HCI_LE_Connection_Complete_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.1 LE Connection Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_LE_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.2 LE Advertising Report Event
|
|
'''
|
|
subevent_code = HCI_LE_ADVERTISING_REPORT_EVENT
|
|
|
|
# Event Types
|
|
ADV_IND = 0x00
|
|
ADV_DIRECT_IND = 0x01
|
|
ADV_SCAN_IND = 0x02
|
|
ADV_NONCONN_IND = 0x03
|
|
SCAN_RSP = 0x04
|
|
|
|
EVENT_TYPE_NAMES = {
|
|
ADV_IND: 'ADV_IND', # Connectable and scannable undirected advertising
|
|
ADV_DIRECT_IND: 'ADV_DIRECT_IND', # Connectable directed advertising
|
|
ADV_SCAN_IND: 'ADV_SCAN_IND', # Scannable undirected advertising
|
|
ADV_NONCONN_IND: 'ADV_NONCONN_IND', # Non connectable undirected advertising
|
|
SCAN_RSP: 'SCAN_RSP' # Scan Response
|
|
}
|
|
|
|
class Report(HCI_Object):
|
|
FIELDS = [
|
|
('event_type', 1),
|
|
('address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('address', Address.parse_address_preceded_by_type),
|
|
('data', {'parser': HCI_Object.parse_length_prefixed_bytes, 'serializer': HCI_Object.serialize_length_prefixed_bytes}),
|
|
('rssi', -1)
|
|
]
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters, offset):
|
|
return cls.from_bytes(parameters, offset, cls.FIELDS)
|
|
|
|
def event_type_string(self):
|
|
return HCI_LE_Advertising_Report_Event.event_type_name(self.event_type)
|
|
|
|
def to_string(self, prefix):
|
|
return super().to_string(prefix, {
|
|
'event_type': HCI_LE_Advertising_Report_Event.event_type_name,
|
|
'address_type': Address.address_type_name,
|
|
'data': lambda x: str(AdvertisingData.from_bytes(x))
|
|
})
|
|
|
|
@classmethod
|
|
def event_type_name(cls, event_type):
|
|
return name_or_number(cls.EVENT_TYPE_NAMES, event_type)
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
num_reports = parameters[1]
|
|
reports = []
|
|
offset = 2
|
|
for _ in range(num_reports):
|
|
report = cls.Report.from_parameters(parameters, offset)
|
|
offset += 10 + len(report.data)
|
|
reports.append(report)
|
|
|
|
return cls(reports)
|
|
|
|
def __init__(self, reports):
|
|
self.reports = reports[:]
|
|
|
|
# Serialize the fields
|
|
parameters = bytes([HCI_LE_ADVERTISING_REPORT_EVENT, len(reports)]) + b''.join([bytes(report) for report in reports])
|
|
|
|
super().__init__(self.subevent_code, parameters)
|
|
|
|
def __str__(self):
|
|
reports = '\n'.join([f'{i}:\n{report.to_string(" ")}' for i, report in enumerate(self.reports)])
|
|
return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
|
|
|
|
|
|
HCI_Event.meta_event_classes[HCI_LE_ADVERTISING_REPORT_EVENT] = HCI_LE_Advertising_Report_Event
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('connection_interval', 2),
|
|
('peripheral_latency', 2),
|
|
('supervision_timeout', 2)
|
|
])
|
|
class HCI_LE_Connection_Update_Complete_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.3 LE Connection Update Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('le_features', 8)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('connection_handle', 2),
|
|
('random_number', 8),
|
|
('encryption_diversifier', 2)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('connection_handle', 2),
|
|
('interval_min', 2),
|
|
('interval_max', 2),
|
|
('max_latency', 2),
|
|
('timeout', 2)
|
|
])
|
|
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
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('connection_handle', 2),
|
|
('max_tx_octets', 2),
|
|
('max_tx_time', 2),
|
|
('max_rx_octets', 2),
|
|
('max_rx_time', 2),
|
|
])
|
|
class HCI_LE_Data_Length_Change_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.7 LE Data Length Change Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('role', {'size': 1, 'mapper': lambda x: 'CENTRAL' if x == 0 else 'PERIPHERAL'}),
|
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
('local_resolvable_private_address', Address.parse_address),
|
|
('peer_resolvable_private_address', Address.parse_address),
|
|
('connection_interval', 2),
|
|
('peripheral_latency', 2),
|
|
('supervision_timeout', 2),
|
|
('central_clock_accuracy', 1)
|
|
])
|
|
class HCI_LE_Enhanced_Connection_Complete_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.10 LE Enhanced Connection Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('tx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('rx_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name})
|
|
])
|
|
class HCI_LE_PHY_Update_Complete_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.12 LE PHY Update Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_LE_Extended_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.13 LE Extended Advertising Report Event
|
|
'''
|
|
subevent_code = HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT
|
|
|
|
# Event types flags
|
|
CONNECTABLE_ADVERTISING = 0
|
|
SCANNABLE_ADVERTISING = 1
|
|
DIRECTED_ADVERTISING = 2
|
|
SCAN_RESPONSE = 3
|
|
LEGACY_ADVERTISING_PDU_USED = 4
|
|
|
|
DATA_COMPLETE = 0x00
|
|
DATA_INCOMPLETE_MORE_TO_COME = 0x01
|
|
DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02
|
|
|
|
EVENT_TYPE_FLAG_NAMES = (
|
|
'CONNECTABLE_ADVERTISING',
|
|
'SCANNABLE_ADVERTISING',
|
|
'DIRECTED_ADVERTISING',
|
|
'SCAN_RESPONSE',
|
|
'LEGACY_ADVERTISING_PDU_USED'
|
|
)
|
|
|
|
LEGACY_PDU_TYPE_MAP = {
|
|
0b0011: HCI_LE_Advertising_Report_Event.ADV_IND,
|
|
0b0101: HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
|
|
0b0010: HCI_LE_Advertising_Report_Event.ADV_SCAN_IND,
|
|
0b0000: HCI_LE_Advertising_Report_Event.ADV_NONCONN_IND,
|
|
0b1011: HCI_LE_Advertising_Report_Event.SCAN_RSP,
|
|
0b1010: HCI_LE_Advertising_Report_Event.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
|
|
|
|
class Report(HCI_Object):
|
|
FIELDS = [
|
|
('event_type', 2),
|
|
('address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('address', Address.parse_address_preceded_by_type),
|
|
('primary_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('secondary_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
('advertising_sid', 1),
|
|
('tx_power', 1),
|
|
('rssi', -1),
|
|
('periodic_advertising_interval', 2),
|
|
('direct_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
('direct_address', Address.parse_address_preceded_by_type),
|
|
('data', {'parser': HCI_Object.parse_length_prefixed_bytes, 'serializer': HCI_Object.serialize_length_prefixed_bytes}),
|
|
]
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters, offset):
|
|
return cls.from_bytes(parameters, offset, cls.FIELDS)
|
|
|
|
def event_type_string(self):
|
|
return HCI_LE_Extended_Advertising_Report_Event.event_type_string(self.event_type)
|
|
|
|
def to_string(self, prefix):
|
|
return super().to_string(prefix, {
|
|
'event_type': HCI_LE_Extended_Advertising_Report_Event.event_type_string,
|
|
'address_type': Address.address_type_name,
|
|
'data': lambda x: str(AdvertisingData.from_bytes(x))
|
|
})
|
|
|
|
@staticmethod
|
|
def event_type_string(event_type):
|
|
event_type_flags = bit_flags_to_strings(
|
|
event_type & 0x1F,
|
|
HCI_LE_Extended_Advertising_Report_Event.EVENT_TYPE_FLAG_NAMES,
|
|
)
|
|
event_type_flags.append(('COMPLETE', 'INCOMPLETE+', 'INCOMPLETE#', '?')[(event_type >> 5) & 3])
|
|
|
|
if event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.LEGACY_ADVERTISING_PDU_USED):
|
|
legacy_pdu_type = HCI_LE_Extended_Advertising_Report_Event.LEGACY_PDU_TYPE_MAP.get(event_type & 0x0F)
|
|
if legacy_pdu_type is not None:
|
|
legacy_info_string = f'({HCI_LE_Advertising_Report_Event.event_type_name(legacy_pdu_type)})'
|
|
else:
|
|
legacy_info_string = ''
|
|
else:
|
|
legacy_info_string = ''
|
|
|
|
return f'0x{event_type:04X} [{",".join(event_type_flags)}]{legacy_info_string}'
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
num_reports = parameters[1]
|
|
reports = []
|
|
offset = 2
|
|
for _ in range(num_reports):
|
|
report = cls.Report.from_parameters(parameters, offset)
|
|
offset += 24 + len(report.data)
|
|
reports.append(report)
|
|
|
|
return cls(reports)
|
|
|
|
def __init__(self, reports):
|
|
self.reports = reports[:]
|
|
|
|
# Serialize the fields
|
|
parameters = bytes([HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT, len(reports)]) + b''.join([bytes(report) for report in reports])
|
|
|
|
super().__init__(self.subevent_code, parameters)
|
|
|
|
def __str__(self):
|
|
reports = '\n'.join([f'{i}:\n{report.to_string(" ")}' for i, report in enumerate(self.reports)])
|
|
return f'{color(self.subevent_name(self.subevent_code), "magenta")}:\n{reports}'
|
|
|
|
|
|
HCI_Event.meta_event_classes[HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT] = HCI_LE_Extended_Advertising_Report_Event
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_LE_Meta_Event.event([
|
|
('connection_handle', 2),
|
|
('channel_selection_algorithm', 1)
|
|
])
|
|
class HCI_LE_Channel_Selection_Algorithm_Event(HCI_LE_Meta_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.65.20 LE Channel Selection Algorithm Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC)
|
|
])
|
|
class HCI_Inquiry_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.1 Inquiry Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.registered
|
|
class HCI_Inquiry_Result_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.2 Inquiry Result Event
|
|
'''
|
|
|
|
RESPONSE_FIELDS = [
|
|
('bd_addr', Address.parse_address),
|
|
('page_scan_repetition_mode', 1),
|
|
('reserved', 1),
|
|
('reserved', 1),
|
|
('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
|
|
('clock_offset', 2)
|
|
]
|
|
|
|
@staticmethod
|
|
def from_parameters(parameters):
|
|
num_responses = parameters[0]
|
|
responses = []
|
|
offset = 1
|
|
for _ in range(num_responses):
|
|
response = HCI_Object.from_bytes(parameters, offset, HCI_Inquiry_Result_Event.RESPONSE_FIELDS)
|
|
offset += 14
|
|
responses.append(response)
|
|
|
|
return HCI_Inquiry_Result_Event(responses)
|
|
|
|
def __init__(self, responses):
|
|
self.responses = responses[:]
|
|
|
|
# Serialize the fields
|
|
parameters = bytes([HCI_INQUIRY_RESULT_EVENT, len(responses)]) + b''.join([bytes(response) for response in responses])
|
|
|
|
super().__init__(HCI_INQUIRY_RESULT_EVENT, parameters)
|
|
|
|
def __str__(self):
|
|
responses = '\n'.join([response.to_string(indentation=' ') for response in self.responses])
|
|
return f'{color("HCI_INQUIRY_RESULT_EVENT", "magenta")}:\n{responses}'
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('bd_addr', Address.parse_address),
|
|
('link_type', {'size': 1, 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x)}),
|
|
('encryption_enabled', 1)
|
|
])
|
|
class HCI_Connection_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.3 Connection Complete Event
|
|
'''
|
|
|
|
SCO_LINK_TYPE = 0x00
|
|
ACL_LINK_TYPE = 0x01
|
|
ESCO_LINK_TYPE = 0x02
|
|
|
|
LINK_TYPE_NAMES = {
|
|
SCO_LINK_TYPE: 'SCO',
|
|
ACL_LINK_TYPE: 'ACL',
|
|
ESCO_LINK_TYPE: 'eSCO'
|
|
}
|
|
|
|
@staticmethod
|
|
def link_type_name(link_type):
|
|
return name_or_number(HCI_Connection_Complete_Event.LINK_TYPE_NAMES, link_type)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('class_of_device', 3),
|
|
('link_type', {'size': 1, 'mapper': lambda x: HCI_Connection_Complete_Event.link_type_name(x)})
|
|
])
|
|
class HCI_Connection_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.4 Connection Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('reason', {'size': 1, 'mapper': HCI_Constant.error_name})
|
|
])
|
|
class HCI_Disconnection_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.5 Disconnection Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Authentication_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.6 Authentication Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address),
|
|
('remote_name', {'size': 248, 'mapper': map_null_terminated_utf8_string})
|
|
])
|
|
class HCI_Remote_Name_Request_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.7 Remote Name Request Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('encryption_enabled', {'size': 1, 'mapper': lambda x: HCI_Encryption_Change_Event.encryption_enabled_name(x)})
|
|
])
|
|
class HCI_Encryption_Change_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.8 Encryption Change Event
|
|
'''
|
|
|
|
OFF = 0x00
|
|
E0_OR_AES_CCM = 0x01
|
|
AES_CCM = 0x02
|
|
|
|
ENCRYPTION_ENABLED_NAMES = {
|
|
OFF: 'OFF',
|
|
E0_OR_AES_CCM: 'E0_OR_AES_CCM',
|
|
AES_CCM: 'AES_CCM'
|
|
}
|
|
|
|
@staticmethod
|
|
def encryption_enabled_name(encryption_enabled):
|
|
return name_or_number(HCI_Encryption_Change_Event.ENCRYPTION_ENABLED_NAMES, encryption_enabled)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('lmp_features', 8)
|
|
])
|
|
class HCI_Read_Remote_Supported_Features_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.11 Read Remote Supported Features Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('version', 1),
|
|
('manufacturer_name', 2),
|
|
('subversion', 2)
|
|
])
|
|
class HCI_Read_Remote_Version_Information_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.12 Read Remote Version Information Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('num_hci_command_packets', 1),
|
|
('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name}),
|
|
('return_parameters', '*')
|
|
])
|
|
class HCI_Command_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.14 Command Complete Event
|
|
'''
|
|
|
|
def map_return_parameters(self, return_parameters):
|
|
# Map simple 'status' return parameters to their named constant form
|
|
if type(return_parameters) is bytes and len(return_parameters) == 1:
|
|
# Byte-array form
|
|
return HCI_Constant.status_name(return_parameters[0])
|
|
elif type(return_parameters) is int:
|
|
# Already converted to an integer status code
|
|
return HCI_Constant.status_name(return_parameters)
|
|
else:
|
|
return return_parameters
|
|
|
|
@staticmethod
|
|
def from_parameters(parameters):
|
|
self = HCI_Command_Complete_Event.__new__(HCI_Command_Complete_Event)
|
|
HCI_Event.__init__(self, self.event_code, parameters)
|
|
HCI_Object.init_from_bytes(self, parameters, 0, HCI_Command_Complete_Event.fields)
|
|
|
|
# Parse the return parameters
|
|
if type(self.return_parameters) is bytes and len(self.return_parameters) == 1:
|
|
# All commands with 1-byte return parameters return a 'status' field, convert it to an integer
|
|
self.return_parameters = self.return_parameters[0]
|
|
else:
|
|
cls = HCI_Command.command_classes.get(self.command_opcode)
|
|
if cls and cls.return_parameters_fields:
|
|
self.return_parameters = HCI_Object.from_bytes(self.return_parameters, 0, cls.return_parameters_fields)
|
|
self.return_parameters.fields = cls.return_parameters_fields
|
|
|
|
return self
|
|
|
|
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([
|
|
('status', {'size': 1, 'mapper': lambda x: HCI_Command_Status_Event.status_name(x)}),
|
|
('num_hci_command_packets', 1),
|
|
('command_opcode', {'size': 2, 'mapper': HCI_Command.command_name})
|
|
])
|
|
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'
|
|
else:
|
|
return HCI_Constant.error_name(status)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address),
|
|
('new_role', {'size': 1, 'mapper': HCI_Constant.role_name})
|
|
])
|
|
class HCI_Role_Change_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.18 Role Change Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.registered
|
|
class HCI_Number_Of_Completed_Packets_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.19 Number Of Completed Packets Event
|
|
'''
|
|
|
|
@classmethod
|
|
def from_parameters(cls, parameters):
|
|
self = cls.__new__(cls)
|
|
self.parameters = parameters
|
|
num_handles = parameters[0]
|
|
self.connection_handles = []
|
|
self.num_completed_packets = []
|
|
for i in range(num_handles):
|
|
self.connection_handles.append(
|
|
struct.unpack_from('<H', parameters, 1 + i * 4)[0]
|
|
)
|
|
self.num_completed_packets.append(
|
|
struct.unpack_from('<H', parameters, 1 + i * 4 + 2)[0]
|
|
)
|
|
|
|
return self
|
|
|
|
def __init__(self, connection_handle_and_completed_packets_list):
|
|
self.connection_handles = []
|
|
self.num_completed_packets = []
|
|
parameters = bytes([len(connection_handle_and_completed_packets_list)])
|
|
for handle, completed_packets in connection_handle_and_completed_packets_list:
|
|
self.connection_handles.append(handle)
|
|
self.num_completed_packets.append(completed_packets)
|
|
parameters += struct.pack('<H', handle)
|
|
parameters += struct.pack('<H', completed_packets)
|
|
super().__init__(HCI_NUMBER_OF_COMPLETED_PACKETS_EVENT, parameters)
|
|
|
|
def __str__(self):
|
|
lines = [
|
|
color(self.name, 'magenta') + ':',
|
|
color(' number_of_handles: ', 'cyan') + f'{len(self.connection_handles)}'
|
|
]
|
|
for i in range(len(self.connection_handles)):
|
|
lines.append(color(f' connection_handle[{i}]: ', 'cyan') + f'{self.connection_handles[i]}')
|
|
lines.append(color(f' num_completed_packets[{i}]: ', 'cyan') + f'{self.num_completed_packets[i]}')
|
|
return '\n'.join(lines)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('current_mode', {'size': 1, 'mapper': lambda x: HCI_Mode_Change_Event.mode_name(x)}),
|
|
('interval', 2)
|
|
])
|
|
class HCI_Mode_Change_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.20 Mode Change Event
|
|
'''
|
|
|
|
ACTIVE_MODE = 0x00
|
|
HOLD_MODE = 0x01
|
|
SNIFF_MODE = 0x02
|
|
|
|
MODE_NAMES = {
|
|
ACTIVE_MODE: 'ACTIVE_MODE',
|
|
HOLD_MODE: 'HOLD_MODE',
|
|
SNIFF_MODE: 'SNIFF_MODE'
|
|
}
|
|
|
|
@staticmethod
|
|
def mode_name(mode):
|
|
return name_or_number(HCI_Mode_Change_Event.MODE_NAMES, mode)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_PIN_Code_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.22 PIN Code Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_Link_Key_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.24 7.7.23 Link Key Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('link_key', 16),
|
|
('key_type', {'size': 1, 'mapper': HCI_Constant.link_key_type_name})
|
|
])
|
|
class HCI_Link_Key_Notification_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.24 Link Key Notification Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('connection_handle', 2),
|
|
('lmp_max_slots', 1)
|
|
])
|
|
class HCI_Max_Slots_Change_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.27 Max Slots Change Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('clock_offset', 2)
|
|
])
|
|
class HCI_Read_Clock_Offset_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.28 Read Clock Offset Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('packet_type', 2)
|
|
])
|
|
class HCI_Connection_Packet_Type_Changed_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.29 Connection Packet Type Changed Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('page_scan_repetition_mode', 1)
|
|
])
|
|
class HCI_Page_Scan_Repetition_Mode_Change_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.31 Page Scan Repetition Mode Change Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.registered
|
|
class HCI_Inquiry_Result_With_RSSI_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.33 Inquiry Result with RSSI Event
|
|
'''
|
|
|
|
RESPONSE_FIELDS = [
|
|
('bd_addr', Address.parse_address),
|
|
('page_scan_repetition_mode', 1),
|
|
('reserved', 1),
|
|
('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
|
|
('clock_offset', 2),
|
|
('rssi', -1)
|
|
]
|
|
|
|
@staticmethod
|
|
def from_parameters(parameters):
|
|
num_responses = parameters[0]
|
|
responses = []
|
|
offset = 1
|
|
for _ in range(num_responses):
|
|
response = HCI_Object.from_bytes(parameters, offset, HCI_Inquiry_Result_With_RSSI_Event.RESPONSE_FIELDS)
|
|
offset += 14
|
|
responses.append(response)
|
|
|
|
return HCI_Inquiry_Result_With_RSSI_Event(responses)
|
|
|
|
def __init__(self, responses):
|
|
self.responses = responses[:]
|
|
|
|
# Serialize the fields
|
|
parameters = bytes([HCI_INQUIRY_RESULT_WITH_RSSI_EVENT, len(responses)]) + b''.join([bytes(response) for response in responses])
|
|
|
|
super().__init__(HCI_INQUIRY_RESULT_WITH_RSSI_EVENT, parameters)
|
|
|
|
def __str__(self):
|
|
responses = '\n'.join([response.to_string(indentation=' ') for response in self.responses])
|
|
return f'{color("HCI_INQUIRY_RESULT_WITH_RSSI_EVENT", "magenta")}:\n{responses}'
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('page_number', 1),
|
|
('maximum_page_number', 1),
|
|
('extended_lmp_features', 8)
|
|
])
|
|
class HCI_Read_Remote_Extended_Features_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.34 Read Remote Extended Features Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('bd_addr', Address.parse_address),
|
|
('link_type', {'size': 1, 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.link_type_name(x)}),
|
|
('transmission_interval', 1),
|
|
('retransmission_window', 1),
|
|
('rx_packet_length', 2),
|
|
('tx_packet_length', 2),
|
|
('air_mode', {'size': 1, 'mapper': lambda x: HCI_Synchronous_Connection_Complete_Event.air_mode_name(x)}),
|
|
])
|
|
class HCI_Synchronous_Connection_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.35 Synchronous Connection Complete Event
|
|
'''
|
|
|
|
SCO_CONNECTION_LINK_TYPE = 0x00
|
|
ESCO_CONNECTION_LINK_TYPE = 0x02
|
|
|
|
LINK_TYPE_NAMES = {
|
|
SCO_CONNECTION_LINK_TYPE: 'SCO',
|
|
ESCO_CONNECTION_LINK_TYPE: 'eSCO'
|
|
}
|
|
|
|
U_LAW_LOG_AIR_MODE = 0x00
|
|
A_LAW_LOG_AIR_MORE = 0x01
|
|
CVSD_AIR_MODE = 0x02
|
|
TRANSPARENT_DATA_AIR_MODE = 0x03
|
|
|
|
AIR_MODE_NAMES = {
|
|
U_LAW_LOG_AIR_MODE: 'u-law log',
|
|
A_LAW_LOG_AIR_MORE: 'A-law log',
|
|
CVSD_AIR_MODE: 'CVSD',
|
|
TRANSPARENT_DATA_AIR_MODE: 'Transparent Data'
|
|
}
|
|
|
|
@staticmethod
|
|
def link_type_name(link_type):
|
|
return name_or_number(HCI_Synchronous_Connection_Complete_Event.LINK_TYPE_NAMES, link_type)
|
|
|
|
@staticmethod
|
|
def air_mode_name(air_mode):
|
|
return name_or_number(HCI_Synchronous_Connection_Complete_Event.AIR_MODE_NAMES, air_mode)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2),
|
|
('transmission_interval', 1),
|
|
('retransmission_window', 1),
|
|
('rx_packet_length', 2),
|
|
('tx_packet_length', 2)
|
|
])
|
|
class HCI_Synchronous_Connection_Changed_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.36 Synchronous Connection Changed Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('num_responses', 1),
|
|
('bd_addr', Address.parse_address),
|
|
('page_scan_repetition_mode', 1),
|
|
('reserved', 1),
|
|
('class_of_device', {'size': 3, 'mapper': map_class_of_device}),
|
|
('clock_offset', 2),
|
|
('rssi', -1),
|
|
('extended_inquiry_response', 240),
|
|
])
|
|
class HCI_Extended_Inquiry_Result_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.38 Extended Inquiry Result Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('connection_handle', 2)
|
|
])
|
|
class HCI_Encryption_Key_Refresh_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.39 Encryption Key Refresh Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_IO_Capability_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.40 IO Capability Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('io_capability', {'size': 1, 'mapper': HCI_Constant.io_capability_name}),
|
|
('oob_data_present', 1),
|
|
('authentication_requirements', {'size': 1, 'mapper': HCI_Constant.authentication_requirements_name})
|
|
])
|
|
class HCI_IO_Capability_Response_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.41 IO Capability Response Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('numeric_value', 4)
|
|
])
|
|
class HCI_User_Confirmation_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.42 User Confirmation Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_User_Passkey_Request_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.43 User Passkey Request Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('status', STATUS_SPEC),
|
|
('bd_addr', Address.parse_address)
|
|
])
|
|
class HCI_Simple_Pairing_Complete_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.45 Simple Pairing Complete Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('connection_handle', 2),
|
|
('link_supervision_timeout', 2)
|
|
])
|
|
class HCI_Link_Supervision_Timeout_Changed_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.46 Link Supervision Timeout Changed Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('passkey', 4)
|
|
])
|
|
class HCI_User_Passkey_Notification_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.48 User Passkey Notification Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
@HCI_Event.event([
|
|
('bd_addr', Address.parse_address),
|
|
('host_supported_features', 8)
|
|
])
|
|
class HCI_Remote_Host_Supported_Features_Notification_Event(HCI_Event):
|
|
'''
|
|
See Bluetooth spec @ 7.7.50 Remote Host Supported Features Notification Event
|
|
'''
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
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):
|
|
# Read the header
|
|
h, data_total_length = struct.unpack_from('<HH', packet, 1)
|
|
connection_handle = h & 0xFFF
|
|
pb_flag = (h >> 12) & 3
|
|
bc_flag = (h >> 14) & 3
|
|
data = packet[5:]
|
|
if len(data) != data_total_length:
|
|
raise ValueError('invalid packet length')
|
|
return HCI_AclDataPacket(connection_handle, pb_flag, bc_flag, data_total_length, data)
|
|
|
|
def to_bytes(self):
|
|
h = (self.pb_flag << 12) | (self.bc_flag << 14) | self.connection_handle
|
|
return struct.pack('<BHH', HCI_ACL_DATA_PACKET, h, self.data_total_length) + self.data
|
|
|
|
def __init__(self, connection_handle, pb_flag, bc_flag, data_total_length, data):
|
|
self.connection_handle = connection_handle
|
|
self.pb_flag = pb_flag
|
|
self.bc_flag = bc_flag
|
|
self.data_total_length = data_total_length
|
|
self.data = data
|
|
|
|
def __bytes__(self):
|
|
return self.to_bytes()
|
|
|
|
def __str__(self):
|
|
return f'{color("ACL", "blue")}: handle=0x{self.connection_handle:04x}, pb={self.pb_flag}, bc={self.bc_flag}, data_total_length={self.data_total_length}, data={self.data.hex()}'
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
class HCI_AclDataPacketAssembler:
|
|
def __init__(self, callback):
|
|
self.callback = callback
|
|
self.current_data = None
|
|
self.l2cap_pdu_length = 0
|
|
|
|
def feed_packet(self, packet):
|
|
if packet.pb_flag == HCI_ACL_PB_FIRST_NON_FLUSHABLE or packet.pb_flag == HCI_ACL_PB_FIRST_FLUSHABLE:
|
|
(l2cap_pdu_length,) = struct.unpack_from('<H', packet.data, 0)
|
|
self.current_data = packet.data
|
|
self.l2cap_pdu_length = l2cap_pdu_length
|
|
elif packet.pb_flag == HCI_ACL_PB_CONTINUATION:
|
|
if self.current_data is None:
|
|
logger.warning('!!! ACL continuation without start')
|
|
return
|
|
self.current_data += packet.data
|
|
|
|
if len(self.current_data) == self.l2cap_pdu_length + 4:
|
|
# The packet is complete, invoke the callback
|
|
logger.debug(f'<<< ACL PDU: {self.current_data.hex()}')
|
|
self.callback(self.current_data)
|
|
|
|
# Reset
|
|
self.current_data = None
|
|
self.l2cap_pdu_length = 0
|
|
else:
|
|
# Sanity check
|
|
if len(self.current_data) > self.l2cap_pdu_length + 4:
|
|
logger.warning('!!! ACL data exceeds L2CAP PDU')
|
|
self.current_data = None
|
|
self.l2cap_pdu_length = 0
|