Dataclass-based HCI packets

This commit is contained in:
Josh Wu
2025-06-13 16:32:07 +08:00
parent bf027cf38f
commit a0498af626
5 changed files with 369 additions and 441 deletions

View File

@@ -21,60 +21,6 @@ import struct
import pytest
from bumble import hci
from bumble.hci import (
HCI_DISCONNECT_COMMAND,
HCI_LE_1M_PHY_BIT,
HCI_LE_CODED_PHY_BIT,
HCI_LE_READ_BUFFER_SIZE_COMMAND,
HCI_RESET_COMMAND,
HCI_VENDOR_EVENT,
HCI_SUCCESS,
HCI_LE_CONNECTION_COMPLETE_EVENT,
HCI_LE_ENHANCED_CONNECTION_COMPLETE_V2_EVENT,
Address,
CodingFormat,
CodecID,
HCI_Command,
HCI_Command_Complete_Event,
HCI_Command_Status_Event,
HCI_CustomPacket,
HCI_Disconnect_Command,
HCI_Event,
HCI_IsoDataPacket,
HCI_LE_Add_Device_To_Filter_Accept_List_Command,
HCI_LE_Advertising_Report_Event,
HCI_LE_Channel_Selection_Algorithm_Event,
HCI_LE_Connection_Complete_Event,
HCI_LE_Connection_Update_Command,
HCI_LE_Connection_Update_Complete_Event,
HCI_LE_Create_Connection_Command,
HCI_LE_Extended_Create_Connection_Command,
HCI_LE_Read_Buffer_Size_Command,
HCI_LE_Read_Remote_Features_Command,
HCI_LE_Read_Remote_Features_Complete_Event,
HCI_LE_Remove_Device_From_Filter_Accept_List_Command,
HCI_LE_Set_Advertising_Data_Command,
HCI_LE_Set_Advertising_Parameters_Command,
HCI_LE_Set_Default_PHY_Command,
HCI_LE_Set_Event_Mask_Command,
HCI_LE_Set_Extended_Advertising_Enable_Command,
HCI_LE_Set_Extended_Scan_Parameters_Command,
HCI_LE_Set_Random_Address_Command,
HCI_LE_Set_Scan_Enable_Command,
HCI_LE_Set_Scan_Parameters_Command,
HCI_LE_Setup_ISO_Data_Path_Command,
HCI_Number_Of_Completed_Packets_Event,
HCI_Packet,
HCI_PIN_Code_Request_Reply_Command,
HCI_Read_Local_Supported_Codecs_Command,
HCI_Read_Local_Supported_Codecs_V2_Command,
HCI_Read_Local_Supported_Commands_Command,
HCI_Read_Local_Supported_Features_Command,
HCI_Read_Local_Version_Information_Command,
HCI_Reset_Command,
HCI_Set_Event_Mask_Command,
HCI_Vendor_Event,
)
# -----------------------------------------------------------------------------
@@ -84,7 +30,7 @@ from bumble.hci import (
def basic_check(x):
packet = bytes(x)
print(packet.hex())
parsed = HCI_Packet.from_bytes(packet)
parsed = hci.HCI_Packet.from_bytes(packet)
x_str = str(x)
parsed_str = str(parsed)
print(x_str)
@@ -95,18 +41,18 @@ def basic_check(x):
# -----------------------------------------------------------------------------
def test_HCI_Event():
event = HCI_Event(event_code=0xF9)
event = hci.HCI_Event(event_code=0xF9)
basic_check(event)
event = HCI_Event(event_code=0xF8, parameters=bytes.fromhex('AABBCC'))
event = hci.HCI_Event(event_code=0xF8, parameters=bytes.fromhex('AABBCC'))
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_LE_Connection_Complete_Event():
address = Address('00:11:22:33:44:55')
event = HCI_LE_Connection_Complete_Event(
status=HCI_SUCCESS,
address = hci.Address('00:11:22:33:44:55')
event = hci.HCI_LE_Connection_Complete_Event(
status=hci.HCI_SUCCESS,
connection_handle=1,
role=1,
peer_address_type=1,
@@ -121,25 +67,47 @@ def test_HCI_LE_Connection_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Advertising_Report_Event():
address = Address('00:11:22:33:44:55/P')
report = HCI_LE_Advertising_Report_Event.Report(
HCI_LE_Advertising_Report_Event.Report.FIELDS,
event_type=HCI_LE_Advertising_Report_Event.ADV_IND,
address_type=Address.PUBLIC_DEVICE_ADDRESS,
address = hci.Address('00:11:22:33:44:55/P')
report = hci.HCI_LE_Advertising_Report_Event.Report(
event_type=hci.HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
address_type=hci.Address.PUBLIC_DEVICE_ADDRESS,
address=address,
data=bytes.fromhex(
'0201061106ba5689a6fabfa2bd01467d6e00fbabad08160a181604659b03'
),
rssi=100,
)
event = HCI_LE_Advertising_Report_Event([report])
event = hci.HCI_LE_Advertising_Report_Event([report])
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_LE_Extended_Advertising_Report_Event():
address = hci.Address('00:11:22:33:44:55/P')
report = hci.HCI_LE_Extended_Advertising_Report_Event.Report(
event_type=hci.HCI_LE_Extended_Advertising_Report_Event.EventType.CONNECTABLE_ADVERTISING,
address_type=hci.Address.PUBLIC_DEVICE_ADDRESS,
address=address,
data=bytes.fromhex(
'0201061106ba5689a6fabfa2bd01467d6e00fbabad08160a181604659b03'
),
rssi=100,
primary_phy=hci.HCI_LE_1M_PHY,
secondary_phy=hci.HCI_LE_CODED_PHY,
advertising_sid=0,
tx_power=10,
periodic_advertising_interval=2,
direct_address=hci.Address('00:11:22:33:44:55/P'),
direct_address_type=hci.Address.PUBLIC_DEVICE_ADDRESS,
)
event = hci.HCI_LE_Extended_Advertising_Report_Event([report])
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_LE_Read_Remote_Features_Complete_Event():
event = HCI_LE_Read_Remote_Features_Complete_Event(
status=HCI_SUCCESS,
event = hci.HCI_LE_Read_Remote_Features_Complete_Event(
status=hci.HCI_SUCCESS,
connection_handle=0x007,
le_features=bytes.fromhex('0011223344556677'),
)
@@ -148,8 +116,8 @@ def test_HCI_LE_Read_Remote_Features_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Connection_Update_Complete_Event():
event = HCI_LE_Connection_Update_Complete_Event(
status=HCI_SUCCESS,
event = hci.HCI_LE_Connection_Update_Complete_Event(
status=hci.HCI_SUCCESS,
connection_handle=0x007,
connection_interval=10,
peripheral_latency=3,
@@ -160,7 +128,7 @@ def test_HCI_LE_Connection_Update_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_LE_Channel_Selection_Algorithm_Event():
event = HCI_LE_Channel_Selection_Algorithm_Event(
event = hci.HCI_LE_Channel_Selection_Algorithm_Event(
connection_handle=7, channel_selection_algorithm=1
)
basic_check(event)
@@ -169,10 +137,10 @@ def test_HCI_LE_Channel_Selection_Algorithm_Event():
# -----------------------------------------------------------------------------
def test_HCI_Command_Complete_Event():
# With a serializable object
event = HCI_Command_Complete_Event(
event = hci.HCI_Command_Complete_Event(
num_hci_command_packets=34,
command_opcode=HCI_LE_READ_BUFFER_SIZE_COMMAND,
return_parameters=HCI_LE_Read_Buffer_Size_Command.create_return_parameters(
command_opcode=hci.HCI_LE_READ_BUFFER_SIZE_COMMAND,
return_parameters=hci.HCI_LE_Read_Buffer_Size_Command.create_return_parameters(
status=0,
le_acl_data_packet_length=1234,
total_num_le_acl_data_packets=56,
@@ -181,26 +149,28 @@ def test_HCI_Command_Complete_Event():
basic_check(event)
# With an arbitrary byte array
event = HCI_Command_Complete_Event(
event = hci.HCI_Command_Complete_Event(
num_hci_command_packets=1,
command_opcode=HCI_RESET_COMMAND,
command_opcode=hci.HCI_RESET_COMMAND,
return_parameters=bytes([1, 2, 3, 4]),
)
basic_check(event)
# With a simple status as a 1-byte array
event = HCI_Command_Complete_Event(
event = hci.HCI_Command_Complete_Event(
num_hci_command_packets=1,
command_opcode=HCI_RESET_COMMAND,
command_opcode=hci.HCI_RESET_COMMAND,
return_parameters=bytes([7]),
)
basic_check(event)
event = HCI_Packet.from_bytes(bytes(event))
event = hci.HCI_Packet.from_bytes(bytes(event))
assert event.return_parameters == 7
# With a simple status as an integer status
event = HCI_Command_Complete_Event(
num_hci_command_packets=1, command_opcode=HCI_RESET_COMMAND, return_parameters=9
event = hci.HCI_Command_Complete_Event(
num_hci_command_packets=1,
command_opcode=hci.HCI_RESET_COMMAND,
return_parameters=9,
)
basic_check(event)
assert event.return_parameters == 9
@@ -208,15 +178,15 @@ def test_HCI_Command_Complete_Event():
# -----------------------------------------------------------------------------
def test_HCI_Command_Status_Event():
event = HCI_Command_Status_Event(
status=0, num_hci_command_packets=37, command_opcode=HCI_DISCONNECT_COMMAND
event = hci.HCI_Command_Status_Event(
status=0, num_hci_command_packets=37, command_opcode=hci.HCI_DISCONNECT_COMMAND
)
basic_check(event)
# -----------------------------------------------------------------------------
def test_HCI_Number_Of_Completed_Packets_Event():
event = HCI_Number_Of_Completed_Packets_Event(
event = hci.HCI_Number_Of_Completed_Packets_Event(
connection_handles=(1, 2),
num_completed_packets=(3, 4),
)
@@ -226,16 +196,16 @@ def test_HCI_Number_Of_Completed_Packets_Event():
# -----------------------------------------------------------------------------
def test_HCI_Vendor_Event():
data = bytes.fromhex('01020304')
event = HCI_Vendor_Event(data=data)
event = hci.HCI_Vendor_Event(data=data)
event_bytes = bytes(event)
parsed = HCI_Packet.from_bytes(event_bytes)
assert isinstance(parsed, HCI_Vendor_Event)
parsed = hci.HCI_Packet.from_bytes(event_bytes)
assert isinstance(parsed, hci.HCI_Vendor_Event)
assert parsed.data == data
class HCI_Custom_Event(HCI_Event):
class HCI_Custom_Event(hci.HCI_Event):
def __init__(self, blabla):
super().__init__(
event_code=HCI_VENDOR_EVENT, parameters=struct.pack("<I", blabla)
event_code=hci.HCI_VENDOR_EVENT, parameters=struct.pack("<I", blabla)
)
self.name = 'HCI_CUSTOM_EVENT'
self.blabla = blabla
@@ -245,27 +215,27 @@ def test_HCI_Vendor_Event():
return HCI_Custom_Event(blabla=struct.unpack('<I', payload)[0])
return None
HCI_Event.add_vendor_factory(create_event)
parsed = HCI_Packet.from_bytes(event_bytes)
hci.HCI_Event.add_vendor_factory(create_event)
parsed = hci.HCI_Packet.from_bytes(event_bytes)
assert isinstance(parsed, HCI_Custom_Event)
assert parsed.blabla == 0x04030201
event_bytes2 = event_bytes[:3] + bytes([7]) + event_bytes[4:]
parsed = HCI_Packet.from_bytes(event_bytes2)
parsed = hci.HCI_Packet.from_bytes(event_bytes2)
assert not isinstance(parsed, HCI_Custom_Event)
assert isinstance(parsed, HCI_Vendor_Event)
HCI_Event.remove_vendor_factory(create_event)
assert isinstance(parsed, hci.HCI_Vendor_Event)
hci.HCI_Event.remove_vendor_factory(create_event)
parsed = HCI_Packet.from_bytes(event_bytes)
parsed = hci.HCI_Packet.from_bytes(event_bytes)
assert not isinstance(parsed, HCI_Custom_Event)
assert isinstance(parsed, HCI_Vendor_Event)
assert isinstance(parsed, hci.HCI_Vendor_Event)
# -----------------------------------------------------------------------------
def test_HCI_Command():
command = HCI_Command(op_code=0x5566)
command = hci.HCI_Command(op_code=0x5566)
basic_check(command)
command = HCI_Command(op_code=0x5566, parameters=bytes.fromhex('AABBCC'))
command = hci.HCI_Command(op_code=0x5566, parameters=bytes.fromhex('AABBCC'))
basic_check(command)
@@ -324,12 +294,12 @@ def test_HCI_PIN_Code_Request_Reply_Command():
pin_code = b'1234'
pin_code_length = len(pin_code)
# here to make the test pass, we need to
# pad pin_code, as HCI_Object.format_fields
# pad pin_code, as hci.HCI_Object.format_fields
# does not do it for us
padded_pin_code = pin_code + bytes(16 - pin_code_length)
command = HCI_PIN_Code_Request_Reply_Command(
bd_addr=Address(
'00:11:22:33:44:55', address_type=Address.PUBLIC_DEVICE_ADDRESS
command = hci.HCI_PIN_Code_Request_Reply_Command(
bd_addr=hci.Address(
'00:11:22:33:44:55', address_type=hci.Address.PUBLIC_DEVICE_ADDRESS
),
pin_code_length=pin_code_length,
pin_code=padded_pin_code,
@@ -338,47 +308,49 @@ def test_HCI_PIN_Code_Request_Reply_Command():
def test_HCI_Reset_Command():
command = HCI_Reset_Command()
command = hci.HCI_Reset_Command()
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Version_Information_Command():
command = HCI_Read_Local_Version_Information_Command()
command = hci.HCI_Read_Local_Version_Information_Command()
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Supported_Commands_Command():
command = HCI_Read_Local_Supported_Commands_Command()
command = hci.HCI_Read_Local_Supported_Commands_Command()
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Supported_Features_Command():
command = HCI_Read_Local_Supported_Features_Command()
command = hci.HCI_Read_Local_Supported_Features_Command()
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Disconnect_Command():
command = HCI_Disconnect_Command(connection_handle=123, reason=0x11)
command = hci.HCI_Disconnect_Command(connection_handle=123, reason=0x11)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_Set_Event_Mask_Command():
command = HCI_Set_Event_Mask_Command(event_mask=bytes.fromhex('0011223344556677'))
command = hci.HCI_Set_Event_Mask_Command(
event_mask=bytes.fromhex('0011223344556677')
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Event_Mask_Command():
command = HCI_LE_Set_Event_Mask_Command(
le_event_mask=HCI_LE_Set_Event_Mask_Command.mask(
command = hci.HCI_LE_Set_Event_Mask_Command(
le_event_mask=hci.HCI_LE_Set_Event_Mask_Command.mask(
[
HCI_LE_CONNECTION_COMPLETE_EVENT,
HCI_LE_ENHANCED_CONNECTION_COMPLETE_V2_EVENT,
hci.HCI_LE_CONNECTION_COMPLETE_EVENT,
hci.HCI_LE_ENHANCED_CONNECTION_COMPLETE_V2_EVENT,
]
)
)
@@ -388,21 +360,21 @@ def test_HCI_LE_Set_Event_Mask_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Random_Address_Command():
command = HCI_LE_Set_Random_Address_Command(
random_address=Address('00:11:22:33:44:55')
command = hci.HCI_LE_Set_Random_Address_Command(
random_address=hci.Address('00:11:22:33:44:55')
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Advertising_Parameters_Command():
command = HCI_LE_Set_Advertising_Parameters_Command(
command = hci.HCI_LE_Set_Advertising_Parameters_Command(
advertising_interval_min=20,
advertising_interval_max=30,
advertising_type=HCI_LE_Set_Advertising_Parameters_Command.ADV_NONCONN_IND,
own_address_type=Address.PUBLIC_DEVICE_ADDRESS,
peer_address_type=Address.RANDOM_DEVICE_ADDRESS,
peer_address=Address('00:11:22:33:44:55'),
advertising_type=hci.HCI_LE_Set_Advertising_Parameters_Command.ADV_NONCONN_IND,
own_address_type=hci.Address.PUBLIC_DEVICE_ADDRESS,
peer_address_type=hci.Address.RANDOM_DEVICE_ADDRESS,
peer_address=hci.Address('00:11:22:33:44:55'),
advertising_channel_map=0x03,
advertising_filter_policy=1,
)
@@ -411,7 +383,7 @@ def test_HCI_LE_Set_Advertising_Parameters_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Advertising_Data_Command():
command = HCI_LE_Set_Advertising_Data_Command(
command = hci.HCI_LE_Set_Advertising_Data_Command(
advertising_data=bytes.fromhex('AABBCC')
)
basic_check(command)
@@ -419,7 +391,7 @@ def test_HCI_LE_Set_Advertising_Data_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Scan_Parameters_Command():
command = HCI_LE_Set_Scan_Parameters_Command(
command = hci.HCI_LE_Set_Scan_Parameters_Command(
le_scan_type=1,
le_scan_interval=20,
le_scan_window=10,
@@ -431,18 +403,18 @@ def test_HCI_LE_Set_Scan_Parameters_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Scan_Enable_Command():
command = HCI_LE_Set_Scan_Enable_Command(le_scan_enable=1, filter_duplicates=0)
command = hci.HCI_LE_Set_Scan_Enable_Command(le_scan_enable=1, filter_duplicates=0)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Create_Connection_Command():
command = HCI_LE_Create_Connection_Command(
command = hci.HCI_LE_Create_Connection_Command(
le_scan_interval=4,
le_scan_window=5,
initiator_filter_policy=1,
peer_address_type=1,
peer_address=Address('00:11:22:33:44:55'),
peer_address=hci.Address('00:11:22:33:44:55'),
own_address_type=2,
connection_interval_min=7,
connection_interval_max=8,
@@ -456,11 +428,11 @@ def test_HCI_LE_Create_Connection_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Extended_Create_Connection_Command():
command = HCI_LE_Extended_Create_Connection_Command(
command = hci.HCI_LE_Extended_Create_Connection_Command(
initiator_filter_policy=0,
own_address_type=0,
peer_address_type=1,
peer_address=Address('00:11:22:33:44:55'),
peer_address=hci.Address('00:11:22:33:44:55'),
initiating_phys=3,
scan_intervals=(10, 11),
scan_windows=(12, 13),
@@ -476,23 +448,23 @@ def test_HCI_LE_Extended_Create_Connection_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Add_Device_To_Filter_Accept_List_Command():
command = HCI_LE_Add_Device_To_Filter_Accept_List_Command(
address_type=1, address=Address('00:11:22:33:44:55')
command = hci.HCI_LE_Add_Device_To_Filter_Accept_List_Command(
address_type=1, address=hci.Address('00:11:22:33:44:55')
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Remove_Device_From_Filter_Accept_List_Command():
command = HCI_LE_Remove_Device_From_Filter_Accept_List_Command(
address_type=1, address=Address('00:11:22:33:44:55')
command = hci.HCI_LE_Remove_Device_From_Filter_Accept_List_Command(
address_type=1, address=hci.Address('00:11:22:33:44:55')
)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Connection_Update_Command():
command = HCI_LE_Connection_Update_Command(
command = hci.HCI_LE_Connection_Update_Command(
connection_handle=0x0002,
connection_interval_min=10,
connection_interval_max=20,
@@ -506,27 +478,29 @@ def test_HCI_LE_Connection_Update_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Read_Remote_Features_Command():
command = HCI_LE_Read_Remote_Features_Command(connection_handle=0x0002)
command = hci.HCI_LE_Read_Remote_Features_Command(connection_handle=0x0002)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Default_PHY_Command():
command = HCI_LE_Set_Default_PHY_Command(all_phys=0, tx_phys=1, rx_phys=1)
command = hci.HCI_LE_Set_Default_PHY_Command(all_phys=0, tx_phys=1, rx_phys=1)
basic_check(command)
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Extended_Scan_Parameters_Command():
command = HCI_LE_Set_Extended_Scan_Parameters_Command(
own_address_type=Address.RANDOM_DEVICE_ADDRESS,
command = hci.HCI_LE_Set_Extended_Scan_Parameters_Command(
own_address_type=hci.Address.RANDOM_DEVICE_ADDRESS,
# pylint: disable-next=line-too-long
scanning_filter_policy=HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_FILTERED_POLICY,
scanning_phys=(1 << HCI_LE_1M_PHY_BIT | 1 << HCI_LE_CODED_PHY_BIT | 1 << 4),
scanning_filter_policy=hci.HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_FILTERED_POLICY,
scanning_phys=(
1 << hci.HCI_LE_1M_PHY_BIT | 1 << hci.HCI_LE_CODED_PHY_BIT | 1 << 4
),
scan_types=[
HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING,
hci.HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
hci.HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
hci.HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING,
],
scan_intervals=[1, 2, 3],
scan_windows=[4, 5, 6],
@@ -536,7 +510,7 @@ def test_HCI_LE_Set_Extended_Scan_Parameters_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Set_Extended_Advertising_Enable_Command():
command = HCI_Packet.from_bytes(
command = hci.HCI_Packet.from_bytes(
bytes.fromhex('0139200e010301050008020600090307000a')
)
assert command.enable == 1
@@ -544,7 +518,7 @@ def test_HCI_LE_Set_Extended_Advertising_Enable_Command():
assert command.durations == [5, 6, 7]
assert command.max_extended_advertising_events == [8, 9, 10]
command = HCI_LE_Set_Extended_Advertising_Enable_Command(
command = hci.HCI_LE_Set_Extended_Advertising_Enable_Command(
enable=1,
advertising_handles=[1, 2, 3],
durations=[5, 6, 7],
@@ -555,20 +529,22 @@ def test_HCI_LE_Set_Extended_Advertising_Enable_Command():
# -----------------------------------------------------------------------------
def test_HCI_LE_Setup_ISO_Data_Path_Command():
command = HCI_Packet.from_bytes(bytes.fromhex('016e200d60000001030000000000000000'))
command = hci.HCI_Packet.from_bytes(
bytes.fromhex('016e200d60000001030000000000000000')
)
assert command.connection_handle == 0x0060
assert command.data_path_direction == 0x00
assert command.data_path_id == 0x01
assert command.codec_id == CodingFormat(CodecID.TRANSPARENT)
assert command.codec_id == hci.CodingFormat(hci.CodecID.TRANSPARENT)
assert command.controller_delay == 0
assert command.codec_configuration == b''
command = HCI_LE_Setup_ISO_Data_Path_Command(
command = hci.HCI_LE_Setup_ISO_Data_Path_Command(
connection_handle=0x0060,
data_path_direction=0x00,
data_path_id=0x01,
codec_id=CodingFormat(CodecID.TRANSPARENT),
codec_id=hci.CodingFormat(hci.CodecID.TRANSPARENT),
controller_delay=0x00,
codec_configuration=b'',
)
@@ -578,54 +554,63 @@ def test_HCI_LE_Setup_ISO_Data_Path_Command():
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Supported_Codecs_Command_Complete():
returned_parameters = (
HCI_Read_Local_Supported_Codecs_Command.parse_return_parameters(
bytes([HCI_SUCCESS, 3, CodecID.A_LOG, CodecID.CVSD, CodecID.LINEAR_PCM, 0])
)
)
assert returned_parameters.standard_codec_ids == [
CodecID.A_LOG,
CodecID.CVSD,
CodecID.LINEAR_PCM,
]
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Supported_Codecs_V2_Command_Complete():
returned_parameters = (
HCI_Read_Local_Supported_Codecs_V2_Command.parse_return_parameters(
hci.HCI_Read_Local_Supported_Codecs_Command.parse_return_parameters(
bytes(
[
HCI_SUCCESS,
hci.HCI_SUCCESS,
3,
CodecID.A_LOG,
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_ACL,
CodecID.CVSD,
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_SCO,
CodecID.LINEAR_PCM,
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.LE_CIS,
hci.CodecID.A_LOG,
hci.CodecID.CVSD,
hci.CodecID.LINEAR_PCM,
0,
]
)
)
)
assert returned_parameters.standard_codec_ids == [
CodecID.A_LOG,
CodecID.CVSD,
CodecID.LINEAR_PCM,
hci.CodecID.A_LOG,
hci.CodecID.CVSD,
hci.CodecID.LINEAR_PCM,
]
# -----------------------------------------------------------------------------
def test_HCI_Read_Local_Supported_Codecs_V2_Command_Complete():
returned_parameters = (
hci.HCI_Read_Local_Supported_Codecs_V2_Command.parse_return_parameters(
bytes(
[
hci.HCI_SUCCESS,
3,
hci.CodecID.A_LOG,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_ACL,
hci.CodecID.CVSD,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_SCO,
hci.CodecID.LINEAR_PCM,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.LE_CIS,
0,
]
)
)
)
assert returned_parameters.standard_codec_ids == [
hci.CodecID.A_LOG,
hci.CodecID.CVSD,
hci.CodecID.LINEAR_PCM,
]
assert returned_parameters.standard_codec_transports == [
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_ACL,
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_SCO,
HCI_Read_Local_Supported_Codecs_V2_Command.Transport.LE_CIS,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_ACL,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.BR_EDR_SCO,
hci.HCI_Read_Local_Supported_Codecs_V2_Command.Transport.LE_CIS,
]
# -----------------------------------------------------------------------------
def test_address():
a = Address('C4:F2:17:1A:1D:BB')
a = hci.Address('C4:F2:17:1A:1D:BB')
assert not a.is_public
assert a.is_random
assert a.address_type == Address.RANDOM_DEVICE_ADDRESS
assert a.address_type == hci.Address.RANDOM_DEVICE_ADDRESS
assert not a.is_resolvable
assert not a.is_resolved
assert a.is_static
@@ -634,7 +619,7 @@ def test_address():
# -----------------------------------------------------------------------------
def test_custom():
data = bytes([0x77, 0x02, 0x01, 0x03])
packet = HCI_CustomPacket(data)
packet = hci.HCI_CustomPacket(data)
assert packet.hci_packet_type == 0x77
assert packet.payload == data
@@ -645,7 +630,7 @@ def test_iso_data_packet():
'05616044002ac9f0a193003c00e83b477b00eba8d41dc018bf1a980f0290afe1e7c37652096697'
'52b6a535a8df61e22931ef5a36281bc77ed6a3206d984bcdabee6be831c699cb50e2'
)
packet = HCI_IsoDataPacket.from_bytes(data)
packet = hci.HCI_IsoDataPacket.from_bytes(data)
assert packet.connection_handle == 0x0061
assert packet.packet_status_flag == 0
assert packet.pb_flag == 0x02