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/_version.py +2 -2
- bumble/apps/bench.py +110 -81
- bumble/apps/ble_rpa_tool.py +63 -0
- bumble/apps/console.py +4 -4
- bumble/apps/controller_info.py +34 -2
- bumble/apps/pair.py +6 -8
- bumble/att.py +53 -11
- bumble/controller.py +28 -1
- bumble/crypto.py +10 -0
- bumble/device.py +630 -134
- bumble/drivers/__init__.py +27 -31
- bumble/drivers/common.py +45 -0
- bumble/drivers/rtk.py +11 -4
- bumble/gatt.py +183 -58
- bumble/gatt_client.py +56 -20
- bumble/gatt_server.py +30 -22
- bumble/hci.py +227 -92
- bumble/helpers.py +81 -42
- bumble/hfp.py +37 -27
- bumble/hid.py +282 -61
- bumble/host.py +158 -93
- bumble/l2cap.py +11 -3
- bumble/profiles/asha_service.py +2 -2
- bumble/profiles/bap.py +1247 -0
- bumble/profiles/cap.py +52 -0
- bumble/profiles/csip.py +205 -0
- bumble/rfcomm.py +24 -17
- bumble/smp.py +1 -1
- bumble/transport/__init__.py +49 -21
- bumble/transport/android_emulator.py +1 -1
- bumble/transport/common.py +3 -2
- bumble/transport/hci_socket.py +1 -4
- bumble/transport/usb.py +1 -1
- bumble/utils.py +3 -6
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/METADATA +1 -1
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/RECORD +40 -35
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/entry_points.txt +1 -0
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/LICENSE +0 -0
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/WHEEL +0 -0
- {bumble-0.0.179.dist-info → bumble-0.0.181.dist-info}/top_level.txt +0 -0
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
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
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
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
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',
|
|
2449
|
-
('receive_coding_format',
|
|
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',
|
|
2455
|
-
('output_coding_format',
|
|
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',
|
|
2529
|
-
('receive_coding_format',
|
|
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',
|
|
2535
|
-
('output_coding_format',
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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=[
|
|
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',
|
|
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:
|
|
4603
|
+
codec_id: CodingFormat
|
|
4488
4604
|
controller_delay: int
|
|
4489
|
-
codec_configuration:
|
|
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 (
|