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/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, data):
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, data
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
- self.central_connections: dict[Address, Connection] = (
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 = asyncio.get_running_loop().create_future()
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.hci_packet_type == HCI_COMMAND_PACKET:
267
+ if isinstance(packet, hci.HCI_Command):
276
268
  self.on_hci_command_packet(packet)
277
- elif packet.hci_packet_type == HCI_EVENT_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(bytes(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
- handle = 0
329
- max_handle = 0
330
- for connection in itertools.chain(
331
- self.central_connections.values(),
332
- self.peripheral_connections.values(),
333
- self.classic_connections.values(),
334
- ):
335
- max_handle = max(max_handle, connection.handle)
336
- if connection.handle == handle:
337
- # Already used, continue searching after the current max
338
- handle = max_handle + 1
339
- for cis_handle in itertools.chain(
340
- self.central_cis_links.keys(), self.peripheral_cis_links.keys()
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(self, 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(self, 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, le_create_connection_command, status
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(self, disconnection_command, status):
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(self, peer_address, _rand, _ediv, _ltk):
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(self, sender_address, transport, 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(self, sender_address: Address, data: bytes):
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 on_classic_connection_request(self, peer_address, link_type):
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(self, peer_address, status):
690
- if status == HCI_SUCCESS:
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
- connection = self.classic_connections.get(peer_address)
694
- if connection is None:
695
- connection_handle = self.allocate_connection_handle()
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
- # Role doesn't matter in Classic because they are managed by HCI_Role_Change and HCI_Role_Discovery
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.get(peer_address):
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
- # Remove the connection
745
- del self.classic_connections[peer_address]
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 on_classic_role_change(self, peer_address, new_role):
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
- connection = Connection(
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.classic_connections[peer_address] = connection
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(self, 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.link.classic_connect(self, command.bd_addr)
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(self, 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.link.classic_disconnect(
897
- self,
1056
+ self.send_lmp_packet(
898
1057
  connection.peer_address,
899
- HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
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
- def on_hci_accept_connection_request_command(self, command):
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
- def on_hci_enhanced_setup_synchronous_connection_command(self, command):
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.link.classic_sco_connect(
962
- self, connection.peer_address, HCI_Connection_Complete_Event.LinkType.ESCO
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
- def on_hci_enhanced_accept_synchronous_connection_request_command(self, command):
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.link.classic_accept_sco_connection(
991
- self, connection.peer_address, HCI_Connection_Complete_Event.LinkType.ESCO
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(self, command: hci.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(self, command: hci.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(self, command: hci.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
- self.send_hci_packet(
1063
- HCI_Command_Status_Event(
1064
- status=HCI_SUCCESS,
1065
- num_hci_command_packets=1,
1066
- command_opcode=command.op_code,
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
- self.link.classic_switch_role(self, command.bd_addr, command.role)
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(self, 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 = command.event_mask
1076
- return bytes([HCI_SUCCESS])
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(self, 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(self, _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(self, _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(self, _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(self, _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(self, 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(self, _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(self, _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(self, _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(self, _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(self, 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 = command.event_mask_page_2
1182
- return bytes([HCI_SUCCESS])
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(self, _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(self, _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(self, 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(self, _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(self, _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(self, _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(self, 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(self, _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(self, _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(self, 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 = command.le_event_mask
1331
- return bytes([HCI_SUCCESS])
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(self, _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(self, _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(self, _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(self, 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(self, 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(self, _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(self, 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(self, 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(self, 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(self, 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(self, 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(self, 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(self, _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(self, _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(self, _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(self, _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(self, _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 on_hci_le_read_remote_features_command(self, command):
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(self, _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(self, 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(self, _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(self, _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(self, 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(self, _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(self, _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(self, _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(self, _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(self, 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(self, 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(self, _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(self, 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(self, 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
- 'all_phys': command.all_phys,
1679
- 'tx_phys': command.tx_phys,
1680
- 'rx_phys': command.rx_phys,
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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, _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(self, 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
- for handle, cis_link in self.central_cis_links.items():
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(self, 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(self, 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
- for cis_handle, cis_link in self.central_cis_links.items():
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(self, 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])