bumble 0.0.213__py3-none-any.whl → 0.0.215__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 +16 -3
- bumble/a2dp.py +15 -16
- bumble/apps/auracast.py +14 -38
- bumble/apps/bench.py +10 -15
- bumble/apps/ble_rpa_tool.py +1 -0
- bumble/apps/console.py +22 -25
- bumble/apps/controller_info.py +20 -25
- bumble/apps/controller_loopback.py +6 -10
- bumble/apps/controllers.py +2 -3
- bumble/apps/device_info.py +4 -5
- bumble/apps/gatt_dump.py +3 -3
- bumble/apps/gg_bridge.py +7 -8
- bumble/apps/hci_bridge.py +4 -3
- bumble/apps/l2cap_bridge.py +5 -5
- bumble/apps/lea_unicast/app.py +16 -26
- bumble/apps/pair.py +30 -43
- bumble/apps/pandora_server.py +5 -4
- bumble/apps/player/player.py +20 -24
- bumble/apps/rfcomm_bridge.py +4 -10
- bumble/apps/scan.py +17 -8
- bumble/apps/show.py +4 -5
- bumble/apps/speaker/speaker.py +23 -27
- bumble/apps/unbond.py +3 -3
- bumble/apps/usb_probe.py +2 -4
- bumble/att.py +241 -246
- bumble/audio/io.py +5 -9
- bumble/avc.py +2 -2
- bumble/avctp.py +6 -7
- bumble/avdtp.py +19 -22
- bumble/avrcp.py +1097 -589
- bumble/codecs.py +2 -0
- bumble/controller.py +142 -35
- bumble/core.py +567 -248
- bumble/crypto/__init__.py +2 -2
- bumble/crypto/builtin.py +1 -1
- bumble/crypto/cryptography.py +2 -4
- bumble/data_types.py +1025 -0
- bumble/device.py +319 -267
- bumble/drivers/__init__.py +3 -2
- bumble/drivers/intel.py +3 -4
- bumble/drivers/rtk.py +26 -9
- bumble/gap.py +4 -4
- bumble/gatt.py +3 -2
- bumble/gatt_adapters.py +3 -11
- bumble/gatt_client.py +69 -81
- bumble/gatt_server.py +124 -124
- bumble/hci.py +114 -18
- bumble/helpers.py +19 -26
- bumble/hfp.py +10 -21
- bumble/hid.py +22 -16
- bumble/host.py +191 -103
- bumble/keys.py +5 -3
- bumble/l2cap.py +138 -104
- bumble/link.py +18 -19
- bumble/logging.py +65 -0
- bumble/pairing.py +7 -6
- bumble/pandora/__init__.py +9 -8
- bumble/pandora/config.py +3 -1
- bumble/pandora/device.py +3 -2
- bumble/pandora/host.py +38 -36
- bumble/pandora/l2cap.py +22 -21
- bumble/pandora/security.py +15 -15
- bumble/pandora/utils.py +5 -3
- bumble/profiles/aics.py +11 -11
- bumble/profiles/ams.py +403 -0
- bumble/profiles/ancs.py +6 -7
- bumble/profiles/ascs.py +14 -9
- bumble/profiles/asha.py +8 -12
- bumble/profiles/bap.py +11 -23
- bumble/profiles/bass.py +2 -7
- bumble/profiles/battery_service.py +3 -4
- bumble/profiles/cap.py +1 -2
- bumble/profiles/csip.py +2 -6
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +4 -4
- bumble/profiles/gatt_service.py +1 -4
- bumble/profiles/gmap.py +5 -5
- bumble/profiles/hap.py +62 -59
- bumble/profiles/heart_rate_service.py +5 -4
- bumble/profiles/le_audio.py +3 -1
- bumble/profiles/mcp.py +3 -7
- bumble/profiles/pacs.py +3 -6
- bumble/profiles/pbp.py +2 -0
- bumble/profiles/tmap.py +2 -3
- bumble/profiles/vcs.py +2 -8
- bumble/profiles/vocs.py +8 -8
- bumble/rfcomm.py +11 -14
- bumble/rtp.py +1 -0
- bumble/sdp.py +10 -8
- bumble/smp.py +151 -159
- bumble/snoop.py +5 -5
- bumble/tools/generate_company_id_list.py +1 -0
- bumble/tools/intel_fw_download.py +3 -3
- bumble/tools/intel_util.py +5 -4
- bumble/tools/rtk_fw_download.py +6 -3
- bumble/tools/rtk_util.py +26 -8
- bumble/transport/__init__.py +19 -15
- bumble/transport/android_emulator.py +8 -13
- bumble/transport/android_netsim.py +19 -18
- bumble/transport/common.py +12 -15
- bumble/transport/file.py +1 -1
- bumble/transport/hci_socket.py +4 -6
- bumble/transport/pty.py +5 -6
- bumble/transport/pyusb.py +7 -10
- bumble/transport/serial.py +2 -1
- bumble/transport/tcp_client.py +2 -2
- bumble/transport/tcp_server.py +11 -14
- bumble/transport/udp.py +3 -3
- bumble/transport/unix.py +67 -1
- bumble/transport/usb.py +6 -6
- bumble/transport/vhci.py +0 -1
- bumble/transport/ws_client.py +2 -1
- bumble/transport/ws_server.py +3 -2
- bumble/utils.py +20 -5
- bumble/vendor/android/hci.py +1 -2
- bumble/vendor/zephyr/hci.py +0 -1
- {bumble-0.0.213.dist-info → bumble-0.0.215.dist-info}/METADATA +4 -2
- bumble-0.0.215.dist-info/RECORD +183 -0
- bumble-0.0.213.dist-info/RECORD +0 -180
- {bumble-0.0.213.dist-info → bumble-0.0.215.dist-info}/WHEEL +0 -0
- {bumble-0.0.213.dist-info → bumble-0.0.215.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.213.dist-info → bumble-0.0.215.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.213.dist-info → bumble-0.0.215.dist-info}/top_level.txt +0 -0
bumble/drivers/__init__.py
CHANGED
|
@@ -20,12 +20,13 @@ like loading firmware after a cold start.
|
|
|
20
20
|
# Imports
|
|
21
21
|
# -----------------------------------------------------------------------------
|
|
22
22
|
from __future__ import annotations
|
|
23
|
+
|
|
23
24
|
import logging
|
|
24
25
|
import pathlib
|
|
25
26
|
import platform
|
|
26
|
-
from typing import Iterable, Optional
|
|
27
|
+
from typing import TYPE_CHECKING, Iterable, Optional
|
|
27
28
|
|
|
28
|
-
from bumble.drivers import
|
|
29
|
+
from bumble.drivers import intel, rtk
|
|
29
30
|
from bumble.drivers.common import Driver
|
|
30
31
|
|
|
31
32
|
if TYPE_CHECKING:
|
bumble/drivers/intel.py
CHANGED
|
@@ -20,6 +20,7 @@ Loosely based on the Fuchsia OS implementation.
|
|
|
20
20
|
# Imports
|
|
21
21
|
# -----------------------------------------------------------------------------
|
|
22
22
|
from __future__ import annotations
|
|
23
|
+
|
|
23
24
|
import asyncio
|
|
24
25
|
import collections
|
|
25
26
|
import dataclasses
|
|
@@ -28,12 +29,10 @@ import os
|
|
|
28
29
|
import pathlib
|
|
29
30
|
import platform
|
|
30
31
|
import struct
|
|
31
|
-
from typing import Any, Optional
|
|
32
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
32
33
|
|
|
33
|
-
from bumble import core
|
|
34
|
+
from bumble import core, hci, utils
|
|
34
35
|
from bumble.drivers import common
|
|
35
|
-
from bumble import hci
|
|
36
|
-
from bumble import utils
|
|
37
36
|
|
|
38
37
|
if TYPE_CHECKING:
|
|
39
38
|
from bumble.host import Host
|
bumble/drivers/rtk.py
CHANGED
|
@@ -17,10 +17,6 @@ Based on various online bits of information, including the Linux kernel.
|
|
|
17
17
|
(see `drivers/bluetooth/btrtl.c`)
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
-
# -----------------------------------------------------------------------------
|
|
21
|
-
# Imports
|
|
22
|
-
# -----------------------------------------------------------------------------
|
|
23
|
-
from dataclasses import dataclass, field
|
|
24
20
|
import asyncio
|
|
25
21
|
import enum
|
|
26
22
|
import logging
|
|
@@ -31,9 +27,12 @@ import platform
|
|
|
31
27
|
import struct
|
|
32
28
|
import weakref
|
|
33
29
|
|
|
30
|
+
# -----------------------------------------------------------------------------
|
|
31
|
+
# Imports
|
|
32
|
+
# -----------------------------------------------------------------------------
|
|
33
|
+
from dataclasses import dataclass, field
|
|
34
34
|
|
|
35
|
-
from bumble import core
|
|
36
|
-
from bumble import hci
|
|
35
|
+
from bumble import core, hci
|
|
37
36
|
from bumble.drivers import common
|
|
38
37
|
|
|
39
38
|
# -----------------------------------------------------------------------------
|
|
@@ -489,6 +488,21 @@ class Driver(common.Driver):
|
|
|
489
488
|
|
|
490
489
|
return True
|
|
491
490
|
|
|
491
|
+
@staticmethod
|
|
492
|
+
async def get_loaded_firmware_version(host):
|
|
493
|
+
response = await host.send_command(HCI_RTK_Read_ROM_Version_Command())
|
|
494
|
+
|
|
495
|
+
if response.return_parameters.status != hci.HCI_SUCCESS:
|
|
496
|
+
return None
|
|
497
|
+
|
|
498
|
+
response = await host.send_command(
|
|
499
|
+
hci.HCI_Read_Local_Version_Information_Command(), check_result=True
|
|
500
|
+
)
|
|
501
|
+
return (
|
|
502
|
+
response.return_parameters.hci_subversion << 16
|
|
503
|
+
| response.return_parameters.lmp_subversion
|
|
504
|
+
)
|
|
505
|
+
|
|
492
506
|
@classmethod
|
|
493
507
|
async def driver_info_for_host(cls, host):
|
|
494
508
|
try:
|
|
@@ -592,7 +606,7 @@ class Driver(common.Driver):
|
|
|
592
606
|
)
|
|
593
607
|
if response.return_parameters.status != hci.HCI_SUCCESS:
|
|
594
608
|
logger.warning("can't get ROM version")
|
|
595
|
-
return
|
|
609
|
+
return None
|
|
596
610
|
rom_version = response.return_parameters.version
|
|
597
611
|
logger.debug(f"ROM version before download: {rom_version:04X}")
|
|
598
612
|
else:
|
|
@@ -600,13 +614,14 @@ class Driver(common.Driver):
|
|
|
600
614
|
|
|
601
615
|
firmware = Firmware(self.firmware)
|
|
602
616
|
logger.debug(f"firmware: project_id=0x{firmware.project_id:04X}")
|
|
617
|
+
logger.debug(f"firmware: version=0x{firmware.version:04X}")
|
|
603
618
|
for patch in firmware.patches:
|
|
604
619
|
if patch[0] == rom_version + 1:
|
|
605
620
|
logger.debug(f"using patch {patch[0]}")
|
|
606
621
|
break
|
|
607
622
|
else:
|
|
608
623
|
logger.warning("no valid patch found for rom version {rom_version}")
|
|
609
|
-
return
|
|
624
|
+
return None
|
|
610
625
|
|
|
611
626
|
# Append the config if there is one.
|
|
612
627
|
if self.config:
|
|
@@ -642,7 +657,9 @@ class Driver(common.Driver):
|
|
|
642
657
|
logger.warning("can't get ROM version")
|
|
643
658
|
else:
|
|
644
659
|
rom_version = response.return_parameters.version
|
|
645
|
-
logger.debug(f"ROM version after download: {rom_version:
|
|
660
|
+
logger.debug(f"ROM version after download: {rom_version:02X}")
|
|
661
|
+
|
|
662
|
+
return firmware.version
|
|
646
663
|
|
|
647
664
|
async def download_firmware(self):
|
|
648
665
|
if self.driver_info.rom == RTK_ROM_LMP_8723A:
|
bumble/gap.py
CHANGED
|
@@ -19,11 +19,11 @@ import logging
|
|
|
19
19
|
import struct
|
|
20
20
|
|
|
21
21
|
from bumble.gatt import (
|
|
22
|
-
Service,
|
|
23
|
-
Characteristic,
|
|
24
|
-
GATT_GENERIC_ACCESS_SERVICE,
|
|
25
|
-
GATT_DEVICE_NAME_CHARACTERISTIC,
|
|
26
22
|
GATT_APPEARANCE_CHARACTERISTIC,
|
|
23
|
+
GATT_DEVICE_NAME_CHARACTERISTIC,
|
|
24
|
+
GATT_GENERIC_ACCESS_SERVICE,
|
|
25
|
+
Characteristic,
|
|
26
|
+
Service,
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
# -----------------------------------------------------------------------------
|
bumble/gatt.py
CHANGED
|
@@ -23,15 +23,16 @@
|
|
|
23
23
|
# Imports
|
|
24
24
|
# -----------------------------------------------------------------------------
|
|
25
25
|
from __future__ import annotations
|
|
26
|
+
|
|
26
27
|
import enum
|
|
27
28
|
import functools
|
|
28
29
|
import logging
|
|
29
30
|
import struct
|
|
30
31
|
from typing import Iterable, Optional, Sequence, TypeVar, Union
|
|
31
32
|
|
|
32
|
-
from bumble.colors import color
|
|
33
|
-
from bumble.core import BaseBumbleError, UUID
|
|
34
33
|
from bumble.att import Attribute, AttributeValue
|
|
34
|
+
from bumble.colors import color
|
|
35
|
+
from bumble.core import UUID, BaseBumbleError
|
|
35
36
|
|
|
36
37
|
# -----------------------------------------------------------------------------
|
|
37
38
|
# Typing
|
bumble/gatt_adapters.py
CHANGED
|
@@ -20,22 +20,14 @@
|
|
|
20
20
|
# Imports
|
|
21
21
|
# -----------------------------------------------------------------------------
|
|
22
22
|
from __future__ import annotations
|
|
23
|
+
|
|
23
24
|
import struct
|
|
24
|
-
from typing import
|
|
25
|
-
Any,
|
|
26
|
-
Callable,
|
|
27
|
-
Generic,
|
|
28
|
-
Iterable,
|
|
29
|
-
Literal,
|
|
30
|
-
Optional,
|
|
31
|
-
TypeVar,
|
|
32
|
-
)
|
|
25
|
+
from typing import Any, Callable, Generic, Iterable, Literal, Optional, TypeVar
|
|
33
26
|
|
|
27
|
+
from bumble import utils
|
|
34
28
|
from bumble.core import InvalidOperationError
|
|
35
29
|
from bumble.gatt import Characteristic
|
|
36
30
|
from bumble.gatt_client import CharacteristicProxy
|
|
37
|
-
from bumble import utils
|
|
38
|
-
|
|
39
31
|
|
|
40
32
|
# -----------------------------------------------------------------------------
|
|
41
33
|
# Typing
|
bumble/gatt_client.py
CHANGED
|
@@ -24,60 +24,38 @@
|
|
|
24
24
|
# Imports
|
|
25
25
|
# -----------------------------------------------------------------------------
|
|
26
26
|
from __future__ import annotations
|
|
27
|
+
|
|
27
28
|
import asyncio
|
|
28
29
|
import logging
|
|
29
30
|
import struct
|
|
30
31
|
from datetime import datetime
|
|
31
32
|
from typing import (
|
|
33
|
+
TYPE_CHECKING,
|
|
32
34
|
Any,
|
|
33
35
|
Callable,
|
|
34
36
|
Generic,
|
|
35
37
|
Iterable,
|
|
36
38
|
Optional,
|
|
37
|
-
Union,
|
|
38
39
|
TypeVar,
|
|
39
|
-
|
|
40
|
+
Union,
|
|
40
41
|
)
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
from bumble import att, core, utils
|
|
43
44
|
from bumble.colors import color
|
|
44
|
-
from bumble.hci import HCI_Constant
|
|
45
|
-
from bumble.att import (
|
|
46
|
-
ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
47
|
-
ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
48
|
-
ATT_CID,
|
|
49
|
-
ATT_DEFAULT_MTU,
|
|
50
|
-
ATT_ERROR_RESPONSE,
|
|
51
|
-
ATT_INVALID_OFFSET_ERROR,
|
|
52
|
-
ATT_PDU,
|
|
53
|
-
ATT_RESPONSES,
|
|
54
|
-
ATT_Exchange_MTU_Request,
|
|
55
|
-
ATT_Find_By_Type_Value_Request,
|
|
56
|
-
ATT_Find_Information_Request,
|
|
57
|
-
ATT_Handle_Value_Confirmation,
|
|
58
|
-
ATT_Read_Blob_Request,
|
|
59
|
-
ATT_Read_By_Group_Type_Request,
|
|
60
|
-
ATT_Read_By_Type_Request,
|
|
61
|
-
ATT_Read_Request,
|
|
62
|
-
ATT_Write_Command,
|
|
63
|
-
ATT_Write_Request,
|
|
64
|
-
ATT_Error,
|
|
65
|
-
)
|
|
66
|
-
from bumble import utils
|
|
67
|
-
from bumble import core
|
|
68
45
|
from bumble.core import UUID, InvalidStateError
|
|
69
46
|
from bumble.gatt import (
|
|
70
47
|
GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
|
|
71
48
|
GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
|
|
49
|
+
GATT_INCLUDE_ATTRIBUTE_TYPE,
|
|
72
50
|
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
|
73
51
|
GATT_REQUEST_TIMEOUT,
|
|
74
52
|
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
|
|
75
|
-
GATT_INCLUDE_ATTRIBUTE_TYPE,
|
|
76
53
|
Characteristic,
|
|
77
54
|
ClientCharacteristicConfigurationBits,
|
|
78
55
|
InvalidServiceError,
|
|
79
56
|
TemplateService,
|
|
80
57
|
)
|
|
58
|
+
from bumble.hci import HCI_Constant
|
|
81
59
|
|
|
82
60
|
# -----------------------------------------------------------------------------
|
|
83
61
|
# Typing
|
|
@@ -291,8 +269,8 @@ class Client:
|
|
|
291
269
|
indication_subscribers: dict[
|
|
292
270
|
int, set[Union[CharacteristicProxy, Callable[[bytes], Any]]]
|
|
293
271
|
]
|
|
294
|
-
pending_response: Optional[asyncio.futures.Future[ATT_PDU]]
|
|
295
|
-
pending_request: Optional[ATT_PDU]
|
|
272
|
+
pending_response: Optional[asyncio.futures.Future[att.ATT_PDU]]
|
|
273
|
+
pending_request: Optional[att.ATT_PDU]
|
|
296
274
|
|
|
297
275
|
def __init__(self, connection: Connection) -> None:
|
|
298
276
|
self.connection = connection
|
|
@@ -308,15 +286,15 @@ class Client:
|
|
|
308
286
|
connection.on(connection.EVENT_DISCONNECTION, self.on_disconnection)
|
|
309
287
|
|
|
310
288
|
def send_gatt_pdu(self, pdu: bytes) -> None:
|
|
311
|
-
self.connection.send_l2cap_pdu(ATT_CID, pdu)
|
|
289
|
+
self.connection.send_l2cap_pdu(att.ATT_CID, pdu)
|
|
312
290
|
|
|
313
|
-
async def send_command(self, command: ATT_PDU) -> None:
|
|
291
|
+
async def send_command(self, command: att.ATT_PDU) -> None:
|
|
314
292
|
logger.debug(
|
|
315
293
|
f'GATT Command from client: [0x{self.connection.handle:04X}] {command}'
|
|
316
294
|
)
|
|
317
295
|
self.send_gatt_pdu(bytes(command))
|
|
318
296
|
|
|
319
|
-
async def send_request(self, request: ATT_PDU):
|
|
297
|
+
async def send_request(self, request: att.ATT_PDU):
|
|
320
298
|
logger.debug(
|
|
321
299
|
f'GATT Request from client: [0x{self.connection.handle:04X}] {request}'
|
|
322
300
|
)
|
|
@@ -345,7 +323,9 @@ class Client:
|
|
|
345
323
|
|
|
346
324
|
return response
|
|
347
325
|
|
|
348
|
-
def send_confirmation(
|
|
326
|
+
def send_confirmation(
|
|
327
|
+
self, confirmation: att.ATT_Handle_Value_Confirmation
|
|
328
|
+
) -> None:
|
|
349
329
|
logger.debug(
|
|
350
330
|
f'GATT Confirmation from client: [0x{self.connection.handle:04X}] '
|
|
351
331
|
f'{confirmation}'
|
|
@@ -354,8 +334,8 @@ class Client:
|
|
|
354
334
|
|
|
355
335
|
async def request_mtu(self, mtu: int) -> int:
|
|
356
336
|
# Check the range
|
|
357
|
-
if mtu < ATT_DEFAULT_MTU:
|
|
358
|
-
raise core.InvalidArgumentError(f'MTU must be >= {ATT_DEFAULT_MTU}')
|
|
337
|
+
if mtu < att.ATT_DEFAULT_MTU:
|
|
338
|
+
raise core.InvalidArgumentError(f'MTU must be >= {att.ATT_DEFAULT_MTU}')
|
|
359
339
|
if mtu > 0xFFFF:
|
|
360
340
|
raise core.InvalidArgumentError('MTU must be <= 0xFFFF')
|
|
361
341
|
|
|
@@ -365,9 +345,11 @@ class Client:
|
|
|
365
345
|
|
|
366
346
|
# Send the request
|
|
367
347
|
self.mtu_exchange_done = True
|
|
368
|
-
response = await self.send_request(
|
|
369
|
-
|
|
370
|
-
|
|
348
|
+
response = await self.send_request(
|
|
349
|
+
att.ATT_Exchange_MTU_Request(client_rx_mtu=mtu)
|
|
350
|
+
)
|
|
351
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
352
|
+
raise att.ATT_Error(error_code=response.error_code, message=response)
|
|
371
353
|
|
|
372
354
|
# Compute the final MTU
|
|
373
355
|
self.connection.att_mtu = min(mtu, response.server_rx_mtu)
|
|
@@ -432,7 +414,7 @@ class Client:
|
|
|
432
414
|
services = []
|
|
433
415
|
while starting_handle < 0xFFFF:
|
|
434
416
|
response = await self.send_request(
|
|
435
|
-
ATT_Read_By_Group_Type_Request(
|
|
417
|
+
att.ATT_Read_By_Group_Type_Request(
|
|
436
418
|
starting_handle=starting_handle,
|
|
437
419
|
ending_handle=0xFFFF,
|
|
438
420
|
attribute_group_type=GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
|
@@ -443,14 +425,14 @@ class Client:
|
|
|
443
425
|
return []
|
|
444
426
|
|
|
445
427
|
# Check if we reached the end of the iteration
|
|
446
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
447
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
428
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
429
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
448
430
|
# Unexpected end
|
|
449
431
|
logger.warning(
|
|
450
432
|
'!!! unexpected error while discovering services: '
|
|
451
433
|
f'{HCI_Constant.error_name(response.error_code)}'
|
|
452
434
|
)
|
|
453
|
-
raise ATT_Error(
|
|
435
|
+
raise att.ATT_Error(
|
|
454
436
|
error_code=response.error_code,
|
|
455
437
|
message='Unexpected error while discovering services',
|
|
456
438
|
)
|
|
@@ -509,7 +491,7 @@ class Client:
|
|
|
509
491
|
services = []
|
|
510
492
|
while starting_handle < 0xFFFF:
|
|
511
493
|
response = await self.send_request(
|
|
512
|
-
ATT_Find_By_Type_Value_Request(
|
|
494
|
+
att.ATT_Find_By_Type_Value_Request(
|
|
513
495
|
starting_handle=starting_handle,
|
|
514
496
|
ending_handle=0xFFFF,
|
|
515
497
|
attribute_type=GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
|
@@ -521,8 +503,8 @@ class Client:
|
|
|
521
503
|
return []
|
|
522
504
|
|
|
523
505
|
# Check if we reached the end of the iteration
|
|
524
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
525
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
506
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
507
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
526
508
|
# Unexpected end
|
|
527
509
|
logger.warning(
|
|
528
510
|
'!!! unexpected error while discovering services: '
|
|
@@ -578,7 +560,7 @@ class Client:
|
|
|
578
560
|
included_services: list[ServiceProxy] = []
|
|
579
561
|
while starting_handle <= ending_handle:
|
|
580
562
|
response = await self.send_request(
|
|
581
|
-
ATT_Read_By_Type_Request(
|
|
563
|
+
att.ATT_Read_By_Type_Request(
|
|
582
564
|
starting_handle=starting_handle,
|
|
583
565
|
ending_handle=ending_handle,
|
|
584
566
|
attribute_type=GATT_INCLUDE_ATTRIBUTE_TYPE,
|
|
@@ -589,14 +571,14 @@ class Client:
|
|
|
589
571
|
return []
|
|
590
572
|
|
|
591
573
|
# Check if we reached the end of the iteration
|
|
592
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
593
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
574
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
575
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
594
576
|
# Unexpected end
|
|
595
577
|
logger.warning(
|
|
596
578
|
'!!! unexpected error while discovering included services: '
|
|
597
579
|
f'{HCI_Constant.error_name(response.error_code)}'
|
|
598
580
|
)
|
|
599
|
-
raise ATT_Error(
|
|
581
|
+
raise att.ATT_Error(
|
|
600
582
|
error_code=response.error_code,
|
|
601
583
|
message='Unexpected error while discovering included services',
|
|
602
584
|
)
|
|
@@ -652,7 +634,7 @@ class Client:
|
|
|
652
634
|
characteristics: list[CharacteristicProxy[bytes]] = []
|
|
653
635
|
while starting_handle <= ending_handle:
|
|
654
636
|
response = await self.send_request(
|
|
655
|
-
ATT_Read_By_Type_Request(
|
|
637
|
+
att.ATT_Read_By_Type_Request(
|
|
656
638
|
starting_handle=starting_handle,
|
|
657
639
|
ending_handle=ending_handle,
|
|
658
640
|
attribute_type=GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
|
|
@@ -663,14 +645,14 @@ class Client:
|
|
|
663
645
|
return []
|
|
664
646
|
|
|
665
647
|
# Check if we reached the end of the iteration
|
|
666
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
667
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
648
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
649
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
668
650
|
# Unexpected end
|
|
669
651
|
logger.warning(
|
|
670
652
|
'!!! unexpected error while discovering characteristics: '
|
|
671
653
|
f'{HCI_Constant.error_name(response.error_code)}'
|
|
672
654
|
)
|
|
673
|
-
raise ATT_Error(
|
|
655
|
+
raise att.ATT_Error(
|
|
674
656
|
error_code=response.error_code,
|
|
675
657
|
message='Unexpected error while discovering characteristics',
|
|
676
658
|
)
|
|
@@ -736,7 +718,7 @@ class Client:
|
|
|
736
718
|
descriptors: list[DescriptorProxy] = []
|
|
737
719
|
while starting_handle <= ending_handle:
|
|
738
720
|
response = await self.send_request(
|
|
739
|
-
ATT_Find_Information_Request(
|
|
721
|
+
att.ATT_Find_Information_Request(
|
|
740
722
|
starting_handle=starting_handle, ending_handle=ending_handle
|
|
741
723
|
)
|
|
742
724
|
)
|
|
@@ -745,8 +727,8 @@ class Client:
|
|
|
745
727
|
return []
|
|
746
728
|
|
|
747
729
|
# Check if we reached the end of the iteration
|
|
748
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
749
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
730
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
731
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
750
732
|
# Unexpected end
|
|
751
733
|
logger.warning(
|
|
752
734
|
'!!! unexpected error while discovering descriptors: '
|
|
@@ -791,7 +773,7 @@ class Client:
|
|
|
791
773
|
attributes = []
|
|
792
774
|
while True:
|
|
793
775
|
response = await self.send_request(
|
|
794
|
-
ATT_Find_Information_Request(
|
|
776
|
+
att.ATT_Find_Information_Request(
|
|
795
777
|
starting_handle=starting_handle, ending_handle=ending_handle
|
|
796
778
|
)
|
|
797
779
|
)
|
|
@@ -799,8 +781,8 @@ class Client:
|
|
|
799
781
|
return []
|
|
800
782
|
|
|
801
783
|
# Check if we reached the end of the iteration
|
|
802
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
803
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
784
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
785
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
804
786
|
# Unexpected end
|
|
805
787
|
logger.warning(
|
|
806
788
|
'!!! unexpected error while discovering attributes: '
|
|
@@ -954,12 +936,12 @@ class Client:
|
|
|
954
936
|
# Send a request to read
|
|
955
937
|
attribute_handle = attribute if isinstance(attribute, int) else attribute.handle
|
|
956
938
|
response = await self.send_request(
|
|
957
|
-
ATT_Read_Request(attribute_handle=attribute_handle)
|
|
939
|
+
att.ATT_Read_Request(attribute_handle=attribute_handle)
|
|
958
940
|
)
|
|
959
941
|
if response is None:
|
|
960
942
|
raise TimeoutError('read timeout')
|
|
961
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
962
|
-
raise ATT_Error(error_code=response.error_code, message=response)
|
|
943
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
944
|
+
raise att.ATT_Error(error_code=response.error_code, message=response)
|
|
963
945
|
|
|
964
946
|
# If the value is the max size for the MTU, try to read more unless the caller
|
|
965
947
|
# specifically asked not to do that
|
|
@@ -969,19 +951,21 @@ class Client:
|
|
|
969
951
|
offset = len(attribute_value)
|
|
970
952
|
while True:
|
|
971
953
|
response = await self.send_request(
|
|
972
|
-
ATT_Read_Blob_Request(
|
|
954
|
+
att.ATT_Read_Blob_Request(
|
|
973
955
|
attribute_handle=attribute_handle, value_offset=offset
|
|
974
956
|
)
|
|
975
957
|
)
|
|
976
958
|
if response is None:
|
|
977
959
|
raise TimeoutError('read timeout')
|
|
978
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
960
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
979
961
|
if response.error_code in (
|
|
980
|
-
ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
981
|
-
ATT_INVALID_OFFSET_ERROR,
|
|
962
|
+
att.ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
963
|
+
att.ATT_INVALID_OFFSET_ERROR,
|
|
982
964
|
):
|
|
983
965
|
break
|
|
984
|
-
raise ATT_Error(
|
|
966
|
+
raise att.ATT_Error(
|
|
967
|
+
error_code=response.error_code, message=response
|
|
968
|
+
)
|
|
985
969
|
|
|
986
970
|
part = response.part_attribute_value
|
|
987
971
|
attribute_value += part
|
|
@@ -1012,7 +996,7 @@ class Client:
|
|
|
1012
996
|
characteristics_values = []
|
|
1013
997
|
while starting_handle <= ending_handle:
|
|
1014
998
|
response = await self.send_request(
|
|
1015
|
-
ATT_Read_By_Type_Request(
|
|
999
|
+
att.ATT_Read_By_Type_Request(
|
|
1016
1000
|
starting_handle=starting_handle,
|
|
1017
1001
|
ending_handle=ending_handle,
|
|
1018
1002
|
attribute_type=uuid,
|
|
@@ -1023,8 +1007,8 @@ class Client:
|
|
|
1023
1007
|
return []
|
|
1024
1008
|
|
|
1025
1009
|
# Check if we reached the end of the iteration
|
|
1026
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
1027
|
-
if response.error_code != ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
1010
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
1011
|
+
if response.error_code != att.ATT_ATTRIBUTE_NOT_FOUND_ERROR:
|
|
1028
1012
|
# Unexpected end
|
|
1029
1013
|
logger.warning(
|
|
1030
1014
|
'!!! unexpected error while reading characteristics: '
|
|
@@ -1069,15 +1053,15 @@ class Client:
|
|
|
1069
1053
|
attribute_handle = attribute if isinstance(attribute, int) else attribute.handle
|
|
1070
1054
|
if with_response:
|
|
1071
1055
|
response = await self.send_request(
|
|
1072
|
-
ATT_Write_Request(
|
|
1056
|
+
att.ATT_Write_Request(
|
|
1073
1057
|
attribute_handle=attribute_handle, attribute_value=value
|
|
1074
1058
|
)
|
|
1075
1059
|
)
|
|
1076
|
-
if response.op_code == ATT_ERROR_RESPONSE:
|
|
1077
|
-
raise ATT_Error(error_code=response.error_code, message=response)
|
|
1060
|
+
if response.op_code == att.Opcode.ATT_ERROR_RESPONSE:
|
|
1061
|
+
raise att.ATT_Error(error_code=response.error_code, message=response)
|
|
1078
1062
|
else:
|
|
1079
1063
|
await self.send_command(
|
|
1080
|
-
ATT_Write_Command(
|
|
1064
|
+
att.ATT_Write_Command(
|
|
1081
1065
|
attribute_handle=attribute_handle, attribute_value=value
|
|
1082
1066
|
)
|
|
1083
1067
|
)
|
|
@@ -1086,11 +1070,11 @@ class Client:
|
|
|
1086
1070
|
if self.pending_response and not self.pending_response.done():
|
|
1087
1071
|
self.pending_response.cancel()
|
|
1088
1072
|
|
|
1089
|
-
def on_gatt_pdu(self, att_pdu: ATT_PDU) -> None:
|
|
1073
|
+
def on_gatt_pdu(self, att_pdu: att.ATT_PDU) -> None:
|
|
1090
1074
|
logger.debug(
|
|
1091
1075
|
f'GATT Response to client: [0x{self.connection.handle:04X}] {att_pdu}'
|
|
1092
1076
|
)
|
|
1093
|
-
if att_pdu.op_code in ATT_RESPONSES:
|
|
1077
|
+
if att_pdu.op_code in att.ATT_RESPONSES:
|
|
1094
1078
|
if self.pending_request is None:
|
|
1095
1079
|
# Not expected!
|
|
1096
1080
|
logger.warning('!!! unexpected response, there is no pending request')
|
|
@@ -1098,7 +1082,7 @@ class Client:
|
|
|
1098
1082
|
|
|
1099
1083
|
# The response should match the pending request unless it is
|
|
1100
1084
|
# an error response
|
|
1101
|
-
if att_pdu.op_code != ATT_ERROR_RESPONSE:
|
|
1085
|
+
if att_pdu.op_code != att.Opcode.ATT_ERROR_RESPONSE:
|
|
1102
1086
|
expected_response_name = self.pending_request.name.replace(
|
|
1103
1087
|
'_REQUEST', '_RESPONSE'
|
|
1104
1088
|
)
|
|
@@ -1126,7 +1110,9 @@ class Client:
|
|
|
1126
1110
|
+ str(att_pdu)
|
|
1127
1111
|
)
|
|
1128
1112
|
|
|
1129
|
-
def on_att_handle_value_notification(
|
|
1113
|
+
def on_att_handle_value_notification(
|
|
1114
|
+
self, notification: att.ATT_Handle_Value_Notification
|
|
1115
|
+
):
|
|
1130
1116
|
# Call all subscribers
|
|
1131
1117
|
subscribers = self.notification_subscribers.get(
|
|
1132
1118
|
notification.attribute_handle, set()
|
|
@@ -1141,7 +1127,9 @@ class Client:
|
|
|
1141
1127
|
else:
|
|
1142
1128
|
subscriber.emit(subscriber.EVENT_UPDATE, notification.attribute_value)
|
|
1143
1129
|
|
|
1144
|
-
def on_att_handle_value_indication(
|
|
1130
|
+
def on_att_handle_value_indication(
|
|
1131
|
+
self, indication: att.ATT_Handle_Value_Indication
|
|
1132
|
+
):
|
|
1145
1133
|
# Call all subscribers
|
|
1146
1134
|
subscribers = self.indication_subscribers.get(
|
|
1147
1135
|
indication.attribute_handle, set()
|
|
@@ -1157,7 +1145,7 @@ class Client:
|
|
|
1157
1145
|
subscriber.emit(subscriber.EVENT_UPDATE, indication.attribute_value)
|
|
1158
1146
|
|
|
1159
1147
|
# Confirm that we received the indication
|
|
1160
|
-
self.send_confirmation(ATT_Handle_Value_Confirmation())
|
|
1148
|
+
self.send_confirmation(att.ATT_Handle_Value_Confirmation())
|
|
1161
1149
|
|
|
1162
1150
|
def cache_value(self, attribute_handle: int, value: bytes) -> None:
|
|
1163
1151
|
self.cached_values[attribute_handle] = (
|