bumble 0.0.179__py3-none-any.whl → 0.0.181__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bumble/hci.py CHANGED
@@ -17,12 +17,15 @@
17
17
  # -----------------------------------------------------------------------------
18
18
  from __future__ import annotations
19
19
  import collections
20
+ import dataclasses
20
21
  import enum
21
22
  import functools
22
23
  import logging
24
+ import secrets
23
25
  import struct
24
26
  from typing import Any, Dict, Callable, Optional, Type, Union, List
25
27
 
28
+ from bumble import crypto
26
29
  from .colors import color
27
30
  from .core import (
28
31
  BT_BR_EDR_TRANSPORT,
@@ -560,6 +563,12 @@ HCI_LE_TRANSMITTER_TEST_V4_COMMAND = hci_c
560
563
  HCI_LE_SET_DATA_RELATED_ADDRESS_CHANGES_COMMAND = hci_command_op_code(0x08, 0x007C)
561
564
  HCI_LE_SET_DEFAULT_SUBRATE_COMMAND = hci_command_op_code(0x08, 0x007D)
562
565
  HCI_LE_SUBRATE_REQUEST_COMMAND = hci_command_op_code(0x08, 0x007E)
566
+ HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V2_COMMAND = hci_command_op_code(0x08, 0x007F)
567
+ HCI_LE_SET_PERIODIC_ADVERTISING_SUBEVENT_DATA_COMMAND = hci_command_op_code(0x08, 0x0082)
568
+ HCI_LE_SET_PERIODIC_ADVERTISING_RESPONSE_DATA_COMMAND = hci_command_op_code(0x08, 0x0083)
569
+ HCI_LE_SET_PERIODIC_SYNC_SUBEVENT_COMMAND = hci_command_op_code(0x08, 0x0084)
570
+ HCI_LE_EXTENDED_CREATE_CONNECTION_V2_COMMAND = hci_command_op_code(0x08, 0x0085)
571
+ HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V2_COMMAND = hci_command_op_code(0x08, 0x0086)
563
572
 
564
573
 
565
574
  # HCI Error Codes
@@ -721,6 +730,19 @@ HCI_LE_PHY_TYPE_TO_BIT = {
721
730
  HCI_LE_CODED_PHY: HCI_LE_CODED_PHY_BIT
722
731
  }
723
732
 
733
+
734
+ class Phy(enum.IntEnum):
735
+ LE_1M = 0x01
736
+ LE_2M = 0x02
737
+ LE_CODED = 0x03
738
+
739
+
740
+ class PhyBit(enum.IntFlag):
741
+ LE_1M = 0b00000001
742
+ LE_2M = 0b00000010
743
+ LE_CODED = 0b00000100
744
+
745
+
724
746
  # Connection Parameters
725
747
  HCI_CONNECTION_INTERVAL_MS_PER_UNIT = 1.25
726
748
  HCI_CONNECTION_LATENCY_MS_PER_UNIT = 1.25
@@ -1316,56 +1338,72 @@ HCI_SUPPORTED_COMMANDS_FLAGS = (
1316
1338
  (
1317
1339
  HCI_LE_SET_DEFAULT_SUBRATE_COMMAND,
1318
1340
  HCI_LE_SUBRATE_REQUEST_COMMAND,
1341
+ HCI_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_V2_COMMAND,
1342
+ None,
1343
+ None,
1344
+ HCI_LE_SET_PERIODIC_ADVERTISING_SUBEVENT_DATA_COMMAND,
1345
+ HCI_LE_SET_PERIODIC_ADVERTISING_RESPONSE_DATA_COMMAND,
1346
+ HCI_LE_SET_PERIODIC_SYNC_SUBEVENT_COMMAND
1347
+ ),
1348
+ # Octet 47
1349
+ (
1350
+ HCI_LE_EXTENDED_CREATE_CONNECTION_V2_COMMAND,
1351
+ HCI_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_V2_COMMAND,
1352
+ None,
1319
1353
  None,
1320
1354
  None,
1321
1355
  None,
1322
1356
  None,
1323
1357
  None,
1324
- None
1325
1358
  )
1326
1359
  )
1327
1360
 
1328
1361
  # LE Supported Features
1329
- HCI_LE_ENCRYPTION_LE_SUPPORTED_FEATURE = 0
1330
- HCI_CONNECTION_PARAMETERS_REQUEST_PROCEDURE_LE_SUPPORTED_FEATURE = 1
1331
- HCI_EXTENDED_REJECT_INDICATION_LE_SUPPORTED_FEATURE = 2
1332
- HCI_PERIPHERAL_INITIATED_FEATURE_EXCHANGE_LE_SUPPORTED_FEATURE = 3
1333
- HCI_LE_PING_LE_SUPPORTED_FEATURE = 4
1334
- HCI_LE_DATA_PACKET_LENGTH_EXTENSION_LE_SUPPORTED_FEATURE = 5
1335
- HCI_LL_PRIVACY_LE_SUPPORTED_FEATURE = 6
1336
- HCI_EXTENDED_SCANNER_FILTER_POLICIES_LE_SUPPORTED_FEATURE = 7
1337
- HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE = 8
1338
- HCI_STABLE_MODULATION_INDEX_TRANSMITTER_LE_SUPPORTED_FEATURE = 9
1339
- HCI_STABLE_MODULATION_INDEX_RECEIVER_LE_SUPPORTED_FEATURE = 10
1340
- HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE = 11
1341
- HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE = 12
1342
- HCI_LE_PERIODIC_ADVERTISING_LE_SUPPORTED_FEATURE = 13
1343
- HCI_CHANNEL_SELECTION_ALGORITHM_2_LE_SUPPORTED_FEATURE = 14
1344
- HCI_LE_POWER_CLASS_1_LE_SUPPORTED_FEATURE = 15
1345
- HCI_MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE_LE_SUPPORTED_FEATURE = 16
1346
- HCI_CONNECTION_CTE_REQUEST_LE_SUPPORTED_FEATURE = 17
1347
- HCI_CONNECTION_CTE_RESPONSE_LE_SUPPORTED_FEATURE = 18
1348
- HCI_CONNECTIONLESS_CTE_TRANSMITTER_LE_SUPPORTED_FEATURE = 19
1349
- HCI_CONNECTIONLESS_CTR_RECEIVER_LE_SUPPORTED_FEATURE = 20
1350
- HCI_ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION_LE_SUPPORTED_FEATURE = 21
1351
- HCI_ANTENNA_SWITCHING_DURING_CTE_RECEPTION_LE_SUPPORTED_FEATURE = 22
1352
- HCI_RECEIVING_CONSTANT_TONE_EXTENSIONS_LE_SUPPORTED_FEATURE = 23
1353
- HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER_LE_SUPPORTED_FEATURE = 24
1354
- HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT_LE_SUPPORTED_FEATURE = 25
1355
- HCI_SLEEP_CLOCK_ACCURACY_UPDATES_LE_SUPPORTED_FEATURE = 26
1356
- HCI_REMOTE_PUBLIC_KEY_VALIDATION_LE_SUPPORTED_FEATURE = 27
1357
- HCI_CONNECTED_ISOCHRONOUS_STREAM_CENTRAL_LE_SUPPORTED_FEATURE = 28
1358
- HCI_CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL_LE_SUPPORTED_FEATURE = 29
1359
- HCI_ISOCHRONOUS_BROADCASTER_LE_SUPPORTED_FEATURE = 30
1360
- HCI_SYNCHRONIZED_RECEIVER_LE_SUPPORTED_FEATURE = 31
1361
- HCI_CONNECTED_ISOCHRONOUS_STREAM_LE_SUPPORTED_FEATURE = 32
1362
- HCI_LE_POWER_CONTROL_REQUEST_LE_SUPPORTED_FEATURE = 33
1363
- HCI_LE_POWER_CONTROL_REQUEST_DUP_LE_SUPPORTED_FEATURE = 34
1364
- HCI_LE_PATH_LOSS_MONITORING_LE_SUPPORTED_FEATURE = 35
1365
- HCI_PERIODIC_ADVERTISING_ADI_SUPPORT_LE_SUPPORTED_FEATURE = 36
1366
- HCI_CONNECTION_SUBRATING_LE_SUPPORTED_FEATURE = 37
1367
- HCI_CONNECTION_SUBRATING_HOST_SUPPORT_LE_SUPPORTED_FEATURE = 38
1368
- HCI_CHANNEL_CLASSIFICATION_LE_SUPPORTED_FEATURE = 39
1362
+ # See Bluetooth spec @ Vol 6, Part B, 4.6 FEATURE SUPPORT
1363
+ HCI_LE_ENCRYPTION_LE_SUPPORTED_FEATURE = 0
1364
+ HCI_CONNECTION_PARAMETERS_REQUEST_PROCEDURE_LE_SUPPORTED_FEATURE = 1
1365
+ HCI_EXTENDED_REJECT_INDICATION_LE_SUPPORTED_FEATURE = 2
1366
+ HCI_PERIPHERAL_INITIATED_FEATURE_EXCHANGE_LE_SUPPORTED_FEATURE = 3
1367
+ HCI_LE_PING_LE_SUPPORTED_FEATURE = 4
1368
+ HCI_LE_DATA_PACKET_LENGTH_EXTENSION_LE_SUPPORTED_FEATURE = 5
1369
+ HCI_LL_PRIVACY_LE_SUPPORTED_FEATURE = 6
1370
+ HCI_EXTENDED_SCANNER_FILTER_POLICIES_LE_SUPPORTED_FEATURE = 7
1371
+ HCI_LE_2M_PHY_LE_SUPPORTED_FEATURE = 8
1372
+ HCI_STABLE_MODULATION_INDEX_TRANSMITTER_LE_SUPPORTED_FEATURE = 9
1373
+ HCI_STABLE_MODULATION_INDEX_RECEIVER_LE_SUPPORTED_FEATURE = 10
1374
+ HCI_LE_CODED_PHY_LE_SUPPORTED_FEATURE = 11
1375
+ HCI_LE_EXTENDED_ADVERTISING_LE_SUPPORTED_FEATURE = 12
1376
+ HCI_LE_PERIODIC_ADVERTISING_LE_SUPPORTED_FEATURE = 13
1377
+ HCI_CHANNEL_SELECTION_ALGORITHM_2_LE_SUPPORTED_FEATURE = 14
1378
+ HCI_LE_POWER_CLASS_1_LE_SUPPORTED_FEATURE = 15
1379
+ HCI_MINIMUM_NUMBER_OF_USED_CHANNELS_PROCEDURE_LE_SUPPORTED_FEATURE = 16
1380
+ HCI_CONNECTION_CTE_REQUEST_LE_SUPPORTED_FEATURE = 17
1381
+ HCI_CONNECTION_CTE_RESPONSE_LE_SUPPORTED_FEATURE = 18
1382
+ HCI_CONNECTIONLESS_CTE_TRANSMITTER_LE_SUPPORTED_FEATURE = 19
1383
+ HCI_CONNECTIONLESS_CTR_RECEIVER_LE_SUPPORTED_FEATURE = 20
1384
+ HCI_ANTENNA_SWITCHING_DURING_CTE_TRANSMISSION_LE_SUPPORTED_FEATURE = 21
1385
+ HCI_ANTENNA_SWITCHING_DURING_CTE_RECEPTION_LE_SUPPORTED_FEATURE = 22
1386
+ HCI_RECEIVING_CONSTANT_TONE_EXTENSIONS_LE_SUPPORTED_FEATURE = 23
1387
+ HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_SENDER_LE_SUPPORTED_FEATURE = 24
1388
+ HCI_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECIPIENT_LE_SUPPORTED_FEATURE = 25
1389
+ HCI_SLEEP_CLOCK_ACCURACY_UPDATES_LE_SUPPORTED_FEATURE = 26
1390
+ HCI_REMOTE_PUBLIC_KEY_VALIDATION_LE_SUPPORTED_FEATURE = 27
1391
+ HCI_CONNECTED_ISOCHRONOUS_STREAM_CENTRAL_LE_SUPPORTED_FEATURE = 28
1392
+ HCI_CONNECTED_ISOCHRONOUS_STREAM_PERIPHERAL_LE_SUPPORTED_FEATURE = 29
1393
+ HCI_ISOCHRONOUS_BROADCASTER_LE_SUPPORTED_FEATURE = 30
1394
+ HCI_SYNCHRONIZED_RECEIVER_LE_SUPPORTED_FEATURE = 31
1395
+ HCI_CONNECTED_ISOCHRONOUS_STREAM_LE_SUPPORTED_FEATURE = 32
1396
+ HCI_LE_POWER_CONTROL_REQUEST_LE_SUPPORTED_FEATURE = 33
1397
+ HCI_LE_POWER_CONTROL_REQUEST_DUP_LE_SUPPORTED_FEATURE = 34
1398
+ HCI_LE_PATH_LOSS_MONITORING_LE_SUPPORTED_FEATURE = 35
1399
+ HCI_PERIODIC_ADVERTISING_ADI_SUPPORT_LE_SUPPORTED_FEATURE = 36
1400
+ HCI_CONNECTION_SUBRATING_LE_SUPPORTED_FEATURE = 37
1401
+ HCI_CONNECTION_SUBRATING_HOST_SUPPORT_LE_SUPPORTED_FEATURE = 38
1402
+ HCI_CHANNEL_CLASSIFICATION_LE_SUPPORTED_FEATURE = 39
1403
+ HCI_ADVERTISING_CODING_SELECTION_LE_SUPPORTED_FEATURE = 40
1404
+ HCI_ADVERTISING_CODING_SELECTION_HOST_SUPPORT_LE_SUPPORTED_FEATURE = 41
1405
+ HCI_PERIODIC_ADVERTISING_WITH_RESPONSES_ADVERTISER_LE_SUPPORTED_FEATURE = 43
1406
+ HCI_PERIODIC_ADVERTISING_WITH_RESPONSES_SCANNER_LE_SUPPORTED_FEATURE = 44
1369
1407
 
1370
1408
  HCI_LE_SUPPORTED_FEATURES_NAMES = {
1371
1409
  flag: feature_name for (feature_name, flag) in globals().items()
@@ -1382,6 +1420,45 @@ HCI_LE_SUPPORTED_FEATURES_NAMES = {
1382
1420
  STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)}
1383
1421
 
1384
1422
 
1423
+ class CodecID(enum.IntEnum):
1424
+ # fmt: off
1425
+ U_LOG = 0x00
1426
+ A_LOG = 0x01
1427
+ CVSD = 0x02
1428
+ TRANSPARENT = 0x03
1429
+ LINEAR_PCM = 0x04
1430
+ MSBC = 0x05
1431
+ LC3 = 0x06
1432
+ G729A = 0x07
1433
+ VENDOR_SPECIFIC = 0xFF
1434
+
1435
+
1436
+ @dataclasses.dataclass(frozen=True)
1437
+ class CodingFormat:
1438
+ codec_id: CodecID
1439
+ company_id: int = 0
1440
+ vendor_specific_codec_id: int = 0
1441
+
1442
+ @classmethod
1443
+ def parse_from_bytes(cls, data: bytes, offset: int):
1444
+ (codec_id, company_id, vendor_specific_codec_id) = struct.unpack_from(
1445
+ '<BHH', data, offset
1446
+ )
1447
+ return offset + 5, cls(
1448
+ codec_id=CodecID(codec_id),
1449
+ company_id=company_id,
1450
+ vendor_specific_codec_id=vendor_specific_codec_id,
1451
+ )
1452
+
1453
+ def to_bytes(self) -> bytes:
1454
+ return struct.pack(
1455
+ '<BHH', self.codec_id, self.company_id, self.vendor_specific_codec_id
1456
+ )
1457
+
1458
+ def __bytes__(self) -> bytes:
1459
+ return self.to_bytes()
1460
+
1461
+
1385
1462
  # -----------------------------------------------------------------------------
1386
1463
  class HCI_Constant:
1387
1464
  @staticmethod
@@ -1477,6 +1554,12 @@ class HCI_Object:
1477
1554
  # The rest of the bytes
1478
1555
  field_value = data[offset:]
1479
1556
  return (field_value, len(field_value))
1557
+ if field_type == 'v':
1558
+ # Variable-length bytes field, with 1-byte length at the beginning
1559
+ field_length = data[offset]
1560
+ offset += 1
1561
+ field_value = data[offset : offset + field_length]
1562
+ return (field_value, field_length + 1)
1480
1563
  if field_type == 1:
1481
1564
  # 8-bit unsigned
1482
1565
  return (data[offset], 1)
@@ -1581,6 +1664,11 @@ class HCI_Object:
1581
1664
  raise ValueError('value too large for *-typed field')
1582
1665
  else:
1583
1666
  field_bytes = bytes(field_value)
1667
+ elif field_type == 'v':
1668
+ # Variable-length bytes field, with 1-byte length at the beginning
1669
+ field_bytes = bytes(field_value)
1670
+ field_length = len(field_bytes)
1671
+ field_bytes = bytes([field_length]) + field_bytes
1584
1672
  elif isinstance(field_value, (bytes, bytearray)) or hasattr(
1585
1673
  field_value, 'to_bytes'
1586
1674
  ):
@@ -1795,6 +1883,43 @@ class Address:
1795
1883
  address_type = data[offset - 1]
1796
1884
  return Address.parse_address_with_type(data, offset, address_type)
1797
1885
 
1886
+ @classmethod
1887
+ def generate_static_address(cls) -> Address:
1888
+ '''Generates Random Static Address, with the 2 most significant bits of 0b11.
1889
+
1890
+ See Bluetooth spec, Vol 6, Part B - Table 1.2.
1891
+ '''
1892
+ address_bytes = secrets.token_bytes(6)
1893
+ address_bytes = address_bytes[:5] + bytes([address_bytes[5] | 0b11000000])
1894
+ return Address(
1895
+ address=address_bytes, address_type=Address.RANDOM_DEVICE_ADDRESS
1896
+ )
1897
+
1898
+ @classmethod
1899
+ def generate_private_address(cls, irk: bytes = b'') -> Address:
1900
+ '''Generates Random Private MAC Address.
1901
+
1902
+ If IRK is present, a Resolvable Private Address, with the 2 most significant
1903
+ bits of 0b01 will be generated. Otherwise, a Non-resolvable Private Address,
1904
+ with the 2 most significant bits of 0b00 will be generated.
1905
+
1906
+ See Bluetooth spec, Vol 6, Part B - Table 1.2.
1907
+
1908
+ Args:
1909
+ irk: Local Identity Resolving Key(IRK), in little-endian. If not set, a
1910
+ non-resolvable address will be generated.
1911
+ '''
1912
+ if irk:
1913
+ prand = crypto.generate_prand()
1914
+ address_bytes = crypto.ah(irk, prand) + prand
1915
+ else:
1916
+ address_bytes = secrets.token_bytes(6)
1917
+ address_bytes = address_bytes[:5] + bytes([address_bytes[5] & 0b00111111])
1918
+
1919
+ return Address(
1920
+ address=address_bytes, address_type=Address.RANDOM_DEVICE_ADDRESS
1921
+ )
1922
+
1798
1923
  def __init__(
1799
1924
  self, address: Union[bytes, str], address_type: int = RANDOM_DEVICE_ADDRESS
1800
1925
  ):
@@ -1888,26 +2013,17 @@ Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS
1888
2013
  Address.ANY = Address(b"\x00\x00\x00\x00\x00\x00", Address.PUBLIC_DEVICE_ADDRESS)
1889
2014
  Address.ANY_RANDOM = Address(b"\x00\x00\x00\x00\x00\x00", Address.RANDOM_DEVICE_ADDRESS)
1890
2015
 
2016
+
1891
2017
  # -----------------------------------------------------------------------------
1892
- class OwnAddressType:
2018
+ class OwnAddressType(enum.IntEnum):
1893
2019
  PUBLIC = 0
1894
2020
  RANDOM = 1
1895
2021
  RESOLVABLE_OR_PUBLIC = 2
1896
2022
  RESOLVABLE_OR_RANDOM = 3
1897
2023
 
1898
- TYPE_NAMES = {
1899
- PUBLIC: 'PUBLIC',
1900
- RANDOM: 'RANDOM',
1901
- RESOLVABLE_OR_PUBLIC: 'RESOLVABLE_OR_PUBLIC',
1902
- RESOLVABLE_OR_RANDOM: 'RESOLVABLE_OR_RANDOM',
1903
- }
1904
-
1905
- @staticmethod
1906
- def type_name(type_id):
1907
- return name_or_number(OwnAddressType.TYPE_NAMES, type_id)
1908
-
1909
- # pylint: disable-next=unnecessary-lambda
1910
- TYPE_SPEC = {'size': 1, 'mapper': lambda x: OwnAddressType.type_name(x)}
2024
+ @classmethod
2025
+ def type_spec(cls):
2026
+ return {'size': 1, 'mapper': lambda x: OwnAddressType(x).name}
1911
2027
 
1912
2028
 
1913
2029
  # -----------------------------------------------------------------------------
@@ -1934,6 +2050,9 @@ class HCI_Packet:
1934
2050
  if packet_type == HCI_EVENT_PACKET:
1935
2051
  return HCI_Event.from_bytes(packet)
1936
2052
 
2053
+ if packet_type == HCI_ISO_DATA_PACKET:
2054
+ return HCI_IsoDataPacket.from_bytes(packet)
2055
+
1937
2056
  return HCI_CustomPacket(packet)
1938
2057
 
1939
2058
  def __init__(self, name):
@@ -1966,6 +2085,7 @@ class HCI_Command(HCI_Packet):
1966
2085
  hci_packet_type = HCI_COMMAND_PACKET
1967
2086
  command_names: Dict[int, str] = {}
1968
2087
  command_classes: Dict[int, Type[HCI_Command]] = {}
2088
+ op_code: int
1969
2089
 
1970
2090
  @staticmethod
1971
2091
  def command(fields=(), return_parameters_fields=()):
@@ -2051,7 +2171,11 @@ class HCI_Command(HCI_Packet):
2051
2171
  return_parameters.fields = cls.return_parameters_fields
2052
2172
  return return_parameters
2053
2173
 
2054
- def __init__(self, op_code, parameters=None, **kwargs):
2174
+ def __init__(self, op_code=-1, parameters=None, **kwargs):
2175
+ # Since the legacy implementation relies on an __init__ injector, typing always
2176
+ # complains that positional argument op_code is not passed, so here sets a
2177
+ # default value to allow building derived HCI_Command without op_code.
2178
+ assert op_code != -1
2055
2179
  super().__init__(HCI_Command.command_name(op_code))
2056
2180
  if (fields := getattr(self, 'fields', None)) and kwargs:
2057
2181
  HCI_Object.init_from_fields(self, fields, kwargs)
@@ -2445,14 +2569,14 @@ class HCI_IO_Capability_Request_Negative_Reply_Command(HCI_Command):
2445
2569
  ('connection_handle', 2),
2446
2570
  ('transmit_bandwidth', 4),
2447
2571
  ('receive_bandwidth', 4),
2448
- ('transmit_coding_format', 5),
2449
- ('receive_coding_format', 5),
2572
+ ('transmit_coding_format', CodingFormat.parse_from_bytes),
2573
+ ('receive_coding_format', CodingFormat.parse_from_bytes),
2450
2574
  ('transmit_codec_frame_size', 2),
2451
2575
  ('receive_codec_frame_size', 2),
2452
2576
  ('input_bandwidth', 4),
2453
2577
  ('output_bandwidth', 4),
2454
- ('input_coding_format', 5),
2455
- ('output_coding_format', 5),
2578
+ ('input_coding_format', CodingFormat.parse_from_bytes),
2579
+ ('output_coding_format', CodingFormat.parse_from_bytes),
2456
2580
  ('input_coded_data_size', 2),
2457
2581
  ('output_coded_data_size', 2),
2458
2582
  ('input_pcm_data_format', 1),
@@ -2473,22 +2597,6 @@ class HCI_Enhanced_Setup_Synchronous_Connection_Command(HCI_Command):
2473
2597
  See Bluetooth spec @ 7.1.45 Enhanced Setup Synchronous Connection Command
2474
2598
  '''
2475
2599
 
2476
- class CodingFormat(enum.IntEnum):
2477
- U_LOG = 0x00
2478
- A_LOG = 0x01
2479
- CVSD = 0x02
2480
- TRANSPARENT = 0x03
2481
- PCM = 0x04
2482
- MSBC = 0x05
2483
- LC3 = 0x06
2484
- G729A = 0x07
2485
-
2486
- def to_bytes(self):
2487
- return self.value.to_bytes(5, 'little')
2488
-
2489
- def __bytes__(self):
2490
- return self.to_bytes()
2491
-
2492
2600
  class PcmDataFormat(enum.IntEnum):
2493
2601
  NA = 0x00
2494
2602
  ONES_COMPLEMENT = 0x01
@@ -2525,14 +2633,14 @@ class HCI_Enhanced_Setup_Synchronous_Connection_Command(HCI_Command):
2525
2633
  ('bd_addr', Address.parse_address),
2526
2634
  ('transmit_bandwidth', 4),
2527
2635
  ('receive_bandwidth', 4),
2528
- ('transmit_coding_format', 5),
2529
- ('receive_coding_format', 5),
2636
+ ('transmit_coding_format', CodingFormat.parse_from_bytes),
2637
+ ('receive_coding_format', CodingFormat.parse_from_bytes),
2530
2638
  ('transmit_codec_frame_size', 2),
2531
2639
  ('receive_codec_frame_size', 2),
2532
2640
  ('input_bandwidth', 4),
2533
2641
  ('output_bandwidth', 4),
2534
- ('input_coding_format', 5),
2535
- ('output_coding_format', 5),
2642
+ ('input_coding_format', CodingFormat.parse_from_bytes),
2643
+ ('output_coding_format', CodingFormat.parse_from_bytes),
2536
2644
  ('input_coded_data_size', 2),
2537
2645
  ('output_coded_data_size', 2),
2538
2646
  ('input_pcm_data_format', 1),
@@ -3308,7 +3416,7 @@ class HCI_LE_Set_Random_Address_Command(HCI_Command):
3308
3416
  ),
3309
3417
  },
3310
3418
  ),
3311
- ('own_address_type', OwnAddressType.TYPE_SPEC),
3419
+ ('own_address_type', OwnAddressType.type_spec()),
3312
3420
  ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
3313
3421
  ('peer_address', Address.parse_address_preceded_by_type),
3314
3422
  ('advertising_channel_map', 1),
@@ -3401,7 +3509,7 @@ class HCI_LE_Set_Advertising_Enable_Command(HCI_Command):
3401
3509
  ('le_scan_type', 1),
3402
3510
  ('le_scan_interval', 2),
3403
3511
  ('le_scan_window', 2),
3404
- ('own_address_type', OwnAddressType.TYPE_SPEC),
3512
+ ('own_address_type', OwnAddressType.type_spec()),
3405
3513
  ('scanning_filter_policy', 1),
3406
3514
  ]
3407
3515
  )
@@ -3440,7 +3548,7 @@ class HCI_LE_Set_Scan_Enable_Command(HCI_Command):
3440
3548
  ('initiator_filter_policy', 1),
3441
3549
  ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
3442
3550
  ('peer_address', Address.parse_address_preceded_by_type),
3443
- ('own_address_type', OwnAddressType.TYPE_SPEC),
3551
+ ('own_address_type', OwnAddressType.type_spec()),
3444
3552
  ('connection_interval_min', 2),
3445
3553
  ('connection_interval_max', 2),
3446
3554
  ('max_latency', 2),
@@ -3847,7 +3955,7 @@ class HCI_LE_Set_Advertising_Set_Random_Address_Command(HCI_Command):
3847
3955
  ),
3848
3956
  },
3849
3957
  ),
3850
- ('own_address_type', OwnAddressType.TYPE_SPEC),
3958
+ ('own_address_type', OwnAddressType.type_spec()),
3851
3959
  ('peer_address_type', Address.ADDRESS_TYPE_SPEC),
3852
3960
  ('peer_address', Address.parse_address_preceded_by_type),
3853
3961
  ('advertising_filter_policy', 1),
@@ -4243,7 +4351,7 @@ class HCI_LE_Extended_Create_Connection_Command(HCI_Command):
4243
4351
  ('initiator_filter_policy:', self.initiator_filter_policy),
4244
4352
  (
4245
4353
  'own_address_type: ',
4246
- OwnAddressType.type_name(self.own_address_type),
4354
+ OwnAddressType(self.own_address_type).name,
4247
4355
  ),
4248
4356
  (
4249
4357
  'peer_address_type: ',
@@ -4451,7 +4559,10 @@ class HCI_LE_Accept_CIS_Request_Command(HCI_Command):
4451
4559
 
4452
4560
  # -----------------------------------------------------------------------------
4453
4561
  @HCI_Command.command(
4454
- fields=[('connection_handle', 2)],
4562
+ fields=[
4563
+ ('connection_handle', 2),
4564
+ ('reason', {'size': 1, 'mapper': HCI_Constant.error_name}),
4565
+ ],
4455
4566
  )
4456
4567
  class HCI_LE_Reject_CIS_Request_Command(HCI_Command):
4457
4568
  '''
@@ -4459,6 +4570,7 @@ class HCI_LE_Reject_CIS_Request_Command(HCI_Command):
4459
4570
  '''
4460
4571
 
4461
4572
  connection_handle: int
4573
+ reason: int
4462
4574
 
4463
4575
 
4464
4576
  # -----------------------------------------------------------------------------
@@ -4467,9 +4579,9 @@ class HCI_LE_Reject_CIS_Request_Command(HCI_Command):
4467
4579
  ('connection_handle', 2),
4468
4580
  ('data_path_direction', 1),
4469
4581
  ('data_path_id', 1),
4470
- ('codec_id', 5),
4582
+ ('codec_id', CodingFormat.parse_from_bytes),
4471
4583
  ('controller_delay', 3),
4472
- ('codec_configuration', '*'),
4584
+ ('codec_configuration', 'v'),
4473
4585
  ],
4474
4586
  return_parameters_fields=[
4475
4587
  ('status', STATUS_SPEC),
@@ -4481,12 +4593,16 @@ class HCI_LE_Setup_ISO_Data_Path_Command(HCI_Command):
4481
4593
  See Bluetooth spec @ 7.8.109 LE Setup ISO Data Path command
4482
4594
  '''
4483
4595
 
4596
+ class Direction(enum.IntEnum):
4597
+ HOST_TO_CONTROLLER = 0x00
4598
+ CONTROLLER_TO_HOST = 0x01
4599
+
4484
4600
  connection_handle: int
4485
4601
  data_path_direction: int
4486
4602
  data_path_id: int
4487
- codec_id: int
4603
+ codec_id: CodingFormat
4488
4604
  controller_delay: int
4489
- codec_configuration: int
4605
+ codec_configuration: bytes
4490
4606
 
4491
4607
 
4492
4608
  # -----------------------------------------------------------------------------
@@ -5120,6 +5236,21 @@ HCI_LE_Meta_Event.subevent_classes[
5120
5236
  ] = HCI_LE_Extended_Advertising_Report_Event
5121
5237
 
5122
5238
 
5239
+ # -----------------------------------------------------------------------------
5240
+ @HCI_LE_Meta_Event.event(
5241
+ [
5242
+ ('status', 1),
5243
+ ('advertising_handle', 1),
5244
+ ('connection_handle', 2),
5245
+ ('number_completed_extended_advertising_events', 1),
5246
+ ]
5247
+ )
5248
+ class HCI_LE_Advertising_Set_Terminated_Event(HCI_LE_Meta_Event):
5249
+ '''
5250
+ See Bluetooth spec @ 7.7.65.18 LE Advertising Set Terminated Event
5251
+ '''
5252
+
5253
+
5123
5254
  # -----------------------------------------------------------------------------
5124
5255
  @HCI_LE_Meta_Event.event([('connection_handle', 2), ('channel_selection_algorithm', 1)])
5125
5256
  class HCI_LE_Channel_Selection_Algorithm_Event(HCI_LE_Meta_Event):
@@ -5296,6 +5427,10 @@ class HCI_Disconnection_Complete_Event(HCI_Event):
5296
5427
  See Bluetooth spec @ 7.7.5 Disconnection Complete Event
5297
5428
  '''
5298
5429
 
5430
+ status: int
5431
+ connection_handle: int
5432
+ reason: int
5433
+
5299
5434
 
5300
5435
  # -----------------------------------------------------------------------------
5301
5436
  @HCI_Event.event([('status', STATUS_SPEC), ('connection_handle', 2)])
@@ -6049,7 +6184,7 @@ class HCI_IsoDataPacket(HCI_Packet):
6049
6184
  if ts_flag:
6050
6185
  if not should_include_sdu_info:
6051
6186
  logger.warn(f'Timestamp included when pb_flag={bin(pb_flag)}')
6052
- time_stamp, _ = struct.unpack_from('<I', packet, pos)
6187
+ time_stamp, *_ = struct.unpack_from('<I', packet, pos)
6053
6188
  pos += 4
6054
6189
 
6055
6190
  if should_include_sdu_info:
@@ -6116,7 +6251,7 @@ class HCI_IsoDataPacket(HCI_Packet):
6116
6251
  self.packet_sequence_number,
6117
6252
  self.iso_sdu_length | self.packet_status_flag << 14,
6118
6253
  ]
6119
- return struct.pack(fmt, args) + self.iso_sdu_fragment
6254
+ return struct.pack(fmt, *args) + self.iso_sdu_fragment
6120
6255
 
6121
6256
  def __str__(self) -> str:
6122
6257
  return (