bumble 0.0.218__py3-none-any.whl → 0.0.220__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 +57 -18
- bumble/apps/auracast.py +7 -13
- bumble/audio/io.py +3 -3
- bumble/avctp.py +8 -12
- bumble/avdtp.py +584 -533
- bumble/avrcp.py +20 -20
- bumble/controller.py +993 -507
- bumble/device.py +107 -183
- bumble/drivers/rtk.py +3 -1
- bumble/hci.py +38 -0
- bumble/hid.py +1 -1
- bumble/link.py +68 -165
- bumble/lmp.py +324 -0
- bumble/rfcomm.py +7 -3
- bumble/snoop.py +10 -4
- bumble/transport/common.py +6 -3
- bumble/transport/ws_client.py +2 -2
- bumble/transport/ws_server.py +16 -8
- bumble/utils.py +1 -5
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/METADATA +3 -3
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/RECORD +26 -25
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/WHEEL +0 -0
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.218.dist-info → bumble-0.0.220.dist-info}/top_level.txt +0 -0
bumble/controller.py
CHANGED
|
@@ -23,45 +23,11 @@ import itertools
|
|
|
23
23
|
import logging
|
|
24
24
|
import random
|
|
25
25
|
import struct
|
|
26
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
26
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
27
27
|
|
|
28
|
-
from bumble import hci
|
|
28
|
+
from bumble import hci, lmp
|
|
29
29
|
from bumble.colors import color
|
|
30
30
|
from bumble.core import PhysicalTransport
|
|
31
|
-
from bumble.hci import (
|
|
32
|
-
HCI_ACL_DATA_PACKET,
|
|
33
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
34
|
-
HCI_COMMAND_PACKET,
|
|
35
|
-
HCI_COMMAND_STATUS_PENDING,
|
|
36
|
-
HCI_CONTROLLER_BUSY_ERROR,
|
|
37
|
-
HCI_EVENT_PACKET,
|
|
38
|
-
HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
39
|
-
HCI_LE_1M_PHY,
|
|
40
|
-
HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
41
|
-
HCI_SUCCESS,
|
|
42
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
43
|
-
HCI_UNKNOWN_HCI_COMMAND_ERROR,
|
|
44
|
-
HCI_VERSION_BLUETOOTH_CORE_5_0,
|
|
45
|
-
Address,
|
|
46
|
-
HCI_AclDataPacket,
|
|
47
|
-
HCI_AclDataPacketAssembler,
|
|
48
|
-
HCI_Command_Complete_Event,
|
|
49
|
-
HCI_Command_Status_Event,
|
|
50
|
-
HCI_Connection_Complete_Event,
|
|
51
|
-
HCI_Connection_Request_Event,
|
|
52
|
-
HCI_Disconnection_Complete_Event,
|
|
53
|
-
HCI_Encryption_Change_Event,
|
|
54
|
-
HCI_LE_Advertising_Report_Event,
|
|
55
|
-
HCI_LE_CIS_Established_Event,
|
|
56
|
-
HCI_LE_CIS_Request_Event,
|
|
57
|
-
HCI_LE_Connection_Complete_Event,
|
|
58
|
-
HCI_LE_Read_Remote_Features_Complete_Event,
|
|
59
|
-
HCI_Number_Of_Completed_Packets_Event,
|
|
60
|
-
HCI_Packet,
|
|
61
|
-
HCI_Role_Change_Event,
|
|
62
|
-
HCI_Synchronous_Connection_Complete_Event,
|
|
63
|
-
Role,
|
|
64
|
-
)
|
|
65
31
|
|
|
66
32
|
if TYPE_CHECKING:
|
|
67
33
|
from bumble.link import LocalLink
|
|
@@ -90,121 +56,147 @@ class CisLink:
|
|
|
90
56
|
data_paths: set[int] = dataclasses.field(default_factory=set)
|
|
91
57
|
|
|
92
58
|
|
|
59
|
+
# -----------------------------------------------------------------------------
|
|
60
|
+
@dataclasses.dataclass
|
|
61
|
+
class ScoLink:
|
|
62
|
+
handle: int
|
|
63
|
+
link_type: int
|
|
64
|
+
peer_address: hci.Address
|
|
65
|
+
|
|
66
|
+
|
|
93
67
|
# -----------------------------------------------------------------------------
|
|
94
68
|
@dataclasses.dataclass
|
|
95
69
|
class Connection:
|
|
96
70
|
controller: Controller
|
|
97
71
|
handle: int
|
|
98
|
-
role: Role
|
|
99
|
-
peer_address: Address
|
|
72
|
+
role: hci.Role
|
|
73
|
+
peer_address: hci.Address
|
|
100
74
|
link: Any
|
|
101
75
|
transport: int
|
|
102
76
|
link_type: int
|
|
77
|
+
classic_allow_role_switch: bool = False
|
|
103
78
|
|
|
104
|
-
def __post_init__(self):
|
|
105
|
-
self.assembler = HCI_AclDataPacketAssembler(self.on_acl_pdu)
|
|
79
|
+
def __post_init__(self) -> None:
|
|
80
|
+
self.assembler = hci.HCI_AclDataPacketAssembler(self.on_acl_pdu)
|
|
106
81
|
|
|
107
|
-
def on_hci_acl_data_packet(self, packet):
|
|
82
|
+
def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
|
|
108
83
|
self.assembler.feed_packet(packet)
|
|
109
84
|
self.controller.send_hci_packet(
|
|
110
|
-
HCI_Number_Of_Completed_Packets_Event(
|
|
85
|
+
hci.HCI_Number_Of_Completed_Packets_Event(
|
|
111
86
|
connection_handles=[self.handle], num_completed_packets=[1]
|
|
112
87
|
)
|
|
113
88
|
)
|
|
114
89
|
|
|
115
|
-
def on_acl_pdu(self,
|
|
90
|
+
def on_acl_pdu(self, pdu: bytes) -> None:
|
|
116
91
|
if self.link:
|
|
117
92
|
self.link.send_acl_data(
|
|
118
|
-
self.controller, self.peer_address, self.transport,
|
|
93
|
+
self.controller, self.peer_address, self.transport, pdu
|
|
119
94
|
)
|
|
120
95
|
|
|
121
96
|
|
|
122
97
|
# -----------------------------------------------------------------------------
|
|
123
98
|
class Controller:
|
|
99
|
+
hci_sink: Optional[TransportSink] = None
|
|
100
|
+
|
|
101
|
+
central_connections: dict[
|
|
102
|
+
hci.Address, Connection
|
|
103
|
+
] # Connections where this controller is the central
|
|
104
|
+
peripheral_connections: dict[
|
|
105
|
+
hci.Address, Connection
|
|
106
|
+
] # Connections where this controller is the peripheral
|
|
107
|
+
classic_connections: dict[hci.Address, Connection] # Connections in BR/EDR
|
|
108
|
+
classic_pending_commands: dict[hci.Address, dict[lmp.Opcode, asyncio.Future[int]]]
|
|
109
|
+
sco_links: dict[hci.Address, ScoLink] # SCO links by address
|
|
110
|
+
central_cis_links: dict[int, CisLink] # CIS links by handle
|
|
111
|
+
peripheral_cis_links: dict[int, CisLink] # CIS links by handle
|
|
112
|
+
|
|
113
|
+
hci_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
114
|
+
hci_revision: int = 0
|
|
115
|
+
lmp_version: int = hci.HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
116
|
+
lmp_subversion: int = 0
|
|
117
|
+
lmp_features: bytes = bytes.fromhex(
|
|
118
|
+
'0000000060000000'
|
|
119
|
+
) # BR/EDR Not Supported, LE Supported (Controller)
|
|
120
|
+
manufacturer_name: int = 0xFFFF
|
|
121
|
+
acl_data_packet_length: int = 27
|
|
122
|
+
total_num_acl_data_packets: int = 64
|
|
123
|
+
le_acl_data_packet_length: int = 27
|
|
124
|
+
total_num_le_acl_data_packets: int = 64
|
|
125
|
+
iso_data_packet_length: int = 960
|
|
126
|
+
total_num_iso_data_packets: int = 64
|
|
127
|
+
event_mask: int = 0
|
|
128
|
+
event_mask_page_2: int = 0
|
|
129
|
+
supported_commands: bytes = bytes.fromhex(
|
|
130
|
+
'2000800000c000000000e4000000a822000000000000040000f7ffff7f000000'
|
|
131
|
+
'30f0f9ff01008004002000000000000000000000000000000000000000000000'
|
|
132
|
+
)
|
|
133
|
+
le_event_mask: int = 0
|
|
134
|
+
advertising_parameters: Optional[hci.HCI_LE_Set_Advertising_Parameters_Command] = (
|
|
135
|
+
None
|
|
136
|
+
)
|
|
137
|
+
le_features: bytes = bytes.fromhex('ff49010000000000')
|
|
138
|
+
le_states: bytes = bytes.fromhex('ffff3fffff030000')
|
|
139
|
+
advertising_channel_tx_power: int = 0
|
|
140
|
+
filter_accept_list_size: int = 8
|
|
141
|
+
filter_duplicates: bool = False
|
|
142
|
+
resolving_list_size: int = 8
|
|
143
|
+
supported_max_tx_octets: int = 27
|
|
144
|
+
supported_max_tx_time: int = 10000
|
|
145
|
+
supported_max_rx_octets: int = 27
|
|
146
|
+
supported_max_rx_time: int = 10000
|
|
147
|
+
suggested_max_tx_octets: int = 27
|
|
148
|
+
suggested_max_tx_time: int = 0x0148
|
|
149
|
+
default_phy: dict[str, int]
|
|
150
|
+
le_scan_type: int = 0
|
|
151
|
+
le_scan_interval: int = 0x10
|
|
152
|
+
le_scan_window: int = 0x10
|
|
153
|
+
le_scan_enable: int = 0
|
|
154
|
+
le_scan_own_address_type: int = hci.Address.RANDOM_DEVICE_ADDRESS
|
|
155
|
+
le_scanning_filter_policy: int = 0
|
|
156
|
+
le_scan_response_data: Optional[bytes] = None
|
|
157
|
+
le_address_resolution: bool = False
|
|
158
|
+
le_rpa_timeout: int = 0
|
|
159
|
+
sync_flow_control: bool = False
|
|
160
|
+
local_name: str = 'Bumble'
|
|
161
|
+
advertising_interval: int = 2000
|
|
162
|
+
advertising_data: Optional[bytes] = None
|
|
163
|
+
advertising_timer_handle: Optional[asyncio.Handle] = None
|
|
164
|
+
classic_scan_enable: int = 0
|
|
165
|
+
classic_allow_role_switch: bool = True
|
|
166
|
+
|
|
167
|
+
_random_address: hci.Address = hci.Address('00:00:00:00:00:00')
|
|
168
|
+
|
|
124
169
|
def __init__(
|
|
125
170
|
self,
|
|
126
171
|
name: str,
|
|
127
172
|
host_source=None,
|
|
128
173
|
host_sink: Optional[TransportSink] = None,
|
|
129
174
|
link: Optional[LocalLink] = None,
|
|
130
|
-
public_address: Optional[Union[bytes, str, Address]] = None,
|
|
131
|
-
):
|
|
175
|
+
public_address: Optional[Union[bytes, str, hci.Address]] = None,
|
|
176
|
+
) -> None:
|
|
132
177
|
self.name = name
|
|
133
|
-
self.hci_sink = None
|
|
134
178
|
self.link = link
|
|
179
|
+
self.central_connections = {}
|
|
180
|
+
self.peripheral_connections = {}
|
|
181
|
+
self.classic_connections = {}
|
|
182
|
+
self.sco_links = {}
|
|
183
|
+
self.classic_pending_commands = {}
|
|
184
|
+
self.central_cis_links = {}
|
|
185
|
+
self.peripheral_cis_links = {}
|
|
186
|
+
self.default_phy = {
|
|
187
|
+
'all_phys': 0,
|
|
188
|
+
'tx_phys': 0,
|
|
189
|
+
'rx_phys': 0,
|
|
190
|
+
}
|
|
135
191
|
|
|
136
|
-
|
|
137
|
-
{}
|
|
138
|
-
) # Connections where this controller is the central
|
|
139
|
-
self.peripheral_connections: dict[Address, Connection] = (
|
|
140
|
-
{}
|
|
141
|
-
) # Connections where this controller is the peripheral
|
|
142
|
-
self.classic_connections: dict[Address, Connection] = (
|
|
143
|
-
{}
|
|
144
|
-
) # Connections in BR/EDR
|
|
145
|
-
self.central_cis_links: dict[int, CisLink] = {} # CIS links by handle
|
|
146
|
-
self.peripheral_cis_links: dict[int, CisLink] = {} # CIS links by handle
|
|
147
|
-
|
|
148
|
-
self.hci_version = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
149
|
-
self.hci_revision = 0
|
|
150
|
-
self.lmp_version = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
151
|
-
self.lmp_subversion = 0
|
|
152
|
-
self.lmp_features = bytes.fromhex(
|
|
153
|
-
'0000000060000000'
|
|
154
|
-
) # BR/EDR Not Supported, LE Supported (Controller)
|
|
155
|
-
self.manufacturer_name = 0xFFFF
|
|
156
|
-
self.acl_data_packet_length = 27
|
|
157
|
-
self.total_num_acl_data_packets = 64
|
|
158
|
-
self.le_acl_data_packet_length = 27
|
|
159
|
-
self.total_num_le_acl_data_packets = 64
|
|
160
|
-
self.iso_data_packet_length = 960
|
|
161
|
-
self.total_num_iso_data_packets = 64
|
|
162
|
-
self.event_mask = 0
|
|
163
|
-
self.event_mask_page_2 = 0
|
|
164
|
-
self.supported_commands = bytes.fromhex(
|
|
165
|
-
'2000800000c000000000e4000000a822000000000000040000f7ffff7f000000'
|
|
166
|
-
'30f0f9ff01008004002000000000000000000000000000000000000000000000'
|
|
167
|
-
)
|
|
168
|
-
self.le_event_mask = 0
|
|
169
|
-
self.advertising_parameters = None
|
|
170
|
-
self.le_features = bytes.fromhex('ff49010000000000')
|
|
171
|
-
self.le_states = bytes.fromhex('ffff3fffff030000')
|
|
172
|
-
self.advertising_channel_tx_power = 0
|
|
173
|
-
self.filter_accept_list_size = 8
|
|
174
|
-
self.filter_duplicates = False
|
|
175
|
-
self.resolving_list_size = 8
|
|
176
|
-
self.supported_max_tx_octets = 27
|
|
177
|
-
self.supported_max_tx_time = 10000 # microseconds
|
|
178
|
-
self.supported_max_rx_octets = 27
|
|
179
|
-
self.supported_max_rx_time = 10000 # microseconds
|
|
180
|
-
self.suggested_max_tx_octets = 27
|
|
181
|
-
self.suggested_max_tx_time = 0x0148 # microseconds
|
|
182
|
-
self.default_phy = bytes([0, 0, 0])
|
|
183
|
-
self.le_scan_type = 0
|
|
184
|
-
self.le_scan_interval = 0x10
|
|
185
|
-
self.le_scan_window = 0x10
|
|
186
|
-
self.le_scan_enable = 0
|
|
187
|
-
self.le_scan_own_address_type = Address.RANDOM_DEVICE_ADDRESS
|
|
188
|
-
self.le_scanning_filter_policy = 0
|
|
189
|
-
self.le_scan_response_data = None
|
|
190
|
-
self.le_address_resolution = False
|
|
191
|
-
self.le_rpa_timeout = 0
|
|
192
|
-
self.sync_flow_control = False
|
|
193
|
-
self.local_name = 'Bumble'
|
|
194
|
-
|
|
195
|
-
self.advertising_interval = 2000 # Fixed for now
|
|
196
|
-
self.advertising_data = None
|
|
197
|
-
self.advertising_timer_handle = None
|
|
198
|
-
|
|
199
|
-
self._random_address = Address('00:00:00:00:00:00')
|
|
200
|
-
if isinstance(public_address, Address):
|
|
192
|
+
if isinstance(public_address, hci.Address):
|
|
201
193
|
self._public_address = public_address
|
|
202
194
|
elif public_address is not None:
|
|
203
|
-
self._public_address = Address(
|
|
204
|
-
public_address, Address.PUBLIC_DEVICE_ADDRESS
|
|
195
|
+
self._public_address = hci.Address(
|
|
196
|
+
public_address, hci.Address.PUBLIC_DEVICE_ADDRESS
|
|
205
197
|
)
|
|
206
198
|
else:
|
|
207
|
-
self._public_address = Address('00:00:00:00:00:00')
|
|
199
|
+
self._public_address = hci.Address('00:00:00:00:00:00')
|
|
208
200
|
|
|
209
201
|
# Set the source and sink interfaces
|
|
210
202
|
if host_source:
|
|
@@ -215,46 +207,46 @@ class Controller:
|
|
|
215
207
|
if link:
|
|
216
208
|
link.add_controller(self)
|
|
217
209
|
|
|
218
|
-
self.terminated =
|
|
210
|
+
self.terminated: asyncio.Future[Any] = (
|
|
211
|
+
asyncio.get_running_loop().create_future()
|
|
212
|
+
)
|
|
219
213
|
|
|
220
214
|
@property
|
|
221
|
-
def host(self):
|
|
215
|
+
def host(self) -> Optional[TransportSink]:
|
|
222
216
|
return self.hci_sink
|
|
223
217
|
|
|
224
218
|
@host.setter
|
|
225
|
-
def host(self, host):
|
|
219
|
+
def host(self, host: Optional[TransportSink]) -> None:
|
|
226
220
|
'''
|
|
227
221
|
Sets the host (sink) for this controller, and set this controller as the
|
|
228
222
|
controller (sink) for the host
|
|
229
223
|
'''
|
|
230
224
|
self.set_packet_sink(host)
|
|
231
|
-
if host:
|
|
232
|
-
host.controller = self
|
|
233
225
|
|
|
234
|
-
def set_packet_sink(self, sink):
|
|
226
|
+
def set_packet_sink(self, sink: Optional[TransportSink]) -> None:
|
|
235
227
|
'''
|
|
236
228
|
Method from the Packet Source interface
|
|
237
229
|
'''
|
|
238
230
|
self.hci_sink = sink
|
|
239
231
|
|
|
240
232
|
@property
|
|
241
|
-
def public_address(self):
|
|
233
|
+
def public_address(self) -> hci.Address:
|
|
242
234
|
return self._public_address
|
|
243
235
|
|
|
244
236
|
@public_address.setter
|
|
245
|
-
def public_address(self, address):
|
|
237
|
+
def public_address(self, address: Union[hci.Address, str]) -> None:
|
|
246
238
|
if isinstance(address, str):
|
|
247
|
-
address = Address(address)
|
|
239
|
+
address = hci.Address(address)
|
|
248
240
|
self._public_address = address
|
|
249
241
|
|
|
250
242
|
@property
|
|
251
|
-
def random_address(self):
|
|
243
|
+
def random_address(self) -> hci.Address:
|
|
252
244
|
return self._random_address
|
|
253
245
|
|
|
254
246
|
@random_address.setter
|
|
255
|
-
def random_address(self, address):
|
|
247
|
+
def random_address(self, address: Union[hci.Address, str]) -> None:
|
|
256
248
|
if isinstance(address, str):
|
|
257
|
-
address = Address(address)
|
|
249
|
+
address = hci.Address(address)
|
|
258
250
|
self._random_address = address
|
|
259
251
|
logger.debug(f'new random address: {address}')
|
|
260
252
|
|
|
@@ -262,42 +254,42 @@ class Controller:
|
|
|
262
254
|
self.link.on_address_changed(self)
|
|
263
255
|
|
|
264
256
|
# Packet Sink protocol (packets coming from the host via HCI)
|
|
265
|
-
def on_packet(self, packet):
|
|
266
|
-
self.on_hci_packet(HCI_Packet.from_bytes(packet))
|
|
257
|
+
def on_packet(self, packet: bytes) -> None:
|
|
258
|
+
self.on_hci_packet(hci.HCI_Packet.from_bytes(packet))
|
|
267
259
|
|
|
268
|
-
def on_hci_packet(self, packet):
|
|
260
|
+
def on_hci_packet(self, packet: hci.HCI_Packet) -> None:
|
|
269
261
|
logger.debug(
|
|
270
262
|
f'{color("<<<", "blue")} [{self.name}] '
|
|
271
263
|
f'{color("HOST -> CONTROLLER", "blue")}: {packet}'
|
|
272
264
|
)
|
|
273
265
|
|
|
274
266
|
# If the packet is a command, invoke the handler for this packet
|
|
275
|
-
if packet.
|
|
267
|
+
if isinstance(packet, hci.HCI_Command):
|
|
276
268
|
self.on_hci_command_packet(packet)
|
|
277
|
-
elif packet.
|
|
278
|
-
self.on_hci_event_packet(packet)
|
|
279
|
-
elif packet.hci_packet_type == HCI_ACL_DATA_PACKET:
|
|
269
|
+
elif isinstance(packet, hci.HCI_AclDataPacket):
|
|
280
270
|
self.on_hci_acl_data_packet(packet)
|
|
271
|
+
elif isinstance(packet, hci.HCI_Event):
|
|
272
|
+
self.on_hci_event_packet(packet)
|
|
281
273
|
else:
|
|
282
274
|
logger.warning(f'!!! unknown packet type {packet.hci_packet_type}')
|
|
283
275
|
|
|
284
|
-
def on_hci_command_packet(self, command):
|
|
276
|
+
def on_hci_command_packet(self, command: hci.HCI_Command) -> None:
|
|
285
277
|
handler_name = f'on_{command.name.lower()}'
|
|
286
278
|
handler = getattr(self, handler_name, self.on_hci_command)
|
|
287
|
-
result = handler(command)
|
|
279
|
+
result: Optional[bytes] = handler(command)
|
|
288
280
|
if isinstance(result, bytes):
|
|
289
281
|
self.send_hci_packet(
|
|
290
|
-
HCI_Command_Complete_Event(
|
|
282
|
+
hci.HCI_Command_Complete_Event(
|
|
291
283
|
num_hci_command_packets=1,
|
|
292
284
|
command_opcode=command.op_code,
|
|
293
285
|
return_parameters=result,
|
|
294
286
|
)
|
|
295
287
|
)
|
|
296
288
|
|
|
297
|
-
def on_hci_event_packet(self, _event):
|
|
289
|
+
def on_hci_event_packet(self, _event: hci.HCI_Packet) -> None:
|
|
298
290
|
logger.warning('!!! unexpected event packet')
|
|
299
291
|
|
|
300
|
-
def on_hci_acl_data_packet(self, packet):
|
|
292
|
+
def on_hci_acl_data_packet(self, packet: hci.HCI_AclDataPacket) -> None:
|
|
301
293
|
# Look for the connection to which this data belongs
|
|
302
294
|
connection = self.find_connection_by_handle(packet.connection_handle)
|
|
303
295
|
if connection is None:
|
|
@@ -309,51 +301,50 @@ class Controller:
|
|
|
309
301
|
# Pass the packet to the connection
|
|
310
302
|
connection.on_hci_acl_data_packet(packet)
|
|
311
303
|
|
|
312
|
-
def send_hci_packet(self, packet):
|
|
304
|
+
def send_hci_packet(self, packet: hci.HCI_Packet) -> None:
|
|
313
305
|
logger.debug(
|
|
314
306
|
f'{color(">>>", "green")} [{self.name}] '
|
|
315
307
|
f'{color("CONTROLLER -> HOST", "green")}: {packet}'
|
|
316
308
|
)
|
|
317
309
|
if self.host:
|
|
318
|
-
self.host.on_packet
|
|
310
|
+
asyncio.get_running_loop().call_soon(self.host.on_packet, bytes(packet))
|
|
319
311
|
|
|
320
312
|
# This method allows the controller to emulate the same API as a transport source
|
|
321
|
-
async def wait_for_termination(self):
|
|
313
|
+
async def wait_for_termination(self) -> None:
|
|
322
314
|
await self.terminated
|
|
323
315
|
|
|
324
316
|
############################################################
|
|
325
317
|
# Link connections
|
|
326
318
|
############################################################
|
|
327
319
|
def allocate_connection_handle(self) -> int:
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
)
|
|
342
|
-
max_handle = max(max_handle, cis_handle)
|
|
343
|
-
if cis_handle == handle:
|
|
344
|
-
# Already used, continue searching after the current max
|
|
345
|
-
handle = max_handle + 1
|
|
346
|
-
return handle
|
|
320
|
+
current_handles = set(
|
|
321
|
+
cast(Connection | CisLink | ScoLink, link).handle
|
|
322
|
+
for link in itertools.chain(
|
|
323
|
+
self.central_connections.values(),
|
|
324
|
+
self.peripheral_connections.values(),
|
|
325
|
+
self.classic_connections.values(),
|
|
326
|
+
self.sco_links.values(),
|
|
327
|
+
self.central_cis_links.values(),
|
|
328
|
+
self.peripheral_cis_links.values(),
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
return next(
|
|
332
|
+
handle for handle in range(0xEFF + 1) if handle not in current_handles
|
|
333
|
+
)
|
|
347
334
|
|
|
348
|
-
def find_le_connection_by_address(
|
|
335
|
+
def find_le_connection_by_address(
|
|
336
|
+
self, address: hci.Address
|
|
337
|
+
) -> Optional[Connection]:
|
|
349
338
|
return self.central_connections.get(address) or self.peripheral_connections.get(
|
|
350
339
|
address
|
|
351
340
|
)
|
|
352
341
|
|
|
353
|
-
def find_classic_connection_by_address(
|
|
342
|
+
def find_classic_connection_by_address(
|
|
343
|
+
self, address: hci.Address
|
|
344
|
+
) -> Optional[Connection]:
|
|
354
345
|
return self.classic_connections.get(address)
|
|
355
346
|
|
|
356
|
-
def find_connection_by_handle(self, handle):
|
|
347
|
+
def find_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
357
348
|
for connection in itertools.chain(
|
|
358
349
|
self.central_connections.values(),
|
|
359
350
|
self.peripheral_connections.values(),
|
|
@@ -363,30 +354,36 @@ class Controller:
|
|
|
363
354
|
return connection
|
|
364
355
|
return None
|
|
365
356
|
|
|
366
|
-
def find_central_connection_by_handle(self, handle):
|
|
357
|
+
def find_central_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
367
358
|
for connection in self.central_connections.values():
|
|
368
359
|
if connection.handle == handle:
|
|
369
360
|
return connection
|
|
370
361
|
return None
|
|
371
362
|
|
|
372
|
-
def find_peripheral_connection_by_handle(self, handle):
|
|
363
|
+
def find_peripheral_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
373
364
|
for connection in self.peripheral_connections.values():
|
|
374
365
|
if connection.handle == handle:
|
|
375
366
|
return connection
|
|
376
367
|
return None
|
|
377
368
|
|
|
378
|
-
def find_classic_connection_by_handle(self, handle):
|
|
369
|
+
def find_classic_connection_by_handle(self, handle: int) -> Optional[Connection]:
|
|
379
370
|
for connection in self.classic_connections.values():
|
|
380
371
|
if connection.handle == handle:
|
|
381
372
|
return connection
|
|
382
373
|
return None
|
|
383
374
|
|
|
375
|
+
def find_classic_sco_link_by_handle(self, handle: int) -> Optional[ScoLink]:
|
|
376
|
+
for connection in self.sco_links.values():
|
|
377
|
+
if connection.handle == handle:
|
|
378
|
+
return connection
|
|
379
|
+
return None
|
|
380
|
+
|
|
384
381
|
def find_iso_link_by_handle(self, handle: int) -> Optional[CisLink]:
|
|
385
382
|
return self.central_cis_links.get(handle) or self.peripheral_cis_links.get(
|
|
386
383
|
handle
|
|
387
384
|
)
|
|
388
385
|
|
|
389
|
-
def on_link_central_connected(self, central_address):
|
|
386
|
+
def on_link_central_connected(self, central_address: hci.Address) -> None:
|
|
390
387
|
'''
|
|
391
388
|
Called when an incoming connection occurs from a central on the link
|
|
392
389
|
'''
|
|
@@ -400,19 +397,19 @@ class Controller:
|
|
|
400
397
|
connection = Connection(
|
|
401
398
|
controller=self,
|
|
402
399
|
handle=connection_handle,
|
|
403
|
-
role=Role.PERIPHERAL,
|
|
400
|
+
role=hci.Role.PERIPHERAL,
|
|
404
401
|
peer_address=peer_address,
|
|
405
402
|
link=self.link,
|
|
406
403
|
transport=PhysicalTransport.LE,
|
|
407
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
404
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
408
405
|
)
|
|
409
406
|
self.peripheral_connections[peer_address] = connection
|
|
410
407
|
logger.debug(f'New PERIPHERAL connection handle: 0x{connection_handle:04X}')
|
|
411
408
|
|
|
412
409
|
# Then say that the connection has completed
|
|
413
410
|
self.send_hci_packet(
|
|
414
|
-
HCI_LE_Connection_Complete_Event(
|
|
415
|
-
status=HCI_SUCCESS,
|
|
411
|
+
hci.HCI_LE_Connection_Complete_Event(
|
|
412
|
+
status=hci.HCI_SUCCESS,
|
|
416
413
|
connection_handle=connection.handle,
|
|
417
414
|
role=connection.role,
|
|
418
415
|
peer_address_type=peer_address_type,
|
|
@@ -424,7 +421,7 @@ class Controller:
|
|
|
424
421
|
)
|
|
425
422
|
)
|
|
426
423
|
|
|
427
|
-
def on_link_disconnected(self, peer_address, reason):
|
|
424
|
+
def on_link_disconnected(self, peer_address: hci.Address, reason: int) -> None:
|
|
428
425
|
'''
|
|
429
426
|
Called when an active disconnection occurs from a peer
|
|
430
427
|
'''
|
|
@@ -432,8 +429,8 @@ class Controller:
|
|
|
432
429
|
# Send a disconnection complete event
|
|
433
430
|
if connection := self.peripheral_connections.get(peer_address):
|
|
434
431
|
self.send_hci_packet(
|
|
435
|
-
HCI_Disconnection_Complete_Event(
|
|
436
|
-
status=HCI_SUCCESS,
|
|
432
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
433
|
+
status=hci.HCI_SUCCESS,
|
|
437
434
|
connection_handle=connection.handle,
|
|
438
435
|
reason=reason,
|
|
439
436
|
)
|
|
@@ -443,8 +440,8 @@ class Controller:
|
|
|
443
440
|
del self.peripheral_connections[peer_address]
|
|
444
441
|
elif connection := self.central_connections.get(peer_address):
|
|
445
442
|
self.send_hci_packet(
|
|
446
|
-
HCI_Disconnection_Complete_Event(
|
|
447
|
-
status=HCI_SUCCESS,
|
|
443
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
444
|
+
status=hci.HCI_SUCCESS,
|
|
448
445
|
connection_handle=connection.handle,
|
|
449
446
|
reason=reason,
|
|
450
447
|
)
|
|
@@ -456,13 +453,15 @@ class Controller:
|
|
|
456
453
|
logger.warning(f'!!! No peripheral connection found for {peer_address}')
|
|
457
454
|
|
|
458
455
|
def on_link_peripheral_connection_complete(
|
|
459
|
-
self,
|
|
460
|
-
|
|
456
|
+
self,
|
|
457
|
+
le_create_connection_command: hci.HCI_LE_Create_Connection_Command,
|
|
458
|
+
status: int,
|
|
459
|
+
) -> None:
|
|
461
460
|
'''
|
|
462
461
|
Called by the link when a connection has been made or has failed to be made
|
|
463
462
|
'''
|
|
464
463
|
|
|
465
|
-
if status == HCI_SUCCESS:
|
|
464
|
+
if status == hci.HCI_SUCCESS:
|
|
466
465
|
# Allocate (or reuse) a connection handle
|
|
467
466
|
peer_address = le_create_connection_command.peer_address
|
|
468
467
|
connection = self.central_connections.get(peer_address)
|
|
@@ -471,11 +470,11 @@ class Controller:
|
|
|
471
470
|
connection = Connection(
|
|
472
471
|
controller=self,
|
|
473
472
|
handle=connection_handle,
|
|
474
|
-
role=Role.CENTRAL,
|
|
473
|
+
role=hci.Role.CENTRAL,
|
|
475
474
|
peer_address=peer_address,
|
|
476
475
|
link=self.link,
|
|
477
476
|
transport=PhysicalTransport.LE,
|
|
478
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
477
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
479
478
|
)
|
|
480
479
|
self.central_connections[peer_address] = connection
|
|
481
480
|
logger.debug(
|
|
@@ -487,10 +486,10 @@ class Controller:
|
|
|
487
486
|
# Say that the connection has completed
|
|
488
487
|
self.send_hci_packet(
|
|
489
488
|
# pylint: disable=line-too-long
|
|
490
|
-
HCI_LE_Connection_Complete_Event(
|
|
489
|
+
hci.HCI_LE_Connection_Complete_Event(
|
|
491
490
|
status=status,
|
|
492
491
|
connection_handle=connection.handle if connection else 0,
|
|
493
|
-
role=Role.CENTRAL,
|
|
492
|
+
role=hci.Role.CENTRAL,
|
|
494
493
|
peer_address_type=le_create_connection_command.peer_address_type,
|
|
495
494
|
peer_address=le_create_connection_command.peer_address,
|
|
496
495
|
connection_interval=le_create_connection_command.connection_interval_min,
|
|
@@ -500,14 +499,16 @@ class Controller:
|
|
|
500
499
|
)
|
|
501
500
|
)
|
|
502
501
|
|
|
503
|
-
def on_link_disconnection_complete(
|
|
502
|
+
def on_link_disconnection_complete(
|
|
503
|
+
self, disconnection_command: hci.HCI_Disconnect_Command, status: int
|
|
504
|
+
) -> None:
|
|
504
505
|
'''
|
|
505
506
|
Called when a disconnection has been completed
|
|
506
507
|
'''
|
|
507
508
|
|
|
508
509
|
# Send a disconnection complete event
|
|
509
510
|
self.send_hci_packet(
|
|
510
|
-
HCI_Disconnection_Complete_Event(
|
|
511
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
511
512
|
status=status,
|
|
512
513
|
connection_handle=disconnection_command.connection_handle,
|
|
513
514
|
reason=disconnection_command.reason,
|
|
@@ -526,16 +527,20 @@ class Controller:
|
|
|
526
527
|
logger.debug(f'PERIPHERAL Connection removed: {connection}')
|
|
527
528
|
del self.peripheral_connections[connection.peer_address]
|
|
528
529
|
|
|
529
|
-
def on_link_encrypted(
|
|
530
|
+
def on_link_encrypted(
|
|
531
|
+
self, peer_address: hci.Address, _rand: bytes, _ediv: int, _ltk: bytes
|
|
532
|
+
) -> None:
|
|
530
533
|
# For now, just setup the encryption without asking the host
|
|
531
534
|
if connection := self.find_le_connection_by_address(peer_address):
|
|
532
535
|
self.send_hci_packet(
|
|
533
|
-
HCI_Encryption_Change_Event(
|
|
536
|
+
hci.HCI_Encryption_Change_Event(
|
|
534
537
|
status=0, connection_handle=connection.handle, encryption_enabled=1
|
|
535
538
|
)
|
|
536
539
|
)
|
|
537
540
|
|
|
538
|
-
def on_link_acl_data(
|
|
541
|
+
def on_link_acl_data(
|
|
542
|
+
self, sender_address: hci.Address, transport: PhysicalTransport, data: bytes
|
|
543
|
+
) -> None:
|
|
539
544
|
# Look for the connection to which this data belongs
|
|
540
545
|
if transport == PhysicalTransport.LE:
|
|
541
546
|
connection = self.find_le_connection_by_address(sender_address)
|
|
@@ -547,36 +552,38 @@ class Controller:
|
|
|
547
552
|
|
|
548
553
|
# Send the data to the host
|
|
549
554
|
# TODO: should fragment
|
|
550
|
-
acl_packet = HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
|
|
555
|
+
acl_packet = hci.HCI_AclDataPacket(connection.handle, 2, 0, len(data), data)
|
|
551
556
|
self.send_hci_packet(acl_packet)
|
|
552
557
|
|
|
553
|
-
def on_link_advertising_data(
|
|
558
|
+
def on_link_advertising_data(
|
|
559
|
+
self, sender_address: hci.Address, data: bytes
|
|
560
|
+
) -> None:
|
|
554
561
|
# Ignore if we're not scanning
|
|
555
562
|
if self.le_scan_enable == 0:
|
|
556
563
|
return
|
|
557
564
|
|
|
558
565
|
# Send a scan report
|
|
559
|
-
report = HCI_LE_Advertising_Report_Event.Report(
|
|
560
|
-
event_type=HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
|
|
566
|
+
report = hci.HCI_LE_Advertising_Report_Event.Report(
|
|
567
|
+
event_type=hci.HCI_LE_Advertising_Report_Event.EventType.ADV_IND,
|
|
561
568
|
address_type=sender_address.address_type,
|
|
562
569
|
address=sender_address,
|
|
563
570
|
data=data,
|
|
564
571
|
rssi=-50,
|
|
565
572
|
)
|
|
566
|
-
self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
|
|
573
|
+
self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
|
|
567
574
|
|
|
568
575
|
# Simulate a scan response
|
|
569
|
-
report = HCI_LE_Advertising_Report_Event.Report(
|
|
570
|
-
event_type=HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP,
|
|
576
|
+
report = hci.HCI_LE_Advertising_Report_Event.Report(
|
|
577
|
+
event_type=hci.HCI_LE_Advertising_Report_Event.EventType.SCAN_RSP,
|
|
571
578
|
address_type=sender_address.address_type,
|
|
572
579
|
address=sender_address,
|
|
573
580
|
data=data,
|
|
574
581
|
rssi=-50,
|
|
575
582
|
)
|
|
576
|
-
self.send_hci_packet(HCI_LE_Advertising_Report_Event([report]))
|
|
583
|
+
self.send_hci_packet(hci.HCI_LE_Advertising_Report_Event([report]))
|
|
577
584
|
|
|
578
585
|
def on_link_cis_request(
|
|
579
|
-
self, central_address: Address, cig_id: int, cis_id: int
|
|
586
|
+
self, central_address: hci.Address, cig_id: int, cis_id: int
|
|
580
587
|
) -> None:
|
|
581
588
|
'''
|
|
582
589
|
Called when an incoming CIS request occurs from a central on the link
|
|
@@ -594,7 +601,7 @@ class Controller:
|
|
|
594
601
|
self.peripheral_cis_links[pending_cis_link.handle] = pending_cis_link
|
|
595
602
|
|
|
596
603
|
self.send_hci_packet(
|
|
597
|
-
HCI_LE_CIS_Request_Event(
|
|
604
|
+
hci.HCI_LE_CIS_Request_Event(
|
|
598
605
|
acl_connection_handle=connection.handle,
|
|
599
606
|
cis_connection_handle=pending_cis_link.handle,
|
|
600
607
|
cig_id=cig_id,
|
|
@@ -616,8 +623,8 @@ class Controller:
|
|
|
616
623
|
)
|
|
617
624
|
|
|
618
625
|
self.send_hci_packet(
|
|
619
|
-
HCI_LE_CIS_Established_Event(
|
|
620
|
-
status=HCI_SUCCESS,
|
|
626
|
+
hci.HCI_LE_CIS_Established_Event(
|
|
627
|
+
status=hci.HCI_SUCCESS,
|
|
621
628
|
connection_handle=cis_link.handle,
|
|
622
629
|
# CIS parameters are ignored.
|
|
623
630
|
cig_sync_delay=0,
|
|
@@ -660,16 +667,16 @@ class Controller:
|
|
|
660
667
|
),
|
|
661
668
|
None,
|
|
662
669
|
):
|
|
663
|
-
# Keep central CIS on disconnection. They should be removed by HCI_LE_Remove_CIG_Command.
|
|
670
|
+
# Keep central CIS on disconnection. They should be removed by hci.HCI_LE_Remove_CIG_Command.
|
|
664
671
|
cis_link.acl_connection = None
|
|
665
672
|
else:
|
|
666
673
|
return
|
|
667
674
|
|
|
668
675
|
self.send_hci_packet(
|
|
669
|
-
HCI_Disconnection_Complete_Event(
|
|
670
|
-
status=HCI_SUCCESS,
|
|
676
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
677
|
+
status=hci.HCI_SUCCESS,
|
|
671
678
|
connection_handle=cis_link.handle,
|
|
672
|
-
reason=HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
679
|
+
reason=hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
673
680
|
)
|
|
674
681
|
)
|
|
675
682
|
|
|
@@ -677,107 +684,213 @@ class Controller:
|
|
|
677
684
|
# Classic link connections
|
|
678
685
|
############################################################
|
|
679
686
|
|
|
680
|
-
def
|
|
687
|
+
def send_lmp_packet(
|
|
688
|
+
self, receiver_address: hci.Address, packet: lmp.Packet
|
|
689
|
+
) -> asyncio.Future[int]:
|
|
690
|
+
loop = asyncio.get_running_loop()
|
|
691
|
+
assert self.link
|
|
692
|
+
self.link.send_lmp_packet(self, receiver_address, packet)
|
|
693
|
+
future = self.classic_pending_commands.setdefault(receiver_address, {})[
|
|
694
|
+
packet.opcode
|
|
695
|
+
] = loop.create_future()
|
|
696
|
+
return future
|
|
697
|
+
|
|
698
|
+
def on_lmp_packet(self, sender_address: hci.Address, packet: lmp.Packet):
|
|
699
|
+
if isinstance(packet, (lmp.LmpAccepted, lmp.LmpAcceptedExt)):
|
|
700
|
+
if future := self.classic_pending_commands.setdefault(
|
|
701
|
+
sender_address, {}
|
|
702
|
+
).get(packet.response_opcode):
|
|
703
|
+
future.set_result(hci.HCI_SUCCESS)
|
|
704
|
+
else:
|
|
705
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
706
|
+
elif isinstance(packet, (lmp.LmpNotAccepted, lmp.LmpNotAcceptedExt)):
|
|
707
|
+
if future := self.classic_pending_commands.setdefault(
|
|
708
|
+
sender_address, {}
|
|
709
|
+
).get(packet.response_opcode):
|
|
710
|
+
future.set_result(packet.error_code)
|
|
711
|
+
else:
|
|
712
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
713
|
+
elif isinstance(packet, (lmp.LmpHostConnectionReq)):
|
|
714
|
+
self.on_classic_connection_request(
|
|
715
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.ACL
|
|
716
|
+
)
|
|
717
|
+
elif isinstance(packet, (lmp.LmpScoLinkReq)):
|
|
718
|
+
self.on_classic_connection_request(
|
|
719
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.SCO
|
|
720
|
+
)
|
|
721
|
+
elif isinstance(packet, (lmp.LmpEscoLinkReq)):
|
|
722
|
+
self.on_classic_connection_request(
|
|
723
|
+
sender_address, hci.HCI_Connection_Complete_Event.LinkType.ESCO
|
|
724
|
+
)
|
|
725
|
+
elif isinstance(packet, (lmp.LmpDetach)):
|
|
726
|
+
self.on_classic_disconnected(
|
|
727
|
+
sender_address, hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
728
|
+
)
|
|
729
|
+
elif isinstance(packet, (lmp.LmpSwitchReq)):
|
|
730
|
+
self.on_classic_role_change_request(sender_address)
|
|
731
|
+
elif isinstance(packet, (lmp.LmpRemoveScoLinkReq, lmp.LmpRemoveEscoLinkReq)):
|
|
732
|
+
self.on_classic_sco_disconnected(sender_address, packet.error_code)
|
|
733
|
+
elif isinstance(packet, lmp.LmpNameReq):
|
|
734
|
+
self.on_classic_remote_name_request(sender_address, packet.name_offset)
|
|
735
|
+
elif isinstance(packet, lmp.LmpNameRes):
|
|
736
|
+
self.on_classic_remote_name_response(
|
|
737
|
+
sender_address,
|
|
738
|
+
packet.name_offset,
|
|
739
|
+
packet.name_length,
|
|
740
|
+
packet.name_fregment,
|
|
741
|
+
)
|
|
742
|
+
else:
|
|
743
|
+
logger.error("!!! Unhandled packet: %s", packet)
|
|
744
|
+
|
|
745
|
+
def on_classic_connection_request(
|
|
746
|
+
self, peer_address: hci.Address, link_type: int
|
|
747
|
+
) -> None:
|
|
748
|
+
if link_type == hci.HCI_Connection_Complete_Event.LinkType.ACL:
|
|
749
|
+
self.classic_connections[peer_address] = Connection(
|
|
750
|
+
controller=self,
|
|
751
|
+
handle=0,
|
|
752
|
+
role=hci.Role.PERIPHERAL,
|
|
753
|
+
peer_address=peer_address,
|
|
754
|
+
link=self.link,
|
|
755
|
+
transport=PhysicalTransport.BR_EDR,
|
|
756
|
+
link_type=link_type,
|
|
757
|
+
classic_allow_role_switch=self.classic_allow_role_switch,
|
|
758
|
+
)
|
|
759
|
+
else:
|
|
760
|
+
self.sco_links[peer_address] = ScoLink(
|
|
761
|
+
handle=0,
|
|
762
|
+
link_type=link_type,
|
|
763
|
+
peer_address=peer_address,
|
|
764
|
+
)
|
|
681
765
|
self.send_hci_packet(
|
|
682
|
-
HCI_Connection_Request_Event(
|
|
766
|
+
hci.HCI_Connection_Request_Event(
|
|
683
767
|
bd_addr=peer_address,
|
|
684
768
|
class_of_device=0,
|
|
685
769
|
link_type=link_type,
|
|
686
770
|
)
|
|
687
771
|
)
|
|
688
772
|
|
|
689
|
-
def on_classic_connection_complete(
|
|
690
|
-
|
|
773
|
+
def on_classic_connection_complete(
|
|
774
|
+
self, peer_address: hci.Address, status: int
|
|
775
|
+
) -> None:
|
|
776
|
+
if status == hci.HCI_SUCCESS:
|
|
691
777
|
# Allocate (or reuse) a connection handle
|
|
692
778
|
peer_address = peer_address
|
|
693
|
-
|
|
694
|
-
if connection
|
|
695
|
-
|
|
779
|
+
connection_handle = self.allocate_connection_handle()
|
|
780
|
+
if connection := self.classic_connections.get(peer_address):
|
|
781
|
+
connection.handle = connection_handle
|
|
782
|
+
else:
|
|
696
783
|
connection = Connection(
|
|
697
784
|
controller=self,
|
|
698
785
|
handle=connection_handle,
|
|
699
|
-
|
|
700
|
-
role=Role.CENTRAL,
|
|
786
|
+
role=hci.Role.CENTRAL,
|
|
701
787
|
peer_address=peer_address,
|
|
702
788
|
link=self.link,
|
|
703
789
|
transport=PhysicalTransport.BR_EDR,
|
|
704
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
790
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
705
791
|
)
|
|
706
792
|
self.classic_connections[peer_address] = connection
|
|
707
793
|
logger.debug(
|
|
708
794
|
f'New CLASSIC connection handle: 0x{connection_handle:04X}'
|
|
709
795
|
)
|
|
710
|
-
else:
|
|
711
|
-
connection_handle = connection.handle
|
|
712
796
|
self.send_hci_packet(
|
|
713
|
-
HCI_Connection_Complete_Event(
|
|
797
|
+
hci.HCI_Connection_Complete_Event(
|
|
714
798
|
status=status,
|
|
715
799
|
connection_handle=connection_handle,
|
|
716
800
|
bd_addr=peer_address,
|
|
717
801
|
encryption_enabled=False,
|
|
718
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
802
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
719
803
|
)
|
|
720
804
|
)
|
|
721
805
|
else:
|
|
722
806
|
connection = None
|
|
723
807
|
self.send_hci_packet(
|
|
724
|
-
HCI_Connection_Complete_Event(
|
|
808
|
+
hci.HCI_Connection_Complete_Event(
|
|
725
809
|
status=status,
|
|
726
810
|
connection_handle=0,
|
|
727
811
|
bd_addr=peer_address,
|
|
728
812
|
encryption_enabled=False,
|
|
729
|
-
link_type=HCI_Connection_Complete_Event.LinkType.ACL,
|
|
813
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
730
814
|
)
|
|
731
815
|
)
|
|
732
816
|
|
|
733
|
-
def on_classic_disconnected(self, peer_address, reason):
|
|
817
|
+
def on_classic_disconnected(self, peer_address: hci.Address, reason: int) -> None:
|
|
734
818
|
# Send a disconnection complete event
|
|
735
|
-
if connection := self.classic_connections.
|
|
819
|
+
if connection := self.classic_connections.pop(peer_address, None):
|
|
736
820
|
self.send_hci_packet(
|
|
737
|
-
HCI_Disconnection_Complete_Event(
|
|
738
|
-
status=HCI_SUCCESS,
|
|
821
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
822
|
+
status=hci.HCI_SUCCESS,
|
|
739
823
|
connection_handle=connection.handle,
|
|
740
824
|
reason=reason,
|
|
741
825
|
)
|
|
742
826
|
)
|
|
827
|
+
else:
|
|
828
|
+
logger.warning(f'!!! No classic connection found for {peer_address}')
|
|
743
829
|
|
|
744
|
-
|
|
745
|
-
|
|
830
|
+
def on_classic_sco_disconnected(
|
|
831
|
+
self, peer_address: hci.Address, reason: int
|
|
832
|
+
) -> None:
|
|
833
|
+
# Send a disconnection complete event
|
|
834
|
+
if sco_link := self.sco_links.pop(peer_address, None):
|
|
835
|
+
self.send_hci_packet(
|
|
836
|
+
hci.HCI_Disconnection_Complete_Event(
|
|
837
|
+
status=hci.HCI_SUCCESS,
|
|
838
|
+
connection_handle=sco_link.handle,
|
|
839
|
+
reason=reason,
|
|
840
|
+
)
|
|
841
|
+
)
|
|
746
842
|
else:
|
|
747
843
|
logger.warning(f'!!! No classic connection found for {peer_address}')
|
|
748
844
|
|
|
749
|
-
def
|
|
845
|
+
def on_classic_role_change_request(self, peer_address: hci.Address) -> None:
|
|
846
|
+
assert (connection := self.classic_connections.get(peer_address))
|
|
847
|
+
if not connection.classic_allow_role_switch:
|
|
848
|
+
self.send_lmp_packet(
|
|
849
|
+
peer_address,
|
|
850
|
+
lmp.LmpNotAccepted(
|
|
851
|
+
lmp.Opcode.LMP_SWITCH_REQ, hci.HCI_ROLE_CHANGE_NOT_ALLOWED_ERROR
|
|
852
|
+
),
|
|
853
|
+
)
|
|
854
|
+
else:
|
|
855
|
+
self.send_lmp_packet(
|
|
856
|
+
peer_address,
|
|
857
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_SWITCH_REQ),
|
|
858
|
+
)
|
|
859
|
+
self.classic_role_change(connection)
|
|
860
|
+
|
|
861
|
+
def classic_role_change(self, connection: Connection) -> None:
|
|
862
|
+
new_role = (
|
|
863
|
+
hci.Role.CENTRAL
|
|
864
|
+
if connection.role == hci.Role.PERIPHERAL
|
|
865
|
+
else hci.Role.PERIPHERAL
|
|
866
|
+
)
|
|
867
|
+
connection.role = new_role
|
|
750
868
|
self.send_hci_packet(
|
|
751
|
-
HCI_Role_Change_Event(
|
|
752
|
-
status=HCI_SUCCESS,
|
|
753
|
-
bd_addr=peer_address,
|
|
869
|
+
hci.HCI_Role_Change_Event(
|
|
870
|
+
status=hci.HCI_SUCCESS,
|
|
871
|
+
bd_addr=connection.peer_address,
|
|
754
872
|
new_role=new_role,
|
|
755
873
|
)
|
|
756
874
|
)
|
|
757
875
|
|
|
758
876
|
def on_classic_sco_connection_complete(
|
|
759
|
-
self, peer_address: Address, status: int, link_type: int
|
|
760
|
-
):
|
|
761
|
-
if status == HCI_SUCCESS:
|
|
877
|
+
self, peer_address: hci.Address, status: int, link_type: int
|
|
878
|
+
) -> None:
|
|
879
|
+
if status == hci.HCI_SUCCESS:
|
|
762
880
|
# Allocate (or reuse) a connection handle
|
|
763
881
|
connection_handle = self.allocate_connection_handle()
|
|
764
|
-
|
|
765
|
-
controller=self,
|
|
882
|
+
sco_link = ScoLink(
|
|
766
883
|
handle=connection_handle,
|
|
767
|
-
# Role doesn't matter in SCO.
|
|
768
|
-
role=Role.CENTRAL,
|
|
769
|
-
peer_address=peer_address,
|
|
770
|
-
link=self.link,
|
|
771
|
-
transport=PhysicalTransport.BR_EDR,
|
|
772
884
|
link_type=link_type,
|
|
885
|
+
peer_address=peer_address,
|
|
773
886
|
)
|
|
774
|
-
self.
|
|
887
|
+
self.sco_links[peer_address] = sco_link
|
|
775
888
|
logger.debug(f'New SCO connection handle: 0x{connection_handle:04X}')
|
|
776
889
|
else:
|
|
777
890
|
connection_handle = 0
|
|
778
891
|
|
|
779
892
|
self.send_hci_packet(
|
|
780
|
-
HCI_Synchronous_Connection_Complete_Event(
|
|
893
|
+
hci.HCI_Synchronous_Connection_Complete_Event(
|
|
781
894
|
status=status,
|
|
782
895
|
connection_handle=connection_handle,
|
|
783
896
|
bd_addr=peer_address,
|
|
@@ -791,16 +904,43 @@ class Controller:
|
|
|
791
904
|
)
|
|
792
905
|
)
|
|
793
906
|
|
|
907
|
+
def on_classic_remote_name_request(
|
|
908
|
+
self, peer_address: hci.Address, name_offset: int
|
|
909
|
+
):
|
|
910
|
+
self.send_lmp_packet(
|
|
911
|
+
peer_address,
|
|
912
|
+
lmp.LmpNameRes(
|
|
913
|
+
name_offset=name_offset,
|
|
914
|
+
name_length=len(self.local_name),
|
|
915
|
+
name_fregment=self.local_name.encode('utf-8'),
|
|
916
|
+
),
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
def on_classic_remote_name_response(
|
|
920
|
+
self,
|
|
921
|
+
peer_address: hci.Address,
|
|
922
|
+
name_offset: int,
|
|
923
|
+
name_length: int,
|
|
924
|
+
name_fregment: bytes,
|
|
925
|
+
):
|
|
926
|
+
self.send_hci_packet(
|
|
927
|
+
hci.HCI_Remote_Name_Request_Complete_Event(
|
|
928
|
+
status=hci.HCI_SUCCESS,
|
|
929
|
+
bd_addr=peer_address,
|
|
930
|
+
remote_name=name_fregment,
|
|
931
|
+
)
|
|
932
|
+
)
|
|
933
|
+
|
|
794
934
|
############################################################
|
|
795
935
|
# Advertising support
|
|
796
936
|
############################################################
|
|
797
|
-
def on_advertising_timer_fired(self):
|
|
937
|
+
def on_advertising_timer_fired(self) -> None:
|
|
798
938
|
self.send_advertising_data()
|
|
799
939
|
self.advertising_timer_handle = asyncio.get_running_loop().call_later(
|
|
800
940
|
self.advertising_interval / 1000.0, self.on_advertising_timer_fired
|
|
801
941
|
)
|
|
802
942
|
|
|
803
|
-
def start_advertising(self):
|
|
943
|
+
def start_advertising(self) -> None:
|
|
804
944
|
# Stop any ongoing advertising before we start again
|
|
805
945
|
self.stop_advertising()
|
|
806
946
|
|
|
@@ -809,65 +949,85 @@ class Controller:
|
|
|
809
949
|
self.on_advertising_timer_fired
|
|
810
950
|
)
|
|
811
951
|
|
|
812
|
-
def stop_advertising(self):
|
|
952
|
+
def stop_advertising(self) -> None:
|
|
813
953
|
if self.advertising_timer_handle is not None:
|
|
814
954
|
self.advertising_timer_handle.cancel()
|
|
815
955
|
self.advertising_timer_handle = None
|
|
816
956
|
|
|
817
|
-
def send_advertising_data(self):
|
|
957
|
+
def send_advertising_data(self) -> None:
|
|
818
958
|
if self.link and self.advertising_data:
|
|
819
959
|
self.link.send_advertising_data(self.random_address, self.advertising_data)
|
|
820
960
|
|
|
821
961
|
@property
|
|
822
|
-
def is_advertising(self):
|
|
962
|
+
def is_advertising(self) -> bool:
|
|
823
963
|
return self.advertising_timer_handle is not None
|
|
824
964
|
|
|
825
965
|
############################################################
|
|
826
966
|
# HCI handlers
|
|
827
967
|
############################################################
|
|
828
|
-
def on_hci_command(self, command):
|
|
968
|
+
def on_hci_command(self, command: hci.HCI_Command) -> Optional[bytes]:
|
|
829
969
|
logger.warning(color(f'--- Unsupported command {command}', 'red'))
|
|
830
|
-
return bytes([HCI_UNKNOWN_HCI_COMMAND_ERROR])
|
|
970
|
+
return bytes([hci.HCI_UNKNOWN_HCI_COMMAND_ERROR])
|
|
831
971
|
|
|
832
|
-
def on_hci_create_connection_command(
|
|
972
|
+
def on_hci_create_connection_command(
|
|
973
|
+
self, command: hci.HCI_Create_Connection_Command
|
|
974
|
+
) -> Optional[bytes]:
|
|
833
975
|
'''
|
|
834
976
|
See Bluetooth spec Vol 4, Part E - 7.1.5 Create Connection command
|
|
835
977
|
'''
|
|
836
978
|
|
|
837
979
|
if self.link is None:
|
|
838
|
-
return
|
|
980
|
+
return None
|
|
839
981
|
logger.debug(f'Connection request to {command.bd_addr}')
|
|
840
982
|
|
|
841
983
|
# Check that we don't already have a pending connection
|
|
842
984
|
if self.link.get_pending_connection():
|
|
843
985
|
self.send_hci_packet(
|
|
844
|
-
HCI_Command_Status_Event(
|
|
845
|
-
status=HCI_CONTROLLER_BUSY_ERROR,
|
|
986
|
+
hci.HCI_Command_Status_Event(
|
|
987
|
+
status=hci.HCI_CONTROLLER_BUSY_ERROR,
|
|
846
988
|
num_hci_command_packets=1,
|
|
847
989
|
command_opcode=command.op_code,
|
|
848
990
|
)
|
|
849
991
|
)
|
|
850
|
-
return
|
|
851
|
-
|
|
852
|
-
self.
|
|
992
|
+
return None
|
|
993
|
+
|
|
994
|
+
self.classic_connections[command.bd_addr] = Connection(
|
|
995
|
+
controller=self,
|
|
996
|
+
handle=0,
|
|
997
|
+
role=hci.Role.CENTRAL,
|
|
998
|
+
peer_address=command.bd_addr,
|
|
999
|
+
link=self.link,
|
|
1000
|
+
transport=PhysicalTransport.BR_EDR,
|
|
1001
|
+
link_type=hci.HCI_Connection_Complete_Event.LinkType.ACL,
|
|
1002
|
+
classic_allow_role_switch=bool(command.allow_role_switch),
|
|
1003
|
+
)
|
|
853
1004
|
|
|
854
1005
|
# Say that the connection is pending
|
|
855
1006
|
self.send_hci_packet(
|
|
856
|
-
HCI_Command_Status_Event(
|
|
857
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1007
|
+
hci.HCI_Command_Status_Event(
|
|
1008
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
858
1009
|
num_hci_command_packets=1,
|
|
859
1010
|
command_opcode=command.op_code,
|
|
860
1011
|
)
|
|
861
1012
|
)
|
|
1013
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpHostConnectionReq())
|
|
1014
|
+
|
|
1015
|
+
def on_response(future: asyncio.Future[int]):
|
|
1016
|
+
self.on_classic_connection_complete(command.bd_addr, future.result())
|
|
1017
|
+
|
|
1018
|
+
future.add_done_callback(on_response)
|
|
1019
|
+
return None
|
|
862
1020
|
|
|
863
|
-
def on_hci_disconnect_command(
|
|
1021
|
+
def on_hci_disconnect_command(
|
|
1022
|
+
self, command: hci.HCI_Disconnect_Command
|
|
1023
|
+
) -> Optional[bytes]:
|
|
864
1024
|
'''
|
|
865
1025
|
See Bluetooth spec Vol 4, Part E - 7.1.6 Disconnect Command
|
|
866
1026
|
'''
|
|
867
1027
|
# First, say that the disconnection is pending
|
|
868
1028
|
self.send_hci_packet(
|
|
869
|
-
HCI_Command_Status_Event(
|
|
870
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1029
|
+
hci.HCI_Command_Status_Event(
|
|
1030
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
871
1031
|
num_hci_command_packets=1,
|
|
872
1032
|
command_opcode=command.op_code,
|
|
873
1033
|
)
|
|
@@ -893,18 +1053,41 @@ class Controller:
|
|
|
893
1053
|
del self.peripheral_connections[connection.peer_address]
|
|
894
1054
|
elif connection := self.find_classic_connection_by_handle(handle):
|
|
895
1055
|
if self.link:
|
|
896
|
-
self.
|
|
897
|
-
self,
|
|
1056
|
+
self.send_lmp_packet(
|
|
898
1057
|
connection.peer_address,
|
|
899
|
-
|
|
1058
|
+
lmp.LmpDetach(command.reason),
|
|
900
1059
|
)
|
|
1060
|
+
self.on_classic_disconnected(connection.peer_address, command.reason)
|
|
901
1061
|
else:
|
|
902
1062
|
# Remove the connection
|
|
903
1063
|
del self.classic_connections[connection.peer_address]
|
|
1064
|
+
elif sco_link := self.find_classic_sco_link_by_handle(handle):
|
|
1065
|
+
if self.link:
|
|
1066
|
+
if (
|
|
1067
|
+
sco_link.link_type
|
|
1068
|
+
== hci.HCI_Connection_Complete_Event.LinkType.ESCO
|
|
1069
|
+
):
|
|
1070
|
+
self.send_lmp_packet(
|
|
1071
|
+
sco_link.peer_address,
|
|
1072
|
+
lmp.LmpRemoveScoLinkReq(
|
|
1073
|
+
sco_handle=0, error_code=command.reason
|
|
1074
|
+
),
|
|
1075
|
+
)
|
|
1076
|
+
else:
|
|
1077
|
+
self.send_lmp_packet(
|
|
1078
|
+
sco_link.peer_address,
|
|
1079
|
+
lmp.LmpRemoveEscoLinkReq(
|
|
1080
|
+
esco_handle=0, error_code=command.reason
|
|
1081
|
+
),
|
|
1082
|
+
)
|
|
1083
|
+
self.on_classic_sco_disconnected(sco_link.peer_address, command.reason)
|
|
1084
|
+
else:
|
|
1085
|
+
# Remove the connection
|
|
1086
|
+
del self.sco_links[sco_link.peer_address]
|
|
904
1087
|
elif cis_link := (
|
|
905
1088
|
self.central_cis_links.get(handle) or self.peripheral_cis_links.get(handle)
|
|
906
1089
|
):
|
|
907
|
-
if self.link:
|
|
1090
|
+
if self.link and cis_link.acl_connection:
|
|
908
1091
|
self.link.disconnect_cis(
|
|
909
1092
|
initiator_controller=self,
|
|
910
1093
|
peer_address=cis_link.acl_connection.peer_address,
|
|
@@ -913,29 +1096,93 @@ class Controller:
|
|
|
913
1096
|
)
|
|
914
1097
|
# Spec requires handle to be kept after disconnection.
|
|
915
1098
|
|
|
916
|
-
|
|
1099
|
+
return None
|
|
1100
|
+
|
|
1101
|
+
def on_hci_accept_connection_request_command(
|
|
1102
|
+
self, command: hci.HCI_Accept_Connection_Request_Command
|
|
1103
|
+
) -> Optional[bytes]:
|
|
917
1104
|
'''
|
|
918
1105
|
See Bluetooth spec Vol 4, Part E - 7.1.8 Accept Connection Request command
|
|
919
1106
|
'''
|
|
920
1107
|
|
|
921
1108
|
if self.link is None:
|
|
922
|
-
return
|
|
1109
|
+
return None
|
|
1110
|
+
|
|
1111
|
+
if not (connection := self.classic_connections.get(command.bd_addr)):
|
|
1112
|
+
self.send_hci_packet(
|
|
1113
|
+
hci.HCI_Command_Status_Event(
|
|
1114
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1115
|
+
num_hci_command_packets=1,
|
|
1116
|
+
command_opcode=command.op_code,
|
|
1117
|
+
)
|
|
1118
|
+
)
|
|
1119
|
+
return None
|
|
923
1120
|
self.send_hci_packet(
|
|
924
|
-
HCI_Command_Status_Event(
|
|
925
|
-
status=HCI_SUCCESS,
|
|
1121
|
+
hci.HCI_Command_Status_Event(
|
|
1122
|
+
status=hci.HCI_SUCCESS,
|
|
926
1123
|
num_hci_command_packets=1,
|
|
927
1124
|
command_opcode=command.op_code,
|
|
928
1125
|
)
|
|
929
1126
|
)
|
|
930
|
-
self.link.classic_accept_connection(self, command.bd_addr, command.role)
|
|
931
1127
|
|
|
932
|
-
|
|
1128
|
+
if command.role == hci.Role.CENTRAL:
|
|
1129
|
+
# Perform role switching before accept.
|
|
1130
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
|
|
1131
|
+
|
|
1132
|
+
def on_response(future: asyncio.Future[int]):
|
|
1133
|
+
if (status := future.result()) == hci.HCI_SUCCESS:
|
|
1134
|
+
self.classic_role_change(connection)
|
|
1135
|
+
# Continue connection setup.
|
|
1136
|
+
self.send_lmp_packet(
|
|
1137
|
+
command.bd_addr,
|
|
1138
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
|
|
1139
|
+
)
|
|
1140
|
+
else:
|
|
1141
|
+
# Abort connection setup.
|
|
1142
|
+
self.send_lmp_packet(
|
|
1143
|
+
command.bd_addr,
|
|
1144
|
+
lmp.LmpNotAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ, status),
|
|
1145
|
+
)
|
|
1146
|
+
self.on_classic_connection_complete(command.bd_addr, status)
|
|
1147
|
+
|
|
1148
|
+
future.add_done_callback(on_response)
|
|
1149
|
+
|
|
1150
|
+
else:
|
|
1151
|
+
# Simply accept connection.
|
|
1152
|
+
self.send_lmp_packet(
|
|
1153
|
+
command.bd_addr,
|
|
1154
|
+
lmp.LmpAccepted(lmp.Opcode.LMP_HOST_CONNECTION_REQ),
|
|
1155
|
+
)
|
|
1156
|
+
self.on_classic_connection_complete(command.bd_addr, hci.HCI_SUCCESS)
|
|
1157
|
+
return None
|
|
1158
|
+
|
|
1159
|
+
def on_hci_remote_name_request_command(
|
|
1160
|
+
self, command: hci.HCI_Remote_Name_Request_Command
|
|
1161
|
+
) -> Optional[bytes]:
|
|
1162
|
+
'''
|
|
1163
|
+
See Bluetooth spec Vol 4, Part E - 7.1.19 Remote Name Request command
|
|
1164
|
+
'''
|
|
1165
|
+
self.send_hci_packet(
|
|
1166
|
+
hci.HCI_Command_Status_Event(
|
|
1167
|
+
status=hci.HCI_SUCCESS,
|
|
1168
|
+
num_hci_command_packets=1,
|
|
1169
|
+
command_opcode=command.op_code,
|
|
1170
|
+
)
|
|
1171
|
+
)
|
|
1172
|
+
|
|
1173
|
+
self.send_lmp_packet(command.bd_addr, lmp.LmpNameReq(0))
|
|
1174
|
+
|
|
1175
|
+
return None
|
|
1176
|
+
|
|
1177
|
+
def on_hci_enhanced_setup_synchronous_connection_command(
|
|
1178
|
+
self, command: hci.HCI_Enhanced_Setup_Synchronous_Connection_Command
|
|
1179
|
+
) -> Optional[bytes]:
|
|
933
1180
|
'''
|
|
934
1181
|
See Bluetooth spec Vol 4, Part E - 7.1.45 Enhanced Setup Synchronous Connection command
|
|
935
1182
|
'''
|
|
936
1183
|
|
|
937
1184
|
if self.link is None:
|
|
938
|
-
return
|
|
1185
|
+
return None
|
|
939
1186
|
|
|
940
1187
|
if not (
|
|
941
1188
|
connection := self.find_classic_connection_by_handle(
|
|
@@ -943,55 +1190,90 @@ class Controller:
|
|
|
943
1190
|
)
|
|
944
1191
|
):
|
|
945
1192
|
self.send_hci_packet(
|
|
946
|
-
HCI_Command_Status_Event(
|
|
947
|
-
status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1193
|
+
hci.HCI_Command_Status_Event(
|
|
1194
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
948
1195
|
num_hci_command_packets=1,
|
|
949
1196
|
command_opcode=command.op_code,
|
|
950
1197
|
)
|
|
951
1198
|
)
|
|
952
|
-
return
|
|
1199
|
+
return None
|
|
953
1200
|
|
|
954
1201
|
self.send_hci_packet(
|
|
955
|
-
HCI_Command_Status_Event(
|
|
956
|
-
status=HCI_SUCCESS,
|
|
1202
|
+
hci.HCI_Command_Status_Event(
|
|
1203
|
+
status=hci.HCI_SUCCESS,
|
|
957
1204
|
num_hci_command_packets=1,
|
|
958
1205
|
command_opcode=command.op_code,
|
|
959
1206
|
)
|
|
960
1207
|
)
|
|
961
|
-
self.
|
|
962
|
-
|
|
1208
|
+
future = self.send_lmp_packet(
|
|
1209
|
+
connection.peer_address,
|
|
1210
|
+
lmp.LmpEscoLinkReq(
|
|
1211
|
+
esco_handle=0,
|
|
1212
|
+
esco_lt_addr=0,
|
|
1213
|
+
timing_control_flags=0,
|
|
1214
|
+
d_esco=0,
|
|
1215
|
+
t_esco=0,
|
|
1216
|
+
w_esco=0,
|
|
1217
|
+
esco_packet_type_c_to_p=0,
|
|
1218
|
+
esco_packet_type_p_to_c=0,
|
|
1219
|
+
packet_length_c_to_p=0,
|
|
1220
|
+
packet_length_p_to_c=0,
|
|
1221
|
+
air_mode=0,
|
|
1222
|
+
negotiation_state=0,
|
|
1223
|
+
),
|
|
963
1224
|
)
|
|
964
1225
|
|
|
965
|
-
|
|
1226
|
+
def on_response(future: asyncio.Future[int]):
|
|
1227
|
+
self.on_classic_sco_connection_complete(
|
|
1228
|
+
connection.peer_address,
|
|
1229
|
+
future.result(),
|
|
1230
|
+
hci.HCI_Connection_Complete_Event.LinkType.ESCO,
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
future.add_done_callback(on_response)
|
|
1234
|
+
return None
|
|
1235
|
+
|
|
1236
|
+
def on_hci_enhanced_accept_synchronous_connection_request_command(
|
|
1237
|
+
self, command: hci.HCI_Enhanced_Accept_Synchronous_Connection_Request_Command
|
|
1238
|
+
) -> Optional[bytes]:
|
|
966
1239
|
'''
|
|
967
1240
|
See Bluetooth spec Vol 4, Part E - 7.1.46 Enhanced Accept Synchronous Connection Request command
|
|
968
1241
|
'''
|
|
969
1242
|
|
|
970
1243
|
if self.link is None:
|
|
971
|
-
return
|
|
1244
|
+
return None
|
|
972
1245
|
|
|
973
1246
|
if not (connection := self.find_classic_connection_by_address(command.bd_addr)):
|
|
974
1247
|
self.send_hci_packet(
|
|
975
|
-
HCI_Command_Status_Event(
|
|
976
|
-
status=HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1248
|
+
hci.HCI_Command_Status_Event(
|
|
1249
|
+
status=hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
977
1250
|
num_hci_command_packets=1,
|
|
978
1251
|
command_opcode=command.op_code,
|
|
979
1252
|
)
|
|
980
1253
|
)
|
|
981
|
-
return
|
|
1254
|
+
return None
|
|
982
1255
|
|
|
983
1256
|
self.send_hci_packet(
|
|
984
|
-
HCI_Command_Status_Event(
|
|
985
|
-
status=HCI_SUCCESS,
|
|
1257
|
+
hci.HCI_Command_Status_Event(
|
|
1258
|
+
status=hci.HCI_SUCCESS,
|
|
986
1259
|
num_hci_command_packets=1,
|
|
987
1260
|
command_opcode=command.op_code,
|
|
988
1261
|
)
|
|
989
1262
|
)
|
|
990
|
-
self.
|
|
991
|
-
|
|
1263
|
+
self.send_lmp_packet(
|
|
1264
|
+
connection.peer_address,
|
|
1265
|
+
lmp.LmpAcceptedExt(lmp.Opcode.LMP_ESCO_LINK_REQ),
|
|
1266
|
+
)
|
|
1267
|
+
self.on_classic_sco_connection_complete(
|
|
1268
|
+
connection.peer_address,
|
|
1269
|
+
hci.HCI_SUCCESS,
|
|
1270
|
+
hci.HCI_Connection_Complete_Event.LinkType.ESCO,
|
|
992
1271
|
)
|
|
1272
|
+
return None
|
|
993
1273
|
|
|
994
|
-
def on_hci_sniff_mode_command(
|
|
1274
|
+
def on_hci_sniff_mode_command(
|
|
1275
|
+
self, command: hci.HCI_Sniff_Mode_Command
|
|
1276
|
+
) -> Optional[bytes]:
|
|
995
1277
|
'''
|
|
996
1278
|
See Bluetooth spec Vol 4, Part E - 7.2.2 Sniff Mode command
|
|
997
1279
|
'''
|
|
@@ -1003,25 +1285,28 @@ class Controller:
|
|
|
1003
1285
|
command_opcode=command.op_code,
|
|
1004
1286
|
)
|
|
1005
1287
|
)
|
|
1006
|
-
return
|
|
1288
|
+
return None
|
|
1007
1289
|
|
|
1008
1290
|
self.send_hci_packet(
|
|
1009
1291
|
hci.HCI_Command_Status_Event(
|
|
1010
|
-
status=HCI_SUCCESS,
|
|
1292
|
+
status=hci.HCI_SUCCESS,
|
|
1011
1293
|
num_hci_command_packets=1,
|
|
1012
1294
|
command_opcode=command.op_code,
|
|
1013
1295
|
)
|
|
1014
1296
|
)
|
|
1015
1297
|
self.send_hci_packet(
|
|
1016
1298
|
hci.HCI_Mode_Change_Event(
|
|
1017
|
-
status=HCI_SUCCESS,
|
|
1299
|
+
status=hci.HCI_SUCCESS,
|
|
1018
1300
|
connection_handle=command.connection_handle,
|
|
1019
1301
|
current_mode=hci.HCI_Mode_Change_Event.Mode.SNIFF,
|
|
1020
1302
|
interval=2,
|
|
1021
1303
|
)
|
|
1022
1304
|
)
|
|
1305
|
+
return None
|
|
1023
1306
|
|
|
1024
|
-
def on_hci_exit_sniff_mode_command(
|
|
1307
|
+
def on_hci_exit_sniff_mode_command(
|
|
1308
|
+
self, command: hci.HCI_Exit_Sniff_Mode_Command
|
|
1309
|
+
) -> Optional[bytes]:
|
|
1025
1310
|
'''
|
|
1026
1311
|
See Bluetooth spec Vol 4, Part E - 7.2.3 Exit Sniff Mode command
|
|
1027
1312
|
'''
|
|
@@ -1034,55 +1319,103 @@ class Controller:
|
|
|
1034
1319
|
command_opcode=command.op_code,
|
|
1035
1320
|
)
|
|
1036
1321
|
)
|
|
1037
|
-
return
|
|
1322
|
+
return None
|
|
1038
1323
|
|
|
1039
1324
|
self.send_hci_packet(
|
|
1040
1325
|
hci.HCI_Command_Status_Event(
|
|
1041
|
-
status=HCI_SUCCESS,
|
|
1326
|
+
status=hci.HCI_SUCCESS,
|
|
1042
1327
|
num_hci_command_packets=1,
|
|
1043
1328
|
command_opcode=command.op_code,
|
|
1044
1329
|
)
|
|
1045
1330
|
)
|
|
1046
1331
|
self.send_hci_packet(
|
|
1047
1332
|
hci.HCI_Mode_Change_Event(
|
|
1048
|
-
status=HCI_SUCCESS,
|
|
1333
|
+
status=hci.HCI_SUCCESS,
|
|
1049
1334
|
connection_handle=command.connection_handle,
|
|
1050
1335
|
current_mode=hci.HCI_Mode_Change_Event.Mode.ACTIVE,
|
|
1051
1336
|
interval=2,
|
|
1052
1337
|
)
|
|
1053
1338
|
)
|
|
1339
|
+
return None
|
|
1054
1340
|
|
|
1055
|
-
def on_hci_switch_role_command(
|
|
1341
|
+
def on_hci_switch_role_command(
|
|
1342
|
+
self, command: hci.HCI_Switch_Role_Command
|
|
1343
|
+
) -> Optional[bytes]:
|
|
1056
1344
|
'''
|
|
1057
|
-
See Bluetooth spec Vol 4, Part E - 7.2.8 Switch Role command
|
|
1345
|
+
See Bluetooth spec Vol 4, Part E - 7.2.8 Switch hci.Role command
|
|
1058
1346
|
'''
|
|
1059
1347
|
|
|
1060
1348
|
if self.link is None:
|
|
1061
|
-
return
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1349
|
+
return None
|
|
1350
|
+
|
|
1351
|
+
if connection := self.classic_connections.get(command.bd_addr):
|
|
1352
|
+
current_role = connection.role
|
|
1353
|
+
self.send_hci_packet(
|
|
1354
|
+
hci.HCI_Command_Status_Event(
|
|
1355
|
+
status=hci.HCI_SUCCESS,
|
|
1356
|
+
num_hci_command_packets=1,
|
|
1357
|
+
command_opcode=command.op_code,
|
|
1358
|
+
)
|
|
1067
1359
|
)
|
|
1068
|
-
|
|
1069
|
-
|
|
1360
|
+
else:
|
|
1361
|
+
# Connection doesn't exist, reject.
|
|
1362
|
+
self.send_hci_packet(
|
|
1363
|
+
hci.HCI_Command_Status_Event(
|
|
1364
|
+
status=hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1365
|
+
num_hci_command_packets=1,
|
|
1366
|
+
command_opcode=command.op_code,
|
|
1367
|
+
)
|
|
1368
|
+
)
|
|
1369
|
+
return None
|
|
1370
|
+
|
|
1371
|
+
# If role doesn't change, only send event to local host.
|
|
1372
|
+
if current_role == command.role:
|
|
1373
|
+
self.send_hci_packet(
|
|
1374
|
+
hci.HCI_Role_Change_Event(
|
|
1375
|
+
status=hci.HCI_SUCCESS,
|
|
1376
|
+
bd_addr=command.bd_addr,
|
|
1377
|
+
new_role=current_role,
|
|
1378
|
+
)
|
|
1379
|
+
)
|
|
1380
|
+
else:
|
|
1381
|
+
future = self.send_lmp_packet(command.bd_addr, lmp.LmpSwitchReq())
|
|
1382
|
+
|
|
1383
|
+
def on_response(future: asyncio.Future[int]):
|
|
1384
|
+
if (status := future.result()) == hci.HCI_SUCCESS:
|
|
1385
|
+
connection.role = hci.Role(command.role)
|
|
1386
|
+
self.send_hci_packet(
|
|
1387
|
+
hci.HCI_Role_Change_Event(
|
|
1388
|
+
status=status,
|
|
1389
|
+
bd_addr=command.bd_addr,
|
|
1390
|
+
new_role=connection.role,
|
|
1391
|
+
)
|
|
1392
|
+
)
|
|
1393
|
+
|
|
1394
|
+
future.add_done_callback(on_response)
|
|
1395
|
+
|
|
1396
|
+
return None
|
|
1070
1397
|
|
|
1071
|
-
def on_hci_set_event_mask_command(
|
|
1398
|
+
def on_hci_set_event_mask_command(
|
|
1399
|
+
self, command: hci.HCI_Set_Event_Mask_Command
|
|
1400
|
+
) -> Optional[bytes]:
|
|
1072
1401
|
'''
|
|
1073
1402
|
See Bluetooth spec Vol 4, Part E - 7.3.1 Set Event Mask Command
|
|
1074
1403
|
'''
|
|
1075
|
-
self.event_mask =
|
|
1076
|
-
|
|
1404
|
+
self.event_mask = int.from_bytes(
|
|
1405
|
+
command.event_mask, byteorder='little', signed=False
|
|
1406
|
+
)
|
|
1407
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1077
1408
|
|
|
1078
|
-
def on_hci_reset_command(self, _command):
|
|
1409
|
+
def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) -> Optional[bytes]:
|
|
1079
1410
|
'''
|
|
1080
1411
|
See Bluetooth spec Vol 4, Part E - 7.3.2 Reset Command
|
|
1081
1412
|
'''
|
|
1082
1413
|
# TODO: cleanup what needs to be reset
|
|
1083
|
-
return bytes([HCI_SUCCESS])
|
|
1414
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1084
1415
|
|
|
1085
|
-
def on_hci_write_local_name_command(
|
|
1416
|
+
def on_hci_write_local_name_command(
|
|
1417
|
+
self, command: hci.HCI_Write_Local_Name_Command
|
|
1418
|
+
) -> Optional[bytes]:
|
|
1086
1419
|
'''
|
|
1087
1420
|
See Bluetooth spec Vol 4, Part E - 7.3.11 Write Local Name Command
|
|
1088
1421
|
'''
|
|
@@ -1095,9 +1428,11 @@ class Controller:
|
|
|
1095
1428
|
self.local_name = str(local_name, 'utf-8')
|
|
1096
1429
|
except UnicodeDecodeError:
|
|
1097
1430
|
pass
|
|
1098
|
-
return bytes([HCI_SUCCESS])
|
|
1431
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1099
1432
|
|
|
1100
|
-
def on_hci_read_local_name_command(
|
|
1433
|
+
def on_hci_read_local_name_command(
|
|
1434
|
+
self, _command: hci.HCI_Read_Local_Name_Command
|
|
1435
|
+
) -> Optional[bytes]:
|
|
1101
1436
|
'''
|
|
1102
1437
|
See Bluetooth spec Vol 4, Part E - 7.3.12 Read Local Name Command
|
|
1103
1438
|
'''
|
|
@@ -1105,21 +1440,27 @@ class Controller:
|
|
|
1105
1440
|
if len(local_name) < 248:
|
|
1106
1441
|
local_name = local_name + bytes(248 - len(local_name))
|
|
1107
1442
|
|
|
1108
|
-
return bytes([HCI_SUCCESS]) + local_name
|
|
1443
|
+
return bytes([hci.HCI_SUCCESS]) + local_name
|
|
1109
1444
|
|
|
1110
|
-
def on_hci_read_class_of_device_command(
|
|
1445
|
+
def on_hci_read_class_of_device_command(
|
|
1446
|
+
self, _command: hci.HCI_Read_Class_Of_Device_Command
|
|
1447
|
+
) -> Optional[bytes]:
|
|
1111
1448
|
'''
|
|
1112
1449
|
See Bluetooth spec Vol 4, Part E - 7.3.25 Read Class of Device Command
|
|
1113
1450
|
'''
|
|
1114
|
-
return bytes([HCI_SUCCESS, 0, 0, 0])
|
|
1451
|
+
return bytes([hci.HCI_SUCCESS, 0, 0, 0])
|
|
1115
1452
|
|
|
1116
|
-
def on_hci_write_class_of_device_command(
|
|
1453
|
+
def on_hci_write_class_of_device_command(
|
|
1454
|
+
self, _command: hci.HCI_Write_Class_Of_Device_Command
|
|
1455
|
+
) -> Optional[bytes]:
|
|
1117
1456
|
'''
|
|
1118
1457
|
See Bluetooth spec Vol 4, Part E - 7.3.26 Write Class of Device Command
|
|
1119
1458
|
'''
|
|
1120
|
-
return bytes([HCI_SUCCESS])
|
|
1459
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1121
1460
|
|
|
1122
|
-
def on_hci_read_synchronous_flow_control_enable_command(
|
|
1461
|
+
def on_hci_read_synchronous_flow_control_enable_command(
|
|
1462
|
+
self, _command: hci.HCI_Read_Synchronous_Flow_Control_Enable_Command
|
|
1463
|
+
) -> Optional[bytes]:
|
|
1123
1464
|
'''
|
|
1124
1465
|
See Bluetooth spec Vol 4, Part E - 7.3.36 Read Synchronous Flow Control Enable
|
|
1125
1466
|
Command
|
|
@@ -1128,87 +1469,109 @@ class Controller:
|
|
|
1128
1469
|
ret = 1
|
|
1129
1470
|
else:
|
|
1130
1471
|
ret = 0
|
|
1131
|
-
return bytes([HCI_SUCCESS, ret])
|
|
1472
|
+
return bytes([hci.HCI_SUCCESS, ret])
|
|
1132
1473
|
|
|
1133
|
-
def on_hci_write_synchronous_flow_control_enable_command(
|
|
1474
|
+
def on_hci_write_synchronous_flow_control_enable_command(
|
|
1475
|
+
self, command: hci.HCI_Write_Synchronous_Flow_Control_Enable_Command
|
|
1476
|
+
) -> Optional[bytes]:
|
|
1134
1477
|
'''
|
|
1135
1478
|
See Bluetooth spec Vol 4, Part E - 7.3.37 Write Synchronous Flow Control Enable
|
|
1136
1479
|
Command
|
|
1137
1480
|
'''
|
|
1138
|
-
ret = HCI_SUCCESS
|
|
1481
|
+
ret = hci.HCI_SUCCESS
|
|
1139
1482
|
if command.synchronous_flow_control_enable == 1:
|
|
1140
1483
|
self.sync_flow_control = True
|
|
1141
1484
|
elif command.synchronous_flow_control_enable == 0:
|
|
1142
1485
|
self.sync_flow_control = False
|
|
1143
1486
|
else:
|
|
1144
|
-
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1487
|
+
ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1145
1488
|
return bytes([ret])
|
|
1146
1489
|
|
|
1147
|
-
def on_hci_set_controller_to_host_flow_control_command(
|
|
1490
|
+
def on_hci_set_controller_to_host_flow_control_command(
|
|
1491
|
+
self, _command: hci.HCI_Set_Controller_To_Host_Flow_Control_Command
|
|
1492
|
+
) -> Optional[bytes]:
|
|
1148
1493
|
'''
|
|
1149
1494
|
See Bluetooth spec Vol 4, Part E - 7.3.38 Set Controller To Host Flow Control
|
|
1150
1495
|
Command
|
|
1151
1496
|
'''
|
|
1152
1497
|
# For now we just accept the command but ignore the values.
|
|
1153
1498
|
# TODO: respect the passed in values.
|
|
1154
|
-
return bytes([HCI_SUCCESS])
|
|
1499
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1155
1500
|
|
|
1156
|
-
def on_hci_host_buffer_size_command(
|
|
1501
|
+
def on_hci_host_buffer_size_command(
|
|
1502
|
+
self, _command: hci.HCI_Host_Buffer_Size_Command
|
|
1503
|
+
) -> Optional[bytes]:
|
|
1157
1504
|
'''
|
|
1158
1505
|
See Bluetooth spec Vol 4, Part E - 7.3.39 Host Buffer Size Command
|
|
1159
1506
|
'''
|
|
1160
1507
|
# For now we just accept the command but ignore the values.
|
|
1161
1508
|
# TODO: respect the passed in values.
|
|
1162
|
-
return bytes([HCI_SUCCESS])
|
|
1509
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1163
1510
|
|
|
1164
|
-
def on_hci_write_extended_inquiry_response_command(
|
|
1511
|
+
def on_hci_write_extended_inquiry_response_command(
|
|
1512
|
+
self, _command: hci.HCI_Write_Extended_Inquiry_Response_Command
|
|
1513
|
+
) -> Optional[bytes]:
|
|
1165
1514
|
'''
|
|
1166
1515
|
See Bluetooth spec Vol 4, Part E - 7.3.56 Write Extended Inquiry Response
|
|
1167
1516
|
Command
|
|
1168
1517
|
'''
|
|
1169
|
-
return bytes([HCI_SUCCESS])
|
|
1518
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1170
1519
|
|
|
1171
|
-
def on_hci_write_simple_pairing_mode_command(
|
|
1520
|
+
def on_hci_write_simple_pairing_mode_command(
|
|
1521
|
+
self, _command: hci.HCI_Write_Simple_Pairing_Mode_Command
|
|
1522
|
+
) -> Optional[bytes]:
|
|
1172
1523
|
'''
|
|
1173
1524
|
See Bluetooth spec Vol 4, Part E - 7.3.59 Write Simple Pairing Mode Command
|
|
1174
1525
|
'''
|
|
1175
|
-
return bytes([HCI_SUCCESS])
|
|
1526
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1176
1527
|
|
|
1177
|
-
def on_hci_set_event_mask_page_2_command(
|
|
1528
|
+
def on_hci_set_event_mask_page_2_command(
|
|
1529
|
+
self, command: hci.HCI_Set_Event_Mask_Page_2_Command
|
|
1530
|
+
) -> Optional[bytes]:
|
|
1178
1531
|
'''
|
|
1179
1532
|
See Bluetooth spec Vol 4, Part E - 7.3.69 Set Event Mask Page 2 Command
|
|
1180
1533
|
'''
|
|
1181
|
-
self.event_mask_page_2 =
|
|
1182
|
-
|
|
1534
|
+
self.event_mask_page_2 = int.from_bytes(
|
|
1535
|
+
command.event_mask_page_2, byteorder='little', signed=False
|
|
1536
|
+
)
|
|
1537
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1183
1538
|
|
|
1184
|
-
def on_hci_read_le_host_support_command(
|
|
1539
|
+
def on_hci_read_le_host_support_command(
|
|
1540
|
+
self, _command: hci.HCI_Read_LE_Host_Support_Command
|
|
1541
|
+
) -> Optional[bytes]:
|
|
1185
1542
|
'''
|
|
1186
1543
|
See Bluetooth spec Vol 4, Part E - 7.3.78 Write LE Host Support Command
|
|
1187
1544
|
'''
|
|
1188
|
-
return bytes([HCI_SUCCESS, 1, 0])
|
|
1545
|
+
return bytes([hci.HCI_SUCCESS, 1, 0])
|
|
1189
1546
|
|
|
1190
|
-
def on_hci_write_le_host_support_command(
|
|
1547
|
+
def on_hci_write_le_host_support_command(
|
|
1548
|
+
self, _command: hci.HCI_Write_LE_Host_Support_Command
|
|
1549
|
+
) -> Optional[bytes]:
|
|
1191
1550
|
'''
|
|
1192
1551
|
See Bluetooth spec Vol 4, Part E - 7.3.79 Write LE Host Support Command
|
|
1193
1552
|
'''
|
|
1194
1553
|
# TODO / Just ignore for now
|
|
1195
|
-
return bytes([HCI_SUCCESS])
|
|
1554
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1196
1555
|
|
|
1197
|
-
def on_hci_write_authenticated_payload_timeout_command(
|
|
1556
|
+
def on_hci_write_authenticated_payload_timeout_command(
|
|
1557
|
+
self, command: hci.HCI_Write_Authenticated_Payload_Timeout_Command
|
|
1558
|
+
) -> Optional[bytes]:
|
|
1198
1559
|
'''
|
|
1199
1560
|
See Bluetooth spec Vol 4, Part E - 7.3.94 Write Authenticated Payload Timeout
|
|
1200
1561
|
Command
|
|
1201
1562
|
'''
|
|
1202
1563
|
# TODO
|
|
1203
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
1564
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
1204
1565
|
|
|
1205
|
-
def on_hci_read_local_version_information_command(
|
|
1566
|
+
def on_hci_read_local_version_information_command(
|
|
1567
|
+
self, _command: hci.HCI_Read_Local_Version_Information_Command
|
|
1568
|
+
) -> Optional[bytes]:
|
|
1206
1569
|
'''
|
|
1207
1570
|
See Bluetooth spec Vol 4, Part E - 7.4.1 Read Local Version Information Command
|
|
1208
1571
|
'''
|
|
1209
1572
|
return struct.pack(
|
|
1210
1573
|
'<BBHBHH',
|
|
1211
|
-
HCI_SUCCESS,
|
|
1574
|
+
hci.HCI_SUCCESS,
|
|
1212
1575
|
self.hci_version,
|
|
1213
1576
|
self.hci_revision,
|
|
1214
1577
|
self.lmp_version,
|
|
@@ -1216,29 +1579,35 @@ class Controller:
|
|
|
1216
1579
|
self.lmp_subversion,
|
|
1217
1580
|
)
|
|
1218
1581
|
|
|
1219
|
-
def on_hci_read_local_supported_commands_command(
|
|
1582
|
+
def on_hci_read_local_supported_commands_command(
|
|
1583
|
+
self, _command: hci.HCI_Read_Local_Supported_Commands_Command
|
|
1584
|
+
) -> Optional[bytes]:
|
|
1220
1585
|
'''
|
|
1221
1586
|
See Bluetooth spec Vol 4, Part E - 7.4.2 Read Local Supported Commands Command
|
|
1222
1587
|
'''
|
|
1223
|
-
return bytes([HCI_SUCCESS]) + self.supported_commands
|
|
1588
|
+
return bytes([hci.HCI_SUCCESS]) + self.supported_commands
|
|
1224
1589
|
|
|
1225
|
-
def on_hci_read_local_supported_features_command(
|
|
1590
|
+
def on_hci_read_local_supported_features_command(
|
|
1591
|
+
self, _command: hci.HCI_Read_Local_Supported_Features_Command
|
|
1592
|
+
) -> Optional[bytes]:
|
|
1226
1593
|
'''
|
|
1227
1594
|
See Bluetooth spec Vol 4, Part E - 7.4.3 Read Local Supported Features Command
|
|
1228
1595
|
'''
|
|
1229
|
-
return bytes([HCI_SUCCESS]) + self.lmp_features[:8]
|
|
1596
|
+
return bytes([hci.HCI_SUCCESS]) + self.lmp_features[:8]
|
|
1230
1597
|
|
|
1231
|
-
def on_hci_read_local_extended_features_command(
|
|
1598
|
+
def on_hci_read_local_extended_features_command(
|
|
1599
|
+
self, command: hci.HCI_Read_Local_Extended_Features_Command
|
|
1600
|
+
) -> Optional[bytes]:
|
|
1232
1601
|
'''
|
|
1233
1602
|
See Bluetooth spec Vol 4, Part E - 7.4.4 Read Local Extended Features Command
|
|
1234
1603
|
'''
|
|
1235
1604
|
if command.page_number * 8 > len(self.lmp_features):
|
|
1236
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1605
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1237
1606
|
return (
|
|
1238
1607
|
bytes(
|
|
1239
1608
|
[
|
|
1240
1609
|
# Status
|
|
1241
|
-
HCI_SUCCESS,
|
|
1610
|
+
hci.HCI_SUCCESS,
|
|
1242
1611
|
# Page number
|
|
1243
1612
|
command.page_number,
|
|
1244
1613
|
# Max page number
|
|
@@ -1249,20 +1618,24 @@ class Controller:
|
|
|
1249
1618
|
+ self.lmp_features[command.page_number * 8 : (command.page_number + 1) * 8]
|
|
1250
1619
|
)
|
|
1251
1620
|
|
|
1252
|
-
def on_hci_read_buffer_size_command(
|
|
1621
|
+
def on_hci_read_buffer_size_command(
|
|
1622
|
+
self, _command: hci.HCI_Read_Buffer_Size_Command
|
|
1623
|
+
) -> Optional[bytes]:
|
|
1253
1624
|
'''
|
|
1254
1625
|
See Bluetooth spec Vol 4, Part E - 7.4.5 Read Buffer Size Command
|
|
1255
1626
|
'''
|
|
1256
1627
|
return struct.pack(
|
|
1257
1628
|
'<BHBHH',
|
|
1258
|
-
HCI_SUCCESS,
|
|
1629
|
+
hci.HCI_SUCCESS,
|
|
1259
1630
|
self.acl_data_packet_length,
|
|
1260
1631
|
0,
|
|
1261
1632
|
self.total_num_acl_data_packets,
|
|
1262
1633
|
0,
|
|
1263
1634
|
)
|
|
1264
1635
|
|
|
1265
|
-
def on_hci_read_bd_addr_command(
|
|
1636
|
+
def on_hci_read_bd_addr_command(
|
|
1637
|
+
self, _command: hci.HCI_Read_BD_ADDR_Command
|
|
1638
|
+
) -> Optional[bytes]:
|
|
1266
1639
|
'''
|
|
1267
1640
|
See Bluetooth spec Vol 4, Part E - 7.4.6 Read BD_ADDR Command
|
|
1268
1641
|
'''
|
|
@@ -1271,11 +1644,11 @@ class Controller:
|
|
|
1271
1644
|
if self._public_address is not None
|
|
1272
1645
|
else bytes(6)
|
|
1273
1646
|
)
|
|
1274
|
-
return bytes([HCI_SUCCESS]) + bd_addr
|
|
1647
|
+
return bytes([hci.HCI_SUCCESS]) + bd_addr
|
|
1275
1648
|
|
|
1276
1649
|
def on_hci_le_set_default_subrate_command(
|
|
1277
1650
|
self, command: hci.HCI_LE_Set_Default_Subrate_Command
|
|
1278
|
-
):
|
|
1651
|
+
) -> Optional[bytes]:
|
|
1279
1652
|
'''
|
|
1280
1653
|
See Bluetooth spec Vol 6, Part E - 7.8.123 LE Set Event Mask Command
|
|
1281
1654
|
'''
|
|
@@ -1285,13 +1658,13 @@ class Controller:
|
|
|
1285
1658
|
or command.subrate_max < command.subrate_min
|
|
1286
1659
|
or command.continuation_number >= command.subrate_max
|
|
1287
1660
|
):
|
|
1288
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1661
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1289
1662
|
|
|
1290
|
-
return bytes([HCI_SUCCESS])
|
|
1663
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1291
1664
|
|
|
1292
1665
|
def on_hci_le_subrate_request_command(
|
|
1293
1666
|
self, command: hci.HCI_LE_Subrate_Request_Command
|
|
1294
|
-
):
|
|
1667
|
+
) -> Optional[bytes]:
|
|
1295
1668
|
'''
|
|
1296
1669
|
See Bluetooth spec Vol 6, Part E - 7.8.124 LE Subrate Request command
|
|
1297
1670
|
'''
|
|
@@ -1301,7 +1674,7 @@ class Controller:
|
|
|
1301
1674
|
or command.subrate_max < command.subrate_min
|
|
1302
1675
|
or command.continuation_number >= command.subrate_max
|
|
1303
1676
|
):
|
|
1304
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1677
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1305
1678
|
|
|
1306
1679
|
self.send_hci_packet(
|
|
1307
1680
|
hci.HCI_Command_Status_Event(
|
|
@@ -1323,80 +1696,102 @@ class Controller:
|
|
|
1323
1696
|
)
|
|
1324
1697
|
return None
|
|
1325
1698
|
|
|
1326
|
-
def on_hci_le_set_event_mask_command(
|
|
1699
|
+
def on_hci_le_set_event_mask_command(
|
|
1700
|
+
self, command: hci.HCI_LE_Set_Event_Mask_Command
|
|
1701
|
+
) -> Optional[bytes]:
|
|
1327
1702
|
'''
|
|
1328
1703
|
See Bluetooth spec Vol 4, Part E - 7.8.1 LE Set Event Mask Command
|
|
1329
1704
|
'''
|
|
1330
|
-
self.le_event_mask =
|
|
1331
|
-
|
|
1705
|
+
self.le_event_mask = int.from_bytes(
|
|
1706
|
+
command.le_event_mask, byteorder='little', signed=False
|
|
1707
|
+
)
|
|
1708
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1332
1709
|
|
|
1333
|
-
def on_hci_le_read_buffer_size_command(
|
|
1710
|
+
def on_hci_le_read_buffer_size_command(
|
|
1711
|
+
self, _command: hci.HCI_LE_Read_Buffer_Size_Command
|
|
1712
|
+
) -> Optional[bytes]:
|
|
1334
1713
|
'''
|
|
1335
1714
|
See Bluetooth spec Vol 4, Part E - 7.8.2 LE Read Buffer Size Command
|
|
1336
1715
|
'''
|
|
1337
1716
|
return struct.pack(
|
|
1338
1717
|
'<BHB',
|
|
1339
|
-
HCI_SUCCESS,
|
|
1718
|
+
hci.HCI_SUCCESS,
|
|
1340
1719
|
self.le_acl_data_packet_length,
|
|
1341
1720
|
self.total_num_le_acl_data_packets,
|
|
1342
1721
|
)
|
|
1343
1722
|
|
|
1344
|
-
def on_hci_le_read_buffer_size_v2_command(
|
|
1723
|
+
def on_hci_le_read_buffer_size_v2_command(
|
|
1724
|
+
self, _command: hci.HCI_LE_Read_Buffer_Size_V2_Command
|
|
1725
|
+
) -> Optional[bytes]:
|
|
1345
1726
|
'''
|
|
1346
1727
|
See Bluetooth spec Vol 4, Part E - 7.8.2 LE Read Buffer Size Command
|
|
1347
1728
|
'''
|
|
1348
1729
|
return struct.pack(
|
|
1349
1730
|
'<BHBHB',
|
|
1350
|
-
HCI_SUCCESS,
|
|
1731
|
+
hci.HCI_SUCCESS,
|
|
1351
1732
|
self.le_acl_data_packet_length,
|
|
1352
1733
|
self.total_num_le_acl_data_packets,
|
|
1353
1734
|
self.iso_data_packet_length,
|
|
1354
1735
|
self.total_num_iso_data_packets,
|
|
1355
1736
|
)
|
|
1356
1737
|
|
|
1357
|
-
def on_hci_le_read_local_supported_features_command(
|
|
1738
|
+
def on_hci_le_read_local_supported_features_command(
|
|
1739
|
+
self, _command: hci.HCI_LE_Read_Local_Supported_Features_Command
|
|
1740
|
+
) -> Optional[bytes]:
|
|
1358
1741
|
'''
|
|
1359
1742
|
See Bluetooth spec Vol 4, Part E - 7.8.3 LE Read Local Supported Features
|
|
1360
1743
|
Command
|
|
1361
1744
|
'''
|
|
1362
|
-
return bytes([HCI_SUCCESS]) + self.le_features
|
|
1745
|
+
return bytes([hci.HCI_SUCCESS]) + self.le_features
|
|
1363
1746
|
|
|
1364
|
-
def on_hci_le_set_random_address_command(
|
|
1747
|
+
def on_hci_le_set_random_address_command(
|
|
1748
|
+
self, command: hci.HCI_LE_Set_Random_Address_Command
|
|
1749
|
+
) -> Optional[bytes]:
|
|
1365
1750
|
'''
|
|
1366
|
-
See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random Address Command
|
|
1751
|
+
See Bluetooth spec Vol 4, Part E - 7.8.4 LE Set Random hci.Address Command
|
|
1367
1752
|
'''
|
|
1368
1753
|
self.random_address = command.random_address
|
|
1369
|
-
return bytes([HCI_SUCCESS])
|
|
1754
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1370
1755
|
|
|
1371
|
-
def on_hci_le_set_advertising_parameters_command(
|
|
1756
|
+
def on_hci_le_set_advertising_parameters_command(
|
|
1757
|
+
self, command: hci.HCI_LE_Set_Advertising_Parameters_Command
|
|
1758
|
+
) -> Optional[bytes]:
|
|
1372
1759
|
'''
|
|
1373
1760
|
See Bluetooth spec Vol 4, Part E - 7.8.5 LE Set Advertising Parameters Command
|
|
1374
1761
|
'''
|
|
1375
1762
|
self.advertising_parameters = command
|
|
1376
|
-
return bytes([HCI_SUCCESS])
|
|
1763
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1377
1764
|
|
|
1378
|
-
def on_hci_le_read_advertising_physical_channel_tx_power_command(
|
|
1765
|
+
def on_hci_le_read_advertising_physical_channel_tx_power_command(
|
|
1766
|
+
self, _command: hci.HCI_LE_Read_Advertising_Physical_Channel_Tx_Power_Command
|
|
1767
|
+
) -> Optional[bytes]:
|
|
1379
1768
|
'''
|
|
1380
1769
|
See Bluetooth spec Vol 4, Part E - 7.8.6 LE Read Advertising Physical Channel
|
|
1381
1770
|
Tx Power Command
|
|
1382
1771
|
'''
|
|
1383
|
-
return bytes([HCI_SUCCESS, self.advertising_channel_tx_power])
|
|
1772
|
+
return bytes([hci.HCI_SUCCESS, self.advertising_channel_tx_power])
|
|
1384
1773
|
|
|
1385
|
-
def on_hci_le_set_advertising_data_command(
|
|
1774
|
+
def on_hci_le_set_advertising_data_command(
|
|
1775
|
+
self, command: hci.HCI_LE_Set_Advertising_Data_Command
|
|
1776
|
+
) -> Optional[bytes]:
|
|
1386
1777
|
'''
|
|
1387
1778
|
See Bluetooth spec Vol 4, Part E - 7.8.7 LE Set Advertising Data Command
|
|
1388
1779
|
'''
|
|
1389
1780
|
self.advertising_data = command.advertising_data
|
|
1390
|
-
return bytes([HCI_SUCCESS])
|
|
1781
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1391
1782
|
|
|
1392
|
-
def on_hci_le_set_scan_response_data_command(
|
|
1783
|
+
def on_hci_le_set_scan_response_data_command(
|
|
1784
|
+
self, command: hci.HCI_LE_Set_Scan_Response_Data_Command
|
|
1785
|
+
) -> Optional[bytes]:
|
|
1393
1786
|
'''
|
|
1394
1787
|
See Bluetooth spec Vol 4, Part E - 7.8.8 LE Set Scan Response Data Command
|
|
1395
1788
|
'''
|
|
1396
1789
|
self.le_scan_response_data = command.scan_response_data
|
|
1397
|
-
return bytes([HCI_SUCCESS])
|
|
1790
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1398
1791
|
|
|
1399
|
-
def on_hci_le_set_advertising_enable_command(
|
|
1792
|
+
def on_hci_le_set_advertising_enable_command(
|
|
1793
|
+
self, command: hci.HCI_LE_Set_Advertising_Enable_Command
|
|
1794
|
+
) -> Optional[bytes]:
|
|
1400
1795
|
'''
|
|
1401
1796
|
See Bluetooth spec Vol 4, Part E - 7.8.9 LE Set Advertising Enable Command
|
|
1402
1797
|
'''
|
|
@@ -1405,97 +1800,125 @@ class Controller:
|
|
|
1405
1800
|
else:
|
|
1406
1801
|
self.stop_advertising()
|
|
1407
1802
|
|
|
1408
|
-
return bytes([HCI_SUCCESS])
|
|
1803
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1409
1804
|
|
|
1410
|
-
def on_hci_le_set_scan_parameters_command(
|
|
1805
|
+
def on_hci_le_set_scan_parameters_command(
|
|
1806
|
+
self, command: hci.HCI_LE_Set_Scan_Parameters_Command
|
|
1807
|
+
) -> Optional[bytes]:
|
|
1411
1808
|
'''
|
|
1412
1809
|
See Bluetooth spec Vol 4, Part E - 7.8.10 LE Set Scan Parameters Command
|
|
1413
1810
|
'''
|
|
1414
1811
|
if self.le_scan_enable:
|
|
1415
|
-
return bytes([HCI_COMMAND_DISALLOWED_ERROR])
|
|
1812
|
+
return bytes([hci.HCI_COMMAND_DISALLOWED_ERROR])
|
|
1416
1813
|
|
|
1417
1814
|
self.le_scan_type = command.le_scan_type
|
|
1418
1815
|
self.le_scan_interval = command.le_scan_interval
|
|
1419
1816
|
self.le_scan_window = command.le_scan_window
|
|
1420
|
-
self.le_scan_own_address_type = command.own_address_type
|
|
1817
|
+
self.le_scan_own_address_type = hci.AddressType(command.own_address_type)
|
|
1421
1818
|
self.le_scanning_filter_policy = command.scanning_filter_policy
|
|
1422
|
-
return bytes([HCI_SUCCESS])
|
|
1819
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1423
1820
|
|
|
1424
|
-
def on_hci_le_set_scan_enable_command(
|
|
1821
|
+
def on_hci_le_set_scan_enable_command(
|
|
1822
|
+
self, command: hci.HCI_LE_Set_Scan_Enable_Command
|
|
1823
|
+
) -> Optional[bytes]:
|
|
1425
1824
|
'''
|
|
1426
1825
|
See Bluetooth spec Vol 4, Part E - 7.8.11 LE Set Scan Enable Command
|
|
1427
1826
|
'''
|
|
1428
|
-
self.le_scan_enable = command.le_scan_enable
|
|
1429
|
-
self.filter_duplicates = command.filter_duplicates
|
|
1430
|
-
return bytes([HCI_SUCCESS])
|
|
1827
|
+
self.le_scan_enable = bool(command.le_scan_enable)
|
|
1828
|
+
self.filter_duplicates = bool(command.filter_duplicates)
|
|
1829
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1431
1830
|
|
|
1432
|
-
def on_hci_le_create_connection_command(
|
|
1831
|
+
def on_hci_le_create_connection_command(
|
|
1832
|
+
self, command: hci.HCI_LE_Create_Connection_Command
|
|
1833
|
+
) -> Optional[bytes]:
|
|
1433
1834
|
'''
|
|
1434
1835
|
See Bluetooth spec Vol 4, Part E - 7.8.12 LE Create Connection Command
|
|
1435
1836
|
'''
|
|
1436
1837
|
|
|
1437
1838
|
if not self.link:
|
|
1438
|
-
return
|
|
1839
|
+
return None
|
|
1439
1840
|
|
|
1440
1841
|
logger.debug(f'Connection request to {command.peer_address}')
|
|
1441
1842
|
|
|
1442
1843
|
# Check that we don't already have a pending connection
|
|
1443
1844
|
if self.link.get_pending_connection():
|
|
1444
1845
|
self.send_hci_packet(
|
|
1445
|
-
HCI_Command_Status_Event(
|
|
1446
|
-
status=HCI_COMMAND_DISALLOWED_ERROR,
|
|
1846
|
+
hci.HCI_Command_Status_Event(
|
|
1847
|
+
status=hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1447
1848
|
num_hci_command_packets=1,
|
|
1448
1849
|
command_opcode=command.op_code,
|
|
1449
1850
|
)
|
|
1450
1851
|
)
|
|
1451
|
-
return
|
|
1852
|
+
return None
|
|
1452
1853
|
|
|
1453
1854
|
# Initiate the connection
|
|
1454
1855
|
self.link.connect(self.random_address, command)
|
|
1455
1856
|
|
|
1456
1857
|
# Say that the connection is pending
|
|
1457
1858
|
self.send_hci_packet(
|
|
1458
|
-
HCI_Command_Status_Event(
|
|
1459
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1859
|
+
hci.HCI_Command_Status_Event(
|
|
1860
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1460
1861
|
num_hci_command_packets=1,
|
|
1461
1862
|
command_opcode=command.op_code,
|
|
1462
1863
|
)
|
|
1463
1864
|
)
|
|
1865
|
+
return None
|
|
1464
1866
|
|
|
1465
|
-
def on_hci_le_create_connection_cancel_command(
|
|
1867
|
+
def on_hci_le_create_connection_cancel_command(
|
|
1868
|
+
self, _command: hci.HCI_LE_Create_Connection_Cancel_Command
|
|
1869
|
+
) -> Optional[bytes]:
|
|
1466
1870
|
'''
|
|
1467
1871
|
See Bluetooth spec Vol 4, Part E - 7.8.13 LE Create Connection Cancel Command
|
|
1468
1872
|
'''
|
|
1469
|
-
return bytes([HCI_SUCCESS])
|
|
1873
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1470
1874
|
|
|
1471
|
-
def on_hci_le_read_filter_accept_list_size_command(
|
|
1875
|
+
def on_hci_le_read_filter_accept_list_size_command(
|
|
1876
|
+
self, _command: hci.HCI_LE_Read_Filter_Accept_List_Size_Command
|
|
1877
|
+
) -> Optional[bytes]:
|
|
1472
1878
|
'''
|
|
1473
1879
|
See Bluetooth spec Vol 4, Part E - 7.8.14 LE Read Filter Accept List Size
|
|
1474
1880
|
Command
|
|
1475
1881
|
'''
|
|
1476
|
-
return bytes([HCI_SUCCESS, self.filter_accept_list_size])
|
|
1882
|
+
return bytes([hci.HCI_SUCCESS, self.filter_accept_list_size])
|
|
1477
1883
|
|
|
1478
|
-
def on_hci_le_clear_filter_accept_list_command(
|
|
1884
|
+
def on_hci_le_clear_filter_accept_list_command(
|
|
1885
|
+
self, _command: hci.HCI_LE_Clear_Filter_Accept_List_Command
|
|
1886
|
+
) -> Optional[bytes]:
|
|
1479
1887
|
'''
|
|
1480
1888
|
See Bluetooth spec Vol 4, Part E - 7.8.15 LE Clear Filter Accept List Command
|
|
1481
1889
|
'''
|
|
1482
|
-
return bytes([HCI_SUCCESS])
|
|
1890
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1483
1891
|
|
|
1484
|
-
def on_hci_le_add_device_to_filter_accept_list_command(
|
|
1892
|
+
def on_hci_le_add_device_to_filter_accept_list_command(
|
|
1893
|
+
self, _command: hci.HCI_LE_Add_Device_To_Filter_Accept_List_Command
|
|
1894
|
+
) -> Optional[bytes]:
|
|
1485
1895
|
'''
|
|
1486
1896
|
See Bluetooth spec Vol 4, Part E - 7.8.16 LE Add Device To Filter Accept List
|
|
1487
1897
|
Command
|
|
1488
1898
|
'''
|
|
1489
|
-
return bytes([HCI_SUCCESS])
|
|
1899
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1490
1900
|
|
|
1491
|
-
def on_hci_le_remove_device_from_filter_accept_list_command(
|
|
1901
|
+
def on_hci_le_remove_device_from_filter_accept_list_command(
|
|
1902
|
+
self, _command: hci.HCI_LE_Remove_Device_From_Filter_Accept_List_Command
|
|
1903
|
+
) -> Optional[bytes]:
|
|
1492
1904
|
'''
|
|
1493
1905
|
See Bluetooth spec Vol 4, Part E - 7.8.17 LE Remove Device From Filter Accept
|
|
1494
1906
|
List Command
|
|
1495
1907
|
'''
|
|
1496
|
-
return bytes([HCI_SUCCESS])
|
|
1908
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1497
1909
|
|
|
1498
|
-
def
|
|
1910
|
+
def on_hci_write_scan_enable_command(
|
|
1911
|
+
self, command: hci.HCI_Write_Scan_Enable_Command
|
|
1912
|
+
) -> Optional[bytes]:
|
|
1913
|
+
'''
|
|
1914
|
+
See Bluetooth spec Vol 4, Part E - 7.3.18 Write Scan Enable Command
|
|
1915
|
+
'''
|
|
1916
|
+
self.classic_scan_enable = command.scan_enable
|
|
1917
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1918
|
+
|
|
1919
|
+
def on_hci_le_read_remote_features_command(
|
|
1920
|
+
self, command: hci.HCI_LE_Read_Remote_Features_Command
|
|
1921
|
+
) -> Optional[bytes]:
|
|
1499
1922
|
'''
|
|
1500
1923
|
See Bluetooth spec Vol 4, Part E - 7.8.21 LE Read Remote Features Command
|
|
1501
1924
|
'''
|
|
@@ -1504,18 +1927,18 @@ class Controller:
|
|
|
1504
1927
|
|
|
1505
1928
|
if not self.find_connection_by_handle(handle):
|
|
1506
1929
|
self.send_hci_packet(
|
|
1507
|
-
HCI_Command_Status_Event(
|
|
1508
|
-
status=HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
1930
|
+
hci.HCI_Command_Status_Event(
|
|
1931
|
+
status=hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
1509
1932
|
num_hci_command_packets=1,
|
|
1510
1933
|
command_opcode=command.op_code,
|
|
1511
1934
|
)
|
|
1512
1935
|
)
|
|
1513
|
-
return
|
|
1936
|
+
return None
|
|
1514
1937
|
|
|
1515
1938
|
# First, say that the command is pending
|
|
1516
1939
|
self.send_hci_packet(
|
|
1517
|
-
HCI_Command_Status_Event(
|
|
1518
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1940
|
+
hci.HCI_Command_Status_Event(
|
|
1941
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1519
1942
|
num_hci_command_packets=1,
|
|
1520
1943
|
command_opcode=command.op_code,
|
|
1521
1944
|
)
|
|
@@ -1523,23 +1946,30 @@ class Controller:
|
|
|
1523
1946
|
|
|
1524
1947
|
# Then send the remote features
|
|
1525
1948
|
self.send_hci_packet(
|
|
1526
|
-
HCI_LE_Read_Remote_Features_Complete_Event(
|
|
1527
|
-
status=HCI_SUCCESS,
|
|
1949
|
+
hci.HCI_LE_Read_Remote_Features_Complete_Event(
|
|
1950
|
+
status=hci.HCI_SUCCESS,
|
|
1528
1951
|
connection_handle=handle,
|
|
1529
1952
|
le_features=bytes.fromhex('dd40000000000000'),
|
|
1530
1953
|
)
|
|
1531
1954
|
)
|
|
1955
|
+
return None
|
|
1532
1956
|
|
|
1533
|
-
def on_hci_le_rand_command(
|
|
1957
|
+
def on_hci_le_rand_command(
|
|
1958
|
+
self, _command: hci.HCI_LE_Rand_Command
|
|
1959
|
+
) -> Optional[bytes]:
|
|
1534
1960
|
'''
|
|
1535
1961
|
See Bluetooth spec Vol 4, Part E - 7.8.23 LE Rand Command
|
|
1536
1962
|
'''
|
|
1537
|
-
return bytes([HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
|
|
1963
|
+
return bytes([hci.HCI_SUCCESS]) + struct.pack('Q', random.randint(0, 1 << 64))
|
|
1538
1964
|
|
|
1539
|
-
def on_hci_le_enable_encryption_command(
|
|
1965
|
+
def on_hci_le_enable_encryption_command(
|
|
1966
|
+
self, command: hci.HCI_LE_Enable_Encryption_Command
|
|
1967
|
+
) -> Optional[bytes]:
|
|
1540
1968
|
'''
|
|
1541
1969
|
See Bluetooth spec Vol 4, Part E - 7.8.24 LE Enable Encryption Command
|
|
1542
1970
|
'''
|
|
1971
|
+
if not self.link:
|
|
1972
|
+
return None
|
|
1543
1973
|
|
|
1544
1974
|
# Check the parameters
|
|
1545
1975
|
if not (
|
|
@@ -1548,7 +1978,7 @@ class Controller:
|
|
|
1548
1978
|
)
|
|
1549
1979
|
):
|
|
1550
1980
|
logger.warning('connection not found')
|
|
1551
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1981
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1552
1982
|
|
|
1553
1983
|
# Notify that the connection is now encrypted
|
|
1554
1984
|
self.link.on_connection_encrypted(
|
|
@@ -1560,8 +1990,8 @@ class Controller:
|
|
|
1560
1990
|
)
|
|
1561
1991
|
|
|
1562
1992
|
self.send_hci_packet(
|
|
1563
|
-
HCI_Command_Status_Event(
|
|
1564
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
1993
|
+
hci.HCI_Command_Status_Event(
|
|
1994
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1565
1995
|
num_hci_command_packets=1,
|
|
1566
1996
|
command_opcode=command.op_code,
|
|
1567
1997
|
)
|
|
@@ -1569,25 +1999,31 @@ class Controller:
|
|
|
1569
1999
|
|
|
1570
2000
|
return None
|
|
1571
2001
|
|
|
1572
|
-
def on_hci_le_read_supported_states_command(
|
|
2002
|
+
def on_hci_le_read_supported_states_command(
|
|
2003
|
+
self, _command: hci.HCI_LE_Read_Supported_States_Command
|
|
2004
|
+
) -> Optional[bytes]:
|
|
1573
2005
|
'''
|
|
1574
2006
|
See Bluetooth spec Vol 4, Part E - 7.8.27 LE Read Supported States Command
|
|
1575
2007
|
'''
|
|
1576
|
-
return bytes([HCI_SUCCESS]) + self.le_states
|
|
2008
|
+
return bytes([hci.HCI_SUCCESS]) + self.le_states
|
|
1577
2009
|
|
|
1578
|
-
def on_hci_le_read_suggested_default_data_length_command(
|
|
2010
|
+
def on_hci_le_read_suggested_default_data_length_command(
|
|
2011
|
+
self, _command: hci.HCI_LE_Read_Suggested_Default_Data_Length_Command
|
|
2012
|
+
) -> Optional[bytes]:
|
|
1579
2013
|
'''
|
|
1580
2014
|
See Bluetooth spec Vol 4, Part E - 7.8.34 LE Read Suggested Default Data Length
|
|
1581
2015
|
Command
|
|
1582
2016
|
'''
|
|
1583
2017
|
return struct.pack(
|
|
1584
2018
|
'<BHH',
|
|
1585
|
-
HCI_SUCCESS,
|
|
2019
|
+
hci.HCI_SUCCESS,
|
|
1586
2020
|
self.suggested_max_tx_octets,
|
|
1587
2021
|
self.suggested_max_tx_time,
|
|
1588
2022
|
)
|
|
1589
2023
|
|
|
1590
|
-
def on_hci_le_write_suggested_default_data_length_command(
|
|
2024
|
+
def on_hci_le_write_suggested_default_data_length_command(
|
|
2025
|
+
self, command: hci.HCI_LE_Write_Suggested_Default_Data_Length_Command
|
|
2026
|
+
) -> Optional[bytes]:
|
|
1591
2027
|
'''
|
|
1592
2028
|
See Bluetooth spec Vol 4, Part E - 7.8.35 LE Write Suggested Default Data Length
|
|
1593
2029
|
Command
|
|
@@ -1595,175 +2031,216 @@ class Controller:
|
|
|
1595
2031
|
self.suggested_max_tx_octets, self.suggested_max_tx_time = struct.unpack(
|
|
1596
2032
|
'<HH', command.parameters[:4]
|
|
1597
2033
|
)
|
|
1598
|
-
return bytes([HCI_SUCCESS])
|
|
2034
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1599
2035
|
|
|
1600
|
-
def on_hci_le_read_local_p_256_public_key_command(
|
|
2036
|
+
def on_hci_le_read_local_p_256_public_key_command(
|
|
2037
|
+
self, _command: hci.HCI_LE_Read_Local_P_256_Public_Key_Command
|
|
2038
|
+
) -> Optional[bytes]:
|
|
1601
2039
|
'''
|
|
1602
2040
|
See Bluetooth spec Vol 4, Part E - 7.8.36 LE Read P-256 Public Key Command
|
|
1603
2041
|
'''
|
|
1604
|
-
# TODO create key and send HCI_LE_Read_Local_P-256_Public_Key_Complete event
|
|
1605
|
-
return bytes([HCI_SUCCESS])
|
|
2042
|
+
# TODO create key and send hci.HCI_LE_Read_Local_P-256_Public_Key_Complete event
|
|
2043
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1606
2044
|
|
|
1607
|
-
def on_hci_le_add_device_to_resolving_list_command(
|
|
2045
|
+
def on_hci_le_add_device_to_resolving_list_command(
|
|
2046
|
+
self, _command: hci.HCI_LE_Add_Device_To_Resolving_List_Command
|
|
2047
|
+
) -> Optional[bytes]:
|
|
1608
2048
|
'''
|
|
1609
2049
|
See Bluetooth spec Vol 4, Part E - 7.8.38 LE Add Device To Resolving List
|
|
1610
2050
|
Command
|
|
1611
2051
|
'''
|
|
1612
|
-
return bytes([HCI_SUCCESS])
|
|
2052
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1613
2053
|
|
|
1614
|
-
def on_hci_le_clear_resolving_list_command(
|
|
2054
|
+
def on_hci_le_clear_resolving_list_command(
|
|
2055
|
+
self, _command: hci.HCI_LE_Clear_Resolving_List_Command
|
|
2056
|
+
) -> Optional[bytes]:
|
|
1615
2057
|
'''
|
|
1616
2058
|
See Bluetooth spec Vol 4, Part E - 7.8.40 LE Clear Resolving List Command
|
|
1617
2059
|
'''
|
|
1618
|
-
return bytes([HCI_SUCCESS])
|
|
2060
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1619
2061
|
|
|
1620
|
-
def on_hci_le_read_resolving_list_size_command(
|
|
2062
|
+
def on_hci_le_read_resolving_list_size_command(
|
|
2063
|
+
self, _command: hci.HCI_LE_Read_Resolving_List_Size_Command
|
|
2064
|
+
) -> Optional[bytes]:
|
|
1621
2065
|
'''
|
|
1622
2066
|
See Bluetooth spec Vol 4, Part E - 7.8.41 LE Read Resolving List Size Command
|
|
1623
2067
|
'''
|
|
1624
|
-
return bytes([HCI_SUCCESS, self.resolving_list_size])
|
|
2068
|
+
return bytes([hci.HCI_SUCCESS, self.resolving_list_size])
|
|
1625
2069
|
|
|
1626
|
-
def on_hci_le_set_address_resolution_enable_command(
|
|
2070
|
+
def on_hci_le_set_address_resolution_enable_command(
|
|
2071
|
+
self, command: hci.HCI_LE_Set_Address_Resolution_Enable_Command
|
|
2072
|
+
) -> Optional[bytes]:
|
|
1627
2073
|
'''
|
|
1628
|
-
See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set Address Resolution Enable
|
|
2074
|
+
See Bluetooth spec Vol 4, Part E - 7.8.44 LE Set hci.Address Resolution Enable
|
|
1629
2075
|
Command
|
|
1630
2076
|
'''
|
|
1631
|
-
ret = HCI_SUCCESS
|
|
2077
|
+
ret = hci.HCI_SUCCESS
|
|
1632
2078
|
if command.address_resolution_enable == 1:
|
|
1633
2079
|
self.le_address_resolution = True
|
|
1634
2080
|
elif command.address_resolution_enable == 0:
|
|
1635
2081
|
self.le_address_resolution = False
|
|
1636
2082
|
else:
|
|
1637
|
-
ret = HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
2083
|
+
ret = hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR
|
|
1638
2084
|
return bytes([ret])
|
|
1639
2085
|
|
|
1640
|
-
def on_hci_le_set_resolvable_private_address_timeout_command(
|
|
2086
|
+
def on_hci_le_set_resolvable_private_address_timeout_command(
|
|
2087
|
+
self, command: hci.HCI_LE_Set_Resolvable_Private_Address_Timeout_Command
|
|
2088
|
+
) -> Optional[bytes]:
|
|
1641
2089
|
'''
|
|
1642
|
-
See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private Address
|
|
2090
|
+
See Bluetooth spec Vol 4, Part E - 7.8.45 LE Set Resolvable Private hci.Address
|
|
1643
2091
|
Timeout Command
|
|
1644
2092
|
'''
|
|
1645
2093
|
self.le_rpa_timeout = command.rpa_timeout
|
|
1646
|
-
return bytes([HCI_SUCCESS])
|
|
2094
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1647
2095
|
|
|
1648
|
-
def on_hci_le_read_maximum_data_length_command(
|
|
2096
|
+
def on_hci_le_read_maximum_data_length_command(
|
|
2097
|
+
self, _command: hci.HCI_LE_Read_Maximum_Data_Length_Command
|
|
2098
|
+
) -> Optional[bytes]:
|
|
1649
2099
|
'''
|
|
1650
2100
|
See Bluetooth spec Vol 4, Part E - 7.8.46 LE Read Maximum Data Length Command
|
|
1651
2101
|
'''
|
|
1652
2102
|
return struct.pack(
|
|
1653
2103
|
'<BHHHH',
|
|
1654
|
-
HCI_SUCCESS,
|
|
2104
|
+
hci.HCI_SUCCESS,
|
|
1655
2105
|
self.supported_max_tx_octets,
|
|
1656
2106
|
self.supported_max_tx_time,
|
|
1657
2107
|
self.supported_max_rx_octets,
|
|
1658
2108
|
self.supported_max_rx_time,
|
|
1659
2109
|
)
|
|
1660
2110
|
|
|
1661
|
-
def on_hci_le_read_phy_command(
|
|
2111
|
+
def on_hci_le_read_phy_command(
|
|
2112
|
+
self, command: hci.HCI_LE_Read_PHY_Command
|
|
2113
|
+
) -> Optional[bytes]:
|
|
1662
2114
|
'''
|
|
1663
2115
|
See Bluetooth spec Vol 4, Part E - 7.8.47 LE Read PHY Command
|
|
1664
2116
|
'''
|
|
1665
2117
|
return struct.pack(
|
|
1666
2118
|
'<BHBB',
|
|
1667
|
-
HCI_SUCCESS,
|
|
2119
|
+
hci.HCI_SUCCESS,
|
|
1668
2120
|
command.connection_handle,
|
|
1669
|
-
HCI_LE_1M_PHY,
|
|
1670
|
-
HCI_LE_1M_PHY,
|
|
2121
|
+
hci.HCI_LE_1M_PHY,
|
|
2122
|
+
hci.HCI_LE_1M_PHY,
|
|
1671
2123
|
)
|
|
1672
2124
|
|
|
1673
|
-
def on_hci_le_set_default_phy_command(
|
|
2125
|
+
def on_hci_le_set_default_phy_command(
|
|
2126
|
+
self, command: hci.HCI_LE_Set_Default_PHY_Command
|
|
2127
|
+
) -> Optional[bytes]:
|
|
1674
2128
|
'''
|
|
1675
2129
|
See Bluetooth spec Vol 4, Part E - 7.8.48 LE Set Default PHY Command
|
|
1676
2130
|
'''
|
|
1677
|
-
self.default_phy =
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
}
|
|
1682
|
-
return bytes([HCI_SUCCESS])
|
|
2131
|
+
self.default_phy['all_phys'] = command.all_phys
|
|
2132
|
+
self.default_phy['tx_phys'] = command.tx_phys
|
|
2133
|
+
self.default_phy['rx_phys'] = command.rx_phys
|
|
2134
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1683
2135
|
|
|
1684
|
-
def on_hci_le_set_advertising_set_random_address_command(
|
|
2136
|
+
def on_hci_le_set_advertising_set_random_address_command(
|
|
2137
|
+
self, _command: hci.HCI_LE_Set_Advertising_Set_Random_Address_Command
|
|
2138
|
+
) -> Optional[bytes]:
|
|
1685
2139
|
'''
|
|
1686
|
-
See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random Address
|
|
2140
|
+
See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random hci.Address
|
|
1687
2141
|
Command
|
|
1688
2142
|
'''
|
|
1689
|
-
return bytes([HCI_SUCCESS])
|
|
2143
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1690
2144
|
|
|
1691
|
-
def on_hci_le_set_extended_advertising_parameters_command(
|
|
2145
|
+
def on_hci_le_set_extended_advertising_parameters_command(
|
|
2146
|
+
self, _command: hci.HCI_LE_Set_Extended_Advertising_Parameters_Command
|
|
2147
|
+
) -> Optional[bytes]:
|
|
1692
2148
|
'''
|
|
1693
2149
|
See Bluetooth spec Vol 4, Part E - 7.8.53 LE Set Extended Advertising Parameters
|
|
1694
2150
|
Command
|
|
1695
2151
|
'''
|
|
1696
|
-
return bytes([HCI_SUCCESS, 0])
|
|
2152
|
+
return bytes([hci.HCI_SUCCESS, 0])
|
|
1697
2153
|
|
|
1698
|
-
def on_hci_le_set_extended_advertising_data_command(
|
|
2154
|
+
def on_hci_le_set_extended_advertising_data_command(
|
|
2155
|
+
self, _command: hci.HCI_LE_Set_Extended_Advertising_Data_Command
|
|
2156
|
+
) -> Optional[bytes]:
|
|
1699
2157
|
'''
|
|
1700
2158
|
See Bluetooth spec Vol 4, Part E - 7.8.54 LE Set Extended Advertising Data
|
|
1701
2159
|
Command
|
|
1702
2160
|
'''
|
|
1703
|
-
return bytes([HCI_SUCCESS])
|
|
2161
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1704
2162
|
|
|
1705
|
-
def on_hci_le_set_extended_scan_response_data_command(
|
|
2163
|
+
def on_hci_le_set_extended_scan_response_data_command(
|
|
2164
|
+
self, _command: hci.HCI_LE_Set_Extended_Scan_Response_Data_Command
|
|
2165
|
+
) -> Optional[bytes]:
|
|
1706
2166
|
'''
|
|
1707
2167
|
See Bluetooth spec Vol 4, Part E - 7.8.55 LE Set Extended Scan Response Data
|
|
1708
2168
|
Command
|
|
1709
2169
|
'''
|
|
1710
|
-
return bytes([HCI_SUCCESS])
|
|
2170
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1711
2171
|
|
|
1712
|
-
def on_hci_le_set_extended_advertising_enable_command(
|
|
2172
|
+
def on_hci_le_set_extended_advertising_enable_command(
|
|
2173
|
+
self, _command: hci.HCI_LE_Set_Extended_Advertising_Enable_Command
|
|
2174
|
+
) -> Optional[bytes]:
|
|
1713
2175
|
'''
|
|
1714
2176
|
See Bluetooth spec Vol 4, Part E - 7.8.56 LE Set Extended Advertising Enable
|
|
1715
2177
|
Command
|
|
1716
2178
|
'''
|
|
1717
|
-
return bytes([HCI_SUCCESS])
|
|
2179
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1718
2180
|
|
|
1719
|
-
def on_hci_le_read_maximum_advertising_data_length_command(
|
|
2181
|
+
def on_hci_le_read_maximum_advertising_data_length_command(
|
|
2182
|
+
self, _command: hci.HCI_LE_Read_Maximum_Advertising_Data_Length_Command
|
|
2183
|
+
) -> Optional[bytes]:
|
|
1720
2184
|
'''
|
|
1721
2185
|
See Bluetooth spec Vol 4, Part E - 7.8.57 LE Read Maximum Advertising Data
|
|
1722
2186
|
Length Command
|
|
1723
2187
|
'''
|
|
1724
|
-
return struct.pack('<BH', HCI_SUCCESS, 0x0672)
|
|
2188
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, 0x0672)
|
|
1725
2189
|
|
|
1726
|
-
def on_hci_le_read_number_of_supported_advertising_sets_command(
|
|
2190
|
+
def on_hci_le_read_number_of_supported_advertising_sets_command(
|
|
2191
|
+
self, _command: hci.HCI_LE_Read_Number_Of_Supported_Advertising_Sets_Command
|
|
2192
|
+
) -> Optional[bytes]:
|
|
1727
2193
|
'''
|
|
1728
2194
|
See Bluetooth spec Vol 4, Part E - 7.8.58 LE Read Number of Supported
|
|
1729
2195
|
Advertising Set Command
|
|
1730
2196
|
'''
|
|
1731
|
-
return struct.pack('<BB', HCI_SUCCESS, 0xF0)
|
|
2197
|
+
return struct.pack('<BB', hci.HCI_SUCCESS, 0xF0)
|
|
1732
2198
|
|
|
1733
|
-
def on_hci_le_set_periodic_advertising_parameters_command(
|
|
2199
|
+
def on_hci_le_set_periodic_advertising_parameters_command(
|
|
2200
|
+
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command
|
|
2201
|
+
) -> Optional[bytes]:
|
|
1734
2202
|
'''
|
|
1735
2203
|
See Bluetooth spec Vol 4, Part E - 7.8.61 LE Set Periodic Advertising Parameters
|
|
1736
2204
|
Command
|
|
1737
2205
|
'''
|
|
1738
|
-
return bytes([HCI_SUCCESS])
|
|
2206
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1739
2207
|
|
|
1740
|
-
def on_hci_le_set_periodic_advertising_data_command(
|
|
2208
|
+
def on_hci_le_set_periodic_advertising_data_command(
|
|
2209
|
+
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Data_Command
|
|
2210
|
+
) -> Optional[bytes]:
|
|
1741
2211
|
'''
|
|
1742
2212
|
See Bluetooth spec Vol 4, Part E - 7.8.62 LE Set Periodic Advertising Data
|
|
1743
2213
|
Command
|
|
1744
2214
|
'''
|
|
1745
|
-
return bytes([HCI_SUCCESS])
|
|
2215
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1746
2216
|
|
|
1747
|
-
def on_hci_le_set_periodic_advertising_enable_command(
|
|
2217
|
+
def on_hci_le_set_periodic_advertising_enable_command(
|
|
2218
|
+
self, _command: hci.HCI_LE_Set_Periodic_Advertising_Enable_Command
|
|
2219
|
+
) -> Optional[bytes]:
|
|
1748
2220
|
'''
|
|
1749
2221
|
See Bluetooth spec Vol 4, Part E - 7.8.63 LE Set Periodic Advertising Enable
|
|
1750
2222
|
Command
|
|
1751
2223
|
'''
|
|
1752
|
-
return bytes([HCI_SUCCESS])
|
|
2224
|
+
return bytes([hci.HCI_SUCCESS])
|
|
1753
2225
|
|
|
1754
|
-
def on_hci_le_read_transmit_power_command(
|
|
2226
|
+
def on_hci_le_read_transmit_power_command(
|
|
2227
|
+
self, _command: hci.HCI_LE_Read_Transmit_Power_Command
|
|
2228
|
+
) -> Optional[bytes]:
|
|
1755
2229
|
'''
|
|
1756
2230
|
See Bluetooth spec Vol 4, Part E - 7.8.74 LE Read Transmit Power Command
|
|
1757
2231
|
'''
|
|
1758
|
-
return struct.pack('<BBB', HCI_SUCCESS, 0, 0)
|
|
2232
|
+
return struct.pack('<BBB', hci.HCI_SUCCESS, 0, 0)
|
|
1759
2233
|
|
|
1760
|
-
def on_hci_le_set_cig_parameters_command(
|
|
2234
|
+
def on_hci_le_set_cig_parameters_command(
|
|
2235
|
+
self, command: hci.HCI_LE_Set_CIG_Parameters_Command
|
|
2236
|
+
) -> Optional[bytes]:
|
|
1761
2237
|
'''
|
|
1762
2238
|
See Bluetooth spec Vol 4, Part E - 7.8.97 LE Set CIG Parameter Command
|
|
1763
2239
|
'''
|
|
1764
2240
|
|
|
1765
2241
|
# Remove old CIG implicitly.
|
|
1766
|
-
|
|
2242
|
+
cis_links = list(self.central_cis_links.items())
|
|
2243
|
+
for handle, cis_link in cis_links:
|
|
1767
2244
|
if cis_link.cig_id == command.cig_id:
|
|
1768
2245
|
self.central_cis_links.pop(handle)
|
|
1769
2246
|
|
|
@@ -1777,26 +2254,28 @@ class Controller:
|
|
|
1777
2254
|
handle=handle,
|
|
1778
2255
|
)
|
|
1779
2256
|
return struct.pack(
|
|
1780
|
-
'<BBB', HCI_SUCCESS, command.cig_id, len(handles)
|
|
2257
|
+
'<BBB', hci.HCI_SUCCESS, command.cig_id, len(handles)
|
|
1781
2258
|
) + b''.join([struct.pack('<H', handle) for handle in handles])
|
|
1782
2259
|
|
|
1783
|
-
def on_hci_le_create_cis_command(
|
|
2260
|
+
def on_hci_le_create_cis_command(
|
|
2261
|
+
self, command: hci.HCI_LE_Create_CIS_Command
|
|
2262
|
+
) -> Optional[bytes]:
|
|
1784
2263
|
'''
|
|
1785
2264
|
See Bluetooth spec Vol 4, Part E - 7.8.99 LE Create CIS Command
|
|
1786
2265
|
'''
|
|
1787
2266
|
if not self.link:
|
|
1788
|
-
return
|
|
2267
|
+
return None
|
|
1789
2268
|
|
|
1790
2269
|
for cis_handle, acl_handle in zip(
|
|
1791
2270
|
command.cis_connection_handle, command.acl_connection_handle
|
|
1792
2271
|
):
|
|
1793
2272
|
if not (connection := self.find_connection_by_handle(acl_handle)):
|
|
1794
2273
|
logger.error(f'Cannot find connection with handle={acl_handle}')
|
|
1795
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2274
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1796
2275
|
|
|
1797
2276
|
if not (cis_link := self.central_cis_links.get(cis_handle)):
|
|
1798
2277
|
logger.error(f'Cannot find CIS with handle={cis_handle}')
|
|
1799
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2278
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1800
2279
|
|
|
1801
2280
|
cis_link.acl_connection = connection
|
|
1802
2281
|
|
|
@@ -1808,39 +2287,45 @@ class Controller:
|
|
|
1808
2287
|
)
|
|
1809
2288
|
|
|
1810
2289
|
self.send_hci_packet(
|
|
1811
|
-
HCI_Command_Status_Event(
|
|
1812
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2290
|
+
hci.HCI_Command_Status_Event(
|
|
2291
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1813
2292
|
num_hci_command_packets=1,
|
|
1814
2293
|
command_opcode=command.op_code,
|
|
1815
2294
|
)
|
|
1816
2295
|
)
|
|
2296
|
+
return None
|
|
1817
2297
|
|
|
1818
|
-
def on_hci_le_remove_cig_command(
|
|
2298
|
+
def on_hci_le_remove_cig_command(
|
|
2299
|
+
self, command: hci.HCI_LE_Remove_CIG_Command
|
|
2300
|
+
) -> Optional[bytes]:
|
|
1819
2301
|
'''
|
|
1820
2302
|
See Bluetooth spec Vol 4, Part E - 7.8.100 LE Remove CIG Command
|
|
1821
2303
|
'''
|
|
1822
2304
|
|
|
1823
|
-
status = HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
|
2305
|
+
status = hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
|
1824
2306
|
|
|
1825
|
-
|
|
2307
|
+
cis_links = list(self.central_cis_links.items())
|
|
2308
|
+
for cis_handle, cis_link in cis_links:
|
|
1826
2309
|
if cis_link.cig_id == command.cig_id:
|
|
1827
2310
|
self.central_cis_links.pop(cis_handle)
|
|
1828
|
-
status = HCI_SUCCESS
|
|
2311
|
+
status = hci.HCI_SUCCESS
|
|
1829
2312
|
|
|
1830
2313
|
return struct.pack('<BH', status, command.cig_id)
|
|
1831
2314
|
|
|
1832
|
-
def on_hci_le_accept_cis_request_command(
|
|
2315
|
+
def on_hci_le_accept_cis_request_command(
|
|
2316
|
+
self, command: hci.HCI_LE_Accept_CIS_Request_Command
|
|
2317
|
+
) -> Optional[bytes]:
|
|
1833
2318
|
'''
|
|
1834
2319
|
See Bluetooth spec Vol 4, Part E - 7.8.101 LE Accept CIS Request Command
|
|
1835
2320
|
'''
|
|
1836
2321
|
if not self.link:
|
|
1837
|
-
return
|
|
2322
|
+
return None
|
|
1838
2323
|
|
|
1839
2324
|
if not (
|
|
1840
2325
|
pending_cis_link := self.peripheral_cis_links.get(command.connection_handle)
|
|
1841
2326
|
):
|
|
1842
2327
|
logger.error(f'Cannot find CIS with handle={command.connection_handle}')
|
|
1843
|
-
return bytes([HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
2328
|
+
return bytes([hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR])
|
|
1844
2329
|
|
|
1845
2330
|
assert pending_cis_link.acl_connection
|
|
1846
2331
|
self.link.accept_cis(
|
|
@@ -1851,44 +2336,45 @@ class Controller:
|
|
|
1851
2336
|
)
|
|
1852
2337
|
|
|
1853
2338
|
self.send_hci_packet(
|
|
1854
|
-
HCI_Command_Status_Event(
|
|
1855
|
-
status=HCI_COMMAND_STATUS_PENDING,
|
|
2339
|
+
hci.HCI_Command_Status_Event(
|
|
2340
|
+
status=hci.HCI_COMMAND_STATUS_PENDING,
|
|
1856
2341
|
num_hci_command_packets=1,
|
|
1857
2342
|
command_opcode=command.op_code,
|
|
1858
2343
|
)
|
|
1859
2344
|
)
|
|
2345
|
+
return None
|
|
1860
2346
|
|
|
1861
2347
|
def on_hci_le_setup_iso_data_path_command(
|
|
1862
2348
|
self, command: hci.HCI_LE_Setup_ISO_Data_Path_Command
|
|
1863
|
-
) -> bytes:
|
|
2349
|
+
) -> Optional[bytes]:
|
|
1864
2350
|
'''
|
|
1865
2351
|
See Bluetooth spec Vol 4, Part E - 7.8.109 LE Setup ISO Data Path Command
|
|
1866
2352
|
'''
|
|
1867
2353
|
if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
|
|
1868
2354
|
return struct.pack(
|
|
1869
2355
|
'<BH',
|
|
1870
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2356
|
+
hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1871
2357
|
command.connection_handle,
|
|
1872
2358
|
)
|
|
1873
2359
|
if command.data_path_direction in iso_link.data_paths:
|
|
1874
2360
|
return struct.pack(
|
|
1875
2361
|
'<BH',
|
|
1876
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
2362
|
+
hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1877
2363
|
command.connection_handle,
|
|
1878
2364
|
)
|
|
1879
2365
|
iso_link.data_paths.add(command.data_path_direction)
|
|
1880
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
2366
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
1881
2367
|
|
|
1882
2368
|
def on_hci_le_remove_iso_data_path_command(
|
|
1883
2369
|
self, command: hci.HCI_LE_Remove_ISO_Data_Path_Command
|
|
1884
|
-
) -> bytes:
|
|
2370
|
+
) -> Optional[bytes]:
|
|
1885
2371
|
'''
|
|
1886
2372
|
See Bluetooth spec Vol 4, Part E - 7.8.110 LE Remove ISO Data Path Command
|
|
1887
2373
|
'''
|
|
1888
2374
|
if not (iso_link := self.find_iso_link_by_handle(command.connection_handle)):
|
|
1889
2375
|
return struct.pack(
|
|
1890
2376
|
'<BH',
|
|
1891
|
-
HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
2377
|
+
hci.HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR,
|
|
1892
2378
|
command.connection_handle,
|
|
1893
2379
|
)
|
|
1894
2380
|
data_paths: set[int] = set(
|
|
@@ -1899,16 +2385,16 @@ class Controller:
|
|
|
1899
2385
|
if not data_paths.issubset(iso_link.data_paths):
|
|
1900
2386
|
return struct.pack(
|
|
1901
2387
|
'<BH',
|
|
1902
|
-
HCI_COMMAND_DISALLOWED_ERROR,
|
|
2388
|
+
hci.HCI_COMMAND_DISALLOWED_ERROR,
|
|
1903
2389
|
command.connection_handle,
|
|
1904
2390
|
)
|
|
1905
2391
|
iso_link.data_paths.difference_update(data_paths)
|
|
1906
|
-
return struct.pack('<BH', HCI_SUCCESS, command.connection_handle)
|
|
2392
|
+
return struct.pack('<BH', hci.HCI_SUCCESS, command.connection_handle)
|
|
1907
2393
|
|
|
1908
2394
|
def on_hci_le_set_host_feature_command(
|
|
1909
2395
|
self, _command: hci.HCI_LE_Set_Host_Feature_Command
|
|
1910
|
-
):
|
|
2396
|
+
) -> Optional[bytes]:
|
|
1911
2397
|
'''
|
|
1912
2398
|
See Bluetooth spec Vol 4, Part E - 7.8.115 LE Set Host Feature command
|
|
1913
2399
|
'''
|
|
1914
|
-
return bytes([HCI_SUCCESS])
|
|
2400
|
+
return bytes([hci.HCI_SUCCESS])
|