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