bumble 0.0.212__py3-none-any.whl → 0.0.214__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/a2dp.py +6 -0
- bumble/apps/README.md +0 -3
- bumble/apps/auracast.py +14 -11
- bumble/apps/bench.py +482 -37
- bumble/apps/console.py +3 -3
- bumble/apps/controller_info.py +44 -12
- bumble/apps/controller_loopback.py +7 -7
- bumble/apps/controllers.py +4 -5
- bumble/apps/device_info.py +4 -5
- bumble/apps/gatt_dump.py +5 -5
- bumble/apps/gg_bridge.py +5 -5
- bumble/apps/hci_bridge.py +5 -4
- bumble/apps/l2cap_bridge.py +5 -5
- bumble/apps/lea_unicast/app.py +8 -3
- bumble/apps/pair.py +19 -11
- bumble/apps/pandora_server.py +2 -2
- bumble/apps/player/player.py +2 -3
- bumble/apps/rfcomm_bridge.py +3 -4
- bumble/apps/scan.py +4 -5
- bumble/apps/show.py +6 -4
- bumble/apps/speaker/speaker.html +1 -0
- bumble/apps/speaker/speaker.js +113 -62
- bumble/apps/speaker/speaker.py +123 -19
- bumble/apps/unbond.py +2 -3
- bumble/apps/usb_probe.py +2 -3
- bumble/at.py +4 -4
- bumble/att.py +2 -6
- bumble/avc.py +7 -7
- bumble/avctp.py +3 -3
- bumble/avdtp.py +16 -20
- bumble/avrcp.py +42 -54
- bumble/colors.py +2 -2
- bumble/controller.py +174 -45
- bumble/device.py +398 -182
- bumble/drivers/__init__.py +2 -2
- bumble/drivers/common.py +0 -2
- bumble/drivers/intel.py +37 -40
- bumble/drivers/rtk.py +28 -35
- bumble/gatt.py +4 -4
- bumble/gatt_adapters.py +4 -5
- bumble/gatt_client.py +26 -31
- bumble/gatt_server.py +7 -11
- bumble/hci.py +2648 -2909
- bumble/helpers.py +4 -5
- bumble/hfp.py +32 -37
- bumble/host.py +104 -35
- bumble/keys.py +5 -5
- bumble/l2cap.py +312 -409
- bumble/link.py +16 -280
- bumble/logging.py +65 -0
- bumble/pairing.py +23 -20
- bumble/pandora/__init__.py +2 -2
- bumble/pandora/config.py +2 -2
- bumble/pandora/device.py +6 -6
- bumble/pandora/host.py +27 -28
- bumble/pandora/l2cap.py +2 -2
- bumble/pandora/security.py +6 -6
- bumble/pandora/utils.py +3 -3
- bumble/profiles/ams.py +404 -0
- bumble/profiles/ascs.py +142 -131
- bumble/profiles/asha.py +2 -2
- bumble/profiles/bap.py +3 -4
- bumble/profiles/csip.py +2 -2
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +2 -2
- bumble/profiles/hap.py +34 -33
- bumble/profiles/le_audio.py +4 -4
- bumble/profiles/mcp.py +4 -4
- bumble/profiles/vcs.py +3 -5
- bumble/rfcomm.py +10 -10
- bumble/rtp.py +1 -2
- bumble/sdp.py +2 -2
- bumble/smp.py +62 -63
- bumble/tools/intel_util.py +3 -2
- bumble/tools/rtk_util.py +6 -5
- bumble/transport/__init__.py +2 -16
- bumble/transport/android_netsim.py +5 -5
- bumble/transport/common.py +4 -4
- bumble/transport/pyusb.py +2 -2
- bumble/utils.py +2 -5
- bumble/vendor/android/hci.py +118 -200
- bumble/vendor/zephyr/hci.py +32 -27
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/METADATA +4 -3
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/RECORD +89 -90
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/WHEEL +1 -1
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/entry_points.txt +0 -1
- bumble/apps/link_relay/__init__.py +0 -0
- bumble/apps/link_relay/link_relay.py +0 -289
- bumble/apps/link_relay/logging.yml +0 -21
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/top_level.txt +0 -0
bumble/tools/intel_util.py
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
import logging
|
|
19
19
|
import asyncio
|
|
20
|
-
import os
|
|
21
20
|
from typing import Any, Optional
|
|
22
21
|
|
|
23
22
|
import click
|
|
@@ -26,6 +25,8 @@ from bumble.colors import color
|
|
|
26
25
|
from bumble import transport
|
|
27
26
|
from bumble.drivers import intel
|
|
28
27
|
from bumble.host import Host
|
|
28
|
+
import bumble.logging
|
|
29
|
+
|
|
29
30
|
|
|
30
31
|
# -----------------------------------------------------------------------------
|
|
31
32
|
# Logging
|
|
@@ -107,7 +108,7 @@ async def do_bootloader(usb_transport: str, force: bool) -> None:
|
|
|
107
108
|
# -----------------------------------------------------------------------------
|
|
108
109
|
@click.group()
|
|
109
110
|
def main():
|
|
110
|
-
logging.
|
|
111
|
+
bumble.logging.setup_basic_logging()
|
|
111
112
|
|
|
112
113
|
|
|
113
114
|
@main.command
|
bumble/tools/rtk_util.py
CHANGED
|
@@ -15,15 +15,16 @@
|
|
|
15
15
|
# -----------------------------------------------------------------------------
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
|
-
import logging
|
|
19
18
|
import asyncio
|
|
20
|
-
import
|
|
19
|
+
import logging
|
|
21
20
|
|
|
22
21
|
import click
|
|
23
22
|
|
|
24
23
|
from bumble import transport
|
|
25
24
|
from bumble.host import Host
|
|
26
25
|
from bumble.drivers import rtk
|
|
26
|
+
import bumble.logging
|
|
27
|
+
|
|
27
28
|
|
|
28
29
|
# -----------------------------------------------------------------------------
|
|
29
30
|
# Logging
|
|
@@ -50,7 +51,7 @@ def do_parse(firmware_path):
|
|
|
50
51
|
|
|
51
52
|
# -----------------------------------------------------------------------------
|
|
52
53
|
async def do_load(usb_transport, force):
|
|
53
|
-
async with await transport.
|
|
54
|
+
async with await transport.open_transport(usb_transport) as (
|
|
54
55
|
hci_source,
|
|
55
56
|
hci_sink,
|
|
56
57
|
):
|
|
@@ -69,7 +70,7 @@ async def do_load(usb_transport, force):
|
|
|
69
70
|
|
|
70
71
|
# -----------------------------------------------------------------------------
|
|
71
72
|
async def do_drop(usb_transport):
|
|
72
|
-
async with await transport.
|
|
73
|
+
async with await transport.open_transport(usb_transport) as (
|
|
73
74
|
hci_source,
|
|
74
75
|
hci_sink,
|
|
75
76
|
):
|
|
@@ -112,7 +113,7 @@ async def do_info(usb_transport, force):
|
|
|
112
113
|
# -----------------------------------------------------------------------------
|
|
113
114
|
@click.group()
|
|
114
115
|
def main():
|
|
115
|
-
logging.
|
|
116
|
+
bumble.logging.setup_basic_logging()
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
@main.command
|
bumble/transport/__init__.py
CHANGED
|
@@ -20,9 +20,9 @@ import logging
|
|
|
20
20
|
import os
|
|
21
21
|
from typing import Optional
|
|
22
22
|
|
|
23
|
+
from bumble import utils
|
|
23
24
|
from bumble.transport.common import (
|
|
24
25
|
Transport,
|
|
25
|
-
AsyncPipeSink,
|
|
26
26
|
SnoopingTransport,
|
|
27
27
|
TransportSpecError,
|
|
28
28
|
)
|
|
@@ -195,6 +195,7 @@ async def _open_transport(scheme: str, spec: Optional[str]) -> Transport:
|
|
|
195
195
|
|
|
196
196
|
|
|
197
197
|
# -----------------------------------------------------------------------------
|
|
198
|
+
@utils.deprecated("RemoteLink has been removed. Use open_transport instead.")
|
|
198
199
|
async def open_transport_or_link(name: str) -> Transport:
|
|
199
200
|
"""
|
|
200
201
|
Open a transport or a link relay.
|
|
@@ -205,21 +206,6 @@ async def open_transport_or_link(name: str) -> Transport:
|
|
|
205
206
|
When the name starts with "link-relay:", open a link relay (see RemoteLink
|
|
206
207
|
for details on what the arguments are).
|
|
207
208
|
For other namespaces, see `open_transport`.
|
|
208
|
-
|
|
209
209
|
"""
|
|
210
|
-
if name.startswith('link-relay:'):
|
|
211
|
-
logger.warning('Link Relay has been deprecated.')
|
|
212
|
-
from bumble.controller import Controller
|
|
213
|
-
from bumble.link import RemoteLink # lazy import
|
|
214
|
-
|
|
215
|
-
link = RemoteLink(name[11:])
|
|
216
|
-
await link.wait_until_connected()
|
|
217
|
-
controller = Controller('remote', link=link) # type:ignore[arg-type]
|
|
218
|
-
|
|
219
|
-
class LinkTransport(Transport):
|
|
220
|
-
async def close(self):
|
|
221
|
-
link.close()
|
|
222
|
-
|
|
223
|
-
return _wrap_transport(LinkTransport(controller, AsyncPipeSink(controller)))
|
|
224
210
|
|
|
225
211
|
return await open_transport(name)
|
|
@@ -22,7 +22,7 @@ import os
|
|
|
22
22
|
import pathlib
|
|
23
23
|
import platform
|
|
24
24
|
import sys
|
|
25
|
-
from typing import
|
|
25
|
+
from typing import Optional
|
|
26
26
|
|
|
27
27
|
import grpc.aio
|
|
28
28
|
|
|
@@ -143,7 +143,7 @@ def publish_grpc_port(grpc_port: int, instance_number: int) -> bool:
|
|
|
143
143
|
|
|
144
144
|
# -----------------------------------------------------------------------------
|
|
145
145
|
async def open_android_netsim_controller_transport(
|
|
146
|
-
server_host: Optional[str], server_port: int, options:
|
|
146
|
+
server_host: Optional[str], server_port: int, options: dict[str, str]
|
|
147
147
|
) -> Transport:
|
|
148
148
|
if not server_port:
|
|
149
149
|
raise TransportSpecError('invalid port')
|
|
@@ -288,7 +288,7 @@ async def open_android_netsim_controller_transport(
|
|
|
288
288
|
async def open_android_netsim_host_transport_with_address(
|
|
289
289
|
server_host: Optional[str],
|
|
290
290
|
server_port: int,
|
|
291
|
-
options: Optional[
|
|
291
|
+
options: Optional[dict[str, str]] = None,
|
|
292
292
|
):
|
|
293
293
|
if server_host == '_' or not server_host:
|
|
294
294
|
server_host = 'localhost'
|
|
@@ -313,7 +313,7 @@ async def open_android_netsim_host_transport_with_address(
|
|
|
313
313
|
|
|
314
314
|
# -----------------------------------------------------------------------------
|
|
315
315
|
async def open_android_netsim_host_transport_with_channel(
|
|
316
|
-
channel, options: Optional[
|
|
316
|
+
channel, options: Optional[dict[str, str]] = None
|
|
317
317
|
):
|
|
318
318
|
# Wrapper for I/O operations
|
|
319
319
|
class HciDevice:
|
|
@@ -451,7 +451,7 @@ async def open_android_netsim_transport(spec: Optional[str]) -> Transport:
|
|
|
451
451
|
port = 0
|
|
452
452
|
params_offset = 0
|
|
453
453
|
|
|
454
|
-
options:
|
|
454
|
+
options: dict[str, str] = {}
|
|
455
455
|
for param in params[params_offset:]:
|
|
456
456
|
if '=' not in param:
|
|
457
457
|
raise TransportSpecError('invalid parameter, expected <name>=<value>')
|
bumble/transport/common.py
CHANGED
|
@@ -21,7 +21,7 @@ import struct
|
|
|
21
21
|
import asyncio
|
|
22
22
|
import logging
|
|
23
23
|
import io
|
|
24
|
-
from typing import Any, ContextManager,
|
|
24
|
+
from typing import Any, ContextManager, Optional, Protocol
|
|
25
25
|
|
|
26
26
|
from bumble import core
|
|
27
27
|
from bumble import hci
|
|
@@ -38,7 +38,7 @@ logger = logging.getLogger(__name__)
|
|
|
38
38
|
# Information needed to parse HCI packets with a generic parser:
|
|
39
39
|
# For each packet type, the info represents:
|
|
40
40
|
# (length-size, length-offset, unpack-type)
|
|
41
|
-
HCI_PACKET_INFO:
|
|
41
|
+
HCI_PACKET_INFO: dict[int, tuple[int, int, str]] = {
|
|
42
42
|
hci.HCI_COMMAND_PACKET: (1, 2, 'B'),
|
|
43
43
|
hci.HCI_ACL_DATA_PACKET: (2, 2, 'H'),
|
|
44
44
|
hci.HCI_SYNCHRONOUS_DATA_PACKET: (1, 2, 'B'),
|
|
@@ -108,8 +108,8 @@ class PacketParser:
|
|
|
108
108
|
NEED_BODY = 2
|
|
109
109
|
|
|
110
110
|
sink: Optional[TransportSink]
|
|
111
|
-
extended_packet_info:
|
|
112
|
-
packet_info: Optional[
|
|
111
|
+
extended_packet_info: dict[int, tuple[int, int, str]]
|
|
112
|
+
packet_info: Optional[tuple[int, int, str]] = None
|
|
113
113
|
|
|
114
114
|
def __init__(self, sink: Optional[TransportSink] = None) -> None:
|
|
115
115
|
self.sink = sink
|
bumble/transport/pyusb.py
CHANGED
|
@@ -23,7 +23,7 @@ import time
|
|
|
23
23
|
import usb.core
|
|
24
24
|
import usb.util
|
|
25
25
|
|
|
26
|
-
from typing import Optional
|
|
26
|
+
from typing import Optional
|
|
27
27
|
from usb.core import Device as UsbDevice
|
|
28
28
|
from usb.core import USBError
|
|
29
29
|
from usb.util import CTRL_TYPE_CLASS, CTRL_RECIPIENT_OTHER
|
|
@@ -49,7 +49,7 @@ logger = logging.getLogger(__name__)
|
|
|
49
49
|
# -----------------------------------------------------------------------------
|
|
50
50
|
# Global
|
|
51
51
|
# -----------------------------------------------------------------------------
|
|
52
|
-
devices_in_use:
|
|
52
|
+
devices_in_use: set[int] = set()
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
# -----------------------------------------------------------------------------
|
bumble/utils.py
CHANGED
|
@@ -27,11 +27,8 @@ from typing import (
|
|
|
27
27
|
Any,
|
|
28
28
|
Awaitable,
|
|
29
29
|
Callable,
|
|
30
|
-
List,
|
|
31
30
|
Optional,
|
|
32
31
|
Protocol,
|
|
33
|
-
Set,
|
|
34
|
-
Tuple,
|
|
35
32
|
TypeVar,
|
|
36
33
|
Union,
|
|
37
34
|
overload,
|
|
@@ -156,7 +153,7 @@ class EventWatcher:
|
|
|
156
153
|
```
|
|
157
154
|
'''
|
|
158
155
|
|
|
159
|
-
handlers:
|
|
156
|
+
handlers: list[tuple[pyee.EventEmitter, str, Callable[..., Any]]]
|
|
160
157
|
|
|
161
158
|
def __init__(self) -> None:
|
|
162
159
|
self.handlers = []
|
|
@@ -329,7 +326,7 @@ class AsyncRunner:
|
|
|
329
326
|
default_queue = WorkQueue()
|
|
330
327
|
|
|
331
328
|
# Shared set of running tasks
|
|
332
|
-
running_tasks:
|
|
329
|
+
running_tasks: set[Awaitable] = set()
|
|
333
330
|
|
|
334
331
|
@staticmethod
|
|
335
332
|
def run_in_task(queue=None):
|
bumble/vendor/android/hci.py
CHANGED
|
@@ -15,21 +15,12 @@
|
|
|
15
15
|
# -----------------------------------------------------------------------------
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
|
+
import dataclasses
|
|
19
|
+
from dataclasses import field
|
|
18
20
|
import struct
|
|
19
|
-
from typing import
|
|
20
|
-
|
|
21
|
-
from bumble
|
|
22
|
-
name_or_number,
|
|
23
|
-
hci_vendor_command_op_code,
|
|
24
|
-
Address,
|
|
25
|
-
HCI_Constant,
|
|
26
|
-
HCI_Object,
|
|
27
|
-
HCI_Command,
|
|
28
|
-
HCI_Event,
|
|
29
|
-
HCI_Extended_Event,
|
|
30
|
-
HCI_VENDOR_EVENT,
|
|
31
|
-
STATUS_SPEC,
|
|
32
|
-
)
|
|
21
|
+
from typing import Optional
|
|
22
|
+
|
|
23
|
+
from bumble import hci
|
|
33
24
|
|
|
34
25
|
|
|
35
26
|
# -----------------------------------------------------------------------------
|
|
@@ -41,22 +32,28 @@ from bumble.hci import (
|
|
|
41
32
|
#
|
|
42
33
|
# pylint: disable-next=line-too-long
|
|
43
34
|
# See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#chip-capabilities-and-configuration
|
|
44
|
-
HCI_LE_GET_VENDOR_CAPABILITIES_COMMAND = hci_vendor_command_op_code(0x153)
|
|
45
|
-
HCI_LE_APCF_COMMAND = hci_vendor_command_op_code(0x157)
|
|
46
|
-
HCI_GET_CONTROLLER_ACTIVITY_ENERGY_INFO_COMMAND = hci_vendor_command_op_code(0x159)
|
|
47
|
-
HCI_A2DP_HARDWARE_OFFLOAD_COMMAND = hci_vendor_command_op_code(0x15D)
|
|
48
|
-
HCI_BLUETOOTH_QUALITY_REPORT_COMMAND = hci_vendor_command_op_code(0x15E)
|
|
49
|
-
HCI_DYNAMIC_AUDIO_BUFFER_COMMAND = hci_vendor_command_op_code(0x15F)
|
|
35
|
+
HCI_LE_GET_VENDOR_CAPABILITIES_COMMAND = hci.hci_vendor_command_op_code(0x153)
|
|
36
|
+
HCI_LE_APCF_COMMAND = hci.hci_vendor_command_op_code(0x157)
|
|
37
|
+
HCI_GET_CONTROLLER_ACTIVITY_ENERGY_INFO_COMMAND = hci.hci_vendor_command_op_code(0x159)
|
|
38
|
+
HCI_A2DP_HARDWARE_OFFLOAD_COMMAND = hci.hci_vendor_command_op_code(0x15D)
|
|
39
|
+
HCI_BLUETOOTH_QUALITY_REPORT_COMMAND = hci.hci_vendor_command_op_code(0x15E)
|
|
40
|
+
HCI_DYNAMIC_AUDIO_BUFFER_COMMAND = hci.hci_vendor_command_op_code(0x15F)
|
|
50
41
|
|
|
51
42
|
HCI_BLUETOOTH_QUALITY_REPORT_EVENT = 0x58
|
|
52
43
|
|
|
53
|
-
HCI_Command.register_commands(globals())
|
|
44
|
+
hci.HCI_Command.register_commands(globals())
|
|
54
45
|
|
|
55
46
|
|
|
56
47
|
# -----------------------------------------------------------------------------
|
|
57
|
-
@HCI_Command.command
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
@hci.HCI_Command.command
|
|
49
|
+
@dataclasses.dataclass
|
|
50
|
+
class HCI_LE_Get_Vendor_Capabilities_Command(hci.HCI_Command):
|
|
51
|
+
# pylint: disable=line-too-long
|
|
52
|
+
'''
|
|
53
|
+
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities
|
|
54
|
+
'''
|
|
55
|
+
return_parameters_fields = [
|
|
56
|
+
('status', hci.STATUS_SPEC),
|
|
60
57
|
('max_advt_instances', 1),
|
|
61
58
|
('offloaded_resolution_of_private_address', 1),
|
|
62
59
|
('total_scan_results_storage', 2),
|
|
@@ -73,12 +70,6 @@ HCI_Command.register_commands(globals())
|
|
|
73
70
|
('bluetooth_quality_report_support', 1),
|
|
74
71
|
('dynamic_audio_buffer_support', 4),
|
|
75
72
|
]
|
|
76
|
-
)
|
|
77
|
-
class HCI_LE_Get_Vendor_Capabilities_Command(HCI_Command):
|
|
78
|
-
# pylint: disable=line-too-long
|
|
79
|
-
'''
|
|
80
|
-
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#vendor-specific-capabilities
|
|
81
|
-
'''
|
|
82
73
|
|
|
83
74
|
@classmethod
|
|
84
75
|
def parse_return_parameters(cls, parameters):
|
|
@@ -86,13 +77,13 @@ class HCI_LE_Get_Vendor_Capabilities_Command(HCI_Command):
|
|
|
86
77
|
# there are no more bytes to parse, and leave un-signal parameters set to
|
|
87
78
|
# None (older versions)
|
|
88
79
|
nones = {field: None for field, _ in cls.return_parameters_fields}
|
|
89
|
-
return_parameters = HCI_Object(cls.return_parameters_fields, **nones)
|
|
80
|
+
return_parameters = hci.HCI_Object(cls.return_parameters_fields, **nones)
|
|
90
81
|
|
|
91
82
|
try:
|
|
92
83
|
offset = 0
|
|
93
84
|
for field in cls.return_parameters_fields:
|
|
94
85
|
field_name, field_type = field
|
|
95
|
-
field_value, field_size = HCI_Object.parse_field(
|
|
86
|
+
field_value, field_size = hci.HCI_Object.parse_field(
|
|
96
87
|
parameters, offset, field_type
|
|
97
88
|
)
|
|
98
89
|
setattr(return_parameters, field_name, field_value)
|
|
@@ -104,30 +95,9 @@ class HCI_LE_Get_Vendor_Capabilities_Command(HCI_Command):
|
|
|
104
95
|
|
|
105
96
|
|
|
106
97
|
# -----------------------------------------------------------------------------
|
|
107
|
-
@HCI_Command.command
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
'opcode',
|
|
111
|
-
{
|
|
112
|
-
'size': 1,
|
|
113
|
-
'mapper': lambda x: HCI_LE_APCF_Command.opcode_name(x),
|
|
114
|
-
},
|
|
115
|
-
),
|
|
116
|
-
('payload', '*'),
|
|
117
|
-
],
|
|
118
|
-
return_parameters_fields=[
|
|
119
|
-
('status', STATUS_SPEC),
|
|
120
|
-
(
|
|
121
|
-
'opcode',
|
|
122
|
-
{
|
|
123
|
-
'size': 1,
|
|
124
|
-
'mapper': lambda x: HCI_LE_APCF_Command.opcode_name(x),
|
|
125
|
-
},
|
|
126
|
-
),
|
|
127
|
-
('payload', '*'),
|
|
128
|
-
],
|
|
129
|
-
)
|
|
130
|
-
class HCI_LE_APCF_Command(HCI_Command):
|
|
98
|
+
@hci.HCI_Command.command
|
|
99
|
+
@dataclasses.dataclass
|
|
100
|
+
class HCI_LE_APCF_Command(hci.HCI_Command):
|
|
131
101
|
# pylint: disable=line-too-long
|
|
132
102
|
'''
|
|
133
103
|
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_apcf_command
|
|
@@ -137,80 +107,50 @@ class HCI_LE_APCF_Command(HCI_Command):
|
|
|
137
107
|
'''
|
|
138
108
|
|
|
139
109
|
# APCF Subcommands
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
APCF_SERVICE_DATA: 'APCF_SERVICE_DATA',
|
|
162
|
-
APCF_TRANSPORT_DISCOVERY_SERVICE: 'APCF_TRANSPORT_DISCOVERY_SERVICE',
|
|
163
|
-
APCF_AD_TYPE_FILTER: 'APCF_AD_TYPE_FILTER',
|
|
164
|
-
APCF_READ_EXTENDED_FEATURES: 'APCF_READ_EXTENDED_FEATURES',
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@classmethod
|
|
168
|
-
def opcode_name(cls, opcode):
|
|
169
|
-
return name_or_number(cls.OPCODE_NAMES, opcode)
|
|
110
|
+
class Opcode(hci.SpecableEnum):
|
|
111
|
+
ENABLE = 0x00
|
|
112
|
+
SET_FILTERING_PARAMETERS = 0x01
|
|
113
|
+
BROADCASTER_ADDRESS = 0x02
|
|
114
|
+
SERVICE_UUID = 0x03
|
|
115
|
+
SERVICE_SOLICITATION_UUID = 0x04
|
|
116
|
+
LOCAL_NAME = 0x05
|
|
117
|
+
MANUFACTURER_DATA = 0x06
|
|
118
|
+
SERVICE_DATA = 0x07
|
|
119
|
+
TRANSPORT_DISCOVERY_SERVICE = 0x08
|
|
120
|
+
AD_TYPE_FILTER = 0x09
|
|
121
|
+
READ_EXTENDED_FEATURES = 0xFF
|
|
122
|
+
|
|
123
|
+
opcode: int = dataclasses.field(metadata=Opcode.type_metadata(1))
|
|
124
|
+
payload: bytes = dataclasses.field(metadata=hci.metadata("*"))
|
|
125
|
+
|
|
126
|
+
return_parameters_fields = [
|
|
127
|
+
('status', hci.STATUS_SPEC),
|
|
128
|
+
('opcode', Opcode.type_spec(1)),
|
|
129
|
+
('payload', '*'),
|
|
130
|
+
]
|
|
170
131
|
|
|
171
132
|
|
|
172
133
|
# -----------------------------------------------------------------------------
|
|
173
|
-
@HCI_Command.command
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
('total_tx_time_ms', 4),
|
|
177
|
-
('total_rx_time_ms', 4),
|
|
178
|
-
('total_idle_time_ms', 4),
|
|
179
|
-
('total_energy_used', 4),
|
|
180
|
-
],
|
|
181
|
-
)
|
|
182
|
-
class HCI_Get_Controller_Activity_Energy_Info_Command(HCI_Command):
|
|
134
|
+
@hci.HCI_Command.command
|
|
135
|
+
@dataclasses.dataclass
|
|
136
|
+
class HCI_Get_Controller_Activity_Energy_Info_Command(hci.HCI_Command):
|
|
183
137
|
# pylint: disable=line-too-long
|
|
184
138
|
'''
|
|
185
139
|
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#le_get_controller_activity_energy_info
|
|
186
140
|
'''
|
|
141
|
+
return_parameters_fields = [
|
|
142
|
+
('status', hci.STATUS_SPEC),
|
|
143
|
+
('total_tx_time_ms', 4),
|
|
144
|
+
('total_rx_time_ms', 4),
|
|
145
|
+
('total_idle_time_ms', 4),
|
|
146
|
+
('total_energy_used', 4),
|
|
147
|
+
]
|
|
187
148
|
|
|
188
149
|
|
|
189
150
|
# -----------------------------------------------------------------------------
|
|
190
|
-
@HCI_Command.command
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
'opcode',
|
|
194
|
-
{
|
|
195
|
-
'size': 1,
|
|
196
|
-
'mapper': lambda x: HCI_A2DP_Hardware_Offload_Command.opcode_name(x),
|
|
197
|
-
},
|
|
198
|
-
),
|
|
199
|
-
('payload', '*'),
|
|
200
|
-
],
|
|
201
|
-
return_parameters_fields=[
|
|
202
|
-
('status', STATUS_SPEC),
|
|
203
|
-
(
|
|
204
|
-
'opcode',
|
|
205
|
-
{
|
|
206
|
-
'size': 1,
|
|
207
|
-
'mapper': lambda x: HCI_A2DP_Hardware_Offload_Command.opcode_name(x),
|
|
208
|
-
},
|
|
209
|
-
),
|
|
210
|
-
('payload', '*'),
|
|
211
|
-
],
|
|
212
|
-
)
|
|
213
|
-
class HCI_A2DP_Hardware_Offload_Command(HCI_Command):
|
|
151
|
+
@hci.HCI_Command.command
|
|
152
|
+
@dataclasses.dataclass
|
|
153
|
+
class HCI_A2DP_Hardware_Offload_Command(hci.HCI_Command):
|
|
214
154
|
# pylint: disable=line-too-long
|
|
215
155
|
'''
|
|
216
156
|
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#a2dp-hardware-offload-support
|
|
@@ -220,45 +160,24 @@ class HCI_A2DP_Hardware_Offload_Command(HCI_Command):
|
|
|
220
160
|
'''
|
|
221
161
|
|
|
222
162
|
# A2DP Hardware Offload Subcommands
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
163
|
+
class Opcode(hci.SpecableEnum):
|
|
164
|
+
START_A2DP_OFFLOAD = 0x01
|
|
165
|
+
STOP_A2DP_OFFLOAD = 0x02
|
|
226
166
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
STOP_A2DP_OFFLOAD: 'STOP_A2DP_OFFLOAD',
|
|
230
|
-
}
|
|
167
|
+
opcode: int = dataclasses.field(metadata=Opcode.type_metadata(1))
|
|
168
|
+
payload: bytes = dataclasses.field(metadata=hci.metadata("*"))
|
|
231
169
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
170
|
+
return_parameters_fields = [
|
|
171
|
+
('status', hci.STATUS_SPEC),
|
|
172
|
+
('opcode', Opcode.type_spec(1)),
|
|
173
|
+
('payload', '*'),
|
|
174
|
+
]
|
|
235
175
|
|
|
236
176
|
|
|
237
177
|
# -----------------------------------------------------------------------------
|
|
238
|
-
@HCI_Command.command
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
'opcode',
|
|
242
|
-
{
|
|
243
|
-
'size': 1,
|
|
244
|
-
'mapper': lambda x: HCI_Dynamic_Audio_Buffer_Command.opcode_name(x),
|
|
245
|
-
},
|
|
246
|
-
),
|
|
247
|
-
('payload', '*'),
|
|
248
|
-
],
|
|
249
|
-
return_parameters_fields=[
|
|
250
|
-
('status', STATUS_SPEC),
|
|
251
|
-
(
|
|
252
|
-
'opcode',
|
|
253
|
-
{
|
|
254
|
-
'size': 1,
|
|
255
|
-
'mapper': lambda x: HCI_Dynamic_Audio_Buffer_Command.opcode_name(x),
|
|
256
|
-
},
|
|
257
|
-
),
|
|
258
|
-
('payload', '*'),
|
|
259
|
-
],
|
|
260
|
-
)
|
|
261
|
-
class HCI_Dynamic_Audio_Buffer_Command(HCI_Command):
|
|
178
|
+
@hci.HCI_Command.command
|
|
179
|
+
@dataclasses.dataclass
|
|
180
|
+
class HCI_Dynamic_Audio_Buffer_Command(hci.HCI_Command):
|
|
262
181
|
# pylint: disable=line-too-long
|
|
263
182
|
'''
|
|
264
183
|
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#dynamic-audio-buffer-command
|
|
@@ -268,27 +187,28 @@ class HCI_Dynamic_Audio_Buffer_Command(HCI_Command):
|
|
|
268
187
|
'''
|
|
269
188
|
|
|
270
189
|
# Dynamic Audio Buffer Subcommands
|
|
271
|
-
|
|
272
|
-
|
|
190
|
+
class Opcode(hci.SpecableEnum):
|
|
191
|
+
GET_AUDIO_BUFFER_TIME_CAPABILITY = 0x01
|
|
273
192
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
193
|
+
opcode: int = dataclasses.field(metadata=Opcode.type_metadata(1))
|
|
194
|
+
payload: bytes = dataclasses.field(metadata=hci.metadata("*"))
|
|
277
195
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
196
|
+
return_parameters_fields = [
|
|
197
|
+
('status', hci.STATUS_SPEC),
|
|
198
|
+
('opcode', Opcode.type_spec(1)),
|
|
199
|
+
('payload', '*'),
|
|
200
|
+
]
|
|
281
201
|
|
|
282
202
|
|
|
283
203
|
# -----------------------------------------------------------------------------
|
|
284
|
-
class HCI_Android_Vendor_Event(HCI_Extended_Event):
|
|
285
|
-
event_code: int = HCI_VENDOR_EVENT
|
|
286
|
-
subevent_classes:
|
|
204
|
+
class HCI_Android_Vendor_Event(hci.HCI_Extended_Event):
|
|
205
|
+
event_code: int = hci.HCI_VENDOR_EVENT
|
|
206
|
+
subevent_classes: dict[int, type[hci.HCI_Extended_Event]] = {}
|
|
287
207
|
|
|
288
208
|
@classmethod
|
|
289
209
|
def subclass_from_parameters(
|
|
290
210
|
cls, parameters: bytes
|
|
291
|
-
) -> Optional[HCI_Extended_Event]:
|
|
211
|
+
) -> Optional[hci.HCI_Extended_Event]:
|
|
292
212
|
subevent_code = parameters[0]
|
|
293
213
|
if subevent_code == HCI_BLUETOOTH_QUALITY_REPORT_EVENT:
|
|
294
214
|
quality_report_id = parameters[1]
|
|
@@ -299,45 +219,43 @@ class HCI_Android_Vendor_Event(HCI_Extended_Event):
|
|
|
299
219
|
|
|
300
220
|
|
|
301
221
|
HCI_Android_Vendor_Event.register_subevents(globals())
|
|
302
|
-
HCI_Event.add_vendor_factory(HCI_Android_Vendor_Event.subclass_from_parameters)
|
|
222
|
+
hci.HCI_Event.add_vendor_factory(HCI_Android_Vendor_Event.subclass_from_parameters)
|
|
303
223
|
|
|
304
224
|
|
|
305
225
|
# -----------------------------------------------------------------------------
|
|
306
|
-
@HCI_Extended_Event.event
|
|
307
|
-
|
|
308
|
-
('quality_report_id', 1),
|
|
309
|
-
('packet_types', 1),
|
|
310
|
-
('connection_handle', 2),
|
|
311
|
-
('connection_role', {'size': 1, 'mapper': HCI_Constant.role_name}),
|
|
312
|
-
('tx_power_level', -1),
|
|
313
|
-
('rssi', -1),
|
|
314
|
-
('snr', 1),
|
|
315
|
-
('unused_afh_channel_count', 1),
|
|
316
|
-
('afh_select_unideal_channel_count', 1),
|
|
317
|
-
('lsto', 2),
|
|
318
|
-
('connection_piconet_clock', 4),
|
|
319
|
-
('retransmission_count', 4),
|
|
320
|
-
('no_rx_count', 4),
|
|
321
|
-
('nak_count', 4),
|
|
322
|
-
('last_tx_ack_timestamp', 4),
|
|
323
|
-
('flow_off_count', 4),
|
|
324
|
-
('last_flow_on_timestamp', 4),
|
|
325
|
-
('buffer_overflow_bytes', 4),
|
|
326
|
-
('buffer_underflow_bytes', 4),
|
|
327
|
-
('bdaddr', Address.parse_address),
|
|
328
|
-
('cal_failed_item_count', 1),
|
|
329
|
-
('tx_total_packets', 4),
|
|
330
|
-
('tx_unacked_packets', 4),
|
|
331
|
-
('tx_flushed_packets', 4),
|
|
332
|
-
('tx_last_subevent_packets', 4),
|
|
333
|
-
('crc_error_packets', 4),
|
|
334
|
-
('rx_duplicate_packets', 4),
|
|
335
|
-
('rx_unreceived_packets', 4),
|
|
336
|
-
('vendor_specific_parameters', '*'),
|
|
337
|
-
]
|
|
338
|
-
)
|
|
226
|
+
@hci.HCI_Extended_Event.event
|
|
227
|
+
@dataclasses.dataclass
|
|
339
228
|
class HCI_Bluetooth_Quality_Report_Event(HCI_Android_Vendor_Event):
|
|
340
229
|
# pylint: disable=line-too-long
|
|
341
230
|
'''
|
|
342
231
|
See https://source.android.com/docs/core/connect/bluetooth/hci_requirements#bluetooth-quality-report-sub-event
|
|
343
232
|
'''
|
|
233
|
+
quality_report_id: int = field(metadata=hci.metadata(1))
|
|
234
|
+
packet_types: int = field(metadata=hci.metadata(1))
|
|
235
|
+
connection_handle: int = field(metadata=hci.metadata(2))
|
|
236
|
+
connection_role: int = field(metadata=hci.Role.type_metadata(1))
|
|
237
|
+
tx_power_level: int = field(metadata=hci.metadata(-1))
|
|
238
|
+
rssi: int = field(metadata=hci.metadata(-1))
|
|
239
|
+
snr: int = field(metadata=hci.metadata(1))
|
|
240
|
+
unused_afh_channel_count: int = field(metadata=hci.metadata(1))
|
|
241
|
+
afh_select_unideal_channel_count: int = field(metadata=hci.metadata(1))
|
|
242
|
+
lsto: int = field(metadata=hci.metadata(2))
|
|
243
|
+
connection_piconet_clock: int = field(metadata=hci.metadata(4))
|
|
244
|
+
retransmission_count: int = field(metadata=hci.metadata(4))
|
|
245
|
+
no_rx_count: int = field(metadata=hci.metadata(4))
|
|
246
|
+
nak_count: int = field(metadata=hci.metadata(4))
|
|
247
|
+
last_tx_ack_timestamp: int = field(metadata=hci.metadata(4))
|
|
248
|
+
flow_off_count: int = field(metadata=hci.metadata(4))
|
|
249
|
+
last_flow_on_timestamp: int = field(metadata=hci.metadata(4))
|
|
250
|
+
buffer_overflow_bytes: int = field(metadata=hci.metadata(4))
|
|
251
|
+
buffer_underflow_bytes: int = field(metadata=hci.metadata(4))
|
|
252
|
+
bdaddr: hci.Address = field(metadata=hci.metadata(hci.Address.parse_address))
|
|
253
|
+
cal_failed_item_count: int = field(metadata=hci.metadata(1))
|
|
254
|
+
tx_total_packets: int = field(metadata=hci.metadata(4))
|
|
255
|
+
tx_unacked_packets: int = field(metadata=hci.metadata(4))
|
|
256
|
+
tx_flushed_packets: int = field(metadata=hci.metadata(4))
|
|
257
|
+
tx_last_subevent_packets: int = field(metadata=hci.metadata(4))
|
|
258
|
+
crc_error_packets: int = field(metadata=hci.metadata(4))
|
|
259
|
+
rx_duplicate_packets: int = field(metadata=hci.metadata(4))
|
|
260
|
+
rx_unreceived_packets: int = field(metadata=hci.metadata(4))
|
|
261
|
+
vendor_specific_parameters: bytes = field(metadata=hci.metadata('*'))
|