bumble 0.0.194__py3-none-any.whl → 0.0.198__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/auracast.py +692 -0
- bumble/apps/bench.py +77 -23
- bumble/apps/console.py +5 -20
- bumble/apps/controller_info.py +3 -3
- bumble/apps/device_info.py +230 -0
- bumble/apps/gatt_dump.py +4 -0
- bumble/apps/lea_unicast/app.py +16 -17
- bumble/at.py +12 -6
- bumble/avc.py +8 -5
- bumble/avctp.py +3 -2
- bumble/avdtp.py +5 -1
- bumble/avrcp.py +2 -1
- bumble/codecs.py +17 -13
- bumble/colors.py +6 -2
- bumble/core.py +726 -122
- bumble/device.py +817 -117
- bumble/drivers/rtk.py +13 -8
- bumble/gatt.py +6 -1
- bumble/gatt_client.py +10 -4
- bumble/hci.py +283 -20
- bumble/hid.py +24 -28
- bumble/host.py +29 -0
- bumble/l2cap.py +24 -17
- bumble/link.py +8 -3
- bumble/pandora/host.py +3 -2
- bumble/profiles/ascs.py +739 -0
- bumble/profiles/bap.py +85 -862
- bumble/profiles/bass.py +440 -0
- bumble/profiles/csip.py +4 -4
- bumble/profiles/gap.py +110 -0
- bumble/profiles/heart_rate_service.py +4 -3
- bumble/profiles/le_audio.py +83 -0
- bumble/profiles/mcp.py +448 -0
- bumble/profiles/pacs.py +210 -0
- bumble/profiles/pbp.py +46 -0
- bumble/profiles/tmap.py +89 -0
- bumble/rfcomm.py +14 -3
- bumble/sdp.py +13 -11
- bumble/smp.py +20 -8
- bumble/snoop.py +5 -4
- bumble/transport/__init__.py +8 -2
- bumble/transport/android_emulator.py +9 -3
- bumble/transport/android_netsim.py +9 -7
- bumble/transport/common.py +46 -18
- bumble/transport/pyusb.py +2 -2
- bumble/transport/unix.py +56 -0
- bumble/transport/usb.py +57 -46
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/METADATA +41 -41
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/RECORD +54 -43
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/WHEEL +1 -1
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/LICENSE +0 -0
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.194.dist-info → bumble-0.0.198.dist-info}/top_level.txt +0 -0
bumble/drivers/rtk.py
CHANGED
|
@@ -33,6 +33,7 @@ from typing import Tuple
|
|
|
33
33
|
import weakref
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
from bumble import core
|
|
36
37
|
from bumble.hci import (
|
|
37
38
|
hci_vendor_command_op_code,
|
|
38
39
|
STATUS_SPEC,
|
|
@@ -49,6 +50,10 @@ from bumble.drivers import common
|
|
|
49
50
|
logger = logging.getLogger(__name__)
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
class RtkFirmwareError(core.BaseBumbleError):
|
|
54
|
+
"""Error raised when RTK firmware initialization fails."""
|
|
55
|
+
|
|
56
|
+
|
|
52
57
|
# -----------------------------------------------------------------------------
|
|
53
58
|
# Constants
|
|
54
59
|
# -----------------------------------------------------------------------------
|
|
@@ -208,15 +213,15 @@ class Firmware:
|
|
|
208
213
|
extension_sig = bytes([0x51, 0x04, 0xFD, 0x77])
|
|
209
214
|
|
|
210
215
|
if not firmware.startswith(RTK_EPATCH_SIGNATURE):
|
|
211
|
-
raise
|
|
216
|
+
raise RtkFirmwareError("Firmware does not start with epatch signature")
|
|
212
217
|
|
|
213
218
|
if not firmware.endswith(extension_sig):
|
|
214
|
-
raise
|
|
219
|
+
raise RtkFirmwareError("Firmware does not end with extension sig")
|
|
215
220
|
|
|
216
221
|
# The firmware should start with a 14 byte header.
|
|
217
222
|
epatch_header_size = 14
|
|
218
223
|
if len(firmware) < epatch_header_size:
|
|
219
|
-
raise
|
|
224
|
+
raise RtkFirmwareError("Firmware too short")
|
|
220
225
|
|
|
221
226
|
# Look for the "project ID", starting from the end.
|
|
222
227
|
offset = len(firmware) - len(extension_sig)
|
|
@@ -230,7 +235,7 @@ class Firmware:
|
|
|
230
235
|
break
|
|
231
236
|
|
|
232
237
|
if length == 0:
|
|
233
|
-
raise
|
|
238
|
+
raise RtkFirmwareError("Invalid 0-length instruction")
|
|
234
239
|
|
|
235
240
|
if opcode == 0 and length == 1:
|
|
236
241
|
project_id = firmware[offset - 1]
|
|
@@ -239,7 +244,7 @@ class Firmware:
|
|
|
239
244
|
offset -= length
|
|
240
245
|
|
|
241
246
|
if project_id < 0:
|
|
242
|
-
raise
|
|
247
|
+
raise RtkFirmwareError("Project ID not found")
|
|
243
248
|
|
|
244
249
|
self.project_id = project_id
|
|
245
250
|
|
|
@@ -252,7 +257,7 @@ class Firmware:
|
|
|
252
257
|
# <PatchLength_1><PatchLength_2>...<PatchLength_N> (16 bits each)
|
|
253
258
|
# <PatchOffset_1><PatchOffset_2>...<PatchOffset_N> (32 bits each)
|
|
254
259
|
if epatch_header_size + 8 * num_patches > len(firmware):
|
|
255
|
-
raise
|
|
260
|
+
raise RtkFirmwareError("Firmware too short")
|
|
256
261
|
chip_id_table_offset = epatch_header_size
|
|
257
262
|
patch_length_table_offset = chip_id_table_offset + 2 * num_patches
|
|
258
263
|
patch_offset_table_offset = chip_id_table_offset + 4 * num_patches
|
|
@@ -266,7 +271,7 @@ class Firmware:
|
|
|
266
271
|
"<I", firmware, patch_offset_table_offset + 4 * patch_index
|
|
267
272
|
)
|
|
268
273
|
if patch_offset + patch_length > len(firmware):
|
|
269
|
-
raise
|
|
274
|
+
raise RtkFirmwareError("Firmware too short")
|
|
270
275
|
|
|
271
276
|
# Get the SVN version for the patch
|
|
272
277
|
(svn_version,) = struct.unpack_from(
|
|
@@ -645,7 +650,7 @@ class Driver(common.Driver):
|
|
|
645
650
|
):
|
|
646
651
|
return await self.download_for_rtl8723b()
|
|
647
652
|
|
|
648
|
-
raise
|
|
653
|
+
raise RtkFirmwareError("ROM not supported")
|
|
649
654
|
|
|
650
655
|
async def init_controller(self):
|
|
651
656
|
await self.download_firmware()
|
bumble/gatt.py
CHANGED
|
@@ -39,7 +39,7 @@ from typing import (
|
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
from bumble.colors import color
|
|
42
|
-
from bumble.core import UUID
|
|
42
|
+
from bumble.core import BaseBumbleError, UUID
|
|
43
43
|
from bumble.att import Attribute, AttributeValue
|
|
44
44
|
|
|
45
45
|
if TYPE_CHECKING:
|
|
@@ -320,6 +320,11 @@ def show_services(services: Iterable[Service]) -> None:
|
|
|
320
320
|
print(color(' ' + str(descriptor), 'green'))
|
|
321
321
|
|
|
322
322
|
|
|
323
|
+
# -----------------------------------------------------------------------------
|
|
324
|
+
class InvalidServiceError(BaseBumbleError):
|
|
325
|
+
"""The service is not compliant with the spec/profile"""
|
|
326
|
+
|
|
327
|
+
|
|
323
328
|
# -----------------------------------------------------------------------------
|
|
324
329
|
class Service(Attribute):
|
|
325
330
|
'''
|
bumble/gatt_client.py
CHANGED
|
@@ -253,7 +253,7 @@ class ProfileServiceProxy:
|
|
|
253
253
|
SERVICE_CLASS: Type[TemplateService]
|
|
254
254
|
|
|
255
255
|
@classmethod
|
|
256
|
-
def from_client(cls, client: Client) -> ProfileServiceProxy:
|
|
256
|
+
def from_client(cls, client: Client) -> Optional[ProfileServiceProxy]:
|
|
257
257
|
return ServiceProxy.from_client(cls, client, cls.SERVICE_CLASS.UUID)
|
|
258
258
|
|
|
259
259
|
|
|
@@ -283,6 +283,8 @@ class Client:
|
|
|
283
283
|
self.services = []
|
|
284
284
|
self.cached_values = {}
|
|
285
285
|
|
|
286
|
+
connection.on('disconnection', self.on_disconnection)
|
|
287
|
+
|
|
286
288
|
def send_gatt_pdu(self, pdu: bytes) -> None:
|
|
287
289
|
self.connection.send_l2cap_pdu(ATT_CID, pdu)
|
|
288
290
|
|
|
@@ -331,9 +333,9 @@ class Client:
|
|
|
331
333
|
async def request_mtu(self, mtu: int) -> int:
|
|
332
334
|
# Check the range
|
|
333
335
|
if mtu < ATT_DEFAULT_MTU:
|
|
334
|
-
raise
|
|
336
|
+
raise core.InvalidArgumentError(f'MTU must be >= {ATT_DEFAULT_MTU}')
|
|
335
337
|
if mtu > 0xFFFF:
|
|
336
|
-
raise
|
|
338
|
+
raise core.InvalidArgumentError('MTU must be <= 0xFFFF')
|
|
337
339
|
|
|
338
340
|
# We can only send one request per connection
|
|
339
341
|
if self.mtu_exchange_done:
|
|
@@ -405,7 +407,7 @@ class Client:
|
|
|
405
407
|
if not already_known:
|
|
406
408
|
self.services.append(service)
|
|
407
409
|
|
|
408
|
-
async def discover_services(self, uuids: Iterable[UUID] =
|
|
410
|
+
async def discover_services(self, uuids: Iterable[UUID] = ()) -> List[ServiceProxy]:
|
|
409
411
|
'''
|
|
410
412
|
See Vol 3, Part G - 4.4.1 Discover All Primary Services
|
|
411
413
|
'''
|
|
@@ -1072,6 +1074,10 @@ class Client:
|
|
|
1072
1074
|
)
|
|
1073
1075
|
)
|
|
1074
1076
|
|
|
1077
|
+
def on_disconnection(self, _) -> None:
|
|
1078
|
+
if self.pending_response and not self.pending_response.done():
|
|
1079
|
+
self.pending_response.cancel()
|
|
1080
|
+
|
|
1075
1081
|
def on_gatt_pdu(self, att_pdu: ATT_PDU) -> None:
|
|
1076
1082
|
logger.debug(
|
|
1077
1083
|
f'GATT Response to client: [0x{self.connection.handle:04X}] {att_pdu}'
|
bumble/hci.py
CHANGED
|
@@ -26,16 +26,19 @@ import struct
|
|
|
26
26
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Type, Union, ClassVar
|
|
27
27
|
|
|
28
28
|
from bumble import crypto
|
|
29
|
-
from .colors import color
|
|
30
|
-
from .core import (
|
|
29
|
+
from bumble.colors import color
|
|
30
|
+
from bumble.core import (
|
|
31
31
|
BT_BR_EDR_TRANSPORT,
|
|
32
32
|
AdvertisingData,
|
|
33
33
|
DeviceClass,
|
|
34
|
+
InvalidArgumentError,
|
|
35
|
+
InvalidPacketError,
|
|
34
36
|
ProtocolError,
|
|
35
37
|
bit_flags_to_strings,
|
|
36
38
|
name_or_number,
|
|
37
39
|
padded_bytes,
|
|
38
40
|
)
|
|
41
|
+
from bumble.utils import OpenIntEnum
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
# -----------------------------------------------------------------------------
|
|
@@ -91,14 +94,14 @@ def map_class_of_device(class_of_device):
|
|
|
91
94
|
)
|
|
92
95
|
|
|
93
96
|
|
|
94
|
-
def phy_list_to_bits(phys):
|
|
97
|
+
def phy_list_to_bits(phys: Optional[Iterable[int]]) -> int:
|
|
95
98
|
if phys is None:
|
|
96
99
|
return 0
|
|
97
100
|
|
|
98
101
|
phy_bits = 0
|
|
99
102
|
for phy in phys:
|
|
100
103
|
if phy not in HCI_LE_PHY_TYPE_TO_BIT:
|
|
101
|
-
raise
|
|
104
|
+
raise InvalidArgumentError('invalid PHY')
|
|
102
105
|
phy_bits |= 1 << HCI_LE_PHY_TYPE_TO_BIT[phy]
|
|
103
106
|
return phy_bits
|
|
104
107
|
|
|
@@ -1104,7 +1107,7 @@ HCI_SUPPORTED_COMMANDS_MASKS = {
|
|
|
1104
1107
|
|
|
1105
1108
|
# LE Supported Features
|
|
1106
1109
|
# See Bluetooth spec @ Vol 6, Part B, 4.6 FEATURE SUPPORT
|
|
1107
|
-
class LeFeature(
|
|
1110
|
+
class LeFeature(OpenIntEnum):
|
|
1108
1111
|
LE_ENCRYPTION = 0
|
|
1109
1112
|
CONNECTION_PARAMETERS_REQUEST_PROCEDURE = 1
|
|
1110
1113
|
EXTENDED_REJECT_INDICATION = 2
|
|
@@ -1380,7 +1383,7 @@ class LmpFeatureMask(enum.IntFlag):
|
|
|
1380
1383
|
STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)}
|
|
1381
1384
|
|
|
1382
1385
|
|
|
1383
|
-
class CodecID(
|
|
1386
|
+
class CodecID(OpenIntEnum):
|
|
1384
1387
|
# fmt: off
|
|
1385
1388
|
U_LOG = 0x00
|
|
1386
1389
|
A_LOG = 0x01
|
|
@@ -1552,7 +1555,7 @@ class HCI_Object:
|
|
|
1552
1555
|
new_offset, field_value = field_type(data, offset)
|
|
1553
1556
|
return (field_value, new_offset - offset)
|
|
1554
1557
|
|
|
1555
|
-
raise
|
|
1558
|
+
raise InvalidArgumentError(f'unknown field type {field_type}')
|
|
1556
1559
|
|
|
1557
1560
|
@staticmethod
|
|
1558
1561
|
def dict_from_bytes(data, offset, fields):
|
|
@@ -1621,7 +1624,7 @@ class HCI_Object:
|
|
|
1621
1624
|
if 0 <= field_value <= 255:
|
|
1622
1625
|
field_bytes = bytes([field_value])
|
|
1623
1626
|
else:
|
|
1624
|
-
raise
|
|
1627
|
+
raise InvalidArgumentError('value too large for *-typed field')
|
|
1625
1628
|
else:
|
|
1626
1629
|
field_bytes = bytes(field_value)
|
|
1627
1630
|
elif field_type == 'v':
|
|
@@ -1640,7 +1643,9 @@ class HCI_Object:
|
|
|
1640
1643
|
elif len(field_bytes) > field_type:
|
|
1641
1644
|
field_bytes = field_bytes[:field_type]
|
|
1642
1645
|
else:
|
|
1643
|
-
raise
|
|
1646
|
+
raise InvalidArgumentError(
|
|
1647
|
+
f"don't know how to serialize type {type(field_value)}"
|
|
1648
|
+
)
|
|
1644
1649
|
|
|
1645
1650
|
return field_bytes
|
|
1646
1651
|
|
|
@@ -1834,6 +1839,12 @@ class Address:
|
|
|
1834
1839
|
data, offset, Address.PUBLIC_DEVICE_ADDRESS
|
|
1835
1840
|
)
|
|
1836
1841
|
|
|
1842
|
+
@staticmethod
|
|
1843
|
+
def parse_random_address(data, offset):
|
|
1844
|
+
return Address.parse_address_with_type(
|
|
1845
|
+
data, offset, Address.RANDOM_DEVICE_ADDRESS
|
|
1846
|
+
)
|
|
1847
|
+
|
|
1837
1848
|
@staticmethod
|
|
1838
1849
|
def parse_address_with_type(data, offset, address_type):
|
|
1839
1850
|
return offset + 6, Address(data[offset : offset + 6], address_type)
|
|
@@ -1904,7 +1915,7 @@ class Address:
|
|
|
1904
1915
|
self.address_bytes = bytes(reversed(bytes.fromhex(address)))
|
|
1905
1916
|
|
|
1906
1917
|
if len(self.address_bytes) != 6:
|
|
1907
|
-
raise
|
|
1918
|
+
raise InvalidArgumentError('invalid address length')
|
|
1908
1919
|
|
|
1909
1920
|
self.address_type = address_type
|
|
1910
1921
|
|
|
@@ -1960,13 +1971,17 @@ class Address:
|
|
|
1960
1971
|
|
|
1961
1972
|
def __eq__(self, other):
|
|
1962
1973
|
return (
|
|
1963
|
-
|
|
1974
|
+
isinstance(other, Address)
|
|
1975
|
+
and self.address_bytes == other.address_bytes
|
|
1964
1976
|
and self.is_public == other.is_public
|
|
1965
1977
|
)
|
|
1966
1978
|
|
|
1967
1979
|
def __str__(self):
|
|
1968
1980
|
return self.to_string()
|
|
1969
1981
|
|
|
1982
|
+
def __repr__(self):
|
|
1983
|
+
return f'Address({self.to_string(False)}/{self.address_type_name(self.address_type)})'
|
|
1984
|
+
|
|
1970
1985
|
|
|
1971
1986
|
# Predefined address values
|
|
1972
1987
|
Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS)
|
|
@@ -2104,7 +2119,7 @@ class HCI_Command(HCI_Packet):
|
|
|
2104
2119
|
op_code, length = struct.unpack_from('<HB', packet, 1)
|
|
2105
2120
|
parameters = packet[4:]
|
|
2106
2121
|
if len(parameters) != length:
|
|
2107
|
-
raise
|
|
2122
|
+
raise InvalidPacketError('invalid packet length')
|
|
2108
2123
|
|
|
2109
2124
|
# Look for a registered class
|
|
2110
2125
|
cls = HCI_Command.command_classes.get(op_code)
|
|
@@ -4452,6 +4467,68 @@ class HCI_LE_Extended_Create_Connection_Command(HCI_Command):
|
|
|
4452
4467
|
)
|
|
4453
4468
|
|
|
4454
4469
|
|
|
4470
|
+
# -----------------------------------------------------------------------------
|
|
4471
|
+
@HCI_Command.command(
|
|
4472
|
+
[
|
|
4473
|
+
(
|
|
4474
|
+
'options',
|
|
4475
|
+
{
|
|
4476
|
+
'size': 1,
|
|
4477
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Create_Sync_Command.Options(
|
|
4478
|
+
x
|
|
4479
|
+
).name,
|
|
4480
|
+
},
|
|
4481
|
+
),
|
|
4482
|
+
('advertising_sid', 1),
|
|
4483
|
+
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
4484
|
+
('advertiser_address', Address.parse_address_preceded_by_type),
|
|
4485
|
+
('skip', 2),
|
|
4486
|
+
('sync_timeout', 2),
|
|
4487
|
+
(
|
|
4488
|
+
'sync_cte_type',
|
|
4489
|
+
{
|
|
4490
|
+
'size': 1,
|
|
4491
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Create_Sync_Command.CteType(
|
|
4492
|
+
x
|
|
4493
|
+
).name,
|
|
4494
|
+
},
|
|
4495
|
+
),
|
|
4496
|
+
]
|
|
4497
|
+
)
|
|
4498
|
+
class HCI_LE_Periodic_Advertising_Create_Sync_Command(HCI_Command):
|
|
4499
|
+
'''
|
|
4500
|
+
See Bluetooth spec @ 7.8.67 LE Periodic Advertising Create Sync command
|
|
4501
|
+
'''
|
|
4502
|
+
|
|
4503
|
+
class Options(enum.IntFlag):
|
|
4504
|
+
USE_PERIODIC_ADVERTISER_LIST = 1 << 0
|
|
4505
|
+
REPORTING_INITIALLY_DISABLED = 1 << 1
|
|
4506
|
+
DUPLICATE_FILTERING_INITIALLY_ENABLED = 1 << 2
|
|
4507
|
+
|
|
4508
|
+
class CteType(enum.IntFlag):
|
|
4509
|
+
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOA_CONSTANT_TONE_EXTENSION = 1 << 0
|
|
4510
|
+
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOD_CONSTANT_TONE_EXTENSION_1US = 1 << 1
|
|
4511
|
+
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOD_CONSTANT_TONE_EXTENSION_2US = 1 << 2
|
|
4512
|
+
DO_NOT_SYNC_TO_PACKETS_WITH_A_TYPE_3_CONSTANT_TONE_EXTENSION = 1 << 3
|
|
4513
|
+
DO_NOT_SYNC_TO_PACKETS_WITHOUT_A_CONSTANT_TONE_EXTENSION = 1 << 4
|
|
4514
|
+
|
|
4515
|
+
|
|
4516
|
+
# -----------------------------------------------------------------------------
|
|
4517
|
+
@HCI_Command.command()
|
|
4518
|
+
class HCI_LE_Periodic_Advertising_Create_Sync_Cancel_Command(HCI_Command):
|
|
4519
|
+
'''
|
|
4520
|
+
See Bluetooth spec @ 7.8.68 LE Periodic Advertising Create Sync Cancel Command
|
|
4521
|
+
'''
|
|
4522
|
+
|
|
4523
|
+
|
|
4524
|
+
# -----------------------------------------------------------------------------
|
|
4525
|
+
@HCI_Command.command([('sync_handle', 2)])
|
|
4526
|
+
class HCI_LE_Periodic_Advertising_Terminate_Sync_Command(HCI_Command):
|
|
4527
|
+
'''
|
|
4528
|
+
See Bluetooth spec @ 7.8.69 LE Periodic Advertising Terminate Sync Command
|
|
4529
|
+
'''
|
|
4530
|
+
|
|
4531
|
+
|
|
4455
4532
|
# -----------------------------------------------------------------------------
|
|
4456
4533
|
@HCI_Command.command(
|
|
4457
4534
|
[
|
|
@@ -4488,10 +4565,28 @@ class HCI_LE_Set_Privacy_Mode_Command(HCI_Command):
|
|
|
4488
4565
|
|
|
4489
4566
|
|
|
4490
4567
|
# -----------------------------------------------------------------------------
|
|
4491
|
-
@HCI_Command.command([('
|
|
4492
|
-
class
|
|
4568
|
+
@HCI_Command.command([('sync_handle', 2), ('enable', 1)])
|
|
4569
|
+
class HCI_LE_Set_Periodic_Advertising_Receive_Enable_Command(HCI_Command):
|
|
4493
4570
|
'''
|
|
4494
|
-
See Bluetooth spec @ 7.8.
|
|
4571
|
+
See Bluetooth spec @ 7.8.88 LE Set Periodic Advertising Receive Enable Command
|
|
4572
|
+
'''
|
|
4573
|
+
|
|
4574
|
+
class Enable(enum.IntFlag):
|
|
4575
|
+
REPORTING_ENABLED = 1 << 0
|
|
4576
|
+
DUPLICATE_FILTERING_ENABLED = 1 << 1
|
|
4577
|
+
|
|
4578
|
+
|
|
4579
|
+
# -----------------------------------------------------------------------------
|
|
4580
|
+
@HCI_Command.command(
|
|
4581
|
+
fields=[('connection_handle', 2), ('service_data', 2), ('sync_handle', 2)],
|
|
4582
|
+
return_parameters_fields=[
|
|
4583
|
+
('status', STATUS_SPEC),
|
|
4584
|
+
('connection_handle', 2),
|
|
4585
|
+
],
|
|
4586
|
+
)
|
|
4587
|
+
class HCI_LE_Periodic_Advertising_Sync_Transfer_Command(HCI_Command):
|
|
4588
|
+
'''
|
|
4589
|
+
See Bluetooth spec @ 7.8.89 LE Periodic Advertising Sync Transfer Command
|
|
4495
4590
|
'''
|
|
4496
4591
|
|
|
4497
4592
|
|
|
@@ -4655,6 +4750,14 @@ class HCI_LE_Remove_ISO_Data_Path_Command(HCI_Command):
|
|
|
4655
4750
|
data_path_direction: int
|
|
4656
4751
|
|
|
4657
4752
|
|
|
4753
|
+
# -----------------------------------------------------------------------------
|
|
4754
|
+
@HCI_Command.command([('bit_number', 1), ('bit_value', 1)])
|
|
4755
|
+
class HCI_LE_Set_Host_Feature_Command(HCI_Command):
|
|
4756
|
+
'''
|
|
4757
|
+
See Bluetooth spec @ 7.8.115 LE Set Host Feature Command
|
|
4758
|
+
'''
|
|
4759
|
+
|
|
4760
|
+
|
|
4658
4761
|
# -----------------------------------------------------------------------------
|
|
4659
4762
|
# HCI Events
|
|
4660
4763
|
# -----------------------------------------------------------------------------
|
|
@@ -4729,7 +4832,7 @@ class HCI_Event(HCI_Packet):
|
|
|
4729
4832
|
length = packet[2]
|
|
4730
4833
|
parameters = packet[3:]
|
|
4731
4834
|
if len(parameters) != length:
|
|
4732
|
-
raise
|
|
4835
|
+
raise InvalidPacketError('invalid packet length')
|
|
4733
4836
|
|
|
4734
4837
|
cls: Any
|
|
4735
4838
|
if event_code == HCI_LE_META_EVENT:
|
|
@@ -5096,8 +5199,8 @@ class HCI_LE_Data_Length_Change_Event(HCI_LE_Meta_Event):
|
|
|
5096
5199
|
),
|
|
5097
5200
|
('peer_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
5098
5201
|
('peer_address', Address.parse_address_preceded_by_type),
|
|
5099
|
-
('local_resolvable_private_address', Address.
|
|
5100
|
-
('peer_resolvable_private_address', Address.
|
|
5202
|
+
('local_resolvable_private_address', Address.parse_random_address),
|
|
5203
|
+
('peer_resolvable_private_address', Address.parse_random_address),
|
|
5101
5204
|
('connection_interval', 2),
|
|
5102
5205
|
('peripheral_latency', 2),
|
|
5103
5206
|
('supervision_timeout', 2),
|
|
@@ -5271,6 +5374,142 @@ HCI_LE_Meta_Event.subevent_classes[HCI_LE_EXTENDED_ADVERTISING_REPORT_EVENT] = (
|
|
|
5271
5374
|
)
|
|
5272
5375
|
|
|
5273
5376
|
|
|
5377
|
+
# -----------------------------------------------------------------------------
|
|
5378
|
+
@HCI_LE_Meta_Event.event(
|
|
5379
|
+
[
|
|
5380
|
+
('status', STATUS_SPEC),
|
|
5381
|
+
('sync_handle', 2),
|
|
5382
|
+
('advertising_sid', 1),
|
|
5383
|
+
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
5384
|
+
('advertiser_address', Address.parse_address_preceded_by_type),
|
|
5385
|
+
('advertiser_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
5386
|
+
('periodic_advertising_interval', 2),
|
|
5387
|
+
('advertiser_clock_accuracy', 1),
|
|
5388
|
+
]
|
|
5389
|
+
)
|
|
5390
|
+
class HCI_LE_Periodic_Advertising_Sync_Established_Event(HCI_LE_Meta_Event):
|
|
5391
|
+
'''
|
|
5392
|
+
See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event
|
|
5393
|
+
'''
|
|
5394
|
+
|
|
5395
|
+
|
|
5396
|
+
# -----------------------------------------------------------------------------
|
|
5397
|
+
@HCI_LE_Meta_Event.event(
|
|
5398
|
+
[
|
|
5399
|
+
('status', STATUS_SPEC),
|
|
5400
|
+
('sync_handle', 2),
|
|
5401
|
+
('advertising_sid', 1),
|
|
5402
|
+
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
|
|
5403
|
+
('advertiser_address', Address.parse_address_preceded_by_type),
|
|
5404
|
+
('advertiser_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
5405
|
+
('periodic_advertising_interval', 2),
|
|
5406
|
+
('advertiser_clock_accuracy', 1),
|
|
5407
|
+
('num_subevents', 1),
|
|
5408
|
+
('subevent_interval', 1),
|
|
5409
|
+
('response_slot_delay', 1),
|
|
5410
|
+
('response_slot_spacing', 1),
|
|
5411
|
+
]
|
|
5412
|
+
)
|
|
5413
|
+
class HCI_LE_Periodic_Advertising_Sync_Established_V2_Event(HCI_LE_Meta_Event):
|
|
5414
|
+
'''
|
|
5415
|
+
See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event
|
|
5416
|
+
'''
|
|
5417
|
+
|
|
5418
|
+
|
|
5419
|
+
# -----------------------------------------------------------------------------
|
|
5420
|
+
@HCI_LE_Meta_Event.event(
|
|
5421
|
+
[
|
|
5422
|
+
('sync_handle', 2),
|
|
5423
|
+
('tx_power', -1),
|
|
5424
|
+
('rssi', -1),
|
|
5425
|
+
(
|
|
5426
|
+
'cte_type',
|
|
5427
|
+
{
|
|
5428
|
+
'size': 1,
|
|
5429
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.CteType(
|
|
5430
|
+
x
|
|
5431
|
+
).name,
|
|
5432
|
+
},
|
|
5433
|
+
),
|
|
5434
|
+
(
|
|
5435
|
+
'data_status',
|
|
5436
|
+
{
|
|
5437
|
+
'size': 1,
|
|
5438
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.DataStatus(
|
|
5439
|
+
x
|
|
5440
|
+
).name,
|
|
5441
|
+
},
|
|
5442
|
+
),
|
|
5443
|
+
('data', 'v'),
|
|
5444
|
+
]
|
|
5445
|
+
)
|
|
5446
|
+
class HCI_LE_Periodic_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
5447
|
+
'''
|
|
5448
|
+
See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event
|
|
5449
|
+
'''
|
|
5450
|
+
|
|
5451
|
+
TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F
|
|
5452
|
+
RSSI_NOT_AVAILABLE = 0x7F
|
|
5453
|
+
|
|
5454
|
+
class CteType(OpenIntEnum):
|
|
5455
|
+
AOA_CONSTANT_TONE_EXTENSION = 0x00
|
|
5456
|
+
AOD_CONSTANT_TONE_EXTENSION_1US = 0x01
|
|
5457
|
+
AOD_CONSTANT_TONE_EXTENSION_2US = 0x02
|
|
5458
|
+
NO_CONSTANT_TONE_EXTENSION = 0xFF
|
|
5459
|
+
|
|
5460
|
+
class DataStatus(OpenIntEnum):
|
|
5461
|
+
DATA_COMPLETE = 0x00
|
|
5462
|
+
DATA_INCOMPLETE_MORE_TO_COME = 0x01
|
|
5463
|
+
DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02
|
|
5464
|
+
|
|
5465
|
+
|
|
5466
|
+
# -----------------------------------------------------------------------------
|
|
5467
|
+
@HCI_LE_Meta_Event.event(
|
|
5468
|
+
[
|
|
5469
|
+
('sync_handle', 2),
|
|
5470
|
+
('tx_power', -1),
|
|
5471
|
+
('rssi', -1),
|
|
5472
|
+
(
|
|
5473
|
+
'cte_type',
|
|
5474
|
+
{
|
|
5475
|
+
'size': 1,
|
|
5476
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.CteType(
|
|
5477
|
+
x
|
|
5478
|
+
).name,
|
|
5479
|
+
},
|
|
5480
|
+
),
|
|
5481
|
+
('periodic_event_counter', 2),
|
|
5482
|
+
('subevent', 1),
|
|
5483
|
+
(
|
|
5484
|
+
'data_status',
|
|
5485
|
+
{
|
|
5486
|
+
'size': 1,
|
|
5487
|
+
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.DataStatus(
|
|
5488
|
+
x
|
|
5489
|
+
).name,
|
|
5490
|
+
},
|
|
5491
|
+
),
|
|
5492
|
+
('data', 'v'),
|
|
5493
|
+
]
|
|
5494
|
+
)
|
|
5495
|
+
class HCI_LE_Periodic_Advertising_Report_V2_Event(HCI_LE_Meta_Event):
|
|
5496
|
+
'''
|
|
5497
|
+
See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event
|
|
5498
|
+
'''
|
|
5499
|
+
|
|
5500
|
+
|
|
5501
|
+
# -----------------------------------------------------------------------------
|
|
5502
|
+
@HCI_LE_Meta_Event.event(
|
|
5503
|
+
[
|
|
5504
|
+
('sync_handle', 2),
|
|
5505
|
+
]
|
|
5506
|
+
)
|
|
5507
|
+
class HCI_LE_Periodic_Advertising_Sync_Lost_Event(HCI_LE_Meta_Event):
|
|
5508
|
+
'''
|
|
5509
|
+
See Bluetooth spec @ 7.7.65.16 LE Periodic Advertising Sync Lost Event
|
|
5510
|
+
'''
|
|
5511
|
+
|
|
5512
|
+
|
|
5274
5513
|
# -----------------------------------------------------------------------------
|
|
5275
5514
|
@HCI_LE_Meta_Event.event(
|
|
5276
5515
|
[
|
|
@@ -5336,6 +5575,30 @@ class HCI_LE_CIS_Request_Event(HCI_LE_Meta_Event):
|
|
|
5336
5575
|
'''
|
|
5337
5576
|
|
|
5338
5577
|
|
|
5578
|
+
# -----------------------------------------------------------------------------
|
|
5579
|
+
@HCI_LE_Meta_Event.event(
|
|
5580
|
+
[
|
|
5581
|
+
('sync_handle', 2),
|
|
5582
|
+
('num_bis', 1),
|
|
5583
|
+
('nse', 1),
|
|
5584
|
+
('iso_interval', 2),
|
|
5585
|
+
('bn', 1),
|
|
5586
|
+
('pto', 1),
|
|
5587
|
+
('irc', 1),
|
|
5588
|
+
('max_pdu', 2),
|
|
5589
|
+
('sdu_interval', 3),
|
|
5590
|
+
('max_sdu', 2),
|
|
5591
|
+
('phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
|
|
5592
|
+
('framing', 1),
|
|
5593
|
+
('encryption', 1),
|
|
5594
|
+
]
|
|
5595
|
+
)
|
|
5596
|
+
class HCI_LE_BIGInfo_Advertising_Report_Event(HCI_LE_Meta_Event):
|
|
5597
|
+
'''
|
|
5598
|
+
See Bluetooth spec @ 7.7.65.34 LE BIGInfo Advertising Report Event
|
|
5599
|
+
'''
|
|
5600
|
+
|
|
5601
|
+
|
|
5339
5602
|
# -----------------------------------------------------------------------------
|
|
5340
5603
|
@HCI_Event.event([('status', STATUS_SPEC)])
|
|
5341
5604
|
class HCI_Inquiry_Complete_Event(HCI_Event):
|
|
@@ -6104,7 +6367,7 @@ class HCI_AclDataPacket(HCI_Packet):
|
|
|
6104
6367
|
bc_flag = (h >> 14) & 3
|
|
6105
6368
|
data = packet[5:]
|
|
6106
6369
|
if len(data) != data_total_length:
|
|
6107
|
-
raise
|
|
6370
|
+
raise InvalidPacketError('invalid packet length')
|
|
6108
6371
|
return HCI_AclDataPacket(
|
|
6109
6372
|
connection_handle, pb_flag, bc_flag, data_total_length, data
|
|
6110
6373
|
)
|
|
@@ -6152,7 +6415,7 @@ class HCI_SynchronousDataPacket(HCI_Packet):
|
|
|
6152
6415
|
packet_status = (h >> 12) & 0b11
|
|
6153
6416
|
data = packet[4:]
|
|
6154
6417
|
if len(data) != data_total_length:
|
|
6155
|
-
raise
|
|
6418
|
+
raise InvalidPacketError(
|
|
6156
6419
|
f'invalid packet length {len(data)} != {data_total_length}'
|
|
6157
6420
|
)
|
|
6158
6421
|
return HCI_SynchronousDataPacket(
|