bumble 0.0.202__py3-none-any.whl → 0.0.204__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bumble/_version.py +2 -2
- bumble/apps/auracast.py +22 -13
- bumble/apps/bench.py +2 -1
- bumble/apps/hci_bridge.py +1 -1
- bumble/apps/lea_unicast/app.py +24 -6
- bumble/apps/pair.py +13 -8
- bumble/apps/show.py +6 -6
- bumble/att.py +11 -15
- bumble/controller.py +58 -2
- bumble/device.py +454 -494
- bumble/drivers/common.py +2 -0
- bumble/drivers/intel.py +593 -24
- bumble/gatt.py +33 -7
- bumble/gatt_client.py +3 -3
- bumble/gatt_server.py +14 -3
- bumble/hci.py +139 -56
- bumble/hfp.py +20 -17
- bumble/host.py +5 -2
- bumble/l2cap.py +2 -8
- bumble/pairing.py +3 -0
- bumble/pandora/host.py +1 -1
- bumble/profiles/aics.py +37 -53
- bumble/profiles/bap.py +114 -42
- bumble/profiles/bass.py +4 -7
- bumble/profiles/device_information_service.py +4 -1
- bumble/profiles/heart_rate_service.py +5 -6
- bumble/profiles/vocs.py +330 -0
- bumble/sdp.py +1 -7
- bumble/smp.py +9 -7
- bumble/tools/intel_fw_download.py +130 -0
- bumble/tools/intel_util.py +154 -0
- bumble/transport/usb.py +8 -2
- bumble/utils.py +20 -5
- bumble/vendor/android/hci.py +29 -4
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/METADATA +15 -15
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/RECORD +40 -37
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/WHEEL +1 -1
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/entry_points.txt +2 -0
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/LICENSE +0 -0
- {bumble-0.0.202.dist-info → bumble-0.0.204.dist-info}/top_level.txt +0 -0
bumble/device.py
CHANGED
|
@@ -51,129 +51,9 @@ from typing_extensions import Self
|
|
|
51
51
|
|
|
52
52
|
from pyee import EventEmitter
|
|
53
53
|
|
|
54
|
-
from bumble import hci
|
|
55
54
|
from .colors import color
|
|
56
55
|
from .att import ATT_CID, ATT_DEFAULT_MTU, ATT_PDU
|
|
57
56
|
from .gatt import Characteristic, Descriptor, Service
|
|
58
|
-
from .hci import (
|
|
59
|
-
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
|
|
60
|
-
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
|
|
61
|
-
HCI_CENTRAL_ROLE,
|
|
62
|
-
HCI_PERIPHERAL_ROLE,
|
|
63
|
-
HCI_COMMAND_STATUS_PENDING,
|
|
64
|
-
HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
|
|
65
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY,
|
|
66
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY,
|
|
67
|
-
HCI_EXTENDED_INQUIRY_MODE,
|
|
68
|
-
HCI_GENERAL_INQUIRY_LAP,
|
|
69
|
-
HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR,
|
|
70
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY,
|
|
71
|
-
HCI_LE_1M_PHY,
|
|
72
|
-
HCI_LE_1M_PHY_BIT,
|
|
73
|
-
HCI_LE_2M_PHY,
|
|
74
|
-
HCI_LE_CODED_PHY,
|
|
75
|
-
HCI_LE_CODED_PHY_BIT,
|
|
76
|
-
HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND,
|
|
77
|
-
HCI_LE_RAND_COMMAND,
|
|
78
|
-
HCI_LE_READ_PHY_COMMAND,
|
|
79
|
-
HCI_LE_SET_PHY_COMMAND,
|
|
80
|
-
HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
81
|
-
HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
82
|
-
HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
83
|
-
HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
84
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY,
|
|
85
|
-
HCI_OPERATION_CANCELLED_BY_HOST_ERROR,
|
|
86
|
-
HCI_R2_PAGE_SCAN_REPETITION_MODE,
|
|
87
|
-
HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
88
|
-
HCI_SUCCESS,
|
|
89
|
-
HCI_WRITE_LE_HOST_SUPPORT_COMMAND,
|
|
90
|
-
HCI_Accept_Connection_Request_Command,
|
|
91
|
-
HCI_Authentication_Requested_Command,
|
|
92
|
-
HCI_Command_Status_Event,
|
|
93
|
-
HCI_Constant,
|
|
94
|
-
HCI_Create_Connection_Cancel_Command,
|
|
95
|
-
HCI_Create_Connection_Command,
|
|
96
|
-
HCI_Connection_Complete_Event,
|
|
97
|
-
HCI_Disconnect_Command,
|
|
98
|
-
HCI_Encryption_Change_Event,
|
|
99
|
-
HCI_Error,
|
|
100
|
-
HCI_IO_Capability_Request_Reply_Command,
|
|
101
|
-
HCI_Inquiry_Cancel_Command,
|
|
102
|
-
HCI_Inquiry_Command,
|
|
103
|
-
HCI_IsoDataPacket,
|
|
104
|
-
HCI_LE_Accept_CIS_Request_Command,
|
|
105
|
-
HCI_LE_Add_Device_To_Resolving_List_Command,
|
|
106
|
-
HCI_LE_Advertising_Report_Event,
|
|
107
|
-
HCI_LE_BIGInfo_Advertising_Report_Event,
|
|
108
|
-
HCI_LE_Clear_Resolving_List_Command,
|
|
109
|
-
HCI_LE_Connection_Update_Command,
|
|
110
|
-
HCI_LE_Create_Connection_Cancel_Command,
|
|
111
|
-
HCI_LE_Create_Connection_Command,
|
|
112
|
-
HCI_LE_Create_CIS_Command,
|
|
113
|
-
HCI_LE_Periodic_Advertising_Create_Sync_Command,
|
|
114
|
-
HCI_LE_Periodic_Advertising_Create_Sync_Cancel_Command,
|
|
115
|
-
HCI_LE_Periodic_Advertising_Report_Event,
|
|
116
|
-
HCI_LE_Periodic_Advertising_Sync_Transfer_Command,
|
|
117
|
-
HCI_LE_Periodic_Advertising_Terminate_Sync_Command,
|
|
118
|
-
HCI_LE_Enable_Encryption_Command,
|
|
119
|
-
HCI_LE_Extended_Advertising_Report_Event,
|
|
120
|
-
HCI_LE_Extended_Create_Connection_Command,
|
|
121
|
-
HCI_LE_Rand_Command,
|
|
122
|
-
HCI_LE_Read_PHY_Command,
|
|
123
|
-
HCI_LE_Read_Remote_Features_Command,
|
|
124
|
-
HCI_LE_Reject_CIS_Request_Command,
|
|
125
|
-
HCI_LE_Remove_Advertising_Set_Command,
|
|
126
|
-
HCI_LE_Set_Address_Resolution_Enable_Command,
|
|
127
|
-
HCI_LE_Set_Advertising_Data_Command,
|
|
128
|
-
HCI_LE_Set_Advertising_Enable_Command,
|
|
129
|
-
HCI_LE_Set_Advertising_Parameters_Command,
|
|
130
|
-
HCI_LE_Set_Advertising_Set_Random_Address_Command,
|
|
131
|
-
HCI_LE_Set_CIG_Parameters_Command,
|
|
132
|
-
HCI_LE_Set_Data_Length_Command,
|
|
133
|
-
HCI_LE_Set_Default_PHY_Command,
|
|
134
|
-
HCI_LE_Set_Extended_Scan_Enable_Command,
|
|
135
|
-
HCI_LE_Set_Extended_Scan_Parameters_Command,
|
|
136
|
-
HCI_LE_Set_Extended_Scan_Response_Data_Command,
|
|
137
|
-
HCI_LE_Set_Extended_Advertising_Data_Command,
|
|
138
|
-
HCI_LE_Set_Extended_Advertising_Enable_Command,
|
|
139
|
-
HCI_LE_Set_Extended_Advertising_Parameters_Command,
|
|
140
|
-
HCI_LE_Set_Host_Feature_Command,
|
|
141
|
-
HCI_LE_Set_Periodic_Advertising_Enable_Command,
|
|
142
|
-
HCI_LE_Set_PHY_Command,
|
|
143
|
-
HCI_LE_Set_Random_Address_Command,
|
|
144
|
-
HCI_LE_Set_Scan_Enable_Command,
|
|
145
|
-
HCI_LE_Set_Scan_Parameters_Command,
|
|
146
|
-
HCI_LE_Set_Scan_Response_Data_Command,
|
|
147
|
-
HCI_PIN_Code_Request_Reply_Command,
|
|
148
|
-
HCI_PIN_Code_Request_Negative_Reply_Command,
|
|
149
|
-
HCI_Read_BD_ADDR_Command,
|
|
150
|
-
HCI_Read_RSSI_Command,
|
|
151
|
-
HCI_Reject_Connection_Request_Command,
|
|
152
|
-
HCI_Remote_Name_Request_Command,
|
|
153
|
-
HCI_Switch_Role_Command,
|
|
154
|
-
HCI_Set_Connection_Encryption_Command,
|
|
155
|
-
HCI_StatusError,
|
|
156
|
-
HCI_SynchronousDataPacket,
|
|
157
|
-
HCI_User_Confirmation_Request_Negative_Reply_Command,
|
|
158
|
-
HCI_User_Confirmation_Request_Reply_Command,
|
|
159
|
-
HCI_User_Passkey_Request_Negative_Reply_Command,
|
|
160
|
-
HCI_User_Passkey_Request_Reply_Command,
|
|
161
|
-
HCI_Write_Class_Of_Device_Command,
|
|
162
|
-
HCI_Write_Extended_Inquiry_Response_Command,
|
|
163
|
-
HCI_Write_Inquiry_Mode_Command,
|
|
164
|
-
HCI_Write_LE_Host_Support_Command,
|
|
165
|
-
HCI_Write_Local_Name_Command,
|
|
166
|
-
HCI_Write_Scan_Enable_Command,
|
|
167
|
-
HCI_Write_Secure_Connections_Host_Support_Command,
|
|
168
|
-
HCI_Write_Simple_Pairing_Mode_Command,
|
|
169
|
-
Address,
|
|
170
|
-
OwnAddressType,
|
|
171
|
-
LeFeature,
|
|
172
|
-
LeFeatureMask,
|
|
173
|
-
LmpFeatureMask,
|
|
174
|
-
Phy,
|
|
175
|
-
phy_list_to_bits,
|
|
176
|
-
)
|
|
177
57
|
from .host import Host
|
|
178
58
|
from .profiles.gap import GenericAccessService
|
|
179
59
|
from .core import (
|
|
@@ -207,6 +87,7 @@ from .keys import (
|
|
|
207
87
|
KeyStore,
|
|
208
88
|
PairingKeys,
|
|
209
89
|
)
|
|
90
|
+
from bumble import hci
|
|
210
91
|
from bumble import pairing
|
|
211
92
|
from bumble import gatt_client
|
|
212
93
|
from bumble import gatt_server
|
|
@@ -262,7 +143,7 @@ DEVICE_DEFAULT_L2CAP_COC_MTU = l2cap.L2CAP_LE_CREDIT_BASED_CONN
|
|
|
262
143
|
DEVICE_DEFAULT_L2CAP_COC_MPS = l2cap.L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_MPS
|
|
263
144
|
DEVICE_DEFAULT_L2CAP_COC_MAX_CREDITS = l2cap.L2CAP_LE_CREDIT_BASED_CONNECTION_DEFAULT_INITIAL_CREDITS
|
|
264
145
|
DEVICE_DEFAULT_ADVERTISING_TX_POWER = (
|
|
265
|
-
HCI_LE_Set_Extended_Advertising_Parameters_Command.TX_POWER_NO_PREFERENCE
|
|
146
|
+
hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.TX_POWER_NO_PREFERENCE
|
|
266
147
|
)
|
|
267
148
|
DEVICE_DEFAULT_PERIODIC_ADVERTISING_SYNC_SKIP = 0
|
|
268
149
|
DEVICE_DEFAULT_PERIODIC_ADVERTISING_SYNC_TIMEOUT = 5.0
|
|
@@ -286,8 +167,8 @@ class ObjectLookupError(BaseBumbleError):
|
|
|
286
167
|
@dataclass
|
|
287
168
|
class Advertisement:
|
|
288
169
|
# Attributes
|
|
289
|
-
address: Address
|
|
290
|
-
rssi: int = HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
170
|
+
address: hci.Address
|
|
171
|
+
rssi: int = hci.HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
291
172
|
is_legacy: bool = False
|
|
292
173
|
is_anonymous: bool = False
|
|
293
174
|
is_connectable: bool = False
|
|
@@ -299,17 +180,17 @@ class Advertisement:
|
|
|
299
180
|
primary_phy: int = 0
|
|
300
181
|
secondary_phy: int = 0
|
|
301
182
|
tx_power: int = (
|
|
302
|
-
HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
183
|
+
hci.HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
303
184
|
)
|
|
304
185
|
sid: int = 0
|
|
305
186
|
data_bytes: bytes = b''
|
|
306
187
|
|
|
307
188
|
# Constants
|
|
308
189
|
TX_POWER_NOT_AVAILABLE: ClassVar[int] = (
|
|
309
|
-
HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
190
|
+
hci.HCI_LE_Extended_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
310
191
|
)
|
|
311
192
|
RSSI_NOT_AVAILABLE: ClassVar[int] = (
|
|
312
|
-
HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
193
|
+
hci.HCI_LE_Extended_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
313
194
|
)
|
|
314
195
|
|
|
315
196
|
def __post_init__(self) -> None:
|
|
@@ -317,10 +198,10 @@ class Advertisement:
|
|
|
317
198
|
|
|
318
199
|
@classmethod
|
|
319
200
|
def from_advertising_report(cls, report) -> Optional[Advertisement]:
|
|
320
|
-
if isinstance(report, HCI_LE_Advertising_Report_Event.Report):
|
|
201
|
+
if isinstance(report, hci.HCI_LE_Advertising_Report_Event.Report):
|
|
321
202
|
return LegacyAdvertisement.from_advertising_report(report)
|
|
322
203
|
|
|
323
|
-
if isinstance(report, HCI_LE_Extended_Advertising_Report_Event.Report):
|
|
204
|
+
if isinstance(report, hci.HCI_LE_Extended_Advertising_Report_Event.Report):
|
|
324
205
|
return ExtendedAdvertisement.from_advertising_report(report)
|
|
325
206
|
|
|
326
207
|
return None
|
|
@@ -336,18 +217,18 @@ class LegacyAdvertisement(Advertisement):
|
|
|
336
217
|
is_legacy=True,
|
|
337
218
|
is_connectable=report.event_type
|
|
338
219
|
in (
|
|
339
|
-
HCI_LE_Advertising_Report_Event.ADV_IND,
|
|
340
|
-
HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
|
|
220
|
+
hci.HCI_LE_Advertising_Report_Event.ADV_IND,
|
|
221
|
+
hci.HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
|
|
341
222
|
),
|
|
342
223
|
is_directed=report.event_type
|
|
343
|
-
== HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
|
|
224
|
+
== hci.HCI_LE_Advertising_Report_Event.ADV_DIRECT_IND,
|
|
344
225
|
is_scannable=report.event_type
|
|
345
226
|
in (
|
|
346
|
-
HCI_LE_Advertising_Report_Event.ADV_IND,
|
|
347
|
-
HCI_LE_Advertising_Report_Event.ADV_SCAN_IND,
|
|
227
|
+
hci.HCI_LE_Advertising_Report_Event.ADV_IND,
|
|
228
|
+
hci.HCI_LE_Advertising_Report_Event.ADV_SCAN_IND,
|
|
348
229
|
),
|
|
349
230
|
is_scan_response=report.event_type
|
|
350
|
-
== HCI_LE_Advertising_Report_Event.SCAN_RSP,
|
|
231
|
+
== hci.HCI_LE_Advertising_Report_Event.SCAN_RSP,
|
|
351
232
|
data_bytes=report.data,
|
|
352
233
|
)
|
|
353
234
|
|
|
@@ -361,14 +242,14 @@ class ExtendedAdvertisement(Advertisement):
|
|
|
361
242
|
return cls(
|
|
362
243
|
address = report.address,
|
|
363
244
|
rssi = report.rssi,
|
|
364
|
-
is_legacy = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.LEGACY_ADVERTISING_PDU_USED) != 0,
|
|
365
|
-
is_anonymous = report.address.address_type == HCI_LE_Extended_Advertising_Report_Event.ANONYMOUS_ADDRESS_TYPE,
|
|
366
|
-
is_connectable = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.CONNECTABLE_ADVERTISING) != 0,
|
|
367
|
-
is_directed = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.DIRECTED_ADVERTISING) != 0,
|
|
368
|
-
is_scannable = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.SCANNABLE_ADVERTISING) != 0,
|
|
369
|
-
is_scan_response = report.event_type & (1 << HCI_LE_Extended_Advertising_Report_Event.SCAN_RESPONSE) != 0,
|
|
370
|
-
is_complete = (report.event_type >> 5 & 3) == HCI_LE_Extended_Advertising_Report_Event.DATA_COMPLETE,
|
|
371
|
-
is_truncated = (report.event_type >> 5 & 3) == HCI_LE_Extended_Advertising_Report_Event.DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME,
|
|
245
|
+
is_legacy = report.event_type & (1 << hci.HCI_LE_Extended_Advertising_Report_Event.LEGACY_ADVERTISING_PDU_USED) != 0,
|
|
246
|
+
is_anonymous = report.address.address_type == hci.HCI_LE_Extended_Advertising_Report_Event.ANONYMOUS_ADDRESS_TYPE,
|
|
247
|
+
is_connectable = report.event_type & (1 << hci.HCI_LE_Extended_Advertising_Report_Event.CONNECTABLE_ADVERTISING) != 0,
|
|
248
|
+
is_directed = report.event_type & (1 << hci.HCI_LE_Extended_Advertising_Report_Event.DIRECTED_ADVERTISING) != 0,
|
|
249
|
+
is_scannable = report.event_type & (1 << hci.HCI_LE_Extended_Advertising_Report_Event.SCANNABLE_ADVERTISING) != 0,
|
|
250
|
+
is_scan_response = report.event_type & (1 << hci.HCI_LE_Extended_Advertising_Report_Event.SCAN_RESPONSE) != 0,
|
|
251
|
+
is_complete = (report.event_type >> 5 & 3) == hci.HCI_LE_Extended_Advertising_Report_Event.DATA_COMPLETE,
|
|
252
|
+
is_truncated = (report.event_type >> 5 & 3) == hci.HCI_LE_Extended_Advertising_Report_Event.DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME,
|
|
372
253
|
primary_phy = report.primary_phy,
|
|
373
254
|
secondary_phy = report.secondary_phy,
|
|
374
255
|
tx_power = report.tx_power,
|
|
@@ -473,15 +354,15 @@ class AdvertisingType(IntEnum):
|
|
|
473
354
|
class LegacyAdvertiser:
|
|
474
355
|
device: Device
|
|
475
356
|
advertising_type: AdvertisingType
|
|
476
|
-
own_address_type: OwnAddressType
|
|
477
|
-
peer_address: Address
|
|
357
|
+
own_address_type: hci.OwnAddressType
|
|
358
|
+
peer_address: hci.Address
|
|
478
359
|
auto_restart: bool
|
|
479
360
|
|
|
480
361
|
async def start(self) -> None:
|
|
481
362
|
# Set/update the advertising data if the advertising type allows it
|
|
482
363
|
if self.advertising_type.has_data:
|
|
483
364
|
await self.device.send_command(
|
|
484
|
-
HCI_LE_Set_Advertising_Data_Command(
|
|
365
|
+
hci.HCI_LE_Set_Advertising_Data_Command(
|
|
485
366
|
advertising_data=self.device.advertising_data
|
|
486
367
|
),
|
|
487
368
|
check_result=True,
|
|
@@ -490,7 +371,7 @@ class LegacyAdvertiser:
|
|
|
490
371
|
# Set/update the scan response data if the advertising is scannable
|
|
491
372
|
if self.advertising_type.is_scannable:
|
|
492
373
|
await self.device.send_command(
|
|
493
|
-
HCI_LE_Set_Scan_Response_Data_Command(
|
|
374
|
+
hci.HCI_LE_Set_Scan_Response_Data_Command(
|
|
494
375
|
scan_response_data=self.device.scan_response_data
|
|
495
376
|
),
|
|
496
377
|
check_result=True,
|
|
@@ -498,7 +379,7 @@ class LegacyAdvertiser:
|
|
|
498
379
|
|
|
499
380
|
# Set the advertising parameters
|
|
500
381
|
await self.device.send_command(
|
|
501
|
-
HCI_LE_Set_Advertising_Parameters_Command(
|
|
382
|
+
hci.HCI_LE_Set_Advertising_Parameters_Command(
|
|
502
383
|
advertising_interval_min=self.device.advertising_interval_min,
|
|
503
384
|
advertising_interval_max=self.device.advertising_interval_max,
|
|
504
385
|
advertising_type=int(self.advertising_type),
|
|
@@ -513,14 +394,14 @@ class LegacyAdvertiser:
|
|
|
513
394
|
|
|
514
395
|
# Enable advertising
|
|
515
396
|
await self.device.send_command(
|
|
516
|
-
HCI_LE_Set_Advertising_Enable_Command(advertising_enable=1),
|
|
397
|
+
hci.HCI_LE_Set_Advertising_Enable_Command(advertising_enable=1),
|
|
517
398
|
check_result=True,
|
|
518
399
|
)
|
|
519
400
|
|
|
520
401
|
async def stop(self) -> None:
|
|
521
402
|
# Disable advertising
|
|
522
403
|
await self.device.send_command(
|
|
523
|
-
HCI_LE_Set_Advertising_Enable_Command(advertising_enable=0),
|
|
404
|
+
hci.HCI_LE_Set_Advertising_Enable_Command(advertising_enable=0),
|
|
524
405
|
check_result=True,
|
|
525
406
|
)
|
|
526
407
|
|
|
@@ -537,8 +418,8 @@ class AdvertisingEventProperties:
|
|
|
537
418
|
include_tx_power: bool = False
|
|
538
419
|
|
|
539
420
|
def __int__(self) -> int:
|
|
540
|
-
properties = (
|
|
541
|
-
|
|
421
|
+
properties = hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.AdvertisingProperties(
|
|
422
|
+
0
|
|
542
423
|
)
|
|
543
424
|
if self.is_connectable:
|
|
544
425
|
properties |= properties.CONNECTABLE_ADVERTISING
|
|
@@ -576,21 +457,21 @@ class AdvertisingEventProperties:
|
|
|
576
457
|
# -----------------------------------------------------------------------------
|
|
577
458
|
@dataclass
|
|
578
459
|
class PeriodicAdvertisement:
|
|
579
|
-
address: Address
|
|
460
|
+
address: hci.Address
|
|
580
461
|
sid: int
|
|
581
462
|
tx_power: int = (
|
|
582
|
-
HCI_LE_Periodic_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
463
|
+
hci.HCI_LE_Periodic_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
583
464
|
)
|
|
584
|
-
rssi: int = HCI_LE_Periodic_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
465
|
+
rssi: int = hci.HCI_LE_Periodic_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
585
466
|
is_truncated: bool = False
|
|
586
467
|
data_bytes: bytes = b''
|
|
587
468
|
|
|
588
469
|
# Constants
|
|
589
470
|
TX_POWER_NOT_AVAILABLE: ClassVar[int] = (
|
|
590
|
-
HCI_LE_Periodic_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
471
|
+
hci.HCI_LE_Periodic_Advertising_Report_Event.TX_POWER_INFORMATION_NOT_AVAILABLE
|
|
591
472
|
)
|
|
592
473
|
RSSI_NOT_AVAILABLE: ClassVar[int] = (
|
|
593
|
-
HCI_LE_Periodic_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
474
|
+
hci.HCI_LE_Periodic_Advertising_Report_Event.RSSI_NOT_AVAILABLE
|
|
594
475
|
)
|
|
595
476
|
|
|
596
477
|
def __post_init__(self) -> None:
|
|
@@ -602,7 +483,7 @@ class PeriodicAdvertisement:
|
|
|
602
483
|
# -----------------------------------------------------------------------------
|
|
603
484
|
@dataclass
|
|
604
485
|
class BIGInfoAdvertisement:
|
|
605
|
-
address: Address
|
|
486
|
+
address: hci.Address
|
|
606
487
|
sid: int
|
|
607
488
|
num_bis: int
|
|
608
489
|
nse: int
|
|
@@ -613,12 +494,12 @@ class BIGInfoAdvertisement:
|
|
|
613
494
|
max_pdu: int
|
|
614
495
|
sdu_interval: int
|
|
615
496
|
max_sdu: int
|
|
616
|
-
phy: Phy
|
|
497
|
+
phy: hci.Phy
|
|
617
498
|
framed: bool
|
|
618
499
|
encrypted: bool
|
|
619
500
|
|
|
620
501
|
@classmethod
|
|
621
|
-
def from_report(cls, address: Address, sid: int, report) -> Self:
|
|
502
|
+
def from_report(cls, address: hci.Address, sid: int, report) -> Self:
|
|
622
503
|
return cls(
|
|
623
504
|
address,
|
|
624
505
|
sid,
|
|
@@ -631,7 +512,7 @@ class BIGInfoAdvertisement:
|
|
|
631
512
|
report.max_pdu,
|
|
632
513
|
report.sdu_interval,
|
|
633
514
|
report.max_sdu,
|
|
634
|
-
Phy(report.phy),
|
|
515
|
+
hci.Phy(report.phy),
|
|
635
516
|
report.framing != 0,
|
|
636
517
|
report.encryption != 0,
|
|
637
518
|
)
|
|
@@ -639,7 +520,9 @@ class BIGInfoAdvertisement:
|
|
|
639
520
|
|
|
640
521
|
# -----------------------------------------------------------------------------
|
|
641
522
|
# TODO: replace with typing.TypeAlias when the code base is all Python >= 3.10
|
|
642
|
-
AdvertisingChannelMap =
|
|
523
|
+
AdvertisingChannelMap = (
|
|
524
|
+
hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap
|
|
525
|
+
)
|
|
643
526
|
|
|
644
527
|
|
|
645
528
|
# -----------------------------------------------------------------------------
|
|
@@ -652,19 +535,19 @@ class AdvertisingParameters:
|
|
|
652
535
|
primary_advertising_interval_min: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
653
536
|
primary_advertising_interval_max: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
654
537
|
primary_advertising_channel_map: (
|
|
655
|
-
HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap
|
|
538
|
+
hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.ChannelMap
|
|
656
539
|
) = (
|
|
657
540
|
AdvertisingChannelMap.CHANNEL_37
|
|
658
541
|
| AdvertisingChannelMap.CHANNEL_38
|
|
659
542
|
| AdvertisingChannelMap.CHANNEL_39
|
|
660
543
|
)
|
|
661
|
-
own_address_type: OwnAddressType = OwnAddressType.RANDOM
|
|
662
|
-
peer_address: Address = Address.ANY
|
|
544
|
+
own_address_type: hci.OwnAddressType = hci.OwnAddressType.RANDOM
|
|
545
|
+
peer_address: hci.Address = hci.Address.ANY
|
|
663
546
|
advertising_filter_policy: int = 0
|
|
664
547
|
advertising_tx_power: int = DEVICE_DEFAULT_ADVERTISING_TX_POWER
|
|
665
|
-
primary_advertising_phy: Phy = Phy.LE_1M
|
|
548
|
+
primary_advertising_phy: hci.Phy = hci.Phy.LE_1M
|
|
666
549
|
secondary_advertising_max_skip: int = 0
|
|
667
|
-
secondary_advertising_phy: Phy = Phy.LE_1M
|
|
550
|
+
secondary_advertising_phy: hci.Phy = hci.Phy.LE_1M
|
|
668
551
|
advertising_sid: int = 0
|
|
669
552
|
enable_scan_request_notifications: bool = False
|
|
670
553
|
primary_advertising_phy_options: int = 0
|
|
@@ -674,8 +557,15 @@ class AdvertisingParameters:
|
|
|
674
557
|
# -----------------------------------------------------------------------------
|
|
675
558
|
@dataclass
|
|
676
559
|
class PeriodicAdvertisingParameters:
|
|
677
|
-
|
|
678
|
-
|
|
560
|
+
periodic_advertising_interval_min: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
561
|
+
periodic_advertising_interval_max: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
562
|
+
periodic_advertising_properties: (
|
|
563
|
+
hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command.Properties
|
|
564
|
+
) = field(
|
|
565
|
+
default_factory=lambda: hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command.Properties(
|
|
566
|
+
0
|
|
567
|
+
)
|
|
568
|
+
)
|
|
679
569
|
|
|
680
570
|
|
|
681
571
|
# -----------------------------------------------------------------------------
|
|
@@ -684,7 +574,7 @@ class AdvertisingSet(EventEmitter):
|
|
|
684
574
|
device: Device
|
|
685
575
|
advertising_handle: int
|
|
686
576
|
auto_restart: bool
|
|
687
|
-
random_address: Optional[Address]
|
|
577
|
+
random_address: Optional[hci.Address]
|
|
688
578
|
advertising_parameters: AdvertisingParameters
|
|
689
579
|
advertising_data: bytes
|
|
690
580
|
scan_response_data: bytes
|
|
@@ -692,6 +582,7 @@ class AdvertisingSet(EventEmitter):
|
|
|
692
582
|
periodic_advertising_data: bytes
|
|
693
583
|
selected_tx_power: int = 0
|
|
694
584
|
enabled: bool = False
|
|
585
|
+
periodic_enabled: bool = False
|
|
695
586
|
|
|
696
587
|
def __post_init__(self) -> None:
|
|
697
588
|
super().__init__()
|
|
@@ -711,7 +602,7 @@ class AdvertisingSet(EventEmitter):
|
|
|
711
602
|
)
|
|
712
603
|
|
|
713
604
|
response = await self.device.send_command(
|
|
714
|
-
HCI_LE_Set_Extended_Advertising_Parameters_Command(
|
|
605
|
+
hci.HCI_LE_Set_Extended_Advertising_Parameters_Command(
|
|
715
606
|
advertising_handle=self.advertising_handle,
|
|
716
607
|
advertising_event_properties=int(
|
|
717
608
|
advertising_parameters.advertising_event_properties
|
|
@@ -720,7 +611,7 @@ class AdvertisingSet(EventEmitter):
|
|
|
720
611
|
int(advertising_parameters.primary_advertising_interval_min / 0.625)
|
|
721
612
|
),
|
|
722
613
|
primary_advertising_interval_max=(
|
|
723
|
-
int(advertising_parameters.
|
|
614
|
+
int(advertising_parameters.primary_advertising_interval_max / 0.625)
|
|
724
615
|
),
|
|
725
616
|
primary_advertising_channel_map=int(
|
|
726
617
|
advertising_parameters.primary_advertising_channel_map
|
|
@@ -752,10 +643,10 @@ class AdvertisingSet(EventEmitter):
|
|
|
752
643
|
async def set_advertising_data(self, advertising_data: bytes) -> None:
|
|
753
644
|
# pylint: disable=line-too-long
|
|
754
645
|
await self.device.send_command(
|
|
755
|
-
HCI_LE_Set_Extended_Advertising_Data_Command(
|
|
646
|
+
hci.HCI_LE_Set_Extended_Advertising_Data_Command(
|
|
756
647
|
advertising_handle=self.advertising_handle,
|
|
757
|
-
operation=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
758
|
-
fragment_preference=HCI_LE_Set_Extended_Advertising_Parameters_Command.SHOULD_NOT_FRAGMENT,
|
|
648
|
+
operation=hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
649
|
+
fragment_preference=hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.SHOULD_NOT_FRAGMENT,
|
|
759
650
|
advertising_data=advertising_data,
|
|
760
651
|
),
|
|
761
652
|
check_result=True,
|
|
@@ -775,10 +666,10 @@ class AdvertisingSet(EventEmitter):
|
|
|
775
666
|
return
|
|
776
667
|
|
|
777
668
|
await self.device.send_command(
|
|
778
|
-
HCI_LE_Set_Extended_Scan_Response_Data_Command(
|
|
669
|
+
hci.HCI_LE_Set_Extended_Scan_Response_Data_Command(
|
|
779
670
|
advertising_handle=self.advertising_handle,
|
|
780
|
-
operation=HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
781
|
-
fragment_preference=HCI_LE_Set_Extended_Advertising_Parameters_Command.SHOULD_NOT_FRAGMENT,
|
|
671
|
+
operation=hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
672
|
+
fragment_preference=hci.HCI_LE_Set_Extended_Advertising_Parameters_Command.SHOULD_NOT_FRAGMENT,
|
|
782
673
|
scan_response_data=scan_response_data,
|
|
783
674
|
),
|
|
784
675
|
check_result=True,
|
|
@@ -788,16 +679,31 @@ class AdvertisingSet(EventEmitter):
|
|
|
788
679
|
async def set_periodic_advertising_parameters(
|
|
789
680
|
self, advertising_parameters: PeriodicAdvertisingParameters
|
|
790
681
|
) -> None:
|
|
791
|
-
|
|
682
|
+
await self.device.send_command(
|
|
683
|
+
hci.HCI_LE_Set_Periodic_Advertising_Parameters_Command(
|
|
684
|
+
advertising_handle=self.advertising_handle,
|
|
685
|
+
periodic_advertising_interval_min=advertising_parameters.periodic_advertising_interval_min,
|
|
686
|
+
periodic_advertising_interval_max=advertising_parameters.periodic_advertising_interval_max,
|
|
687
|
+
periodic_advertising_properties=advertising_parameters.periodic_advertising_properties,
|
|
688
|
+
),
|
|
689
|
+
check_result=True,
|
|
690
|
+
)
|
|
792
691
|
self.periodic_advertising_parameters = advertising_parameters
|
|
793
692
|
|
|
794
693
|
async def set_periodic_advertising_data(self, advertising_data: bytes) -> None:
|
|
795
|
-
|
|
694
|
+
await self.device.send_command(
|
|
695
|
+
hci.HCI_LE_Set_Periodic_Advertising_Data_Command(
|
|
696
|
+
advertising_handle=self.advertising_handle,
|
|
697
|
+
operation=hci.HCI_LE_Set_Extended_Advertising_Data_Command.Operation.COMPLETE_DATA,
|
|
698
|
+
advertising_data=advertising_data,
|
|
699
|
+
),
|
|
700
|
+
check_result=True,
|
|
701
|
+
)
|
|
796
702
|
self.periodic_advertising_data = advertising_data
|
|
797
703
|
|
|
798
|
-
async def set_random_address(self, random_address: Address) -> None:
|
|
704
|
+
async def set_random_address(self, random_address: hci.Address) -> None:
|
|
799
705
|
await self.device.send_command(
|
|
800
|
-
HCI_LE_Set_Advertising_Set_Random_Address_Command(
|
|
706
|
+
hci.HCI_LE_Set_Advertising_Set_Random_Address_Command(
|
|
801
707
|
advertising_handle=self.advertising_handle,
|
|
802
708
|
random_address=(random_address or self.device.random_address),
|
|
803
709
|
),
|
|
@@ -818,7 +724,7 @@ class AdvertisingSet(EventEmitter):
|
|
|
818
724
|
(the default) for an unlimited number of advertisements.
|
|
819
725
|
"""
|
|
820
726
|
await self.device.send_command(
|
|
821
|
-
HCI_LE_Set_Extended_Advertising_Enable_Command(
|
|
727
|
+
hci.HCI_LE_Set_Extended_Advertising_Enable_Command(
|
|
822
728
|
enable=1,
|
|
823
729
|
advertising_handles=[self.advertising_handle],
|
|
824
730
|
durations=[round(duration * 100)],
|
|
@@ -830,20 +736,9 @@ class AdvertisingSet(EventEmitter):
|
|
|
830
736
|
|
|
831
737
|
self.emit('start')
|
|
832
738
|
|
|
833
|
-
async def start_periodic(self, include_adi: bool = False) -> None:
|
|
834
|
-
await self.device.send_command(
|
|
835
|
-
HCI_LE_Set_Periodic_Advertising_Enable_Command(
|
|
836
|
-
enable=1 | (2 if include_adi else 0),
|
|
837
|
-
advertising_handles=self.advertising_handle,
|
|
838
|
-
),
|
|
839
|
-
check_result=True,
|
|
840
|
-
)
|
|
841
|
-
|
|
842
|
-
self.emit('start_periodic')
|
|
843
|
-
|
|
844
739
|
async def stop(self) -> None:
|
|
845
740
|
await self.device.send_command(
|
|
846
|
-
HCI_LE_Set_Extended_Advertising_Enable_Command(
|
|
741
|
+
hci.HCI_LE_Set_Extended_Advertising_Enable_Command(
|
|
847
742
|
enable=0,
|
|
848
743
|
advertising_handles=[self.advertising_handle],
|
|
849
744
|
durations=[0],
|
|
@@ -855,20 +750,37 @@ class AdvertisingSet(EventEmitter):
|
|
|
855
750
|
|
|
856
751
|
self.emit('stop')
|
|
857
752
|
|
|
753
|
+
async def start_periodic(self, include_adi: bool = False) -> None:
|
|
754
|
+
if self.periodic_enabled:
|
|
755
|
+
return
|
|
756
|
+
await self.device.send_command(
|
|
757
|
+
hci.HCI_LE_Set_Periodic_Advertising_Enable_Command(
|
|
758
|
+
enable=1 | (2 if include_adi else 0),
|
|
759
|
+
advertising_handle=self.advertising_handle,
|
|
760
|
+
),
|
|
761
|
+
check_result=True,
|
|
762
|
+
)
|
|
763
|
+
self.periodic_enabled = True
|
|
764
|
+
|
|
765
|
+
self.emit('start_periodic')
|
|
766
|
+
|
|
858
767
|
async def stop_periodic(self) -> None:
|
|
768
|
+
if not self.periodic_enabled:
|
|
769
|
+
return
|
|
859
770
|
await self.device.send_command(
|
|
860
|
-
HCI_LE_Set_Periodic_Advertising_Enable_Command(
|
|
771
|
+
hci.HCI_LE_Set_Periodic_Advertising_Enable_Command(
|
|
861
772
|
enable=0,
|
|
862
|
-
|
|
773
|
+
advertising_handle=self.advertising_handle,
|
|
863
774
|
),
|
|
864
775
|
check_result=True,
|
|
865
776
|
)
|
|
777
|
+
self.periodic_enabled = False
|
|
866
778
|
|
|
867
779
|
self.emit('stop_periodic')
|
|
868
780
|
|
|
869
781
|
async def remove(self) -> None:
|
|
870
782
|
await self.device.send_command(
|
|
871
|
-
HCI_LE_Remove_Advertising_Set_Command(
|
|
783
|
+
hci.HCI_LE_Remove_Advertising_Set_Command(
|
|
872
784
|
advertising_handle=self.advertising_handle
|
|
873
785
|
),
|
|
874
786
|
check_result=True,
|
|
@@ -893,7 +805,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
893
805
|
|
|
894
806
|
_state: State
|
|
895
807
|
sync_handle: Optional[int]
|
|
896
|
-
advertiser_address: Address
|
|
808
|
+
advertiser_address: hci.Address
|
|
897
809
|
sid: int
|
|
898
810
|
skip: int
|
|
899
811
|
sync_timeout: float # Sync timeout, in seconds
|
|
@@ -906,7 +818,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
906
818
|
def __init__(
|
|
907
819
|
self,
|
|
908
820
|
device: Device,
|
|
909
|
-
advertiser_address: Address,
|
|
821
|
+
advertiser_address: hci.Address,
|
|
910
822
|
sid: int,
|
|
911
823
|
skip: int,
|
|
912
824
|
sync_timeout: float,
|
|
@@ -921,7 +833,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
921
833
|
self.skip = skip
|
|
922
834
|
self.sync_timeout = sync_timeout
|
|
923
835
|
self.filter_duplicates = filter_duplicates
|
|
924
|
-
self.status = HCI_SUCCESS
|
|
836
|
+
self.status = hci.HCI_SUCCESS
|
|
925
837
|
self.advertiser_phy = 0
|
|
926
838
|
self.periodic_advertising_interval = 0
|
|
927
839
|
self.advertiser_clock_accuracy = 0
|
|
@@ -941,14 +853,14 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
941
853
|
if self.state != self.State.INIT:
|
|
942
854
|
raise InvalidStateError('sync not in init state')
|
|
943
855
|
|
|
944
|
-
options = HCI_LE_Periodic_Advertising_Create_Sync_Command.Options(0)
|
|
856
|
+
options = hci.HCI_LE_Periodic_Advertising_Create_Sync_Command.Options(0)
|
|
945
857
|
if self.filter_duplicates:
|
|
946
858
|
options |= (
|
|
947
|
-
HCI_LE_Periodic_Advertising_Create_Sync_Command.Options.DUPLICATE_FILTERING_INITIALLY_ENABLED
|
|
859
|
+
hci.HCI_LE_Periodic_Advertising_Create_Sync_Command.Options.DUPLICATE_FILTERING_INITIALLY_ENABLED
|
|
948
860
|
)
|
|
949
861
|
|
|
950
862
|
response = await self.device.send_command(
|
|
951
|
-
HCI_LE_Periodic_Advertising_Create_Sync_Command(
|
|
863
|
+
hci.HCI_LE_Periodic_Advertising_Create_Sync_Command(
|
|
952
864
|
options=options,
|
|
953
865
|
advertising_sid=self.sid,
|
|
954
866
|
advertiser_address_type=self.advertiser_address.address_type,
|
|
@@ -958,8 +870,8 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
958
870
|
sync_cte_type=0,
|
|
959
871
|
)
|
|
960
872
|
)
|
|
961
|
-
if response.status != HCI_Command_Status_Event.PENDING:
|
|
962
|
-
raise HCI_StatusError(response)
|
|
873
|
+
if response.status != hci.HCI_Command_Status_Event.PENDING:
|
|
874
|
+
raise hci.HCI_StatusError(response)
|
|
963
875
|
|
|
964
876
|
self.state = self.State.PENDING
|
|
965
877
|
|
|
@@ -970,9 +882,9 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
970
882
|
if self.state == self.State.PENDING:
|
|
971
883
|
self.state = self.State.CANCELLED
|
|
972
884
|
response = await self.device.send_command(
|
|
973
|
-
HCI_LE_Periodic_Advertising_Create_Sync_Cancel_Command(),
|
|
885
|
+
hci.HCI_LE_Periodic_Advertising_Create_Sync_Cancel_Command(),
|
|
974
886
|
)
|
|
975
|
-
if response.return_parameters == HCI_SUCCESS:
|
|
887
|
+
if response.return_parameters == hci.HCI_SUCCESS:
|
|
976
888
|
if self in self.device.periodic_advertising_syncs:
|
|
977
889
|
self.device.periodic_advertising_syncs.remove(self)
|
|
978
890
|
return
|
|
@@ -981,7 +893,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
981
893
|
self.state = self.State.TERMINATED
|
|
982
894
|
if self.sync_handle is not None:
|
|
983
895
|
await self.device.send_command(
|
|
984
|
-
HCI_LE_Periodic_Advertising_Terminate_Sync_Command(
|
|
896
|
+
hci.HCI_LE_Periodic_Advertising_Terminate_Sync_Command(
|
|
985
897
|
sync_handle=self.sync_handle
|
|
986
898
|
)
|
|
987
899
|
)
|
|
@@ -1013,7 +925,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
1013
925
|
AsyncRunner.spawn(self.terminate())
|
|
1014
926
|
return
|
|
1015
927
|
|
|
1016
|
-
if status == HCI_SUCCESS:
|
|
928
|
+
if status == hci.HCI_SUCCESS:
|
|
1017
929
|
self.sync_handle = sync_handle
|
|
1018
930
|
self.advertiser_phy = advertiser_phy
|
|
1019
931
|
self.periodic_advertising_interval = periodic_advertising_interval
|
|
@@ -1026,7 +938,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
1026
938
|
if self in self.device.periodic_advertising_syncs:
|
|
1027
939
|
self.device.periodic_advertising_syncs.remove(self)
|
|
1028
940
|
|
|
1029
|
-
if status == HCI_OPERATION_CANCELLED_BY_HOST_ERROR:
|
|
941
|
+
if status == hci.HCI_OPERATION_CANCELLED_BY_HOST_ERROR:
|
|
1030
942
|
self.state = self.State.CANCELLED
|
|
1031
943
|
self.emit('cancellation')
|
|
1032
944
|
return
|
|
@@ -1042,7 +954,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
1042
954
|
self.data_accumulator += report.data
|
|
1043
955
|
if (
|
|
1044
956
|
report.data_status
|
|
1045
|
-
== HCI_LE_Periodic_Advertising_Report_Event.DataStatus.DATA_INCOMPLETE_MORE_TO_COME
|
|
957
|
+
== hci.HCI_LE_Periodic_Advertising_Report_Event.DataStatus.DATA_INCOMPLETE_MORE_TO_COME
|
|
1046
958
|
):
|
|
1047
959
|
return
|
|
1048
960
|
|
|
@@ -1055,7 +967,7 @@ class PeriodicAdvertisingSync(EventEmitter):
|
|
|
1055
967
|
report.rssi,
|
|
1056
968
|
is_truncated=(
|
|
1057
969
|
report.data_status
|
|
1058
|
-
== HCI_LE_Periodic_Advertising_Report_Event.DataStatus.DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME
|
|
970
|
+
== hci.HCI_LE_Periodic_Advertising_Report_Event.DataStatus.DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME
|
|
1059
971
|
),
|
|
1060
972
|
data_bytes=self.data_accumulator,
|
|
1061
973
|
),
|
|
@@ -1278,13 +1190,13 @@ class ScoLink(CompositeEventEmitter):
|
|
|
1278
1190
|
acl_connection: Connection
|
|
1279
1191
|
handle: int
|
|
1280
1192
|
link_type: int
|
|
1281
|
-
sink: Optional[Callable[[HCI_SynchronousDataPacket], Any]] = None
|
|
1193
|
+
sink: Optional[Callable[[hci.HCI_SynchronousDataPacket], Any]] = None
|
|
1282
1194
|
|
|
1283
1195
|
def __post_init__(self) -> None:
|
|
1284
1196
|
super().__init__()
|
|
1285
1197
|
|
|
1286
1198
|
async def disconnect(
|
|
1287
|
-
self, reason: int = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1199
|
+
self, reason: int = hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1288
1200
|
) -> None:
|
|
1289
1201
|
await self.device.disconnect(self, reason)
|
|
1290
1202
|
|
|
@@ -1302,13 +1214,13 @@ class CisLink(CompositeEventEmitter):
|
|
|
1302
1214
|
cis_id: int # CIS ID assigned by Central device
|
|
1303
1215
|
cig_id: int # CIG ID assigned by Central device
|
|
1304
1216
|
state: State = State.PENDING
|
|
1305
|
-
sink: Optional[Callable[[HCI_IsoDataPacket], Any]] = None
|
|
1217
|
+
sink: Optional[Callable[[hci.HCI_IsoDataPacket], Any]] = None
|
|
1306
1218
|
|
|
1307
1219
|
def __post_init__(self) -> None:
|
|
1308
1220
|
super().__init__()
|
|
1309
1221
|
|
|
1310
1222
|
async def disconnect(
|
|
1311
|
-
self, reason: int = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1223
|
+
self, reason: int = hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1312
1224
|
) -> None:
|
|
1313
1225
|
await self.device.disconnect(self, reason)
|
|
1314
1226
|
|
|
@@ -1318,11 +1230,11 @@ class Connection(CompositeEventEmitter):
|
|
|
1318
1230
|
device: Device
|
|
1319
1231
|
handle: int
|
|
1320
1232
|
transport: int
|
|
1321
|
-
self_address: Address
|
|
1322
|
-
self_resolvable_address: Optional[Address]
|
|
1323
|
-
peer_address: Address
|
|
1324
|
-
peer_resolvable_address: Optional[Address]
|
|
1325
|
-
peer_le_features: Optional[LeFeatureMask]
|
|
1233
|
+
self_address: hci.Address
|
|
1234
|
+
self_resolvable_address: Optional[hci.Address]
|
|
1235
|
+
peer_address: hci.Address
|
|
1236
|
+
peer_resolvable_address: Optional[hci.Address]
|
|
1237
|
+
peer_le_features: Optional[hci.LeFeatureMask]
|
|
1326
1238
|
role: int
|
|
1327
1239
|
encryption: int
|
|
1328
1240
|
authenticated: bool
|
|
@@ -1478,7 +1390,7 @@ class Connection(CompositeEventEmitter):
|
|
|
1478
1390
|
return await self.device.create_l2cap_channel(connection=self, spec=spec)
|
|
1479
1391
|
|
|
1480
1392
|
async def disconnect(
|
|
1481
|
-
self, reason: int = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1393
|
+
self, reason: int = hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR
|
|
1482
1394
|
) -> None:
|
|
1483
1395
|
await self.device.disconnect(self, reason)
|
|
1484
1396
|
|
|
@@ -1549,7 +1461,7 @@ class Connection(CompositeEventEmitter):
|
|
|
1549
1461
|
async def request_remote_name(self):
|
|
1550
1462
|
return await self.device.request_remote_name(self)
|
|
1551
1463
|
|
|
1552
|
-
async def get_remote_le_features(self) -> LeFeatureMask:
|
|
1464
|
+
async def get_remote_le_features(self) -> hci.LeFeatureMask:
|
|
1553
1465
|
"""[LE Only] Reads remote LE supported features.
|
|
1554
1466
|
|
|
1555
1467
|
Returns:
|
|
@@ -1565,9 +1477,9 @@ class Connection(CompositeEventEmitter):
|
|
|
1565
1477
|
if exc_type is None:
|
|
1566
1478
|
try:
|
|
1567
1479
|
await self.disconnect()
|
|
1568
|
-
except HCI_StatusError as error:
|
|
1480
|
+
except hci.HCI_StatusError as error:
|
|
1569
1481
|
# Invalid parameter means the connection is no longer valid
|
|
1570
|
-
if error.error_code != HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR:
|
|
1482
|
+
if error.error_code != hci.HCI_INVALID_HCI_COMMAND_PARAMETERS_ERROR:
|
|
1571
1483
|
raise
|
|
1572
1484
|
|
|
1573
1485
|
def __str__(self):
|
|
@@ -1594,7 +1506,7 @@ class Connection(CompositeEventEmitter):
|
|
|
1594
1506
|
class DeviceConfiguration:
|
|
1595
1507
|
# Setup defaults
|
|
1596
1508
|
name: str = DEVICE_DEFAULT_NAME
|
|
1597
|
-
address: Address = Address(DEVICE_DEFAULT_ADDRESS)
|
|
1509
|
+
address: hci.Address = hci.Address(DEVICE_DEFAULT_ADDRESS)
|
|
1598
1510
|
class_of_device: int = DEVICE_DEFAULT_CLASS_OF_DEVICE
|
|
1599
1511
|
scan_response_data: bytes = DEVICE_DEFAULT_SCAN_RESPONSE_DATA
|
|
1600
1512
|
advertising_interval_min: int = DEVICE_DEFAULT_ADVERTISING_INTERVAL
|
|
@@ -1632,12 +1544,12 @@ class DeviceConfiguration:
|
|
|
1632
1544
|
|
|
1633
1545
|
# Load simple properties
|
|
1634
1546
|
if address := config.pop('address', None):
|
|
1635
|
-
self.address = Address(address)
|
|
1547
|
+
self.address = hci.Address(address)
|
|
1636
1548
|
|
|
1637
1549
|
# Load or synthesize an IRK
|
|
1638
1550
|
if irk := config.pop('irk', None):
|
|
1639
1551
|
self.irk = bytes.fromhex(irk)
|
|
1640
|
-
elif self.address != Address(DEVICE_DEFAULT_ADDRESS):
|
|
1552
|
+
elif self.address != hci.Address(DEVICE_DEFAULT_ADDRESS):
|
|
1641
1553
|
# Construct an IRK from the address bytes
|
|
1642
1554
|
# NOTE: this is not secure, but will always give the same IRK for the same
|
|
1643
1555
|
# address
|
|
@@ -1660,6 +1572,10 @@ class DeviceConfiguration:
|
|
|
1660
1572
|
)
|
|
1661
1573
|
)
|
|
1662
1574
|
|
|
1575
|
+
# Load scan response data
|
|
1576
|
+
if scan_response_data := config.pop('scan_response_data', None):
|
|
1577
|
+
self.scan_response_data = bytes.fromhex(scan_response_data)
|
|
1578
|
+
|
|
1663
1579
|
# Load advertising interval (for backward compatibility)
|
|
1664
1580
|
if advertising_interval := config.pop('advertising_interval', None):
|
|
1665
1581
|
self.advertising_interval_min = advertising_interval
|
|
@@ -1774,9 +1690,11 @@ device_host_event_handlers: List[str] = []
|
|
|
1774
1690
|
# -----------------------------------------------------------------------------
|
|
1775
1691
|
class Device(CompositeEventEmitter):
|
|
1776
1692
|
# Incomplete list of fields.
|
|
1777
|
-
random_address: Address # Random private address that may change periodically
|
|
1778
|
-
public_address:
|
|
1779
|
-
|
|
1693
|
+
random_address: hci.Address # Random private address that may change periodically
|
|
1694
|
+
public_address: (
|
|
1695
|
+
hci.Address
|
|
1696
|
+
) # Public address that is globally unique (from controller)
|
|
1697
|
+
static_address: hci.Address # Random static address that does not change once set
|
|
1780
1698
|
classic_enabled: bool
|
|
1781
1699
|
name: str
|
|
1782
1700
|
class_of_device: int
|
|
@@ -1784,11 +1702,12 @@ class Device(CompositeEventEmitter):
|
|
|
1784
1702
|
advertising_data: bytes
|
|
1785
1703
|
scan_response_data: bytes
|
|
1786
1704
|
connections: Dict[int, Connection]
|
|
1787
|
-
pending_connections: Dict[Address, Connection]
|
|
1705
|
+
pending_connections: Dict[hci.Address, Connection]
|
|
1788
1706
|
classic_pending_accepts: Dict[
|
|
1789
|
-
|
|
1707
|
+
hci.Address,
|
|
1708
|
+
List[asyncio.Future[Union[Connection, Tuple[hci.Address, int, int]]]],
|
|
1790
1709
|
]
|
|
1791
|
-
advertisement_accumulators: Dict[Address, AdvertisementDataAccumulator]
|
|
1710
|
+
advertisement_accumulators: Dict[hci.Address, AdvertisementDataAccumulator]
|
|
1792
1711
|
periodic_advertising_syncs: List[PeriodicAdvertisingSync]
|
|
1793
1712
|
config: DeviceConfiguration
|
|
1794
1713
|
legacy_advertiser: Optional[LegacyAdvertiser]
|
|
@@ -1822,7 +1741,7 @@ class Device(CompositeEventEmitter):
|
|
|
1822
1741
|
def with_hci(
|
|
1823
1742
|
cls,
|
|
1824
1743
|
name: str,
|
|
1825
|
-
address: Address,
|
|
1744
|
+
address: hci.Address,
|
|
1826
1745
|
hci_source: TransportSource,
|
|
1827
1746
|
hci_sink: TransportSink,
|
|
1828
1747
|
) -> Device:
|
|
@@ -1858,7 +1777,7 @@ class Device(CompositeEventEmitter):
|
|
|
1858
1777
|
def __init__(
|
|
1859
1778
|
self,
|
|
1860
1779
|
name: Optional[str] = None,
|
|
1861
|
-
address: Optional[Address] = None,
|
|
1780
|
+
address: Optional[hci.Address] = None,
|
|
1862
1781
|
config: Optional[DeviceConfiguration] = None,
|
|
1863
1782
|
host: Optional[Host] = None,
|
|
1864
1783
|
generic_access_service: bool = True,
|
|
@@ -1890,8 +1809,8 @@ class Device(CompositeEventEmitter):
|
|
|
1890
1809
|
self.inquiry_response = None
|
|
1891
1810
|
self.address_resolver = None
|
|
1892
1811
|
self.classic_pending_accepts = {
|
|
1893
|
-
Address.ANY: []
|
|
1894
|
-
} # Futures, by BD address OR [Futures] for Address.ANY
|
|
1812
|
+
hci.Address.ANY: []
|
|
1813
|
+
} # Futures, by BD address OR [Futures] for hci.Address.ANY
|
|
1895
1814
|
|
|
1896
1815
|
# In Python <= 3.9 + Rust Runtime, asyncio.Lock cannot be properly initiated.
|
|
1897
1816
|
if sys.version_info >= (3, 10):
|
|
@@ -1907,7 +1826,7 @@ class Device(CompositeEventEmitter):
|
|
|
1907
1826
|
self.config = config
|
|
1908
1827
|
|
|
1909
1828
|
self.name = config.name
|
|
1910
|
-
self.public_address = Address.ANY
|
|
1829
|
+
self.public_address = hci.Address.ANY
|
|
1911
1830
|
self.random_address = config.address
|
|
1912
1831
|
self.static_address = config.address
|
|
1913
1832
|
self.class_of_device = config.class_of_device
|
|
@@ -1982,7 +1901,7 @@ class Device(CompositeEventEmitter):
|
|
|
1982
1901
|
# If an address is passed, override the address from the config
|
|
1983
1902
|
if address:
|
|
1984
1903
|
if isinstance(address, str):
|
|
1985
|
-
address = Address(address)
|
|
1904
|
+
address = hci.Address(address)
|
|
1986
1905
|
self.random_address = address
|
|
1987
1906
|
self.static_address = address
|
|
1988
1907
|
|
|
@@ -2062,12 +1981,12 @@ class Device(CompositeEventEmitter):
|
|
|
2062
1981
|
|
|
2063
1982
|
def find_connection_by_bd_addr(
|
|
2064
1983
|
self,
|
|
2065
|
-
bd_addr: Address,
|
|
1984
|
+
bd_addr: hci.Address,
|
|
2066
1985
|
transport: Optional[int] = None,
|
|
2067
1986
|
check_address_type: bool = False,
|
|
2068
1987
|
) -> Optional[Connection]:
|
|
2069
1988
|
for connection in self.connections.values():
|
|
2070
|
-
if connection.peer_address
|
|
1989
|
+
if bytes(connection.peer_address) == bytes(bd_addr):
|
|
2071
1990
|
if (
|
|
2072
1991
|
check_address_type
|
|
2073
1992
|
and connection.peer_address.address_type != bd_addr.address_type
|
|
@@ -2201,8 +2120,8 @@ class Device(CompositeEventEmitter):
|
|
|
2201
2120
|
await self.host.reset()
|
|
2202
2121
|
|
|
2203
2122
|
# Try to get the public address from the controller
|
|
2204
|
-
response = await self.send_command(HCI_Read_BD_ADDR_Command())
|
|
2205
|
-
if response.return_parameters.status == HCI_SUCCESS:
|
|
2123
|
+
response = await self.send_command(hci.HCI_Read_BD_ADDR_Command())
|
|
2124
|
+
if response.return_parameters.status == hci.HCI_SUCCESS:
|
|
2206
2125
|
logger.debug(
|
|
2207
2126
|
color(f'BD_ADDR: {response.return_parameters.bd_addr}', 'yellow')
|
|
2208
2127
|
)
|
|
@@ -2219,9 +2138,9 @@ class Device(CompositeEventEmitter):
|
|
|
2219
2138
|
smp.SMP_BR_CID, self.on_smp_pdu
|
|
2220
2139
|
)
|
|
2221
2140
|
|
|
2222
|
-
if self.host.supports_command(HCI_WRITE_LE_HOST_SUPPORT_COMMAND):
|
|
2141
|
+
if self.host.supports_command(hci.HCI_WRITE_LE_HOST_SUPPORT_COMMAND):
|
|
2223
2142
|
await self.send_command(
|
|
2224
|
-
HCI_Write_LE_Host_Support_Command(
|
|
2143
|
+
hci.HCI_Write_LE_Host_Support_Command(
|
|
2225
2144
|
le_supported_host=int(self.le_enabled),
|
|
2226
2145
|
simultaneous_le_host=int(self.le_simultaneous_enabled),
|
|
2227
2146
|
),
|
|
@@ -2230,12 +2149,12 @@ class Device(CompositeEventEmitter):
|
|
|
2230
2149
|
|
|
2231
2150
|
if self.le_enabled:
|
|
2232
2151
|
# Generate a random address if not set.
|
|
2233
|
-
if self.static_address == Address.ANY_RANDOM:
|
|
2234
|
-
self.static_address = Address.generate_static_address()
|
|
2152
|
+
if self.static_address == hci.Address.ANY_RANDOM:
|
|
2153
|
+
self.static_address = hci.Address.generate_static_address()
|
|
2235
2154
|
|
|
2236
2155
|
# If LE Privacy is enabled, generate an RPA
|
|
2237
2156
|
if self.le_privacy_enabled:
|
|
2238
|
-
self.random_address = Address.generate_private_address(self.irk)
|
|
2157
|
+
self.random_address = hci.Address.generate_private_address(self.irk)
|
|
2239
2158
|
logger.info(f'Initial RPA: {self.random_address}')
|
|
2240
2159
|
if self.le_rpa_timeout > 0:
|
|
2241
2160
|
# Start a task to periodically generate a new RPA
|
|
@@ -2245,15 +2164,15 @@ class Device(CompositeEventEmitter):
|
|
|
2245
2164
|
else:
|
|
2246
2165
|
self.random_address = self.static_address
|
|
2247
2166
|
|
|
2248
|
-
if self.random_address != Address.ANY_RANDOM:
|
|
2167
|
+
if self.random_address != hci.Address.ANY_RANDOM:
|
|
2249
2168
|
logger.debug(
|
|
2250
2169
|
color(
|
|
2251
|
-
f'LE Random Address: {self.random_address}',
|
|
2170
|
+
f'LE Random hci.Address: {self.random_address}',
|
|
2252
2171
|
'yellow',
|
|
2253
2172
|
)
|
|
2254
2173
|
)
|
|
2255
2174
|
await self.send_command(
|
|
2256
|
-
HCI_LE_Set_Random_Address_Command(
|
|
2175
|
+
hci.HCI_LE_Set_Random_Address_Command(
|
|
2257
2176
|
random_address=self.random_address
|
|
2258
2177
|
),
|
|
2259
2178
|
check_result=True,
|
|
@@ -2266,7 +2185,7 @@ class Device(CompositeEventEmitter):
|
|
|
2266
2185
|
# Enable address resolution
|
|
2267
2186
|
if self.address_resolution_offload:
|
|
2268
2187
|
await self.send_command(
|
|
2269
|
-
HCI_LE_Set_Address_Resolution_Enable_Command(
|
|
2188
|
+
hci.HCI_LE_Set_Address_Resolution_Enable_Command(
|
|
2270
2189
|
address_resolution_enable=1
|
|
2271
2190
|
),
|
|
2272
2191
|
check_result=True,
|
|
@@ -2274,8 +2193,8 @@ class Device(CompositeEventEmitter):
|
|
|
2274
2193
|
|
|
2275
2194
|
if self.cis_enabled:
|
|
2276
2195
|
await self.send_command(
|
|
2277
|
-
HCI_LE_Set_Host_Feature_Command(
|
|
2278
|
-
bit_number=LeFeature.CONNECTED_ISOCHRONOUS_STREAM,
|
|
2196
|
+
hci.HCI_LE_Set_Host_Feature_Command(
|
|
2197
|
+
bit_number=hci.LeFeature.CONNECTED_ISOCHRONOUS_STREAM,
|
|
2279
2198
|
bit_value=1,
|
|
2280
2199
|
),
|
|
2281
2200
|
check_result=True,
|
|
@@ -2283,18 +2202,20 @@ class Device(CompositeEventEmitter):
|
|
|
2283
2202
|
|
|
2284
2203
|
if self.classic_enabled:
|
|
2285
2204
|
await self.send_command(
|
|
2286
|
-
HCI_Write_Local_Name_Command(local_name=self.name.encode('utf8'))
|
|
2205
|
+
hci.HCI_Write_Local_Name_Command(local_name=self.name.encode('utf8'))
|
|
2287
2206
|
)
|
|
2288
2207
|
await self.send_command(
|
|
2289
|
-
HCI_Write_Class_Of_Device_Command(
|
|
2208
|
+
hci.HCI_Write_Class_Of_Device_Command(
|
|
2209
|
+
class_of_device=self.class_of_device
|
|
2210
|
+
)
|
|
2290
2211
|
)
|
|
2291
2212
|
await self.send_command(
|
|
2292
|
-
HCI_Write_Simple_Pairing_Mode_Command(
|
|
2213
|
+
hci.HCI_Write_Simple_Pairing_Mode_Command(
|
|
2293
2214
|
simple_pairing_mode=int(self.classic_ssp_enabled)
|
|
2294
2215
|
)
|
|
2295
2216
|
)
|
|
2296
2217
|
await self.send_command(
|
|
2297
|
-
HCI_Write_Secure_Connections_Host_Support_Command(
|
|
2218
|
+
hci.HCI_Write_Secure_Connections_Host_Support_Command(
|
|
2298
2219
|
secure_connections_host_support=int(self.classic_sc_enabled)
|
|
2299
2220
|
)
|
|
2300
2221
|
)
|
|
@@ -2302,14 +2223,16 @@ class Device(CompositeEventEmitter):
|
|
|
2302
2223
|
await self.set_discoverable(self.discoverable)
|
|
2303
2224
|
|
|
2304
2225
|
if self.classic_interlaced_scan_enabled:
|
|
2305
|
-
if self.host.supports_lmp_features(
|
|
2226
|
+
if self.host.supports_lmp_features(
|
|
2227
|
+
hci.LmpFeatureMask.INTERLACED_PAGE_SCAN
|
|
2228
|
+
):
|
|
2306
2229
|
await self.send_command(
|
|
2307
2230
|
hci.HCI_Write_Page_Scan_Type_Command(page_scan_type=1),
|
|
2308
2231
|
check_result=True,
|
|
2309
2232
|
)
|
|
2310
2233
|
|
|
2311
2234
|
if self.host.supports_lmp_features(
|
|
2312
|
-
LmpFeatureMask.INTERLACED_INQUIRY_SCAN
|
|
2235
|
+
hci.LmpFeatureMask.INTERLACED_INQUIRY_SCAN
|
|
2313
2236
|
):
|
|
2314
2237
|
await self.send_command(
|
|
2315
2238
|
hci.HCI_Write_Inquiry_Scan_Type_Command(scan_type=1),
|
|
@@ -2344,11 +2267,11 @@ class Device(CompositeEventEmitter):
|
|
|
2344
2267
|
logger.debug('skipping RPA update')
|
|
2345
2268
|
return False
|
|
2346
2269
|
|
|
2347
|
-
random_address = Address.generate_private_address(self.irk)
|
|
2270
|
+
random_address = hci.Address.generate_private_address(self.irk)
|
|
2348
2271
|
response = await self.send_command(
|
|
2349
|
-
HCI_LE_Set_Random_Address_Command(random_address=self.random_address)
|
|
2272
|
+
hci.HCI_LE_Set_Random_Address_Command(random_address=self.random_address)
|
|
2350
2273
|
)
|
|
2351
|
-
if response.return_parameters == HCI_SUCCESS:
|
|
2274
|
+
if response.return_parameters == hci.HCI_SUCCESS:
|
|
2352
2275
|
logger.info(f'new RPA: {random_address}')
|
|
2353
2276
|
self.random_address = random_address
|
|
2354
2277
|
return True
|
|
@@ -2371,13 +2294,13 @@ class Device(CompositeEventEmitter):
|
|
|
2371
2294
|
self.address_resolver = smp.AddressResolver(resolving_keys)
|
|
2372
2295
|
|
|
2373
2296
|
if self.address_resolution_offload or self.address_generation_offload:
|
|
2374
|
-
await self.send_command(HCI_LE_Clear_Resolving_List_Command())
|
|
2297
|
+
await self.send_command(hci.HCI_LE_Clear_Resolving_List_Command())
|
|
2375
2298
|
|
|
2376
2299
|
# Add an empty entry for non-directed address generation.
|
|
2377
2300
|
await self.send_command(
|
|
2378
|
-
HCI_LE_Add_Device_To_Resolving_List_Command(
|
|
2379
|
-
peer_identity_address_type=Address.ANY.address_type,
|
|
2380
|
-
peer_identity_address=Address.ANY,
|
|
2301
|
+
hci.HCI_LE_Add_Device_To_Resolving_List_Command(
|
|
2302
|
+
peer_identity_address_type=hci.Address.ANY.address_type,
|
|
2303
|
+
peer_identity_address=hci.Address.ANY,
|
|
2381
2304
|
peer_irk=bytes(16),
|
|
2382
2305
|
local_irk=self.irk,
|
|
2383
2306
|
)
|
|
@@ -2385,7 +2308,7 @@ class Device(CompositeEventEmitter):
|
|
|
2385
2308
|
|
|
2386
2309
|
for irk, address in resolving_keys:
|
|
2387
2310
|
await self.send_command(
|
|
2388
|
-
HCI_LE_Add_Device_To_Resolving_List_Command(
|
|
2311
|
+
hci.HCI_LE_Add_Device_To_Resolving_List_Command(
|
|
2389
2312
|
peer_identity_address_type=address.address_type,
|
|
2390
2313
|
peer_identity_address=address,
|
|
2391
2314
|
peer_irk=irk,
|
|
@@ -2393,16 +2316,16 @@ class Device(CompositeEventEmitter):
|
|
|
2393
2316
|
)
|
|
2394
2317
|
)
|
|
2395
2318
|
|
|
2396
|
-
def supports_le_features(self, feature: LeFeatureMask) -> bool:
|
|
2319
|
+
def supports_le_features(self, feature: hci.LeFeatureMask) -> bool:
|
|
2397
2320
|
return self.host.supports_le_features(feature)
|
|
2398
2321
|
|
|
2399
2322
|
def supports_le_phy(self, phy: int) -> bool:
|
|
2400
|
-
if phy == HCI_LE_1M_PHY:
|
|
2323
|
+
if phy == hci.HCI_LE_1M_PHY:
|
|
2401
2324
|
return True
|
|
2402
2325
|
|
|
2403
2326
|
feature_map = {
|
|
2404
|
-
HCI_LE_2M_PHY: LeFeatureMask.LE_2M_PHY,
|
|
2405
|
-
HCI_LE_CODED_PHY: LeFeatureMask.LE_CODED_PHY,
|
|
2327
|
+
hci.HCI_LE_2M_PHY: hci.LeFeatureMask.LE_2M_PHY,
|
|
2328
|
+
hci.HCI_LE_CODED_PHY: hci.LeFeatureMask.LE_CODED_PHY,
|
|
2406
2329
|
}
|
|
2407
2330
|
if phy not in feature_map:
|
|
2408
2331
|
raise InvalidArgumentError('invalid PHY')
|
|
@@ -2411,17 +2334,17 @@ class Device(CompositeEventEmitter):
|
|
|
2411
2334
|
|
|
2412
2335
|
@property
|
|
2413
2336
|
def supports_le_extended_advertising(self):
|
|
2414
|
-
return self.supports_le_features(LeFeatureMask.LE_EXTENDED_ADVERTISING)
|
|
2337
|
+
return self.supports_le_features(hci.LeFeatureMask.LE_EXTENDED_ADVERTISING)
|
|
2415
2338
|
|
|
2416
2339
|
@property
|
|
2417
2340
|
def supports_le_periodic_advertising(self):
|
|
2418
|
-
return self.supports_le_features(LeFeatureMask.LE_PERIODIC_ADVERTISING)
|
|
2341
|
+
return self.supports_le_features(hci.LeFeatureMask.LE_PERIODIC_ADVERTISING)
|
|
2419
2342
|
|
|
2420
2343
|
async def start_advertising(
|
|
2421
2344
|
self,
|
|
2422
2345
|
advertising_type: AdvertisingType = AdvertisingType.UNDIRECTED_CONNECTABLE_SCANNABLE,
|
|
2423
|
-
target: Optional[Address] = None,
|
|
2424
|
-
own_address_type: int = OwnAddressType.RANDOM,
|
|
2346
|
+
target: Optional[hci.Address] = None,
|
|
2347
|
+
own_address_type: int = hci.OwnAddressType.RANDOM,
|
|
2425
2348
|
auto_restart: bool = False,
|
|
2426
2349
|
advertising_data: Optional[bytes] = None,
|
|
2427
2350
|
scan_response_data: Optional[bytes] = None,
|
|
@@ -2472,7 +2395,7 @@ class Device(CompositeEventEmitter):
|
|
|
2472
2395
|
raise InvalidArgumentError('directed advertising requires a target')
|
|
2473
2396
|
peer_address = target
|
|
2474
2397
|
else:
|
|
2475
|
-
peer_address = Address.ANY
|
|
2398
|
+
peer_address = hci.Address.ANY
|
|
2476
2399
|
|
|
2477
2400
|
# If we're already advertising, stop now because we'll be re-creating
|
|
2478
2401
|
# a new advertiser or advertising set.
|
|
@@ -2494,7 +2417,7 @@ class Device(CompositeEventEmitter):
|
|
|
2494
2417
|
),
|
|
2495
2418
|
primary_advertising_interval_min=self.advertising_interval_min,
|
|
2496
2419
|
primary_advertising_interval_max=self.advertising_interval_max,
|
|
2497
|
-
own_address_type=OwnAddressType(own_address_type),
|
|
2420
|
+
own_address_type=hci.OwnAddressType(own_address_type),
|
|
2498
2421
|
peer_address=peer_address,
|
|
2499
2422
|
),
|
|
2500
2423
|
advertising_data=(
|
|
@@ -2509,7 +2432,7 @@ class Device(CompositeEventEmitter):
|
|
|
2509
2432
|
self.legacy_advertiser = LegacyAdvertiser(
|
|
2510
2433
|
device=self,
|
|
2511
2434
|
advertising_type=advertising_type,
|
|
2512
|
-
own_address_type=OwnAddressType(own_address_type),
|
|
2435
|
+
own_address_type=hci.OwnAddressType(own_address_type),
|
|
2513
2436
|
peer_address=peer_address,
|
|
2514
2437
|
auto_restart=auto_restart,
|
|
2515
2438
|
)
|
|
@@ -2531,7 +2454,7 @@ class Device(CompositeEventEmitter):
|
|
|
2531
2454
|
async def create_advertising_set(
|
|
2532
2455
|
self,
|
|
2533
2456
|
advertising_parameters: Optional[AdvertisingParameters] = None,
|
|
2534
|
-
random_address: Optional[Address] = None,
|
|
2457
|
+
random_address: Optional[hci.Address] = None,
|
|
2535
2458
|
advertising_data: bytes = b'',
|
|
2536
2459
|
scan_response_data: bytes = b'',
|
|
2537
2460
|
periodic_advertising_parameters: Optional[PeriodicAdvertisingParameters] = None,
|
|
@@ -2571,14 +2494,27 @@ class Device(CompositeEventEmitter):
|
|
|
2571
2494
|
if advertising_parameters is None:
|
|
2572
2495
|
advertising_parameters = AdvertisingParameters()
|
|
2573
2496
|
|
|
2497
|
+
if periodic_advertising_data and periodic_advertising_parameters is None:
|
|
2498
|
+
periodic_advertising_parameters = PeriodicAdvertisingParameters()
|
|
2499
|
+
|
|
2574
2500
|
if (
|
|
2575
2501
|
not advertising_parameters.advertising_event_properties.is_legacy
|
|
2576
2502
|
and advertising_data
|
|
2577
2503
|
and scan_response_data
|
|
2578
2504
|
):
|
|
2579
2505
|
raise InvalidArgumentError(
|
|
2580
|
-
"Extended advertisements can't have both data and scan
|
|
2581
|
-
|
|
2506
|
+
"Extended advertisements can't have both data and scan response data"
|
|
2507
|
+
)
|
|
2508
|
+
|
|
2509
|
+
if periodic_advertising_parameters and (
|
|
2510
|
+
advertising_parameters.advertising_event_properties.is_connectable
|
|
2511
|
+
or advertising_parameters.advertising_event_properties.is_scannable
|
|
2512
|
+
or advertising_parameters.advertising_event_properties.is_anonymous
|
|
2513
|
+
or advertising_parameters.advertising_event_properties.is_legacy
|
|
2514
|
+
):
|
|
2515
|
+
raise InvalidArgumentError(
|
|
2516
|
+
"Periodic advertising set cannot be connectable, scannable, anonymous,"
|
|
2517
|
+
"or legacy"
|
|
2582
2518
|
)
|
|
2583
2519
|
|
|
2584
2520
|
# Allocate a new handle
|
|
@@ -2600,7 +2536,7 @@ class Device(CompositeEventEmitter):
|
|
|
2600
2536
|
# provided.
|
|
2601
2537
|
if (
|
|
2602
2538
|
advertising_parameters.own_address_type
|
|
2603
|
-
in (OwnAddressType.RANDOM, OwnAddressType.RESOLVABLE_OR_RANDOM)
|
|
2539
|
+
in (hci.OwnAddressType.RANDOM, hci.OwnAddressType.RESOLVABLE_OR_RANDOM)
|
|
2604
2540
|
and random_address is None
|
|
2605
2541
|
):
|
|
2606
2542
|
random_address = self.random_address
|
|
@@ -2633,18 +2569,20 @@ class Device(CompositeEventEmitter):
|
|
|
2633
2569
|
await advertising_set.set_scan_response_data(scan_response_data)
|
|
2634
2570
|
|
|
2635
2571
|
if periodic_advertising_parameters:
|
|
2636
|
-
|
|
2637
|
-
|
|
2572
|
+
await advertising_set.set_periodic_advertising_parameters(
|
|
2573
|
+
periodic_advertising_parameters
|
|
2574
|
+
)
|
|
2638
2575
|
|
|
2639
2576
|
if periodic_advertising_data:
|
|
2640
|
-
|
|
2641
|
-
|
|
2577
|
+
await advertising_set.set_periodic_advertising_data(
|
|
2578
|
+
periodic_advertising_data
|
|
2579
|
+
)
|
|
2642
2580
|
|
|
2643
|
-
except HCI_Error as error:
|
|
2581
|
+
except hci.HCI_Error as error:
|
|
2644
2582
|
# Remove the advertising set so that it doesn't stay dangling in the
|
|
2645
2583
|
# controller.
|
|
2646
2584
|
await self.send_command(
|
|
2647
|
-
HCI_LE_Remove_Advertising_Set_Command(
|
|
2585
|
+
hci.HCI_LE_Remove_Advertising_Set_Command(
|
|
2648
2586
|
advertising_handle=advertising_handle
|
|
2649
2587
|
),
|
|
2650
2588
|
check_result=False,
|
|
@@ -2687,9 +2625,9 @@ class Device(CompositeEventEmitter):
|
|
|
2687
2625
|
active: bool = True,
|
|
2688
2626
|
scan_interval: int = DEVICE_DEFAULT_SCAN_INTERVAL, # Scan interval in ms
|
|
2689
2627
|
scan_window: int = DEVICE_DEFAULT_SCAN_WINDOW, # Scan window in ms
|
|
2690
|
-
own_address_type: int = OwnAddressType.RANDOM,
|
|
2628
|
+
own_address_type: int = hci.OwnAddressType.RANDOM,
|
|
2691
2629
|
filter_duplicates: bool = False,
|
|
2692
|
-
scanning_phys: List[int] = [HCI_LE_1M_PHY, HCI_LE_CODED_PHY],
|
|
2630
|
+
scanning_phys: List[int] = [hci.HCI_LE_1M_PHY, hci.HCI_LE_CODED_PHY],
|
|
2693
2631
|
) -> None:
|
|
2694
2632
|
# Check that the arguments are legal
|
|
2695
2633
|
if scan_interval < scan_window:
|
|
@@ -2709,29 +2647,29 @@ class Device(CompositeEventEmitter):
|
|
|
2709
2647
|
if not legacy and self.supports_le_extended_advertising:
|
|
2710
2648
|
# Set the scanning parameters
|
|
2711
2649
|
scan_type = (
|
|
2712
|
-
HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING
|
|
2650
|
+
hci.HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING
|
|
2713
2651
|
if active
|
|
2714
|
-
else HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING
|
|
2652
|
+
else hci.HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING
|
|
2715
2653
|
)
|
|
2716
2654
|
scanning_filter_policy = (
|
|
2717
|
-
HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY
|
|
2655
|
+
hci.HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY
|
|
2718
2656
|
) # TODO: support other types
|
|
2719
2657
|
|
|
2720
2658
|
scanning_phy_count = 0
|
|
2721
2659
|
scanning_phys_bits = 0
|
|
2722
|
-
if HCI_LE_1M_PHY in scanning_phys:
|
|
2723
|
-
scanning_phys_bits |= 1 << HCI_LE_1M_PHY_BIT
|
|
2660
|
+
if hci.HCI_LE_1M_PHY in scanning_phys:
|
|
2661
|
+
scanning_phys_bits |= 1 << hci.HCI_LE_1M_PHY_BIT
|
|
2724
2662
|
scanning_phy_count += 1
|
|
2725
|
-
if HCI_LE_CODED_PHY in scanning_phys:
|
|
2726
|
-
if self.supports_le_features(LeFeatureMask.LE_CODED_PHY):
|
|
2727
|
-
scanning_phys_bits |= 1 << HCI_LE_CODED_PHY_BIT
|
|
2663
|
+
if hci.HCI_LE_CODED_PHY in scanning_phys:
|
|
2664
|
+
if self.supports_le_features(hci.LeFeatureMask.LE_CODED_PHY):
|
|
2665
|
+
scanning_phys_bits |= 1 << hci.HCI_LE_CODED_PHY_BIT
|
|
2728
2666
|
scanning_phy_count += 1
|
|
2729
2667
|
|
|
2730
2668
|
if scanning_phy_count == 0:
|
|
2731
2669
|
raise InvalidArgumentError('at least one scanning PHY must be enabled')
|
|
2732
2670
|
|
|
2733
2671
|
await self.send_command(
|
|
2734
|
-
HCI_LE_Set_Extended_Scan_Parameters_Command(
|
|
2672
|
+
hci.HCI_LE_Set_Extended_Scan_Parameters_Command(
|
|
2735
2673
|
own_address_type=own_address_type,
|
|
2736
2674
|
scanning_filter_policy=scanning_filter_policy,
|
|
2737
2675
|
scanning_phys=scanning_phys_bits,
|
|
@@ -2744,7 +2682,7 @@ class Device(CompositeEventEmitter):
|
|
|
2744
2682
|
|
|
2745
2683
|
# Enable scanning
|
|
2746
2684
|
await self.send_command(
|
|
2747
|
-
HCI_LE_Set_Extended_Scan_Enable_Command(
|
|
2685
|
+
hci.HCI_LE_Set_Extended_Scan_Enable_Command(
|
|
2748
2686
|
enable=1,
|
|
2749
2687
|
filter_duplicates=1 if filter_duplicates else 0,
|
|
2750
2688
|
duration=0, # TODO allow other values
|
|
@@ -2755,25 +2693,25 @@ class Device(CompositeEventEmitter):
|
|
|
2755
2693
|
else:
|
|
2756
2694
|
# Set the scanning parameters
|
|
2757
2695
|
scan_type = (
|
|
2758
|
-
HCI_LE_Set_Scan_Parameters_Command.ACTIVE_SCANNING
|
|
2696
|
+
hci.HCI_LE_Set_Scan_Parameters_Command.ACTIVE_SCANNING
|
|
2759
2697
|
if active
|
|
2760
|
-
else HCI_LE_Set_Scan_Parameters_Command.PASSIVE_SCANNING
|
|
2698
|
+
else hci.HCI_LE_Set_Scan_Parameters_Command.PASSIVE_SCANNING
|
|
2761
2699
|
)
|
|
2762
2700
|
await self.send_command(
|
|
2763
2701
|
# pylint: disable=line-too-long
|
|
2764
|
-
HCI_LE_Set_Scan_Parameters_Command(
|
|
2702
|
+
hci.HCI_LE_Set_Scan_Parameters_Command(
|
|
2765
2703
|
le_scan_type=scan_type,
|
|
2766
2704
|
le_scan_interval=int(scan_window / 0.625),
|
|
2767
2705
|
le_scan_window=int(scan_window / 0.625),
|
|
2768
2706
|
own_address_type=own_address_type,
|
|
2769
|
-
scanning_filter_policy=HCI_LE_Set_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY,
|
|
2707
|
+
scanning_filter_policy=hci.HCI_LE_Set_Scan_Parameters_Command.BASIC_UNFILTERED_POLICY,
|
|
2770
2708
|
),
|
|
2771
2709
|
check_result=True,
|
|
2772
2710
|
)
|
|
2773
2711
|
|
|
2774
2712
|
# Enable scanning
|
|
2775
2713
|
await self.send_command(
|
|
2776
|
-
HCI_LE_Set_Scan_Enable_Command(
|
|
2714
|
+
hci.HCI_LE_Set_Scan_Enable_Command(
|
|
2777
2715
|
le_scan_enable=1, filter_duplicates=1 if filter_duplicates else 0
|
|
2778
2716
|
),
|
|
2779
2717
|
check_result=True,
|
|
@@ -2786,14 +2724,16 @@ class Device(CompositeEventEmitter):
|
|
|
2786
2724
|
# Disable scanning
|
|
2787
2725
|
if not legacy and self.supports_le_extended_advertising:
|
|
2788
2726
|
await self.send_command(
|
|
2789
|
-
HCI_LE_Set_Extended_Scan_Enable_Command(
|
|
2727
|
+
hci.HCI_LE_Set_Extended_Scan_Enable_Command(
|
|
2790
2728
|
enable=0, filter_duplicates=0, duration=0, period=0
|
|
2791
2729
|
),
|
|
2792
2730
|
check_result=True,
|
|
2793
2731
|
)
|
|
2794
2732
|
else:
|
|
2795
2733
|
await self.send_command(
|
|
2796
|
-
HCI_LE_Set_Scan_Enable_Command(
|
|
2734
|
+
hci.HCI_LE_Set_Scan_Enable_Command(
|
|
2735
|
+
le_scan_enable=0, filter_duplicates=0
|
|
2736
|
+
),
|
|
2797
2737
|
check_result=True,
|
|
2798
2738
|
)
|
|
2799
2739
|
|
|
@@ -2813,7 +2753,7 @@ class Device(CompositeEventEmitter):
|
|
|
2813
2753
|
|
|
2814
2754
|
async def create_periodic_advertising_sync(
|
|
2815
2755
|
self,
|
|
2816
|
-
advertiser_address: Address,
|
|
2756
|
+
advertiser_address: hci.Address,
|
|
2817
2757
|
sid: int,
|
|
2818
2758
|
skip: int = DEVICE_DEFAULT_PERIODIC_ADVERTISING_SYNC_SKIP,
|
|
2819
2759
|
sync_timeout: float = DEVICE_DEFAULT_PERIODIC_ADVERTISING_SYNC_TIMEOUT,
|
|
@@ -2874,7 +2814,7 @@ class Device(CompositeEventEmitter):
|
|
|
2874
2814
|
status: int,
|
|
2875
2815
|
sync_handle: int,
|
|
2876
2816
|
advertising_sid: int,
|
|
2877
|
-
advertiser_address: Address,
|
|
2817
|
+
advertiser_address: hci.Address,
|
|
2878
2818
|
advertiser_phy: int,
|
|
2879
2819
|
periodic_advertising_interval: int,
|
|
2880
2820
|
advertiser_clock_accuracy: int,
|
|
@@ -2912,7 +2852,7 @@ class Device(CompositeEventEmitter):
|
|
|
2912
2852
|
def on_periodic_advertising_report(
|
|
2913
2853
|
self,
|
|
2914
2854
|
periodic_advertising_sync: PeriodicAdvertisingSync,
|
|
2915
|
-
report: HCI_LE_Periodic_Advertising_Report_Event,
|
|
2855
|
+
report: hci.HCI_LE_Periodic_Advertising_Report_Event,
|
|
2916
2856
|
):
|
|
2917
2857
|
periodic_advertising_sync.on_periodic_advertising_report(report)
|
|
2918
2858
|
|
|
@@ -2921,33 +2861,35 @@ class Device(CompositeEventEmitter):
|
|
|
2921
2861
|
def on_biginfo_advertising_report(
|
|
2922
2862
|
self,
|
|
2923
2863
|
periodic_advertising_sync: PeriodicAdvertisingSync,
|
|
2924
|
-
report: HCI_LE_BIGInfo_Advertising_Report_Event,
|
|
2864
|
+
report: hci.HCI_LE_BIGInfo_Advertising_Report_Event,
|
|
2925
2865
|
):
|
|
2926
2866
|
periodic_advertising_sync.on_biginfo_advertising_report(report)
|
|
2927
2867
|
|
|
2928
2868
|
async def start_discovery(self, auto_restart: bool = True) -> None:
|
|
2929
2869
|
await self.send_command(
|
|
2930
|
-
HCI_Write_Inquiry_Mode_Command(
|
|
2870
|
+
hci.HCI_Write_Inquiry_Mode_Command(
|
|
2871
|
+
inquiry_mode=hci.HCI_EXTENDED_INQUIRY_MODE
|
|
2872
|
+
),
|
|
2931
2873
|
check_result=True,
|
|
2932
2874
|
)
|
|
2933
2875
|
|
|
2934
2876
|
response = await self.send_command(
|
|
2935
|
-
HCI_Inquiry_Command(
|
|
2936
|
-
lap=HCI_GENERAL_INQUIRY_LAP,
|
|
2877
|
+
hci.HCI_Inquiry_Command(
|
|
2878
|
+
lap=hci.HCI_GENERAL_INQUIRY_LAP,
|
|
2937
2879
|
inquiry_length=DEVICE_DEFAULT_INQUIRY_LENGTH,
|
|
2938
2880
|
num_responses=0, # Unlimited number of responses.
|
|
2939
2881
|
)
|
|
2940
2882
|
)
|
|
2941
|
-
if response.status != HCI_Command_Status_Event.PENDING:
|
|
2883
|
+
if response.status != hci.HCI_Command_Status_Event.PENDING:
|
|
2942
2884
|
self.discovering = False
|
|
2943
|
-
raise HCI_StatusError(response)
|
|
2885
|
+
raise hci.HCI_StatusError(response)
|
|
2944
2886
|
|
|
2945
2887
|
self.auto_restart_inquiry = auto_restart
|
|
2946
2888
|
self.discovering = True
|
|
2947
2889
|
|
|
2948
2890
|
async def stop_discovery(self) -> None:
|
|
2949
2891
|
if self.discovering:
|
|
2950
|
-
await self.send_command(HCI_Inquiry_Cancel_Command(), check_result=True)
|
|
2892
|
+
await self.send_command(hci.HCI_Inquiry_Cancel_Command(), check_result=True)
|
|
2951
2893
|
self.auto_restart_inquiry = True
|
|
2952
2894
|
self.discovering = False
|
|
2953
2895
|
|
|
@@ -2972,7 +2914,7 @@ class Device(CompositeEventEmitter):
|
|
|
2972
2914
|
scan_enable = 0x00
|
|
2973
2915
|
|
|
2974
2916
|
return await self.send_command(
|
|
2975
|
-
HCI_Write_Scan_Enable_Command(scan_enable=scan_enable)
|
|
2917
|
+
hci.HCI_Write_Scan_Enable_Command(scan_enable=scan_enable)
|
|
2976
2918
|
)
|
|
2977
2919
|
|
|
2978
2920
|
async def set_discoverable(self, discoverable: bool = True) -> None:
|
|
@@ -2993,7 +2935,7 @@ class Device(CompositeEventEmitter):
|
|
|
2993
2935
|
|
|
2994
2936
|
# Update the controller
|
|
2995
2937
|
await self.send_command(
|
|
2996
|
-
HCI_Write_Extended_Inquiry_Response_Command(
|
|
2938
|
+
hci.HCI_Write_Extended_Inquiry_Response_Command(
|
|
2997
2939
|
fec_required=0, extended_inquiry_response=self.inquiry_response
|
|
2998
2940
|
),
|
|
2999
2941
|
check_result=True,
|
|
@@ -3013,12 +2955,12 @@ class Device(CompositeEventEmitter):
|
|
|
3013
2955
|
|
|
3014
2956
|
async def connect(
|
|
3015
2957
|
self,
|
|
3016
|
-
peer_address: Union[Address, str],
|
|
2958
|
+
peer_address: Union[hci.Address, str],
|
|
3017
2959
|
transport: int = BT_LE_TRANSPORT,
|
|
3018
2960
|
connection_parameters_preferences: Optional[
|
|
3019
2961
|
Dict[int, ConnectionParametersPreferences]
|
|
3020
2962
|
] = None,
|
|
3021
|
-
own_address_type: int = OwnAddressType.RANDOM,
|
|
2963
|
+
own_address_type: int = hci.OwnAddressType.RANDOM,
|
|
3022
2964
|
timeout: Optional[float] = DEVICE_DEFAULT_CONNECT_TIMEOUT,
|
|
3023
2965
|
always_resolve: bool = False,
|
|
3024
2966
|
) -> Connection:
|
|
@@ -3030,7 +2972,7 @@ class Device(CompositeEventEmitter):
|
|
|
3030
2972
|
|
|
3031
2973
|
Args:
|
|
3032
2974
|
peer_address:
|
|
3033
|
-
Address or name of the device to connect to.
|
|
2975
|
+
hci.Address or name of the device to connect to.
|
|
3034
2976
|
If a string is passed:
|
|
3035
2977
|
If the string is an address followed by a `@` suffix, the `always_resolve`
|
|
3036
2978
|
argument is implicitly set to True, so the connection is made to the
|
|
@@ -3050,8 +2992,8 @@ class Device(CompositeEventEmitter):
|
|
|
3050
2992
|
|
|
3051
2993
|
own_address_type:
|
|
3052
2994
|
(BLE only, ignored for BR/EDR)
|
|
3053
|
-
OwnAddressType.RANDOM to use this device's random address, or
|
|
3054
|
-
OwnAddressType.PUBLIC to use this device's public address.
|
|
2995
|
+
hci.OwnAddressType.RANDOM to use this device's random address, or
|
|
2996
|
+
hci.OwnAddressType.PUBLIC to use this device's public address.
|
|
3055
2997
|
|
|
3056
2998
|
timeout:
|
|
3057
2999
|
Maximum time to wait for a connection to be established, in seconds.
|
|
@@ -3080,13 +3022,13 @@ class Device(CompositeEventEmitter):
|
|
|
3080
3022
|
if isinstance(peer_address, str):
|
|
3081
3023
|
try:
|
|
3082
3024
|
if transport == BT_LE_TRANSPORT and peer_address.endswith('@'):
|
|
3083
|
-
peer_address = Address.from_string_for_transport(
|
|
3025
|
+
peer_address = hci.Address.from_string_for_transport(
|
|
3084
3026
|
peer_address[:-1], transport
|
|
3085
3027
|
)
|
|
3086
3028
|
always_resolve = True
|
|
3087
3029
|
logger.debug('forcing address resolution')
|
|
3088
3030
|
else:
|
|
3089
|
-
peer_address = Address.from_string_for_transport(
|
|
3031
|
+
peer_address = hci.Address.from_string_for_transport(
|
|
3090
3032
|
peer_address, transport
|
|
3091
3033
|
)
|
|
3092
3034
|
except (InvalidArgumentError, ValueError):
|
|
@@ -3100,11 +3042,11 @@ class Device(CompositeEventEmitter):
|
|
|
3100
3042
|
# All BR/EDR addresses should be public addresses
|
|
3101
3043
|
if (
|
|
3102
3044
|
transport == BT_BR_EDR_TRANSPORT
|
|
3103
|
-
and peer_address.address_type != Address.PUBLIC_DEVICE_ADDRESS
|
|
3045
|
+
and peer_address.address_type != hci.Address.PUBLIC_DEVICE_ADDRESS
|
|
3104
3046
|
):
|
|
3105
3047
|
raise InvalidArgumentError('BR/EDR addresses must be PUBLIC')
|
|
3106
3048
|
|
|
3107
|
-
assert isinstance(peer_address, Address)
|
|
3049
|
+
assert isinstance(peer_address, hci.Address)
|
|
3108
3050
|
|
|
3109
3051
|
if transport == BT_LE_TRANSPORT and always_resolve:
|
|
3110
3052
|
logger.debug('resolving address')
|
|
@@ -3139,13 +3081,13 @@ class Device(CompositeEventEmitter):
|
|
|
3139
3081
|
if connection_parameters_preferences is None:
|
|
3140
3082
|
if connection_parameters_preferences is None:
|
|
3141
3083
|
connection_parameters_preferences = {
|
|
3142
|
-
HCI_LE_1M_PHY: ConnectionParametersPreferences.default
|
|
3084
|
+
hci.HCI_LE_1M_PHY: ConnectionParametersPreferences.default
|
|
3143
3085
|
}
|
|
3144
3086
|
|
|
3145
3087
|
self.connect_own_address_type = own_address_type
|
|
3146
3088
|
|
|
3147
3089
|
if self.host.supports_command(
|
|
3148
|
-
HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
|
|
3090
|
+
hci.HCI_LE_EXTENDED_CREATE_CONNECTION_COMMAND
|
|
3149
3091
|
):
|
|
3150
3092
|
# Only keep supported PHYs
|
|
3151
3093
|
phys = sorted(
|
|
@@ -3162,7 +3104,7 @@ class Device(CompositeEventEmitter):
|
|
|
3162
3104
|
raise InvalidArgumentError('at least one supported PHY needed')
|
|
3163
3105
|
|
|
3164
3106
|
phy_count = len(phys)
|
|
3165
|
-
initiating_phys = phy_list_to_bits(phys)
|
|
3107
|
+
initiating_phys = hci.phy_list_to_bits(phys)
|
|
3166
3108
|
|
|
3167
3109
|
connection_interval_mins = [
|
|
3168
3110
|
int(
|
|
@@ -3207,7 +3149,7 @@ class Device(CompositeEventEmitter):
|
|
|
3207
3149
|
]
|
|
3208
3150
|
|
|
3209
3151
|
result = await self.send_command(
|
|
3210
|
-
HCI_LE_Extended_Create_Connection_Command(
|
|
3152
|
+
hci.HCI_LE_Extended_Create_Connection_Command(
|
|
3211
3153
|
initiator_filter_policy=0,
|
|
3212
3154
|
own_address_type=own_address_type,
|
|
3213
3155
|
peer_address_type=peer_address.address_type,
|
|
@@ -3230,12 +3172,12 @@ class Device(CompositeEventEmitter):
|
|
|
3230
3172
|
)
|
|
3231
3173
|
)
|
|
3232
3174
|
else:
|
|
3233
|
-
if HCI_LE_1M_PHY not in connection_parameters_preferences:
|
|
3175
|
+
if hci.HCI_LE_1M_PHY not in connection_parameters_preferences:
|
|
3234
3176
|
raise InvalidArgumentError('1M PHY preferences required')
|
|
3235
3177
|
|
|
3236
|
-
prefs = connection_parameters_preferences[HCI_LE_1M_PHY]
|
|
3178
|
+
prefs = connection_parameters_preferences[hci.HCI_LE_1M_PHY]
|
|
3237
3179
|
result = await self.send_command(
|
|
3238
|
-
HCI_LE_Create_Connection_Command(
|
|
3180
|
+
hci.HCI_LE_Create_Connection_Command(
|
|
3239
3181
|
le_scan_interval=int(
|
|
3240
3182
|
DEVICE_DEFAULT_CONNECT_SCAN_INTERVAL / 0.625
|
|
3241
3183
|
),
|
|
@@ -3266,18 +3208,18 @@ class Device(CompositeEventEmitter):
|
|
|
3266
3208
|
|
|
3267
3209
|
# TODO: allow passing other settings
|
|
3268
3210
|
result = await self.send_command(
|
|
3269
|
-
HCI_Create_Connection_Command(
|
|
3211
|
+
hci.HCI_Create_Connection_Command(
|
|
3270
3212
|
bd_addr=peer_address,
|
|
3271
3213
|
packet_type=0xCC18, # FIXME: change
|
|
3272
|
-
page_scan_repetition_mode=HCI_R2_PAGE_SCAN_REPETITION_MODE,
|
|
3214
|
+
page_scan_repetition_mode=hci.HCI_R2_PAGE_SCAN_REPETITION_MODE,
|
|
3273
3215
|
clock_offset=0x0000,
|
|
3274
3216
|
allow_role_switch=0x01,
|
|
3275
3217
|
reserved=0,
|
|
3276
3218
|
)
|
|
3277
3219
|
)
|
|
3278
3220
|
|
|
3279
|
-
if result.status != HCI_Command_Status_Event.PENDING:
|
|
3280
|
-
raise HCI_StatusError(result)
|
|
3221
|
+
if result.status != hci.HCI_Command_Status_Event.PENDING:
|
|
3222
|
+
raise hci.HCI_StatusError(result)
|
|
3281
3223
|
|
|
3282
3224
|
# Wait for the connection process to complete
|
|
3283
3225
|
if transport == BT_LE_TRANSPORT:
|
|
@@ -3292,10 +3234,12 @@ class Device(CompositeEventEmitter):
|
|
|
3292
3234
|
)
|
|
3293
3235
|
except asyncio.TimeoutError:
|
|
3294
3236
|
if transport == BT_LE_TRANSPORT:
|
|
3295
|
-
await self.send_command(
|
|
3237
|
+
await self.send_command(
|
|
3238
|
+
hci.HCI_LE_Create_Connection_Cancel_Command()
|
|
3239
|
+
)
|
|
3296
3240
|
else:
|
|
3297
3241
|
await self.send_command(
|
|
3298
|
-
HCI_Create_Connection_Cancel_Command(bd_addr=peer_address)
|
|
3242
|
+
hci.HCI_Create_Connection_Cancel_Command(bd_addr=peer_address)
|
|
3299
3243
|
)
|
|
3300
3244
|
|
|
3301
3245
|
try:
|
|
@@ -3313,7 +3257,7 @@ class Device(CompositeEventEmitter):
|
|
|
3313
3257
|
|
|
3314
3258
|
async def accept(
|
|
3315
3259
|
self,
|
|
3316
|
-
peer_address: Union[Address, str] = Address.ANY,
|
|
3260
|
+
peer_address: Union[hci.Address, str] = hci.Address.ANY,
|
|
3317
3261
|
role: int = BT_PERIPHERAL_ROLE,
|
|
3318
3262
|
timeout: Optional[float] = DEVICE_DEFAULT_CONNECT_TIMEOUT,
|
|
3319
3263
|
) -> Connection:
|
|
@@ -3330,7 +3274,7 @@ class Device(CompositeEventEmitter):
|
|
|
3330
3274
|
|
|
3331
3275
|
if isinstance(peer_address, str):
|
|
3332
3276
|
try:
|
|
3333
|
-
peer_address = Address(peer_address)
|
|
3277
|
+
peer_address = hci.Address(peer_address)
|
|
3334
3278
|
except InvalidArgumentError:
|
|
3335
3279
|
# If the address is not parsable, assume it is a name instead
|
|
3336
3280
|
logger.debug('looking for peer by name')
|
|
@@ -3338,16 +3282,16 @@ class Device(CompositeEventEmitter):
|
|
|
3338
3282
|
peer_address, BT_BR_EDR_TRANSPORT
|
|
3339
3283
|
) # TODO: timeout
|
|
3340
3284
|
|
|
3341
|
-
assert isinstance(peer_address, Address)
|
|
3285
|
+
assert isinstance(peer_address, hci.Address)
|
|
3342
3286
|
|
|
3343
|
-
if peer_address == Address.NIL:
|
|
3287
|
+
if peer_address == hci.Address.NIL:
|
|
3344
3288
|
raise InvalidArgumentError('accept on nil address')
|
|
3345
3289
|
|
|
3346
3290
|
# Create a future so that we can wait for the request
|
|
3347
3291
|
pending_request_fut = asyncio.get_running_loop().create_future()
|
|
3348
3292
|
|
|
3349
|
-
if peer_address == Address.ANY:
|
|
3350
|
-
self.classic_pending_accepts[Address.ANY].append(pending_request_fut)
|
|
3293
|
+
if peer_address == hci.Address.ANY:
|
|
3294
|
+
self.classic_pending_accepts[hci.Address.ANY].append(pending_request_fut)
|
|
3351
3295
|
elif peer_address in self.classic_pending_accepts:
|
|
3352
3296
|
raise InvalidStateError('accept connection already pending')
|
|
3353
3297
|
else:
|
|
@@ -3363,8 +3307,10 @@ class Device(CompositeEventEmitter):
|
|
|
3363
3307
|
)
|
|
3364
3308
|
except Exception:
|
|
3365
3309
|
# Remove future from device context
|
|
3366
|
-
if peer_address == Address.ANY:
|
|
3367
|
-
self.classic_pending_accepts[Address.ANY].remove(
|
|
3310
|
+
if peer_address == hci.Address.ANY:
|
|
3311
|
+
self.classic_pending_accepts[hci.Address.ANY].remove(
|
|
3312
|
+
pending_request_fut
|
|
3313
|
+
)
|
|
3368
3314
|
else:
|
|
3369
3315
|
self.classic_pending_accepts.pop(peer_address)
|
|
3370
3316
|
raise
|
|
@@ -3376,7 +3322,7 @@ class Device(CompositeEventEmitter):
|
|
|
3376
3322
|
|
|
3377
3323
|
# Otherwise, result came from `on_connection_request`
|
|
3378
3324
|
peer_address, _class_of_device, _link_type = result
|
|
3379
|
-
assert isinstance(peer_address, Address)
|
|
3325
|
+
assert isinstance(peer_address, hci.Address)
|
|
3380
3326
|
|
|
3381
3327
|
# Create a future so that we can wait for the connection's result
|
|
3382
3328
|
pending_connection = asyncio.get_running_loop().create_future()
|
|
@@ -3399,7 +3345,7 @@ class Device(CompositeEventEmitter):
|
|
|
3399
3345
|
self.on('connection_failure', on_connection_failure)
|
|
3400
3346
|
|
|
3401
3347
|
# Save pending connection, with the Peripheral role.
|
|
3402
|
-
# Even if we requested a role switch in the HCI_Accept_Connection_Request
|
|
3348
|
+
# Even if we requested a role switch in the hci.HCI_Accept_Connection_Request
|
|
3403
3349
|
# command, this connection is still considered Peripheral until an eventual
|
|
3404
3350
|
# role change event.
|
|
3405
3351
|
self.pending_connections[peer_address] = Connection.incomplete(
|
|
@@ -3409,7 +3355,9 @@ class Device(CompositeEventEmitter):
|
|
|
3409
3355
|
try:
|
|
3410
3356
|
# Accept connection request
|
|
3411
3357
|
await self.send_command(
|
|
3412
|
-
HCI_Accept_Connection_Request_Command(
|
|
3358
|
+
hci.HCI_Accept_Connection_Request_Command(
|
|
3359
|
+
bd_addr=peer_address, role=role
|
|
3360
|
+
)
|
|
3413
3361
|
)
|
|
3414
3362
|
|
|
3415
3363
|
# Wait for connection complete
|
|
@@ -3444,7 +3392,7 @@ class Device(CompositeEventEmitter):
|
|
|
3444
3392
|
if not self.is_le_connecting:
|
|
3445
3393
|
return
|
|
3446
3394
|
await self.send_command(
|
|
3447
|
-
HCI_LE_Create_Connection_Cancel_Command(), check_result=True
|
|
3395
|
+
hci.HCI_LE_Create_Connection_Cancel_Command(), check_result=True
|
|
3448
3396
|
)
|
|
3449
3397
|
|
|
3450
3398
|
# BR/EDR: try to cancel to ongoing connection
|
|
@@ -3453,7 +3401,7 @@ class Device(CompositeEventEmitter):
|
|
|
3453
3401
|
else:
|
|
3454
3402
|
if isinstance(peer_address, str):
|
|
3455
3403
|
try:
|
|
3456
|
-
peer_address = Address(peer_address)
|
|
3404
|
+
peer_address = hci.Address(peer_address)
|
|
3457
3405
|
except InvalidArgumentError:
|
|
3458
3406
|
# If the address is not parsable, assume it is a name instead
|
|
3459
3407
|
logger.debug('looking for peer by name')
|
|
@@ -3462,7 +3410,7 @@ class Device(CompositeEventEmitter):
|
|
|
3462
3410
|
) # TODO: timeout
|
|
3463
3411
|
|
|
3464
3412
|
await self.send_command(
|
|
3465
|
-
HCI_Create_Connection_Cancel_Command(bd_addr=peer_address),
|
|
3413
|
+
hci.HCI_Create_Connection_Cancel_Command(bd_addr=peer_address),
|
|
3466
3414
|
check_result=True,
|
|
3467
3415
|
)
|
|
3468
3416
|
|
|
@@ -3476,12 +3424,14 @@ class Device(CompositeEventEmitter):
|
|
|
3476
3424
|
|
|
3477
3425
|
# Request a disconnection
|
|
3478
3426
|
result = await self.send_command(
|
|
3479
|
-
HCI_Disconnect_Command(
|
|
3427
|
+
hci.HCI_Disconnect_Command(
|
|
3428
|
+
connection_handle=connection.handle, reason=reason
|
|
3429
|
+
)
|
|
3480
3430
|
)
|
|
3481
3431
|
|
|
3482
3432
|
try:
|
|
3483
|
-
if result.status != HCI_Command_Status_Event.PENDING:
|
|
3484
|
-
raise HCI_StatusError(result)
|
|
3433
|
+
if result.status != hci.HCI_Command_Status_Event.PENDING:
|
|
3434
|
+
raise hci.HCI_StatusError(result)
|
|
3485
3435
|
|
|
3486
3436
|
# Wait for the disconnection process to complete
|
|
3487
3437
|
self.disconnecting = True
|
|
@@ -3503,7 +3453,7 @@ class Device(CompositeEventEmitter):
|
|
|
3503
3453
|
raise InvalidArgumentError('tx_time must be between 0x0148 and 0x4290')
|
|
3504
3454
|
|
|
3505
3455
|
return await self.send_command(
|
|
3506
|
-
HCI_LE_Set_Data_Length_Command(
|
|
3456
|
+
hci.HCI_LE_Set_Data_Length_Command(
|
|
3507
3457
|
connection_handle=connection.handle,
|
|
3508
3458
|
tx_octets=tx_octets,
|
|
3509
3459
|
tx_time=tx_time,
|
|
@@ -3545,7 +3495,7 @@ class Device(CompositeEventEmitter):
|
|
|
3545
3495
|
raise ConnectionParameterUpdateError(l2cap_result)
|
|
3546
3496
|
|
|
3547
3497
|
result = await self.send_command(
|
|
3548
|
-
HCI_LE_Connection_Update_Command(
|
|
3498
|
+
hci.HCI_LE_Connection_Update_Command(
|
|
3549
3499
|
connection_handle=connection.handle,
|
|
3550
3500
|
connection_interval_min=connection_interval_min,
|
|
3551
3501
|
connection_interval_max=connection_interval_max,
|
|
@@ -3555,18 +3505,18 @@ class Device(CompositeEventEmitter):
|
|
|
3555
3505
|
max_ce_length=max_ce_length,
|
|
3556
3506
|
)
|
|
3557
3507
|
)
|
|
3558
|
-
if result.status != HCI_Command_Status_Event.PENDING:
|
|
3559
|
-
raise HCI_StatusError(result)
|
|
3508
|
+
if result.status != hci.HCI_Command_Status_Event.PENDING:
|
|
3509
|
+
raise hci.HCI_StatusError(result)
|
|
3560
3510
|
|
|
3561
3511
|
async def get_connection_rssi(self, connection):
|
|
3562
3512
|
result = await self.send_command(
|
|
3563
|
-
HCI_Read_RSSI_Command(handle=connection.handle), check_result=True
|
|
3513
|
+
hci.HCI_Read_RSSI_Command(handle=connection.handle), check_result=True
|
|
3564
3514
|
)
|
|
3565
3515
|
return result.return_parameters.rssi
|
|
3566
3516
|
|
|
3567
3517
|
async def get_connection_phy(self, connection):
|
|
3568
3518
|
result = await self.send_command(
|
|
3569
|
-
HCI_LE_Read_PHY_Command(connection_handle=connection.handle),
|
|
3519
|
+
hci.HCI_LE_Read_PHY_Command(connection_handle=connection.handle),
|
|
3570
3520
|
check_result=True,
|
|
3571
3521
|
)
|
|
3572
3522
|
return (result.return_parameters.tx_phy, result.return_parameters.rx_phy)
|
|
@@ -3574,7 +3524,7 @@ class Device(CompositeEventEmitter):
|
|
|
3574
3524
|
async def set_connection_phy(
|
|
3575
3525
|
self, connection, tx_phys=None, rx_phys=None, phy_options=None
|
|
3576
3526
|
):
|
|
3577
|
-
if not self.host.supports_command(HCI_LE_SET_PHY_COMMAND):
|
|
3527
|
+
if not self.host.supports_command(hci.HCI_LE_SET_PHY_COMMAND):
|
|
3578
3528
|
logger.warning('ignoring request, command not supported')
|
|
3579
3529
|
return
|
|
3580
3530
|
|
|
@@ -3583,21 +3533,21 @@ class Device(CompositeEventEmitter):
|
|
|
3583
3533
|
)
|
|
3584
3534
|
|
|
3585
3535
|
result = await self.send_command(
|
|
3586
|
-
HCI_LE_Set_PHY_Command(
|
|
3536
|
+
hci.HCI_LE_Set_PHY_Command(
|
|
3587
3537
|
connection_handle=connection.handle,
|
|
3588
3538
|
all_phys=all_phys_bits,
|
|
3589
|
-
tx_phys=phy_list_to_bits(tx_phys),
|
|
3590
|
-
rx_phys=phy_list_to_bits(rx_phys),
|
|
3539
|
+
tx_phys=hci.phy_list_to_bits(tx_phys),
|
|
3540
|
+
rx_phys=hci.phy_list_to_bits(rx_phys),
|
|
3591
3541
|
phy_options=0 if phy_options is None else int(phy_options),
|
|
3592
3542
|
)
|
|
3593
3543
|
)
|
|
3594
3544
|
|
|
3595
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3545
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3596
3546
|
logger.warning(
|
|
3597
3547
|
'HCI_LE_Set_PHY_Command failed: '
|
|
3598
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3548
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3599
3549
|
)
|
|
3600
|
-
raise HCI_StatusError(result)
|
|
3550
|
+
raise hci.HCI_StatusError(result)
|
|
3601
3551
|
|
|
3602
3552
|
async def set_default_phy(self, tx_phys=None, rx_phys=None):
|
|
3603
3553
|
all_phys_bits = (1 if tx_phys is None else 0) | (
|
|
@@ -3605,10 +3555,10 @@ class Device(CompositeEventEmitter):
|
|
|
3605
3555
|
)
|
|
3606
3556
|
|
|
3607
3557
|
return await self.send_command(
|
|
3608
|
-
HCI_LE_Set_Default_PHY_Command(
|
|
3558
|
+
hci.HCI_LE_Set_Default_PHY_Command(
|
|
3609
3559
|
all_phys=all_phys_bits,
|
|
3610
|
-
tx_phys=phy_list_to_bits(tx_phys),
|
|
3611
|
-
rx_phys=phy_list_to_bits(rx_phys),
|
|
3560
|
+
tx_phys=hci.phy_list_to_bits(tx_phys),
|
|
3561
|
+
rx_phys=hci.phy_list_to_bits(rx_phys),
|
|
3612
3562
|
),
|
|
3613
3563
|
check_result=True,
|
|
3614
3564
|
)
|
|
@@ -3617,7 +3567,7 @@ class Device(CompositeEventEmitter):
|
|
|
3617
3567
|
self, connection: Connection, sync_handle: int, service_data: int = 0
|
|
3618
3568
|
) -> None:
|
|
3619
3569
|
return await self.send_command(
|
|
3620
|
-
HCI_LE_Periodic_Advertising_Sync_Transfer_Command(
|
|
3570
|
+
hci.HCI_LE_Periodic_Advertising_Sync_Transfer_Command(
|
|
3621
3571
|
connection_handle=connection.handle,
|
|
3622
3572
|
service_data=service_data,
|
|
3623
3573
|
sync_handle=sync_handle,
|
|
@@ -3681,7 +3631,9 @@ class Device(CompositeEventEmitter):
|
|
|
3681
3631
|
elif transport == BT_BR_EDR_TRANSPORT and not was_discovering:
|
|
3682
3632
|
await self.stop_discovery()
|
|
3683
3633
|
|
|
3684
|
-
async def find_peer_by_identity_address(
|
|
3634
|
+
async def find_peer_by_identity_address(
|
|
3635
|
+
self, identity_address: hci.Address
|
|
3636
|
+
) -> hci.Address:
|
|
3685
3637
|
"""
|
|
3686
3638
|
Scan for a peer with a resolvable address that can be resolved to a given
|
|
3687
3639
|
identity address.
|
|
@@ -3777,7 +3729,7 @@ class Device(CompositeEventEmitter):
|
|
|
3777
3729
|
return keys.ltk_peripheral.value
|
|
3778
3730
|
return None
|
|
3779
3731
|
|
|
3780
|
-
async def get_link_key(self, address: Address) -> Optional[bytes]:
|
|
3732
|
+
async def get_link_key(self, address: hci.Address) -> Optional[bytes]:
|
|
3781
3733
|
if self.keystore is None:
|
|
3782
3734
|
return None
|
|
3783
3735
|
|
|
@@ -3803,7 +3755,7 @@ class Device(CompositeEventEmitter):
|
|
|
3803
3755
|
pending_authentication.set_result(None)
|
|
3804
3756
|
|
|
3805
3757
|
def on_authentication_failure(error_code):
|
|
3806
|
-
pending_authentication.set_exception(HCI_Error(error_code))
|
|
3758
|
+
pending_authentication.set_exception(hci.HCI_Error(error_code))
|
|
3807
3759
|
|
|
3808
3760
|
connection.on('connection_authentication', on_authentication)
|
|
3809
3761
|
connection.on('connection_authentication_failure', on_authentication_failure)
|
|
@@ -3811,16 +3763,16 @@ class Device(CompositeEventEmitter):
|
|
|
3811
3763
|
# Request the authentication
|
|
3812
3764
|
try:
|
|
3813
3765
|
result = await self.send_command(
|
|
3814
|
-
HCI_Authentication_Requested_Command(
|
|
3766
|
+
hci.HCI_Authentication_Requested_Command(
|
|
3815
3767
|
connection_handle=connection.handle
|
|
3816
3768
|
)
|
|
3817
3769
|
)
|
|
3818
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3770
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3819
3771
|
logger.warning(
|
|
3820
3772
|
'HCI_Authentication_Requested_Command failed: '
|
|
3821
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3773
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3822
3774
|
)
|
|
3823
|
-
raise HCI_StatusError(result)
|
|
3775
|
+
raise hci.HCI_StatusError(result)
|
|
3824
3776
|
|
|
3825
3777
|
# Wait for the authentication to complete
|
|
3826
3778
|
await connection.abort_on('disconnection', pending_authentication)
|
|
@@ -3841,7 +3793,7 @@ class Device(CompositeEventEmitter):
|
|
|
3841
3793
|
pending_encryption.set_result(None)
|
|
3842
3794
|
|
|
3843
3795
|
def on_encryption_failure(error_code):
|
|
3844
|
-
pending_encryption.set_exception(HCI_Error(error_code))
|
|
3796
|
+
pending_encryption.set_exception(hci.HCI_Error(error_code))
|
|
3845
3797
|
|
|
3846
3798
|
connection.on('connection_encryption_change', on_encryption_change)
|
|
3847
3799
|
connection.on('connection_encryption_failure', on_encryption_failure)
|
|
@@ -3869,11 +3821,11 @@ class Device(CompositeEventEmitter):
|
|
|
3869
3821
|
else:
|
|
3870
3822
|
raise InvalidOperationError('no LTK found for peer')
|
|
3871
3823
|
|
|
3872
|
-
if connection.role != HCI_CENTRAL_ROLE:
|
|
3824
|
+
if connection.role != hci.HCI_CENTRAL_ROLE:
|
|
3873
3825
|
raise InvalidStateError('only centrals can start encryption')
|
|
3874
3826
|
|
|
3875
3827
|
result = await self.send_command(
|
|
3876
|
-
HCI_LE_Enable_Encryption_Command(
|
|
3828
|
+
hci.HCI_LE_Enable_Encryption_Command(
|
|
3877
3829
|
connection_handle=connection.handle,
|
|
3878
3830
|
random_number=rand,
|
|
3879
3831
|
encrypted_diversifier=ediv,
|
|
@@ -3881,26 +3833,26 @@ class Device(CompositeEventEmitter):
|
|
|
3881
3833
|
)
|
|
3882
3834
|
)
|
|
3883
3835
|
|
|
3884
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3836
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3885
3837
|
logger.warning(
|
|
3886
3838
|
'HCI_LE_Enable_Encryption_Command failed: '
|
|
3887
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3839
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3888
3840
|
)
|
|
3889
|
-
raise HCI_StatusError(result)
|
|
3841
|
+
raise hci.HCI_StatusError(result)
|
|
3890
3842
|
else:
|
|
3891
3843
|
result = await self.send_command(
|
|
3892
|
-
HCI_Set_Connection_Encryption_Command(
|
|
3844
|
+
hci.HCI_Set_Connection_Encryption_Command(
|
|
3893
3845
|
connection_handle=connection.handle,
|
|
3894
3846
|
encryption_enable=0x01 if enable else 0x00,
|
|
3895
3847
|
)
|
|
3896
3848
|
)
|
|
3897
3849
|
|
|
3898
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3850
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3899
3851
|
logger.warning(
|
|
3900
3852
|
'HCI_Set_Connection_Encryption_Command failed: '
|
|
3901
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3853
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3902
3854
|
)
|
|
3903
|
-
raise HCI_StatusError(result)
|
|
3855
|
+
raise hci.HCI_StatusError(result)
|
|
3904
3856
|
|
|
3905
3857
|
# Wait for the result
|
|
3906
3858
|
await connection.abort_on('disconnection', pending_encryption)
|
|
@@ -3932,32 +3884,34 @@ class Device(CompositeEventEmitter):
|
|
|
3932
3884
|
pending_role_change.set_result(new_role)
|
|
3933
3885
|
|
|
3934
3886
|
def on_role_change_failure(error_code):
|
|
3935
|
-
pending_role_change.set_exception(HCI_Error(error_code))
|
|
3887
|
+
pending_role_change.set_exception(hci.HCI_Error(error_code))
|
|
3936
3888
|
|
|
3937
3889
|
connection.on('role_change', on_role_change)
|
|
3938
3890
|
connection.on('role_change_failure', on_role_change_failure)
|
|
3939
3891
|
|
|
3940
3892
|
try:
|
|
3941
3893
|
result = await self.send_command(
|
|
3942
|
-
HCI_Switch_Role_Command(bd_addr=connection.peer_address, role=role)
|
|
3894
|
+
hci.HCI_Switch_Role_Command(bd_addr=connection.peer_address, role=role)
|
|
3943
3895
|
)
|
|
3944
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3896
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3945
3897
|
logger.warning(
|
|
3946
3898
|
'HCI_Switch_Role_Command failed: '
|
|
3947
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3899
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3948
3900
|
)
|
|
3949
|
-
raise HCI_StatusError(result)
|
|
3901
|
+
raise hci.HCI_StatusError(result)
|
|
3950
3902
|
await connection.abort_on('disconnection', pending_role_change)
|
|
3951
3903
|
finally:
|
|
3952
3904
|
connection.remove_listener('role_change', on_role_change)
|
|
3953
3905
|
connection.remove_listener('role_change_failure', on_role_change_failure)
|
|
3954
3906
|
|
|
3955
3907
|
# [Classic only]
|
|
3956
|
-
async def request_remote_name(self, remote: Union[Address, Connection]) -> str:
|
|
3908
|
+
async def request_remote_name(self, remote: Union[hci.Address, Connection]) -> str:
|
|
3957
3909
|
# Set up event handlers
|
|
3958
3910
|
pending_name = asyncio.get_running_loop().create_future()
|
|
3959
3911
|
|
|
3960
|
-
peer_address =
|
|
3912
|
+
peer_address = (
|
|
3913
|
+
remote if isinstance(remote, hci.Address) else remote.peer_address
|
|
3914
|
+
)
|
|
3961
3915
|
|
|
3962
3916
|
handler = self.on(
|
|
3963
3917
|
'remote_name',
|
|
@@ -3970,7 +3924,7 @@ class Device(CompositeEventEmitter):
|
|
|
3970
3924
|
failure_handler = self.on(
|
|
3971
3925
|
'remote_name_failure',
|
|
3972
3926
|
lambda address, error_code: (
|
|
3973
|
-
pending_name.set_exception(HCI_Error(error_code))
|
|
3927
|
+
pending_name.set_exception(hci.HCI_Error(error_code))
|
|
3974
3928
|
if address == peer_address
|
|
3975
3929
|
else None
|
|
3976
3930
|
),
|
|
@@ -3978,20 +3932,20 @@ class Device(CompositeEventEmitter):
|
|
|
3978
3932
|
|
|
3979
3933
|
try:
|
|
3980
3934
|
result = await self.send_command(
|
|
3981
|
-
HCI_Remote_Name_Request_Command(
|
|
3935
|
+
hci.HCI_Remote_Name_Request_Command(
|
|
3982
3936
|
bd_addr=peer_address,
|
|
3983
|
-
page_scan_repetition_mode=HCI_Remote_Name_Request_Command.R2,
|
|
3937
|
+
page_scan_repetition_mode=hci.HCI_Remote_Name_Request_Command.R2,
|
|
3984
3938
|
reserved=0,
|
|
3985
3939
|
clock_offset=0, # TODO investigate non-0 values
|
|
3986
3940
|
)
|
|
3987
3941
|
)
|
|
3988
3942
|
|
|
3989
|
-
if result.status != HCI_COMMAND_STATUS_PENDING:
|
|
3943
|
+
if result.status != hci.HCI_COMMAND_STATUS_PENDING:
|
|
3990
3944
|
logger.warning(
|
|
3991
3945
|
'HCI_Remote_Name_Request_Command failed: '
|
|
3992
|
-
f'{HCI_Constant.error_name(result.status)}'
|
|
3946
|
+
f'{hci.HCI_Constant.error_name(result.status)}'
|
|
3993
3947
|
)
|
|
3994
|
-
raise HCI_StatusError(result)
|
|
3948
|
+
raise hci.HCI_StatusError(result)
|
|
3995
3949
|
|
|
3996
3950
|
# Wait for the result
|
|
3997
3951
|
return await self.abort_on('flush', pending_name)
|
|
@@ -4011,7 +3965,7 @@ class Device(CompositeEventEmitter):
|
|
|
4011
3965
|
retransmission_number: int,
|
|
4012
3966
|
max_transport_latency: Tuple[int, int],
|
|
4013
3967
|
) -> List[int]:
|
|
4014
|
-
"""Sends HCI_LE_Set_CIG_Parameters_Command.
|
|
3968
|
+
"""Sends hci.HCI_LE_Set_CIG_Parameters_Command.
|
|
4015
3969
|
|
|
4016
3970
|
Args:
|
|
4017
3971
|
cig_id: CIG_ID.
|
|
@@ -4029,7 +3983,7 @@ class Device(CompositeEventEmitter):
|
|
|
4029
3983
|
num_cis = len(cis_id)
|
|
4030
3984
|
|
|
4031
3985
|
response = await self.send_command(
|
|
4032
|
-
HCI_LE_Set_CIG_Parameters_Command(
|
|
3986
|
+
hci.HCI_LE_Set_CIG_Parameters_Command(
|
|
4033
3987
|
cig_id=cig_id,
|
|
4034
3988
|
sdu_interval_c_to_p=sdu_interval[0],
|
|
4035
3989
|
sdu_interval_p_to_c=sdu_interval[1],
|
|
@@ -4041,8 +3995,8 @@ class Device(CompositeEventEmitter):
|
|
|
4041
3995
|
cis_id=cis_id,
|
|
4042
3996
|
max_sdu_c_to_p=[max_sdu[0]] * num_cis,
|
|
4043
3997
|
max_sdu_p_to_c=[max_sdu[1]] * num_cis,
|
|
4044
|
-
phy_c_to_p=[HCI_LE_2M_PHY] * num_cis,
|
|
4045
|
-
phy_p_to_c=[HCI_LE_2M_PHY] * num_cis,
|
|
3998
|
+
phy_c_to_p=[hci.HCI_LE_2M_PHY] * num_cis,
|
|
3999
|
+
phy_p_to_c=[hci.HCI_LE_2M_PHY] * num_cis,
|
|
4046
4000
|
rtn_c_to_p=[retransmission_number] * num_cis,
|
|
4047
4001
|
rtn_p_to_c=[retransmission_number] * num_cis,
|
|
4048
4002
|
),
|
|
@@ -4084,12 +4038,12 @@ class Device(CompositeEventEmitter):
|
|
|
4084
4038
|
|
|
4085
4039
|
def on_cis_establishment_failure(cis_handle: int, status: int) -> None:
|
|
4086
4040
|
if pending_future := pending_cis_establishments.get(cis_handle):
|
|
4087
|
-
pending_future.set_exception(HCI_Error(status))
|
|
4041
|
+
pending_future.set_exception(hci.HCI_Error(status))
|
|
4088
4042
|
|
|
4089
4043
|
watcher.on(self, 'cis_establishment', on_cis_establishment)
|
|
4090
4044
|
watcher.on(self, 'cis_establishment_failure', on_cis_establishment_failure)
|
|
4091
4045
|
await self.send_command(
|
|
4092
|
-
HCI_LE_Create_CIS_Command(
|
|
4046
|
+
hci.HCI_LE_Create_CIS_Command(
|
|
4093
4047
|
cis_connection_handle=[p[0] for p in cis_acl_pairs],
|
|
4094
4048
|
acl_connection_handle=[p[1] for p in cis_acl_pairs],
|
|
4095
4049
|
),
|
|
@@ -4128,13 +4082,13 @@ class Device(CompositeEventEmitter):
|
|
|
4128
4082
|
pending_establishment.set_result(None)
|
|
4129
4083
|
|
|
4130
4084
|
def on_establishment_failure(status: int) -> None:
|
|
4131
|
-
pending_establishment.set_exception(HCI_Error(status))
|
|
4085
|
+
pending_establishment.set_exception(hci.HCI_Error(status))
|
|
4132
4086
|
|
|
4133
4087
|
watcher.on(cis_link, 'establishment', on_establishment)
|
|
4134
4088
|
watcher.on(cis_link, 'establishment_failure', on_establishment_failure)
|
|
4135
4089
|
|
|
4136
4090
|
await self.send_command(
|
|
4137
|
-
HCI_LE_Accept_CIS_Request_Command(connection_handle=handle),
|
|
4091
|
+
hci.HCI_LE_Accept_CIS_Request_Command(connection_handle=handle),
|
|
4138
4092
|
check_result=True,
|
|
4139
4093
|
)
|
|
4140
4094
|
|
|
@@ -4149,14 +4103,16 @@ class Device(CompositeEventEmitter):
|
|
|
4149
4103
|
async def reject_cis_request(
|
|
4150
4104
|
self,
|
|
4151
4105
|
handle: int,
|
|
4152
|
-
reason: int = HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
4106
|
+
reason: int = hci.HCI_REMOTE_USER_TERMINATED_CONNECTION_ERROR,
|
|
4153
4107
|
) -> None:
|
|
4154
4108
|
await self.send_command(
|
|
4155
|
-
HCI_LE_Reject_CIS_Request_Command(
|
|
4109
|
+
hci.HCI_LE_Reject_CIS_Request_Command(
|
|
4110
|
+
connection_handle=handle, reason=reason
|
|
4111
|
+
),
|
|
4156
4112
|
check_result=True,
|
|
4157
4113
|
)
|
|
4158
4114
|
|
|
4159
|
-
async def get_remote_le_features(self, connection: Connection) -> LeFeatureMask:
|
|
4115
|
+
async def get_remote_le_features(self, connection: Connection) -> hci.LeFeatureMask:
|
|
4160
4116
|
"""[LE Only] Reads remote LE supported features.
|
|
4161
4117
|
|
|
4162
4118
|
Args:
|
|
@@ -4166,22 +4122,22 @@ class Device(CompositeEventEmitter):
|
|
|
4166
4122
|
LE features supported by the remote device.
|
|
4167
4123
|
"""
|
|
4168
4124
|
with closing(EventWatcher()) as watcher:
|
|
4169
|
-
read_feature_future: asyncio.Future[LeFeatureMask] = (
|
|
4125
|
+
read_feature_future: asyncio.Future[hci.LeFeatureMask] = (
|
|
4170
4126
|
asyncio.get_running_loop().create_future()
|
|
4171
4127
|
)
|
|
4172
4128
|
|
|
4173
4129
|
def on_le_remote_features(handle: int, features: int):
|
|
4174
4130
|
if handle == connection.handle:
|
|
4175
|
-
read_feature_future.set_result(LeFeatureMask(features))
|
|
4131
|
+
read_feature_future.set_result(hci.LeFeatureMask(features))
|
|
4176
4132
|
|
|
4177
4133
|
def on_failure(handle: int, status: int):
|
|
4178
4134
|
if handle == connection.handle:
|
|
4179
|
-
read_feature_future.set_exception(HCI_Error(status))
|
|
4135
|
+
read_feature_future.set_exception(hci.HCI_Error(status))
|
|
4180
4136
|
|
|
4181
4137
|
watcher.on(self.host, 'le_remote_features', on_le_remote_features)
|
|
4182
4138
|
watcher.on(self.host, 'le_remote_features_failure', on_failure)
|
|
4183
4139
|
await self.send_command(
|
|
4184
|
-
HCI_LE_Read_Remote_Features_Command(
|
|
4140
|
+
hci.HCI_LE_Read_Remote_Features_Command(
|
|
4185
4141
|
connection_handle=connection.handle
|
|
4186
4142
|
),
|
|
4187
4143
|
check_result=True,
|
|
@@ -4201,8 +4157,8 @@ class Device(CompositeEventEmitter):
|
|
|
4201
4157
|
# Store the keys in the key store
|
|
4202
4158
|
if self.keystore:
|
|
4203
4159
|
authenticated = key_type in (
|
|
4204
|
-
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
|
|
4205
|
-
HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
|
|
4160
|
+
hci.HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_192_TYPE,
|
|
4161
|
+
hci.HCI_AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P_256_TYPE,
|
|
4206
4162
|
)
|
|
4207
4163
|
pairing_keys = PairingKeys()
|
|
4208
4164
|
pairing_keys.link_key = PairingKeys.Key(
|
|
@@ -4256,7 +4212,7 @@ class Device(CompositeEventEmitter):
|
|
|
4256
4212
|
|
|
4257
4213
|
advertising_set.on_termination(status)
|
|
4258
4214
|
|
|
4259
|
-
if status != HCI_SUCCESS:
|
|
4215
|
+
if status != hci.HCI_SUCCESS:
|
|
4260
4216
|
logger.debug(
|
|
4261
4217
|
f'advertising set {advertising_handle} '
|
|
4262
4218
|
f'terminated with status {status}'
|
|
@@ -4285,13 +4241,13 @@ class Device(CompositeEventEmitter):
|
|
|
4285
4241
|
advertising_set.random_address
|
|
4286
4242
|
if advertising_set.random_address is not None
|
|
4287
4243
|
and advertising_set.advertising_parameters.own_address_type
|
|
4288
|
-
in (OwnAddressType.RANDOM, OwnAddressType.RESOLVABLE_OR_RANDOM)
|
|
4244
|
+
in (hci.OwnAddressType.RANDOM, hci.OwnAddressType.RESOLVABLE_OR_RANDOM)
|
|
4289
4245
|
else self.public_address
|
|
4290
4246
|
)
|
|
4291
4247
|
|
|
4292
4248
|
if advertising_set.advertising_parameters.own_address_type in (
|
|
4293
|
-
OwnAddressType.RANDOM,
|
|
4294
|
-
OwnAddressType.PUBLIC,
|
|
4249
|
+
hci.OwnAddressType.RANDOM,
|
|
4250
|
+
hci.OwnAddressType.PUBLIC,
|
|
4295
4251
|
):
|
|
4296
4252
|
connection.self_resolvable_address = None
|
|
4297
4253
|
|
|
@@ -4307,11 +4263,11 @@ class Device(CompositeEventEmitter):
|
|
|
4307
4263
|
def _emit_le_connection(self, connection: Connection) -> None:
|
|
4308
4264
|
# If supported, read which PHY we're connected with before
|
|
4309
4265
|
# notifying listeners of the new connection.
|
|
4310
|
-
if self.host.supports_command(HCI_LE_READ_PHY_COMMAND):
|
|
4266
|
+
if self.host.supports_command(hci.HCI_LE_READ_PHY_COMMAND):
|
|
4311
4267
|
|
|
4312
4268
|
async def read_phy():
|
|
4313
4269
|
result = await self.send_command(
|
|
4314
|
-
HCI_LE_Read_PHY_Command(connection_handle=connection.handle),
|
|
4270
|
+
hci.HCI_LE_Read_PHY_Command(connection_handle=connection.handle),
|
|
4315
4271
|
check_result=True,
|
|
4316
4272
|
)
|
|
4317
4273
|
connection.phy = ConnectionPHY(
|
|
@@ -4332,24 +4288,24 @@ class Device(CompositeEventEmitter):
|
|
|
4332
4288
|
self,
|
|
4333
4289
|
connection_handle: int,
|
|
4334
4290
|
transport: int,
|
|
4335
|
-
peer_address: Address,
|
|
4336
|
-
self_resolvable_address: Optional[Address],
|
|
4337
|
-
peer_resolvable_address: Optional[Address],
|
|
4291
|
+
peer_address: hci.Address,
|
|
4292
|
+
self_resolvable_address: Optional[hci.Address],
|
|
4293
|
+
peer_resolvable_address: Optional[hci.Address],
|
|
4338
4294
|
role: int,
|
|
4339
4295
|
connection_parameters: ConnectionParameters,
|
|
4340
4296
|
) -> None:
|
|
4341
4297
|
# Convert all-zeros addresses into None.
|
|
4342
|
-
if self_resolvable_address == Address.ANY_RANDOM:
|
|
4298
|
+
if self_resolvable_address == hci.Address.ANY_RANDOM:
|
|
4343
4299
|
self_resolvable_address = None
|
|
4344
4300
|
if (
|
|
4345
|
-
peer_resolvable_address == Address.ANY_RANDOM
|
|
4301
|
+
peer_resolvable_address == hci.Address.ANY_RANDOM
|
|
4346
4302
|
or not peer_address.is_resolved
|
|
4347
4303
|
):
|
|
4348
4304
|
peer_resolvable_address = None
|
|
4349
4305
|
|
|
4350
4306
|
logger.debug(
|
|
4351
4307
|
f'*** Connection: [0x{connection_handle:04X}] '
|
|
4352
|
-
f'{peer_address} {"" if role is None else HCI_Constant.role_name(role)}'
|
|
4308
|
+
f'{peer_address} {"" if role is None else hci.HCI_Constant.role_name(role)}'
|
|
4353
4309
|
)
|
|
4354
4310
|
if connection_handle in self.connections:
|
|
4355
4311
|
logger.warning(
|
|
@@ -4373,20 +4329,20 @@ class Device(CompositeEventEmitter):
|
|
|
4373
4329
|
if peer_address.is_resolvable:
|
|
4374
4330
|
resolved_address = self.address_resolver.resolve(peer_address)
|
|
4375
4331
|
if resolved_address is not None:
|
|
4376
|
-
logger.debug(f'*** Address resolved as {resolved_address}')
|
|
4332
|
+
logger.debug(f'*** hci.Address resolved as {resolved_address}')
|
|
4377
4333
|
peer_resolvable_address = peer_address
|
|
4378
4334
|
peer_address = resolved_address
|
|
4379
4335
|
|
|
4380
4336
|
self_address = None
|
|
4381
4337
|
own_address_type: Optional[int] = None
|
|
4382
|
-
if role == HCI_CENTRAL_ROLE:
|
|
4338
|
+
if role == hci.HCI_CENTRAL_ROLE:
|
|
4383
4339
|
own_address_type = self.connect_own_address_type
|
|
4384
4340
|
assert own_address_type is not None
|
|
4385
4341
|
else:
|
|
4386
4342
|
if self.supports_le_extended_advertising:
|
|
4387
4343
|
# We'll know the address when the advertising set terminates,
|
|
4388
4344
|
# Use a temporary placeholder value for self_address.
|
|
4389
|
-
self_address = Address.ANY_RANDOM
|
|
4345
|
+
self_address = hci.Address.ANY_RANDOM
|
|
4390
4346
|
else:
|
|
4391
4347
|
# We were connected via a legacy advertisement.
|
|
4392
4348
|
if self.legacy_advertiser:
|
|
@@ -4401,15 +4357,15 @@ class Device(CompositeEventEmitter):
|
|
|
4401
4357
|
self.public_address
|
|
4402
4358
|
if own_address_type
|
|
4403
4359
|
in (
|
|
4404
|
-
OwnAddressType.PUBLIC,
|
|
4405
|
-
OwnAddressType.RESOLVABLE_OR_PUBLIC,
|
|
4360
|
+
hci.OwnAddressType.PUBLIC,
|
|
4361
|
+
hci.OwnAddressType.RESOLVABLE_OR_PUBLIC,
|
|
4406
4362
|
)
|
|
4407
4363
|
else self.random_address
|
|
4408
4364
|
)
|
|
4409
4365
|
|
|
4410
4366
|
# Some controllers may return local resolvable address even not using address
|
|
4411
4367
|
# generation offloading. Ignore the value to prevent SMP failure.
|
|
4412
|
-
if own_address_type in (OwnAddressType.RANDOM, OwnAddressType.PUBLIC):
|
|
4368
|
+
if own_address_type in (hci.OwnAddressType.RANDOM, hci.OwnAddressType.PUBLIC):
|
|
4413
4369
|
self_resolvable_address = None
|
|
4414
4370
|
|
|
4415
4371
|
# Create a connection.
|
|
@@ -4423,11 +4379,11 @@ class Device(CompositeEventEmitter):
|
|
|
4423
4379
|
peer_resolvable_address,
|
|
4424
4380
|
role,
|
|
4425
4381
|
connection_parameters,
|
|
4426
|
-
ConnectionPHY(HCI_LE_1M_PHY, HCI_LE_1M_PHY),
|
|
4382
|
+
ConnectionPHY(hci.HCI_LE_1M_PHY, hci.HCI_LE_1M_PHY),
|
|
4427
4383
|
)
|
|
4428
4384
|
self.connections[connection_handle] = connection
|
|
4429
4385
|
|
|
4430
|
-
if role == HCI_PERIPHERAL_ROLE and self.legacy_advertiser:
|
|
4386
|
+
if role == hci.HCI_PERIPHERAL_ROLE and self.legacy_advertiser:
|
|
4431
4387
|
if self.legacy_advertiser.auto_restart:
|
|
4432
4388
|
advertiser = self.legacy_advertiser
|
|
4433
4389
|
connection.once(
|
|
@@ -4437,12 +4393,12 @@ class Device(CompositeEventEmitter):
|
|
|
4437
4393
|
else:
|
|
4438
4394
|
self.legacy_advertiser = None
|
|
4439
4395
|
|
|
4440
|
-
if role == HCI_CENTRAL_ROLE or not self.supports_le_extended_advertising:
|
|
4396
|
+
if role == hci.HCI_CENTRAL_ROLE or not self.supports_le_extended_advertising:
|
|
4441
4397
|
# We can emit now, we have all the info we need
|
|
4442
4398
|
self._emit_le_connection(connection)
|
|
4443
4399
|
return
|
|
4444
4400
|
|
|
4445
|
-
if role == HCI_PERIPHERAL_ROLE and self.supports_le_extended_advertising:
|
|
4401
|
+
if role == hci.HCI_PERIPHERAL_ROLE and self.supports_le_extended_advertising:
|
|
4446
4402
|
if advertising_set := self.connecting_extended_advertising_sets.pop(
|
|
4447
4403
|
connection_handle, None
|
|
4448
4404
|
):
|
|
@@ -4453,7 +4409,9 @@ class Device(CompositeEventEmitter):
|
|
|
4453
4409
|
|
|
4454
4410
|
@host_event_handler
|
|
4455
4411
|
def on_connection_failure(self, transport, peer_address, error_code):
|
|
4456
|
-
logger.debug(
|
|
4412
|
+
logger.debug(
|
|
4413
|
+
f'*** Connection failed: {hci.HCI_Constant.error_name(error_code)}'
|
|
4414
|
+
)
|
|
4457
4415
|
|
|
4458
4416
|
# For directed advertising, this means a timeout
|
|
4459
4417
|
if (
|
|
@@ -4469,7 +4427,7 @@ class Device(CompositeEventEmitter):
|
|
|
4469
4427
|
transport,
|
|
4470
4428
|
peer_address,
|
|
4471
4429
|
'hci',
|
|
4472
|
-
HCI_Constant.error_name(error_code),
|
|
4430
|
+
hci.HCI_Constant.error_name(error_code),
|
|
4473
4431
|
)
|
|
4474
4432
|
self.emit('connection_failure', error)
|
|
4475
4433
|
|
|
@@ -4480,8 +4438,8 @@ class Device(CompositeEventEmitter):
|
|
|
4480
4438
|
|
|
4481
4439
|
# Handle SCO request.
|
|
4482
4440
|
if link_type in (
|
|
4483
|
-
HCI_Connection_Complete_Event.SCO_LINK_TYPE,
|
|
4484
|
-
HCI_Connection_Complete_Event.ESCO_LINK_TYPE,
|
|
4441
|
+
hci.HCI_Connection_Complete_Event.SCO_LINK_TYPE,
|
|
4442
|
+
hci.HCI_Connection_Complete_Event.ESCO_LINK_TYPE,
|
|
4485
4443
|
):
|
|
4486
4444
|
if connection := self.find_connection_by_bd_addr(
|
|
4487
4445
|
bd_addr, transport=BT_BR_EDR_TRANSPORT
|
|
@@ -4497,8 +4455,8 @@ class Device(CompositeEventEmitter):
|
|
|
4497
4455
|
future.set_result((bd_addr, class_of_device, link_type))
|
|
4498
4456
|
|
|
4499
4457
|
# match first pending future for ANY address
|
|
4500
|
-
elif len(self.classic_pending_accepts[Address.ANY]) > 0:
|
|
4501
|
-
future = self.classic_pending_accepts[Address.ANY].pop(0)
|
|
4458
|
+
elif len(self.classic_pending_accepts[hci.Address.ANY]) > 0:
|
|
4459
|
+
future = self.classic_pending_accepts[hci.Address.ANY].pop(0)
|
|
4502
4460
|
future.set_result((bd_addr, class_of_device, link_type))
|
|
4503
4461
|
|
|
4504
4462
|
# device configuration is set to accept any incoming connection
|
|
@@ -4509,7 +4467,7 @@ class Device(CompositeEventEmitter):
|
|
|
4509
4467
|
)
|
|
4510
4468
|
|
|
4511
4469
|
self.host.send_command_sync(
|
|
4512
|
-
HCI_Accept_Connection_Request_Command(
|
|
4470
|
+
hci.HCI_Accept_Connection_Request_Command(
|
|
4513
4471
|
bd_addr=bd_addr, role=0x01 # Remain the peripheral
|
|
4514
4472
|
)
|
|
4515
4473
|
)
|
|
@@ -4517,9 +4475,9 @@ class Device(CompositeEventEmitter):
|
|
|
4517
4475
|
# reject incoming connection
|
|
4518
4476
|
else:
|
|
4519
4477
|
self.host.send_command_sync(
|
|
4520
|
-
HCI_Reject_Connection_Request_Command(
|
|
4478
|
+
hci.HCI_Reject_Connection_Request_Command(
|
|
4521
4479
|
bd_addr=bd_addr,
|
|
4522
|
-
reason=HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
|
|
4480
|
+
reason=hci.HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES_ERROR,
|
|
4523
4481
|
)
|
|
4524
4482
|
)
|
|
4525
4483
|
|
|
@@ -4552,7 +4510,7 @@ class Device(CompositeEventEmitter):
|
|
|
4552
4510
|
connection.transport,
|
|
4553
4511
|
connection.peer_address,
|
|
4554
4512
|
'hci',
|
|
4555
|
-
HCI_Constant.error_name(error_code),
|
|
4513
|
+
hci.HCI_Constant.error_name(error_code),
|
|
4556
4514
|
)
|
|
4557
4515
|
connection.emit('disconnection_failure', error)
|
|
4558
4516
|
|
|
@@ -4597,19 +4555,19 @@ class Device(CompositeEventEmitter):
|
|
|
4597
4555
|
authentication_requirements = (
|
|
4598
4556
|
# No Bonding
|
|
4599
4557
|
(
|
|
4600
|
-
HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4601
|
-
HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4558
|
+
hci.HCI_MITM_NOT_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4559
|
+
hci.HCI_MITM_REQUIRED_NO_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4602
4560
|
),
|
|
4603
4561
|
# General Bonding
|
|
4604
4562
|
(
|
|
4605
|
-
HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4606
|
-
HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4563
|
+
hci.HCI_MITM_NOT_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4564
|
+
hci.HCI_MITM_REQUIRED_GENERAL_BONDING_AUTHENTICATION_REQUIREMENTS,
|
|
4607
4565
|
),
|
|
4608
4566
|
)[1 if pairing_config.bonding else 0][1 if pairing_config.mitm else 0]
|
|
4609
4567
|
|
|
4610
4568
|
# Respond
|
|
4611
4569
|
self.host.send_command_sync(
|
|
4612
|
-
HCI_IO_Capability_Request_Reply_Command(
|
|
4570
|
+
hci.HCI_IO_Capability_Request_Reply_Command(
|
|
4613
4571
|
bd_addr=connection.peer_address,
|
|
4614
4572
|
io_capability=pairing_config.delegate.classic_io_capability,
|
|
4615
4573
|
oob_data_present=0x00, # Not present
|
|
@@ -4659,29 +4617,29 @@ class Device(CompositeEventEmitter):
|
|
|
4659
4617
|
|
|
4660
4618
|
# See Bluetooth spec @ Vol 3, Part C 5.2.2.6
|
|
4661
4619
|
methods = {
|
|
4662
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY: {
|
|
4663
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
|
|
4664
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
|
|
4665
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4666
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4620
|
+
hci.HCI_DISPLAY_ONLY_IO_CAPABILITY: {
|
|
4621
|
+
hci.HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
|
|
4622
|
+
hci.HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
|
|
4623
|
+
hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4624
|
+
hci.HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4667
4625
|
},
|
|
4668
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY: {
|
|
4669
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
|
|
4670
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
|
|
4671
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4672
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4626
|
+
hci.HCI_DISPLAY_YES_NO_IO_CAPABILITY: {
|
|
4627
|
+
hci.HCI_DISPLAY_ONLY_IO_CAPABILITY: display_auto_confirm,
|
|
4628
|
+
hci.HCI_DISPLAY_YES_NO_IO_CAPABILITY: display_confirm,
|
|
4629
|
+
hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4630
|
+
hci.HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4673
4631
|
},
|
|
4674
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY: {
|
|
4675
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY: na,
|
|
4676
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY: na,
|
|
4677
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4678
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4632
|
+
hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY: {
|
|
4633
|
+
hci.HCI_DISPLAY_ONLY_IO_CAPABILITY: na,
|
|
4634
|
+
hci.HCI_DISPLAY_YES_NO_IO_CAPABILITY: na,
|
|
4635
|
+
hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY: na,
|
|
4636
|
+
hci.HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4679
4637
|
},
|
|
4680
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: {
|
|
4681
|
-
HCI_DISPLAY_ONLY_IO_CAPABILITY: confirm,
|
|
4682
|
-
HCI_DISPLAY_YES_NO_IO_CAPABILITY: confirm,
|
|
4683
|
-
HCI_KEYBOARD_ONLY_IO_CAPABILITY: auto_confirm,
|
|
4684
|
-
HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4638
|
+
hci.HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: {
|
|
4639
|
+
hci.HCI_DISPLAY_ONLY_IO_CAPABILITY: confirm,
|
|
4640
|
+
hci.HCI_DISPLAY_YES_NO_IO_CAPABILITY: confirm,
|
|
4641
|
+
hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY: auto_confirm,
|
|
4642
|
+
hci.HCI_NO_INPUT_NO_OUTPUT_IO_CAPABILITY: auto_confirm,
|
|
4685
4643
|
},
|
|
4686
4644
|
}
|
|
4687
4645
|
|
|
@@ -4691,7 +4649,7 @@ class Device(CompositeEventEmitter):
|
|
|
4691
4649
|
try:
|
|
4692
4650
|
if await connection.abort_on('disconnection', method()):
|
|
4693
4651
|
await self.host.send_command(
|
|
4694
|
-
HCI_User_Confirmation_Request_Reply_Command(
|
|
4652
|
+
hci.HCI_User_Confirmation_Request_Reply_Command(
|
|
4695
4653
|
bd_addr=connection.peer_address
|
|
4696
4654
|
)
|
|
4697
4655
|
)
|
|
@@ -4700,7 +4658,7 @@ class Device(CompositeEventEmitter):
|
|
|
4700
4658
|
logger.warning(f'exception while confirming: {error}')
|
|
4701
4659
|
|
|
4702
4660
|
await self.host.send_command(
|
|
4703
|
-
HCI_User_Confirmation_Request_Negative_Reply_Command(
|
|
4661
|
+
hci.HCI_User_Confirmation_Request_Negative_Reply_Command(
|
|
4704
4662
|
bd_addr=connection.peer_address
|
|
4705
4663
|
)
|
|
4706
4664
|
)
|
|
@@ -4721,7 +4679,7 @@ class Device(CompositeEventEmitter):
|
|
|
4721
4679
|
)
|
|
4722
4680
|
if number is not None:
|
|
4723
4681
|
await self.host.send_command(
|
|
4724
|
-
HCI_User_Passkey_Request_Reply_Command(
|
|
4682
|
+
hci.HCI_User_Passkey_Request_Reply_Command(
|
|
4725
4683
|
bd_addr=connection.peer_address, numeric_value=number
|
|
4726
4684
|
)
|
|
4727
4685
|
)
|
|
@@ -4730,7 +4688,7 @@ class Device(CompositeEventEmitter):
|
|
|
4730
4688
|
logger.warning(f'exception while asking for pass-key: {error}')
|
|
4731
4689
|
|
|
4732
4690
|
await self.host.send_command(
|
|
4733
|
-
HCI_User_Passkey_Request_Negative_Reply_Command(
|
|
4691
|
+
hci.HCI_User_Passkey_Request_Negative_Reply_Command(
|
|
4734
4692
|
bd_addr=connection.peer_address
|
|
4735
4693
|
)
|
|
4736
4694
|
)
|
|
@@ -4747,7 +4705,7 @@ class Device(CompositeEventEmitter):
|
|
|
4747
4705
|
io_capability = pairing_config.delegate.classic_io_capability
|
|
4748
4706
|
|
|
4749
4707
|
# Respond
|
|
4750
|
-
if io_capability == HCI_KEYBOARD_ONLY_IO_CAPABILITY:
|
|
4708
|
+
if io_capability == hci.HCI_KEYBOARD_ONLY_IO_CAPABILITY:
|
|
4751
4709
|
# Ask the user to enter a string
|
|
4752
4710
|
async def get_pin_code():
|
|
4753
4711
|
pin_code = await connection.abort_on(
|
|
@@ -4759,7 +4717,7 @@ class Device(CompositeEventEmitter):
|
|
|
4759
4717
|
pin_code_len = len(pin_code)
|
|
4760
4718
|
assert 0 < pin_code_len <= 16, "pin_code should be 1-16 bytes"
|
|
4761
4719
|
await self.host.send_command(
|
|
4762
|
-
HCI_PIN_Code_Request_Reply_Command(
|
|
4720
|
+
hci.HCI_PIN_Code_Request_Reply_Command(
|
|
4763
4721
|
bd_addr=connection.peer_address,
|
|
4764
4722
|
pin_code_length=pin_code_len,
|
|
4765
4723
|
pin_code=pin_code,
|
|
@@ -4768,7 +4726,7 @@ class Device(CompositeEventEmitter):
|
|
|
4768
4726
|
else:
|
|
4769
4727
|
logger.debug("delegate.get_string() returned None")
|
|
4770
4728
|
await self.host.send_command(
|
|
4771
|
-
HCI_PIN_Code_Request_Negative_Reply_Command(
|
|
4729
|
+
hci.HCI_PIN_Code_Request_Negative_Reply_Command(
|
|
4772
4730
|
bd_addr=connection.peer_address
|
|
4773
4731
|
)
|
|
4774
4732
|
)
|
|
@@ -4776,7 +4734,7 @@ class Device(CompositeEventEmitter):
|
|
|
4776
4734
|
asyncio.create_task(get_pin_code())
|
|
4777
4735
|
else:
|
|
4778
4736
|
self.host.send_command_sync(
|
|
4779
|
-
HCI_PIN_Code_Request_Negative_Reply_Command(
|
|
4737
|
+
hci.HCI_PIN_Code_Request_Negative_Reply_Command(
|
|
4780
4738
|
bd_addr=connection.peer_address
|
|
4781
4739
|
)
|
|
4782
4740
|
)
|
|
@@ -4852,7 +4810,9 @@ class Device(CompositeEventEmitter):
|
|
|
4852
4810
|
# [Classic only]
|
|
4853
4811
|
@host_event_handler
|
|
4854
4812
|
@experimental('Only for testing')
|
|
4855
|
-
def on_sco_packet(
|
|
4813
|
+
def on_sco_packet(
|
|
4814
|
+
self, sco_handle: int, packet: hci.HCI_SynchronousDataPacket
|
|
4815
|
+
) -> None:
|
|
4856
4816
|
if (sco_link := self.sco_links.get(sco_handle)) and sco_link.sink:
|
|
4857
4817
|
sco_link.sink(packet)
|
|
4858
4818
|
|
|
@@ -4916,7 +4876,7 @@ class Device(CompositeEventEmitter):
|
|
|
4916
4876
|
# [LE only]
|
|
4917
4877
|
@host_event_handler
|
|
4918
4878
|
@experimental('Only for testing')
|
|
4919
|
-
def on_iso_packet(self, handle: int, packet: HCI_IsoDataPacket) -> None:
|
|
4879
|
+
def on_iso_packet(self, handle: int, packet: hci.HCI_IsoDataPacket) -> None:
|
|
4920
4880
|
if (cis_link := self.cis_links.get(handle)) and cis_link.sink:
|
|
4921
4881
|
cis_link.sink(packet)
|
|
4922
4882
|
|
|
@@ -4932,14 +4892,14 @@ class Device(CompositeEventEmitter):
|
|
|
4932
4892
|
if (
|
|
4933
4893
|
not connection.authenticated
|
|
4934
4894
|
and connection.transport == BT_BR_EDR_TRANSPORT
|
|
4935
|
-
and encryption == HCI_Encryption_Change_Event.AES_CCM
|
|
4895
|
+
and encryption == hci.HCI_Encryption_Change_Event.AES_CCM
|
|
4936
4896
|
):
|
|
4937
4897
|
connection.authenticated = True
|
|
4938
4898
|
connection.sc = True
|
|
4939
4899
|
if (
|
|
4940
4900
|
not connection.authenticated
|
|
4941
4901
|
and connection.transport == BT_LE_TRANSPORT
|
|
4942
|
-
and encryption == HCI_Encryption_Change_Event.E0_OR_AES_CCM
|
|
4902
|
+
and encryption == hci.HCI_Encryption_Change_Event.E0_OR_AES_CCM
|
|
4943
4903
|
):
|
|
4944
4904
|
connection.authenticated = True
|
|
4945
4905
|
connection.sc = True
|
|
@@ -5067,7 +5027,7 @@ class Device(CompositeEventEmitter):
|
|
|
5067
5027
|
def on_pairing(
|
|
5068
5028
|
self,
|
|
5069
5029
|
connection: Connection,
|
|
5070
|
-
identity_address: Optional[Address],
|
|
5030
|
+
identity_address: Optional[hci.Address],
|
|
5071
5031
|
keys: PairingKeys,
|
|
5072
5032
|
sc: bool,
|
|
5073
5033
|
) -> None:
|