• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021-2022 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# -----------------------------------------------------------------------------
16# Imports
17# -----------------------------------------------------------------------------
18
19from bumble.hci import (
20    HCI_DISCONNECT_COMMAND,
21    HCI_LE_1M_PHY_BIT,
22    HCI_LE_CODED_PHY_BIT,
23    HCI_LE_READ_BUFFER_SIZE_COMMAND,
24    HCI_RESET_COMMAND,
25    HCI_SUCCESS,
26    Address,
27    HCI_Command,
28    HCI_Command_Complete_Event,
29    HCI_Command_Status_Event,
30    HCI_CustomPacket,
31    HCI_Disconnect_Command,
32    HCI_Event,
33    HCI_LE_Add_Device_To_Filter_Accept_List_Command,
34    HCI_LE_Advertising_Report_Event,
35    HCI_LE_Channel_Selection_Algorithm_Event,
36    HCI_LE_Connection_Complete_Event,
37    HCI_LE_Connection_Update_Command,
38    HCI_LE_Connection_Update_Complete_Event,
39    HCI_LE_Create_Connection_Command,
40    HCI_LE_Extended_Create_Connection_Command,
41    HCI_LE_Read_Buffer_Size_Command,
42    HCI_LE_Read_Remote_Features_Command,
43    HCI_LE_Read_Remote_Features_Complete_Event,
44    HCI_LE_Remove_Device_From_Filter_Accept_List_Command,
45    HCI_LE_Set_Advertising_Data_Command,
46    HCI_LE_Set_Advertising_Parameters_Command,
47    HCI_LE_Set_Default_PHY_Command,
48    HCI_LE_Set_Event_Mask_Command,
49    HCI_LE_Set_Extended_Scan_Parameters_Command,
50    HCI_LE_Set_Random_Address_Command,
51    HCI_LE_Set_Scan_Enable_Command,
52    HCI_LE_Set_Scan_Parameters_Command,
53    HCI_Number_Of_Completed_Packets_Event,
54    HCI_Packet,
55    HCI_PIN_Code_Request_Reply_Command,
56    HCI_Read_Local_Supported_Commands_Command,
57    HCI_Read_Local_Supported_Features_Command,
58    HCI_Read_Local_Version_Information_Command,
59    HCI_Reset_Command,
60    HCI_Set_Event_Mask_Command,
61)
62
63
64# -----------------------------------------------------------------------------
65# pylint: disable=invalid-name
66
67
68def basic_check(x):
69    packet = x.to_bytes()
70    print(packet.hex())
71    parsed = HCI_Packet.from_bytes(packet)
72    x_str = str(x)
73    parsed_str = str(parsed)
74    print(x_str)
75    parsed_bytes = parsed.to_bytes()
76    assert x_str == parsed_str
77    assert packet == parsed_bytes
78
79
80# -----------------------------------------------------------------------------
81def test_HCI_Event():
82    event = HCI_Event(0xF9)
83    basic_check(event)
84
85    event = HCI_Event(0xF8, bytes.fromhex('AABBCC'))
86    basic_check(event)
87
88
89# -----------------------------------------------------------------------------
90def test_HCI_LE_Connection_Complete_Event():
91    address = Address('00:11:22:33:44:55')
92    event = HCI_LE_Connection_Complete_Event(
93        status=HCI_SUCCESS,
94        connection_handle=1,
95        role=1,
96        peer_address_type=1,
97        peer_address=address,
98        connection_interval=3,
99        peripheral_latency=4,
100        supervision_timeout=5,
101        central_clock_accuracy=6,
102    )
103    basic_check(event)
104
105
106# -----------------------------------------------------------------------------
107def test_HCI_LE_Advertising_Report_Event():
108    address = Address('00:11:22:33:44:55/P')
109    report = HCI_LE_Advertising_Report_Event.Report(
110        HCI_LE_Advertising_Report_Event.Report.FIELDS,
111        event_type=HCI_LE_Advertising_Report_Event.ADV_IND,
112        address_type=Address.PUBLIC_DEVICE_ADDRESS,
113        address=address,
114        data=bytes.fromhex(
115            '0201061106ba5689a6fabfa2bd01467d6e00fbabad08160a181604659b03'
116        ),
117        rssi=100,
118    )
119    event = HCI_LE_Advertising_Report_Event([report])
120    basic_check(event)
121
122
123# -----------------------------------------------------------------------------
124def test_HCI_LE_Read_Remote_Features_Complete_Event():
125    event = HCI_LE_Read_Remote_Features_Complete_Event(
126        status=HCI_SUCCESS,
127        connection_handle=0x007,
128        le_features=bytes.fromhex('0011223344556677'),
129    )
130    basic_check(event)
131
132
133# -----------------------------------------------------------------------------
134def test_HCI_LE_Connection_Update_Complete_Event():
135    event = HCI_LE_Connection_Update_Complete_Event(
136        status=HCI_SUCCESS,
137        connection_handle=0x007,
138        connection_interval=10,
139        peripheral_latency=3,
140        supervision_timeout=5,
141    )
142    basic_check(event)
143
144
145# -----------------------------------------------------------------------------
146def test_HCI_LE_Channel_Selection_Algorithm_Event():
147    event = HCI_LE_Channel_Selection_Algorithm_Event(
148        connection_handle=7, channel_selection_algorithm=1
149    )
150    basic_check(event)
151
152
153# -----------------------------------------------------------------------------
154def test_HCI_Command_Complete_Event():
155    # With a serializable object
156    event = HCI_Command_Complete_Event(
157        num_hci_command_packets=34,
158        command_opcode=HCI_LE_READ_BUFFER_SIZE_COMMAND,
159        return_parameters=HCI_LE_Read_Buffer_Size_Command.create_return_parameters(
160            status=0,
161            hc_le_acl_data_packet_length=1234,
162            hc_total_num_le_acl_data_packets=56,
163        ),
164    )
165    basic_check(event)
166
167    # With an arbitrary byte array
168    event = HCI_Command_Complete_Event(
169        num_hci_command_packets=1,
170        command_opcode=HCI_RESET_COMMAND,
171        return_parameters=bytes([1, 2, 3, 4]),
172    )
173    basic_check(event)
174
175    # With a simple status as a 1-byte array
176    event = HCI_Command_Complete_Event(
177        num_hci_command_packets=1,
178        command_opcode=HCI_RESET_COMMAND,
179        return_parameters=bytes([7]),
180    )
181    basic_check(event)
182    event = HCI_Packet.from_bytes(event.to_bytes())
183    assert event.return_parameters == 7
184
185    # With a simple status as an integer status
186    event = HCI_Command_Complete_Event(
187        num_hci_command_packets=1, command_opcode=HCI_RESET_COMMAND, return_parameters=9
188    )
189    basic_check(event)
190    assert event.return_parameters == 9
191
192
193# -----------------------------------------------------------------------------
194def test_HCI_Command_Status_Event():
195    event = HCI_Command_Status_Event(
196        status=0, num_hci_command_packets=37, command_opcode=HCI_DISCONNECT_COMMAND
197    )
198    basic_check(event)
199
200
201# -----------------------------------------------------------------------------
202def test_HCI_Number_Of_Completed_Packets_Event():
203    event = HCI_Number_Of_Completed_Packets_Event([(1, 2), (3, 4)])
204    basic_check(event)
205
206
207# -----------------------------------------------------------------------------
208def test_HCI_Command():
209    command = HCI_Command(0x5566)
210    basic_check(command)
211
212    command = HCI_Command(0x5566, bytes.fromhex('AABBCC'))
213    basic_check(command)
214
215
216# -----------------------------------------------------------------------------
217def test_HCI_PIN_Code_Request_Reply_Command():
218    pin_code = b'1234'
219    pin_code_length = len(pin_code)
220    # here to make the test pass, we need to
221    # pad pin_code, as HCI_Object.format_fields
222    # does not do it for us
223    padded_pin_code = pin_code + bytes(16 - pin_code_length)
224    command = HCI_PIN_Code_Request_Reply_Command(
225        bd_addr=Address(
226            '00:11:22:33:44:55', address_type=Address.PUBLIC_DEVICE_ADDRESS
227        ),
228        pin_code_length=pin_code_length,
229        pin_code=padded_pin_code,
230    )
231    basic_check(command)
232
233
234def test_HCI_Reset_Command():
235    command = HCI_Reset_Command()
236    basic_check(command)
237
238
239# -----------------------------------------------------------------------------
240def test_HCI_Read_Local_Version_Information_Command():
241    command = HCI_Read_Local_Version_Information_Command()
242    basic_check(command)
243
244
245# -----------------------------------------------------------------------------
246def test_HCI_Read_Local_Supported_Commands_Command():
247    command = HCI_Read_Local_Supported_Commands_Command()
248    basic_check(command)
249
250
251# -----------------------------------------------------------------------------
252def test_HCI_Read_Local_Supported_Features_Command():
253    command = HCI_Read_Local_Supported_Features_Command()
254    basic_check(command)
255
256
257# -----------------------------------------------------------------------------
258def test_HCI_Disconnect_Command():
259    command = HCI_Disconnect_Command(connection_handle=123, reason=0x11)
260    basic_check(command)
261
262
263# -----------------------------------------------------------------------------
264def test_HCI_Set_Event_Mask_Command():
265    command = HCI_Set_Event_Mask_Command(event_mask=bytes.fromhex('0011223344556677'))
266    basic_check(command)
267
268
269# -----------------------------------------------------------------------------
270def test_HCI_LE_Set_Event_Mask_Command():
271    command = HCI_LE_Set_Event_Mask_Command(
272        le_event_mask=bytes.fromhex('0011223344556677')
273    )
274    basic_check(command)
275
276
277# -----------------------------------------------------------------------------
278def test_HCI_LE_Set_Random_Address_Command():
279    command = HCI_LE_Set_Random_Address_Command(
280        random_address=Address('00:11:22:33:44:55')
281    )
282    basic_check(command)
283
284
285# -----------------------------------------------------------------------------
286def test_HCI_LE_Set_Advertising_Parameters_Command():
287    command = HCI_LE_Set_Advertising_Parameters_Command(
288        advertising_interval_min=20,
289        advertising_interval_max=30,
290        advertising_type=HCI_LE_Set_Advertising_Parameters_Command.ADV_NONCONN_IND,
291        own_address_type=Address.PUBLIC_DEVICE_ADDRESS,
292        peer_address_type=Address.RANDOM_DEVICE_ADDRESS,
293        peer_address=Address('00:11:22:33:44:55'),
294        advertising_channel_map=0x03,
295        advertising_filter_policy=1,
296    )
297    basic_check(command)
298
299
300# -----------------------------------------------------------------------------
301def test_HCI_LE_Set_Advertising_Data_Command():
302    command = HCI_LE_Set_Advertising_Data_Command(
303        advertising_data=bytes.fromhex('AABBCC')
304    )
305    basic_check(command)
306
307
308# -----------------------------------------------------------------------------
309def test_HCI_LE_Set_Scan_Parameters_Command():
310    command = HCI_LE_Set_Scan_Parameters_Command(
311        le_scan_type=1,
312        le_scan_interval=20,
313        le_scan_window=10,
314        own_address_type=1,
315        scanning_filter_policy=0,
316    )
317    basic_check(command)
318
319
320# -----------------------------------------------------------------------------
321def test_HCI_LE_Set_Scan_Enable_Command():
322    command = HCI_LE_Set_Scan_Enable_Command(le_scan_enable=1, filter_duplicates=0)
323    basic_check(command)
324
325
326# -----------------------------------------------------------------------------
327def test_HCI_LE_Create_Connection_Command():
328    command = HCI_LE_Create_Connection_Command(
329        le_scan_interval=4,
330        le_scan_window=5,
331        initiator_filter_policy=1,
332        peer_address_type=1,
333        peer_address=Address('00:11:22:33:44:55'),
334        own_address_type=2,
335        connection_interval_min=7,
336        connection_interval_max=8,
337        max_latency=9,
338        supervision_timeout=10,
339        min_ce_length=11,
340        max_ce_length=12,
341    )
342    basic_check(command)
343
344
345# -----------------------------------------------------------------------------
346def test_HCI_LE_Extended_Create_Connection_Command():
347    command = HCI_LE_Extended_Create_Connection_Command(
348        initiator_filter_policy=0,
349        own_address_type=0,
350        peer_address_type=1,
351        peer_address=Address('00:11:22:33:44:55'),
352        initiating_phys=3,
353        scan_intervals=(10, 11),
354        scan_windows=(12, 13),
355        connection_interval_mins=(14, 15),
356        connection_interval_maxs=(16, 17),
357        max_latencies=(18, 19),
358        supervision_timeouts=(20, 21),
359        min_ce_lengths=(100, 101),
360        max_ce_lengths=(102, 103),
361    )
362    basic_check(command)
363
364
365# -----------------------------------------------------------------------------
366def test_HCI_LE_Add_Device_To_Filter_Accept_List_Command():
367    command = HCI_LE_Add_Device_To_Filter_Accept_List_Command(
368        address_type=1, address=Address('00:11:22:33:44:55')
369    )
370    basic_check(command)
371
372
373# -----------------------------------------------------------------------------
374def test_HCI_LE_Remove_Device_From_Filter_Accept_List_Command():
375    command = HCI_LE_Remove_Device_From_Filter_Accept_List_Command(
376        address_type=1, address=Address('00:11:22:33:44:55')
377    )
378    basic_check(command)
379
380
381# -----------------------------------------------------------------------------
382def test_HCI_LE_Connection_Update_Command():
383    command = HCI_LE_Connection_Update_Command(
384        connection_handle=0x0002,
385        connection_interval_min=10,
386        connection_interval_max=20,
387        max_latency=7,
388        supervision_timeout=3,
389        min_ce_length=100,
390        max_ce_length=200,
391    )
392    basic_check(command)
393
394
395# -----------------------------------------------------------------------------
396def test_HCI_LE_Read_Remote_Features_Command():
397    command = HCI_LE_Read_Remote_Features_Command(connection_handle=0x0002)
398    basic_check(command)
399
400
401# -----------------------------------------------------------------------------
402def test_HCI_LE_Set_Default_PHY_Command():
403    command = HCI_LE_Set_Default_PHY_Command(all_phys=0, tx_phys=1, rx_phys=1)
404    basic_check(command)
405
406
407# -----------------------------------------------------------------------------
408def test_HCI_LE_Set_Extended_Scan_Parameters_Command():
409    command = HCI_LE_Set_Extended_Scan_Parameters_Command(
410        own_address_type=Address.RANDOM_DEVICE_ADDRESS,
411        # pylint: disable-next=line-too-long
412        scanning_filter_policy=HCI_LE_Set_Extended_Scan_Parameters_Command.BASIC_FILTERED_POLICY,
413        scanning_phys=(1 << HCI_LE_1M_PHY_BIT | 1 << HCI_LE_CODED_PHY_BIT | 1 << 4),
414        scan_types=[
415            HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
416            HCI_LE_Set_Extended_Scan_Parameters_Command.ACTIVE_SCANNING,
417            HCI_LE_Set_Extended_Scan_Parameters_Command.PASSIVE_SCANNING,
418        ],
419        scan_intervals=[1, 2, 3],
420        scan_windows=[4, 5, 6],
421    )
422    basic_check(command)
423
424
425# -----------------------------------------------------------------------------
426def test_address():
427    a = Address('C4:F2:17:1A:1D:BB')
428    assert not a.is_public
429    assert a.is_random
430    assert a.address_type == Address.RANDOM_DEVICE_ADDRESS
431    assert not a.is_resolvable
432    assert not a.is_resolved
433    assert a.is_static
434
435
436# -----------------------------------------------------------------------------
437def test_custom():
438    data = bytes([0x77, 0x02, 0x01, 0x03])
439    packet = HCI_CustomPacket(data)
440    assert packet.hci_packet_type == 0x77
441    assert packet.payload == data
442
443
444# -----------------------------------------------------------------------------
445def run_test_events():
446    test_HCI_Event()
447    test_HCI_LE_Connection_Complete_Event()
448    test_HCI_LE_Advertising_Report_Event()
449    test_HCI_LE_Connection_Update_Complete_Event()
450    test_HCI_LE_Read_Remote_Features_Complete_Event()
451    test_HCI_LE_Channel_Selection_Algorithm_Event()
452    test_HCI_Command_Complete_Event()
453    test_HCI_Command_Status_Event()
454    test_HCI_Number_Of_Completed_Packets_Event()
455
456
457# -----------------------------------------------------------------------------
458def run_test_commands():
459    test_HCI_Command()
460    test_HCI_Reset_Command()
461    test_HCI_PIN_Code_Request_Reply_Command()
462    test_HCI_Read_Local_Version_Information_Command()
463    test_HCI_Read_Local_Supported_Commands_Command()
464    test_HCI_Read_Local_Supported_Features_Command()
465    test_HCI_Disconnect_Command()
466    test_HCI_Set_Event_Mask_Command()
467    test_HCI_LE_Set_Event_Mask_Command()
468    test_HCI_LE_Set_Random_Address_Command()
469    test_HCI_LE_Set_Advertising_Parameters_Command()
470    test_HCI_LE_Set_Advertising_Data_Command()
471    test_HCI_LE_Set_Scan_Parameters_Command()
472    test_HCI_LE_Set_Scan_Enable_Command()
473    test_HCI_LE_Create_Connection_Command()
474    test_HCI_LE_Extended_Create_Connection_Command()
475    test_HCI_LE_Add_Device_To_Filter_Accept_List_Command()
476    test_HCI_LE_Remove_Device_From_Filter_Accept_List_Command()
477    test_HCI_LE_Connection_Update_Command()
478    test_HCI_LE_Read_Remote_Features_Command()
479    test_HCI_LE_Set_Default_PHY_Command()
480    test_HCI_LE_Set_Extended_Scan_Parameters_Command()
481
482
483# -----------------------------------------------------------------------------
484if __name__ == '__main__':
485    run_test_events()
486    run_test_commands()
487    test_address()
488    test_custom()
489