bumble 0.0.214__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 +13 -38
- bumble/apps/bench.py +9 -10
- bumble/apps/ble_rpa_tool.py +1 -0
- bumble/apps/console.py +22 -25
- bumble/apps/controller_info.py +19 -19
- bumble/apps/controller_loopback.py +2 -2
- bumble/apps/controllers.py +1 -1
- bumble/apps/device_info.py +3 -3
- bumble/apps/gatt_dump.py +1 -1
- bumble/apps/gg_bridge.py +5 -6
- bumble/apps/hci_bridge.py +3 -3
- bumble/apps/l2cap_bridge.py +3 -3
- bumble/apps/lea_unicast/app.py +15 -25
- bumble/apps/pair.py +30 -43
- bumble/apps/pandora_server.py +5 -4
- bumble/apps/player/player.py +19 -22
- bumble/apps/rfcomm_bridge.py +3 -8
- bumble/apps/scan.py +16 -6
- bumble/apps/show.py +3 -4
- bumble/apps/speaker/speaker.py +22 -22
- bumble/apps/unbond.py +2 -1
- bumble/apps/usb_probe.py +1 -2
- 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 +1096 -588
- bumble/codecs.py +2 -0
- bumble/controller.py +52 -13
- 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 +280 -278
- 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 +67 -18
- bumble/helpers.py +19 -26
- bumble/hfp.py +10 -21
- bumble/hid.py +22 -16
- bumble/host.py +181 -103
- bumble/keys.py +5 -3
- bumble/l2cap.py +121 -74
- bumble/link.py +8 -9
- bumble/pairing.py +7 -6
- bumble/pandora/__init__.py +8 -7
- 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 +7 -8
- bumble/profiles/ancs.py +6 -7
- bumble/profiles/ascs.py +4 -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 +142 -153
- 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 +4 -4
- bumble/tools/rtk_fw_download.py +6 -3
- bumble/tools/rtk_util.py +24 -7
- 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.214.dist-info → bumble-0.0.215.dist-info}/METADATA +2 -1
- bumble-0.0.215.dist-info/RECORD +183 -0
- bumble-0.0.214.dist-info/RECORD +0 -182
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/WHEEL +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.215.dist-info}/top_level.txt +0 -0
bumble/gatt_server.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
# -----------------------------------------------------------------------------
|
|
16
|
-
# GATT - Generic Attribute Profile
|
|
16
|
+
# GATT - Generic att.Attribute Profile
|
|
17
17
|
# Server
|
|
18
18
|
#
|
|
19
19
|
# See Bluetooth spec @ Vol 3, Part G
|
|
@@ -24,46 +24,16 @@
|
|
|
24
24
|
# Imports
|
|
25
25
|
# -----------------------------------------------------------------------------
|
|
26
26
|
from __future__ import annotations
|
|
27
|
+
|
|
27
28
|
import asyncio
|
|
28
29
|
import logging
|
|
29
|
-
from collections import defaultdict
|
|
30
30
|
import struct
|
|
31
|
-
from
|
|
32
|
-
|
|
33
|
-
Optional,
|
|
34
|
-
TypeVar,
|
|
35
|
-
TYPE_CHECKING,
|
|
36
|
-
)
|
|
31
|
+
from collections import defaultdict
|
|
32
|
+
from typing import TYPE_CHECKING, Iterable, Optional, TypeVar
|
|
37
33
|
|
|
34
|
+
from bumble import att, utils
|
|
38
35
|
from bumble.colors import color
|
|
39
36
|
from bumble.core import UUID
|
|
40
|
-
from bumble.att import (
|
|
41
|
-
ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
42
|
-
ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
43
|
-
ATT_CID,
|
|
44
|
-
ATT_DEFAULT_MTU,
|
|
45
|
-
ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
|
|
46
|
-
ATT_INVALID_HANDLE_ERROR,
|
|
47
|
-
ATT_INVALID_OFFSET_ERROR,
|
|
48
|
-
ATT_REQUEST_NOT_SUPPORTED_ERROR,
|
|
49
|
-
ATT_REQUESTS,
|
|
50
|
-
ATT_PDU,
|
|
51
|
-
ATT_UNLIKELY_ERROR_ERROR,
|
|
52
|
-
ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
|
|
53
|
-
ATT_Error,
|
|
54
|
-
ATT_Error_Response,
|
|
55
|
-
ATT_Exchange_MTU_Response,
|
|
56
|
-
ATT_Find_By_Type_Value_Response,
|
|
57
|
-
ATT_Find_Information_Response,
|
|
58
|
-
ATT_Handle_Value_Indication,
|
|
59
|
-
ATT_Handle_Value_Notification,
|
|
60
|
-
ATT_Read_Blob_Response,
|
|
61
|
-
ATT_Read_By_Group_Type_Response,
|
|
62
|
-
ATT_Read_By_Type_Response,
|
|
63
|
-
ATT_Read_Response,
|
|
64
|
-
ATT_Write_Response,
|
|
65
|
-
Attribute,
|
|
66
|
-
)
|
|
67
37
|
from bumble.gatt import (
|
|
68
38
|
GATT_CHARACTERISTIC_ATTRIBUTE_TYPE,
|
|
69
39
|
GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
|
|
@@ -74,14 +44,13 @@ from bumble.gatt import (
|
|
|
74
44
|
Characteristic,
|
|
75
45
|
CharacteristicDeclaration,
|
|
76
46
|
CharacteristicValue,
|
|
77
|
-
IncludedServiceDeclaration,
|
|
78
47
|
Descriptor,
|
|
48
|
+
IncludedServiceDeclaration,
|
|
79
49
|
Service,
|
|
80
50
|
)
|
|
81
|
-
from bumble import utils
|
|
82
51
|
|
|
83
52
|
if TYPE_CHECKING:
|
|
84
|
-
from bumble.device import
|
|
53
|
+
from bumble.device import Connection, Device
|
|
85
54
|
|
|
86
55
|
# -----------------------------------------------------------------------------
|
|
87
56
|
# Logging
|
|
@@ -99,9 +68,9 @@ GATT_SERVER_DEFAULT_MAX_MTU = 517
|
|
|
99
68
|
# GATT Server
|
|
100
69
|
# -----------------------------------------------------------------------------
|
|
101
70
|
class Server(utils.EventEmitter):
|
|
102
|
-
attributes: list[Attribute]
|
|
71
|
+
attributes: list[att.Attribute]
|
|
103
72
|
services: list[Service]
|
|
104
|
-
attributes_by_handle: dict[int, Attribute]
|
|
73
|
+
attributes_by_handle: dict[int, att.Attribute]
|
|
105
74
|
subscribers: dict[int, dict[int, bytes]]
|
|
106
75
|
indication_semaphores: defaultdict[int, asyncio.Semaphore]
|
|
107
76
|
pending_confirmations: defaultdict[int, Optional[asyncio.futures.Future]]
|
|
@@ -112,7 +81,7 @@ class Server(utils.EventEmitter):
|
|
|
112
81
|
super().__init__()
|
|
113
82
|
self.device = device
|
|
114
83
|
self.services = []
|
|
115
|
-
self.attributes = [] # Attributes, ordered by increasing handle values
|
|
84
|
+
self.attributes = [] # att.Attributes, ordered by increasing handle values
|
|
116
85
|
self.attributes_by_handle = {} # Map for fast attribute access by handle
|
|
117
86
|
self.max_mtu = (
|
|
118
87
|
GATT_SERVER_DEFAULT_MAX_MTU # The max MTU we're willing to negotiate
|
|
@@ -127,12 +96,12 @@ class Server(utils.EventEmitter):
|
|
|
127
96
|
return "\n".join(map(str, self.attributes))
|
|
128
97
|
|
|
129
98
|
def send_gatt_pdu(self, connection_handle: int, pdu: bytes) -> None:
|
|
130
|
-
self.device.send_l2cap_pdu(connection_handle, ATT_CID, pdu)
|
|
99
|
+
self.device.send_l2cap_pdu(connection_handle, att.ATT_CID, pdu)
|
|
131
100
|
|
|
132
101
|
def next_handle(self) -> int:
|
|
133
102
|
return 1 + len(self.attributes)
|
|
134
103
|
|
|
135
|
-
def get_advertising_service_data(self) -> dict[Attribute, bytes]:
|
|
104
|
+
def get_advertising_service_data(self) -> dict[att.Attribute, bytes]:
|
|
136
105
|
return {
|
|
137
106
|
attribute: data
|
|
138
107
|
for attribute in self.attributes
|
|
@@ -140,7 +109,7 @@ class Server(utils.EventEmitter):
|
|
|
140
109
|
and (data := attribute.get_advertising_data())
|
|
141
110
|
}
|
|
142
111
|
|
|
143
|
-
def get_attribute(self, handle: int) -> Optional[Attribute]:
|
|
112
|
+
def get_attribute(self, handle: int) -> Optional[att.Attribute]:
|
|
144
113
|
attribute = self.attributes_by_handle.get(handle)
|
|
145
114
|
if attribute:
|
|
146
115
|
return attribute
|
|
@@ -231,7 +200,7 @@ class Server(utils.EventEmitter):
|
|
|
231
200
|
None,
|
|
232
201
|
)
|
|
233
202
|
|
|
234
|
-
def add_attribute(self, attribute: Attribute) -> None:
|
|
203
|
+
def add_attribute(self, attribute: att.Attribute) -> None:
|
|
235
204
|
# Assign a handle to this attribute
|
|
236
205
|
attribute.handle = self.next_handle()
|
|
237
206
|
attribute.end_group_handle = (
|
|
@@ -286,7 +255,7 @@ class Server(utils.EventEmitter):
|
|
|
286
255
|
# pylint: disable=line-too-long
|
|
287
256
|
Descriptor(
|
|
288
257
|
GATT_CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR,
|
|
289
|
-
Attribute.READABLE | Attribute.WRITEABLE,
|
|
258
|
+
att.Attribute.READABLE | att.Attribute.WRITEABLE,
|
|
290
259
|
CharacteristicValue(
|
|
291
260
|
read=lambda connection, characteristic=characteristic: self.read_cccd(
|
|
292
261
|
connection, characteristic
|
|
@@ -355,7 +324,7 @@ class Server(utils.EventEmitter):
|
|
|
355
324
|
indicate_enabled,
|
|
356
325
|
)
|
|
357
326
|
|
|
358
|
-
def send_response(self, connection: Connection, response: ATT_PDU) -> None:
|
|
327
|
+
def send_response(self, connection: Connection, response: att.ATT_PDU) -> None:
|
|
359
328
|
logger.debug(
|
|
360
329
|
f'GATT Response from server: [0x{connection.handle:04X}] {response}'
|
|
361
330
|
)
|
|
@@ -364,7 +333,7 @@ class Server(utils.EventEmitter):
|
|
|
364
333
|
async def notify_subscriber(
|
|
365
334
|
self,
|
|
366
335
|
connection: Connection,
|
|
367
|
-
attribute: Attribute,
|
|
336
|
+
attribute: att.Attribute,
|
|
368
337
|
value: Optional[bytes] = None,
|
|
369
338
|
force: bool = False,
|
|
370
339
|
) -> None:
|
|
@@ -396,7 +365,7 @@ class Server(utils.EventEmitter):
|
|
|
396
365
|
value = value[: connection.att_mtu - 3]
|
|
397
366
|
|
|
398
367
|
# Notify
|
|
399
|
-
notification = ATT_Handle_Value_Notification(
|
|
368
|
+
notification = att.ATT_Handle_Value_Notification(
|
|
400
369
|
attribute_handle=attribute.handle, attribute_value=value
|
|
401
370
|
)
|
|
402
371
|
logger.debug(
|
|
@@ -407,7 +376,7 @@ class Server(utils.EventEmitter):
|
|
|
407
376
|
async def indicate_subscriber(
|
|
408
377
|
self,
|
|
409
378
|
connection: Connection,
|
|
410
|
-
attribute: Attribute,
|
|
379
|
+
attribute: att.Attribute,
|
|
411
380
|
value: Optional[bytes] = None,
|
|
412
381
|
force: bool = False,
|
|
413
382
|
) -> None:
|
|
@@ -439,7 +408,7 @@ class Server(utils.EventEmitter):
|
|
|
439
408
|
value = value[: connection.att_mtu - 3]
|
|
440
409
|
|
|
441
410
|
# Indicate
|
|
442
|
-
indication = ATT_Handle_Value_Indication(
|
|
411
|
+
indication = att.ATT_Handle_Value_Indication(
|
|
443
412
|
attribute_handle=attribute.handle, attribute_value=value
|
|
444
413
|
)
|
|
445
414
|
logger.debug(
|
|
@@ -467,7 +436,7 @@ class Server(utils.EventEmitter):
|
|
|
467
436
|
async def _notify_or_indicate_subscribers(
|
|
468
437
|
self,
|
|
469
438
|
indicate: bool,
|
|
470
|
-
attribute: Attribute,
|
|
439
|
+
attribute: att.Attribute,
|
|
471
440
|
value: Optional[bytes] = None,
|
|
472
441
|
force: bool = False,
|
|
473
442
|
) -> None:
|
|
@@ -494,7 +463,7 @@ class Server(utils.EventEmitter):
|
|
|
494
463
|
|
|
495
464
|
async def notify_subscribers(
|
|
496
465
|
self,
|
|
497
|
-
attribute: Attribute,
|
|
466
|
+
attribute: att.Attribute,
|
|
498
467
|
value: Optional[bytes] = None,
|
|
499
468
|
force: bool = False,
|
|
500
469
|
):
|
|
@@ -504,7 +473,7 @@ class Server(utils.EventEmitter):
|
|
|
504
473
|
|
|
505
474
|
async def indicate_subscribers(
|
|
506
475
|
self,
|
|
507
|
-
attribute: Attribute,
|
|
476
|
+
attribute: att.Attribute,
|
|
508
477
|
value: Optional[bytes] = None,
|
|
509
478
|
force: bool = False,
|
|
510
479
|
):
|
|
@@ -518,33 +487,33 @@ class Server(utils.EventEmitter):
|
|
|
518
487
|
if connection.handle in self.pending_confirmations:
|
|
519
488
|
del self.pending_confirmations[connection.handle]
|
|
520
489
|
|
|
521
|
-
def on_gatt_pdu(self, connection: Connection, att_pdu: ATT_PDU) -> None:
|
|
490
|
+
def on_gatt_pdu(self, connection: Connection, att_pdu: att.ATT_PDU) -> None:
|
|
522
491
|
logger.debug(f'GATT Request to server: [0x{connection.handle:04X}] {att_pdu}')
|
|
523
492
|
handler_name = f'on_{att_pdu.name.lower()}'
|
|
524
493
|
handler = getattr(self, handler_name, None)
|
|
525
494
|
if handler is not None:
|
|
526
495
|
try:
|
|
527
496
|
handler(connection, att_pdu)
|
|
528
|
-
except ATT_Error as error:
|
|
497
|
+
except att.ATT_Error as error:
|
|
529
498
|
logger.debug(f'normal exception returned by handler: {error}')
|
|
530
|
-
response = ATT_Error_Response(
|
|
499
|
+
response = att.ATT_Error_Response(
|
|
531
500
|
request_opcode_in_error=att_pdu.op_code,
|
|
532
501
|
attribute_handle_in_error=error.att_handle,
|
|
533
502
|
error_code=error.error_code,
|
|
534
503
|
)
|
|
535
504
|
self.send_response(connection, response)
|
|
536
|
-
except Exception
|
|
537
|
-
logger.
|
|
538
|
-
response = ATT_Error_Response(
|
|
505
|
+
except Exception:
|
|
506
|
+
logger.exception(color("!!! Exception in handler:", "red"))
|
|
507
|
+
response = att.ATT_Error_Response(
|
|
539
508
|
request_opcode_in_error=att_pdu.op_code,
|
|
540
509
|
attribute_handle_in_error=0x0000,
|
|
541
|
-
error_code=ATT_UNLIKELY_ERROR_ERROR,
|
|
510
|
+
error_code=att.ATT_UNLIKELY_ERROR_ERROR,
|
|
542
511
|
)
|
|
543
512
|
self.send_response(connection, response)
|
|
544
|
-
raise
|
|
513
|
+
raise
|
|
545
514
|
else:
|
|
546
515
|
# No specific handler registered
|
|
547
|
-
if att_pdu.op_code in ATT_REQUESTS:
|
|
516
|
+
if att_pdu.op_code in att.ATT_REQUESTS:
|
|
548
517
|
# Invoke the generic handler
|
|
549
518
|
self.on_att_request(connection, att_pdu)
|
|
550
519
|
else:
|
|
@@ -560,7 +529,7 @@ class Server(utils.EventEmitter):
|
|
|
560
529
|
#######################################################
|
|
561
530
|
# ATT handlers
|
|
562
531
|
#######################################################
|
|
563
|
-
def on_att_request(self, connection: Connection, pdu: ATT_PDU) -> None:
|
|
532
|
+
def on_att_request(self, connection: Connection, pdu: att.ATT_PDU) -> None:
|
|
564
533
|
'''
|
|
565
534
|
Handler for requests without a more specific handler
|
|
566
535
|
'''
|
|
@@ -570,23 +539,25 @@ class Server(utils.EventEmitter):
|
|
|
570
539
|
)
|
|
571
540
|
+ str(pdu)
|
|
572
541
|
)
|
|
573
|
-
response = ATT_Error_Response(
|
|
542
|
+
response = att.ATT_Error_Response(
|
|
574
543
|
request_opcode_in_error=pdu.op_code,
|
|
575
544
|
attribute_handle_in_error=0x0000,
|
|
576
|
-
error_code=ATT_REQUEST_NOT_SUPPORTED_ERROR,
|
|
545
|
+
error_code=att.ATT_REQUEST_NOT_SUPPORTED_ERROR,
|
|
577
546
|
)
|
|
578
547
|
self.send_response(connection, response)
|
|
579
548
|
|
|
580
|
-
def on_att_exchange_mtu_request(
|
|
549
|
+
def on_att_exchange_mtu_request(
|
|
550
|
+
self, connection: Connection, request: att.ATT_Exchange_MTU_Request
|
|
551
|
+
):
|
|
581
552
|
'''
|
|
582
553
|
See Bluetooth spec Vol 3, Part F - 3.4.2.1 Exchange MTU Request
|
|
583
554
|
'''
|
|
584
555
|
self.send_response(
|
|
585
|
-
connection, ATT_Exchange_MTU_Response(server_rx_mtu=self.max_mtu)
|
|
556
|
+
connection, att.ATT_Exchange_MTU_Response(server_rx_mtu=self.max_mtu)
|
|
586
557
|
)
|
|
587
558
|
|
|
588
559
|
# Compute the final MTU
|
|
589
|
-
if request.client_rx_mtu >= ATT_DEFAULT_MTU:
|
|
560
|
+
if request.client_rx_mtu >= att.ATT_DEFAULT_MTU:
|
|
590
561
|
mtu = min(self.max_mtu, request.client_rx_mtu)
|
|
591
562
|
|
|
592
563
|
# Notify the device
|
|
@@ -594,11 +565,14 @@ class Server(utils.EventEmitter):
|
|
|
594
565
|
else:
|
|
595
566
|
logger.warning('invalid client_rx_mtu received, MTU not changed')
|
|
596
567
|
|
|
597
|
-
def on_att_find_information_request(
|
|
568
|
+
def on_att_find_information_request(
|
|
569
|
+
self, connection: Connection, request: att.ATT_Find_Information_Request
|
|
570
|
+
):
|
|
598
571
|
'''
|
|
599
572
|
See Bluetooth spec Vol 3, Part F - 3.4.3.1 Find Information Request
|
|
600
573
|
'''
|
|
601
574
|
|
|
575
|
+
response: att.ATT_PDU
|
|
602
576
|
# Check the request parameters
|
|
603
577
|
if (
|
|
604
578
|
request.starting_handle == 0
|
|
@@ -606,17 +580,17 @@ class Server(utils.EventEmitter):
|
|
|
606
580
|
):
|
|
607
581
|
self.send_response(
|
|
608
582
|
connection,
|
|
609
|
-
ATT_Error_Response(
|
|
583
|
+
att.ATT_Error_Response(
|
|
610
584
|
request_opcode_in_error=request.op_code,
|
|
611
585
|
attribute_handle_in_error=request.starting_handle,
|
|
612
|
-
error_code=ATT_INVALID_HANDLE_ERROR,
|
|
586
|
+
error_code=att.ATT_INVALID_HANDLE_ERROR,
|
|
613
587
|
),
|
|
614
588
|
)
|
|
615
589
|
return
|
|
616
590
|
|
|
617
591
|
# Build list of returned attributes
|
|
618
592
|
pdu_space_available = connection.att_mtu - 2
|
|
619
|
-
attributes = []
|
|
593
|
+
attributes: list[att.Attribute] = []
|
|
620
594
|
uuid_size = 0
|
|
621
595
|
for attribute in (
|
|
622
596
|
attribute
|
|
@@ -646,21 +620,23 @@ class Server(utils.EventEmitter):
|
|
|
646
620
|
struct.pack('<H', attribute.handle) + attribute.type.to_pdu_bytes()
|
|
647
621
|
for attribute in attributes
|
|
648
622
|
]
|
|
649
|
-
response = ATT_Find_Information_Response(
|
|
623
|
+
response = att.ATT_Find_Information_Response(
|
|
650
624
|
format=1 if len(attributes[0].type.to_pdu_bytes()) == 2 else 2,
|
|
651
625
|
information_data=b''.join(information_data_list),
|
|
652
626
|
)
|
|
653
627
|
else:
|
|
654
|
-
response = ATT_Error_Response(
|
|
628
|
+
response = att.ATT_Error_Response(
|
|
655
629
|
request_opcode_in_error=request.op_code,
|
|
656
630
|
attribute_handle_in_error=request.starting_handle,
|
|
657
|
-
error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
631
|
+
error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
658
632
|
)
|
|
659
633
|
|
|
660
634
|
self.send_response(connection, response)
|
|
661
635
|
|
|
662
636
|
@utils.AsyncRunner.run_in_task()
|
|
663
|
-
async def on_att_find_by_type_value_request(
|
|
637
|
+
async def on_att_find_by_type_value_request(
|
|
638
|
+
self, connection: Connection, request: att.ATT_Find_By_Type_Value_Request
|
|
639
|
+
):
|
|
664
640
|
'''
|
|
665
641
|
See Bluetooth spec Vol 3, Part F - 3.4.3.3 Find By Type Value Request
|
|
666
642
|
'''
|
|
@@ -668,6 +644,7 @@ class Server(utils.EventEmitter):
|
|
|
668
644
|
# Build list of returned attributes
|
|
669
645
|
pdu_space_available = connection.att_mtu - 2
|
|
670
646
|
attributes = []
|
|
647
|
+
response: att.ATT_PDU
|
|
671
648
|
async for attribute in (
|
|
672
649
|
attribute
|
|
673
650
|
for attribute in self.attributes
|
|
@@ -700,33 +677,35 @@ class Server(utils.EventEmitter):
|
|
|
700
677
|
handles_information_list.append(
|
|
701
678
|
struct.pack('<HH', attribute.handle, group_end_handle)
|
|
702
679
|
)
|
|
703
|
-
response = ATT_Find_By_Type_Value_Response(
|
|
680
|
+
response = att.ATT_Find_By_Type_Value_Response(
|
|
704
681
|
handles_information_list=b''.join(handles_information_list)
|
|
705
682
|
)
|
|
706
683
|
else:
|
|
707
|
-
response = ATT_Error_Response(
|
|
684
|
+
response = att.ATT_Error_Response(
|
|
708
685
|
request_opcode_in_error=request.op_code,
|
|
709
686
|
attribute_handle_in_error=request.starting_handle,
|
|
710
|
-
error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
687
|
+
error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
711
688
|
)
|
|
712
689
|
|
|
713
690
|
self.send_response(connection, response)
|
|
714
691
|
|
|
715
692
|
@utils.AsyncRunner.run_in_task()
|
|
716
|
-
async def on_att_read_by_type_request(
|
|
693
|
+
async def on_att_read_by_type_request(
|
|
694
|
+
self, connection: Connection, request: att.ATT_Read_By_Type_Request
|
|
695
|
+
):
|
|
717
696
|
'''
|
|
718
697
|
See Bluetooth spec Vol 3, Part F - 3.4.4.1 Read By Type Request
|
|
719
698
|
'''
|
|
720
699
|
|
|
721
700
|
pdu_space_available = connection.att_mtu - 2
|
|
722
701
|
|
|
723
|
-
response = ATT_Error_Response(
|
|
702
|
+
response: att.ATT_PDU = att.ATT_Error_Response(
|
|
724
703
|
request_opcode_in_error=request.op_code,
|
|
725
704
|
attribute_handle_in_error=request.starting_handle,
|
|
726
|
-
error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
705
|
+
error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
727
706
|
)
|
|
728
707
|
|
|
729
|
-
attributes = []
|
|
708
|
+
attributes: list[tuple[int, bytes]] = []
|
|
730
709
|
for attribute in (
|
|
731
710
|
attribute
|
|
732
711
|
for attribute in self.attributes
|
|
@@ -737,11 +716,11 @@ class Server(utils.EventEmitter):
|
|
|
737
716
|
):
|
|
738
717
|
try:
|
|
739
718
|
attribute_value = await attribute.read_value(connection)
|
|
740
|
-
except ATT_Error as error:
|
|
719
|
+
except att.ATT_Error as error:
|
|
741
720
|
# If the first attribute is unreadable, return an error
|
|
742
721
|
# Otherwise return attributes up to this point
|
|
743
722
|
if not attributes:
|
|
744
|
-
response = ATT_Error_Response(
|
|
723
|
+
response = att.ATT_Error_Response(
|
|
745
724
|
request_opcode_in_error=request.op_code,
|
|
746
725
|
attribute_handle_in_error=attribute.handle,
|
|
747
726
|
error_code=error.error_code,
|
|
@@ -770,7 +749,7 @@ class Server(utils.EventEmitter):
|
|
|
770
749
|
attribute_data_list = [
|
|
771
750
|
struct.pack('<H', handle) + value for handle, value in attributes
|
|
772
751
|
]
|
|
773
|
-
response = ATT_Read_By_Type_Response(
|
|
752
|
+
response = att.ATT_Read_By_Type_Response(
|
|
774
753
|
length=entry_size, attribute_data_list=b''.join(attribute_data_list)
|
|
775
754
|
)
|
|
776
755
|
else:
|
|
@@ -779,95 +758,104 @@ class Server(utils.EventEmitter):
|
|
|
779
758
|
self.send_response(connection, response)
|
|
780
759
|
|
|
781
760
|
@utils.AsyncRunner.run_in_task()
|
|
782
|
-
async def on_att_read_request(
|
|
761
|
+
async def on_att_read_request(
|
|
762
|
+
self, connection: Connection, request: att.ATT_Read_Request
|
|
763
|
+
):
|
|
783
764
|
'''
|
|
784
765
|
See Bluetooth spec Vol 3, Part F - 3.4.4.3 Read Request
|
|
785
766
|
'''
|
|
786
767
|
|
|
768
|
+
response: att.ATT_PDU
|
|
787
769
|
if attribute := self.get_attribute(request.attribute_handle):
|
|
788
770
|
try:
|
|
789
771
|
value = await attribute.read_value(connection)
|
|
790
|
-
except ATT_Error as error:
|
|
791
|
-
response = ATT_Error_Response(
|
|
772
|
+
except att.ATT_Error as error:
|
|
773
|
+
response = att.ATT_Error_Response(
|
|
792
774
|
request_opcode_in_error=request.op_code,
|
|
793
775
|
attribute_handle_in_error=request.attribute_handle,
|
|
794
776
|
error_code=error.error_code,
|
|
795
777
|
)
|
|
796
778
|
else:
|
|
797
779
|
value_size = min(connection.att_mtu - 1, len(value))
|
|
798
|
-
response = ATT_Read_Response(attribute_value=value[:value_size])
|
|
780
|
+
response = att.ATT_Read_Response(attribute_value=value[:value_size])
|
|
799
781
|
else:
|
|
800
|
-
response = ATT_Error_Response(
|
|
782
|
+
response = att.ATT_Error_Response(
|
|
801
783
|
request_opcode_in_error=request.op_code,
|
|
802
784
|
attribute_handle_in_error=request.attribute_handle,
|
|
803
|
-
error_code=ATT_INVALID_HANDLE_ERROR,
|
|
785
|
+
error_code=att.ATT_INVALID_HANDLE_ERROR,
|
|
804
786
|
)
|
|
805
787
|
self.send_response(connection, response)
|
|
806
788
|
|
|
807
789
|
@utils.AsyncRunner.run_in_task()
|
|
808
|
-
async def on_att_read_blob_request(
|
|
790
|
+
async def on_att_read_blob_request(
|
|
791
|
+
self, connection: Connection, request: att.ATT_Read_Blob_Request
|
|
792
|
+
):
|
|
809
793
|
'''
|
|
810
794
|
See Bluetooth spec Vol 3, Part F - 3.4.4.5 Read Blob Request
|
|
811
795
|
'''
|
|
812
796
|
|
|
797
|
+
response: att.ATT_PDU
|
|
813
798
|
if attribute := self.get_attribute(request.attribute_handle):
|
|
814
799
|
try:
|
|
815
800
|
value = await attribute.read_value(connection)
|
|
816
|
-
except ATT_Error as error:
|
|
817
|
-
response = ATT_Error_Response(
|
|
801
|
+
except att.ATT_Error as error:
|
|
802
|
+
response = att.ATT_Error_Response(
|
|
818
803
|
request_opcode_in_error=request.op_code,
|
|
819
804
|
attribute_handle_in_error=request.attribute_handle,
|
|
820
805
|
error_code=error.error_code,
|
|
821
806
|
)
|
|
822
807
|
else:
|
|
823
808
|
if request.value_offset > len(value):
|
|
824
|
-
response = ATT_Error_Response(
|
|
809
|
+
response = att.ATT_Error_Response(
|
|
825
810
|
request_opcode_in_error=request.op_code,
|
|
826
811
|
attribute_handle_in_error=request.attribute_handle,
|
|
827
|
-
error_code=ATT_INVALID_OFFSET_ERROR,
|
|
812
|
+
error_code=att.ATT_INVALID_OFFSET_ERROR,
|
|
828
813
|
)
|
|
829
814
|
elif len(value) <= connection.att_mtu - 1:
|
|
830
|
-
response = ATT_Error_Response(
|
|
815
|
+
response = att.ATT_Error_Response(
|
|
831
816
|
request_opcode_in_error=request.op_code,
|
|
832
817
|
attribute_handle_in_error=request.attribute_handle,
|
|
833
|
-
error_code=ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
818
|
+
error_code=att.ATT_ATTRIBUTE_NOT_LONG_ERROR,
|
|
834
819
|
)
|
|
835
820
|
else:
|
|
836
821
|
part_size = min(
|
|
837
822
|
connection.att_mtu - 1, len(value) - request.value_offset
|
|
838
823
|
)
|
|
839
|
-
response = ATT_Read_Blob_Response(
|
|
824
|
+
response = att.ATT_Read_Blob_Response(
|
|
840
825
|
part_attribute_value=value[
|
|
841
826
|
request.value_offset : request.value_offset + part_size
|
|
842
827
|
]
|
|
843
828
|
)
|
|
844
829
|
else:
|
|
845
|
-
response = ATT_Error_Response(
|
|
830
|
+
response = att.ATT_Error_Response(
|
|
846
831
|
request_opcode_in_error=request.op_code,
|
|
847
832
|
attribute_handle_in_error=request.attribute_handle,
|
|
848
|
-
error_code=ATT_INVALID_HANDLE_ERROR,
|
|
833
|
+
error_code=att.ATT_INVALID_HANDLE_ERROR,
|
|
849
834
|
)
|
|
850
835
|
self.send_response(connection, response)
|
|
851
836
|
|
|
852
837
|
@utils.AsyncRunner.run_in_task()
|
|
853
|
-
async def on_att_read_by_group_type_request(
|
|
838
|
+
async def on_att_read_by_group_type_request(
|
|
839
|
+
self, connection: Connection, request: att.ATT_Read_By_Group_Type_Request
|
|
840
|
+
):
|
|
854
841
|
'''
|
|
855
842
|
See Bluetooth spec Vol 3, Part F - 3.4.4.9 Read by Group Type Request
|
|
856
843
|
'''
|
|
844
|
+
response: att.ATT_PDU
|
|
857
845
|
if request.attribute_group_type not in (
|
|
858
846
|
GATT_PRIMARY_SERVICE_ATTRIBUTE_TYPE,
|
|
859
847
|
GATT_SECONDARY_SERVICE_ATTRIBUTE_TYPE,
|
|
860
848
|
):
|
|
861
|
-
response = ATT_Error_Response(
|
|
849
|
+
response = att.ATT_Error_Response(
|
|
862
850
|
request_opcode_in_error=request.op_code,
|
|
863
851
|
attribute_handle_in_error=request.starting_handle,
|
|
864
|
-
error_code=ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
|
|
852
|
+
error_code=att.ATT_UNSUPPORTED_GROUP_TYPE_ERROR,
|
|
865
853
|
)
|
|
866
854
|
self.send_response(connection, response)
|
|
867
855
|
return
|
|
868
856
|
|
|
869
857
|
pdu_space_available = connection.att_mtu - 2
|
|
870
|
-
attributes = []
|
|
858
|
+
attributes: list[tuple[int, int, bytes]] = []
|
|
871
859
|
for attribute in (
|
|
872
860
|
attribute
|
|
873
861
|
for attribute in self.attributes
|
|
@@ -904,21 +892,23 @@ class Server(utils.EventEmitter):
|
|
|
904
892
|
struct.pack('<HH', handle, end_group_handle) + value
|
|
905
893
|
for handle, end_group_handle, value in attributes
|
|
906
894
|
]
|
|
907
|
-
response = ATT_Read_By_Group_Type_Response(
|
|
895
|
+
response = att.ATT_Read_By_Group_Type_Response(
|
|
908
896
|
length=len(attribute_data_list[0]),
|
|
909
897
|
attribute_data_list=b''.join(attribute_data_list),
|
|
910
898
|
)
|
|
911
899
|
else:
|
|
912
|
-
response = ATT_Error_Response(
|
|
900
|
+
response = att.ATT_Error_Response(
|
|
913
901
|
request_opcode_in_error=request.op_code,
|
|
914
902
|
attribute_handle_in_error=request.starting_handle,
|
|
915
|
-
error_code=ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
903
|
+
error_code=att.ATT_ATTRIBUTE_NOT_FOUND_ERROR,
|
|
916
904
|
)
|
|
917
905
|
|
|
918
906
|
self.send_response(connection, response)
|
|
919
907
|
|
|
920
908
|
@utils.AsyncRunner.run_in_task()
|
|
921
|
-
async def on_att_write_request(
|
|
909
|
+
async def on_att_write_request(
|
|
910
|
+
self, connection: Connection, request: att.ATT_Write_Request
|
|
911
|
+
):
|
|
922
912
|
'''
|
|
923
913
|
See Bluetooth spec Vol 3, Part F - 3.4.5.1 Write Request
|
|
924
914
|
'''
|
|
@@ -928,10 +918,10 @@ class Server(utils.EventEmitter):
|
|
|
928
918
|
if attribute is None:
|
|
929
919
|
self.send_response(
|
|
930
920
|
connection,
|
|
931
|
-
ATT_Error_Response(
|
|
921
|
+
att.ATT_Error_Response(
|
|
932
922
|
request_opcode_in_error=request.op_code,
|
|
933
923
|
attribute_handle_in_error=request.attribute_handle,
|
|
934
|
-
error_code=ATT_INVALID_HANDLE_ERROR,
|
|
924
|
+
error_code=att.ATT_INVALID_HANDLE_ERROR,
|
|
935
925
|
),
|
|
936
926
|
)
|
|
937
927
|
return
|
|
@@ -942,30 +932,33 @@ class Server(utils.EventEmitter):
|
|
|
942
932
|
if len(request.attribute_value) > GATT_MAX_ATTRIBUTE_VALUE_SIZE:
|
|
943
933
|
self.send_response(
|
|
944
934
|
connection,
|
|
945
|
-
ATT_Error_Response(
|
|
935
|
+
att.ATT_Error_Response(
|
|
946
936
|
request_opcode_in_error=request.op_code,
|
|
947
937
|
attribute_handle_in_error=request.attribute_handle,
|
|
948
|
-
error_code=ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
|
|
938
|
+
error_code=att.ATT_INVALID_ATTRIBUTE_LENGTH_ERROR,
|
|
949
939
|
),
|
|
950
940
|
)
|
|
951
941
|
return
|
|
952
942
|
|
|
943
|
+
response: att.ATT_PDU
|
|
953
944
|
try:
|
|
954
945
|
# Accept the value
|
|
955
946
|
await attribute.write_value(connection, request.attribute_value)
|
|
956
|
-
except ATT_Error as error:
|
|
957
|
-
response = ATT_Error_Response(
|
|
947
|
+
except att.ATT_Error as error:
|
|
948
|
+
response = att.ATT_Error_Response(
|
|
958
949
|
request_opcode_in_error=request.op_code,
|
|
959
950
|
attribute_handle_in_error=request.attribute_handle,
|
|
960
951
|
error_code=error.error_code,
|
|
961
952
|
)
|
|
962
953
|
else:
|
|
963
954
|
# Done
|
|
964
|
-
response = ATT_Write_Response()
|
|
955
|
+
response = att.ATT_Write_Response()
|
|
965
956
|
self.send_response(connection, response)
|
|
966
957
|
|
|
967
958
|
@utils.AsyncRunner.run_in_task()
|
|
968
|
-
async def on_att_write_command(
|
|
959
|
+
async def on_att_write_command(
|
|
960
|
+
self, connection: Connection, request: att.ATT_Write_Command
|
|
961
|
+
):
|
|
969
962
|
'''
|
|
970
963
|
See Bluetooth spec Vol 3, Part F - 3.4.5.3 Write Command
|
|
971
964
|
'''
|
|
@@ -984,18 +977,25 @@ class Server(utils.EventEmitter):
|
|
|
984
977
|
# Accept the value
|
|
985
978
|
try:
|
|
986
979
|
await attribute.write_value(connection, request.attribute_value)
|
|
987
|
-
except Exception
|
|
988
|
-
logger.exception(
|
|
980
|
+
except Exception:
|
|
981
|
+
logger.exception('!!! ignoring exception')
|
|
989
982
|
|
|
990
|
-
def on_att_handle_value_confirmation(
|
|
983
|
+
def on_att_handle_value_confirmation(
|
|
984
|
+
self,
|
|
985
|
+
connection: Connection,
|
|
986
|
+
confirmation: att.ATT_Handle_Value_Confirmation,
|
|
987
|
+
):
|
|
991
988
|
'''
|
|
992
989
|
See Bluetooth spec Vol 3, Part F - 3.4.7.3 Handle Value Confirmation
|
|
993
990
|
'''
|
|
994
|
-
|
|
991
|
+
del confirmation # Unused.
|
|
992
|
+
if (
|
|
993
|
+
pending_confirmation := self.pending_confirmations[connection.handle]
|
|
994
|
+
) is None:
|
|
995
995
|
# Not expected!
|
|
996
996
|
logger.warning(
|
|
997
997
|
'!!! unexpected confirmation, there is no pending indication'
|
|
998
998
|
)
|
|
999
999
|
return
|
|
1000
1000
|
|
|
1001
|
-
|
|
1001
|
+
pending_confirmation.set_result(None)
|