1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17GATT Client Libraries 18""" 19 20from acts.test_utils.bt.bt_constants import default_le_connection_interval_ms 21from acts.test_utils.bt.bt_constants import default_bluetooth_socket_timeout_ms 22from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection 23from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection 24from acts.test_utils.bt.bt_gatt_utils import setup_gatt_mtu 25from acts.test_utils.bt.bt_constants import ble_scan_settings_modes 26from acts.test_utils.bt.bt_constants import gatt_cb_strings 27from acts.test_utils.bt.bt_constants import gatt_char_desc_uuids 28from acts.test_utils.bt.bt_constants import gatt_descriptor 29from acts.test_utils.bt.bt_constants import gatt_transport 30from acts.test_utils.bt.bt_constants import le_default_supervision_timeout 31from acts.test_utils.bt.bt_constants import le_connection_interval_time_step_ms 32from acts.test_utils.bt.bt_constants import scan_result 33from acts.test_utils.bt.bt_gatt_utils import log_gatt_server_uuids 34 35import time 36import os 37 38 39class GattClientLib(): 40 def __init__(self, log, dut, target_mac_addr=None): 41 self.dut = dut 42 self.log = log 43 self.gatt_callback = None 44 self.bluetooth_gatt = None 45 self.discovered_services_index = None 46 self.target_mac_addr = target_mac_addr 47 self.generic_uuid = "0000{}-0000-1000-8000-00805f9b34fb" 48 49 def set_target_mac_addr(self, mac_addr): 50 self.target_mac_addr = mac_addr 51 52 def connect_over_le_based_off_name(self, autoconnect, name): 53 """Perform GATT connection over LE""" 54 self.dut.droid.bleSetScanSettingsScanMode( 55 ble_scan_settings_modes['low_latency']) 56 filter_list = self.dut.droid.bleGenFilterList() 57 scan_settings = self.dut.droid.bleBuildScanSetting() 58 scan_callback = self.dut.droid.bleGenScanCallback() 59 event_name = scan_result.format(scan_callback) 60 self.dut.droid.bleSetScanFilterDeviceName("BLE Rect") 61 self.dut.droid.bleBuildScanFilter(filter_list) 62 self.dut.droid.bleStartBleScan(filter_list, scan_settings, 63 scan_callback) 64 65 try: 66 event = self.dut.ed.pop_event(event_name, 10) 67 self.log.info("Found scan result: {}".format(event)) 68 except Exception: 69 self.log.info("Didn't find any scan results.") 70 mac_addr = event['data']['Result']['deviceInfo']['address'] 71 self.bluetooth_gatt, self.gatt_callback = setup_gatt_connection( 72 self.dut, mac_addr, autoconnect, transport=gatt_transport['le']) 73 self.dut.droid.bleStopBleScan(scan_callback) 74 self.discovered_services_index = None 75 76 def connect_over_le(self, autoconnect): 77 """Perform GATT connection over LE""" 78 self.bluetooth_gatt, self.gatt_callback = setup_gatt_connection( 79 self.dut, 80 self.target_mac_addr, 81 autoconnect, 82 transport=gatt_transport['le']) 83 self.discovered_services_index = None 84 85 def connect_over_bredr(self): 86 """Perform GATT connection over BREDR""" 87 self.bluetooth_gatt, self.gatt_callback = setup_gatt_connection( 88 self.dut, 89 self.target_mac_addr, 90 False, 91 transport=gatt_transport['bredr']) 92 93 def disconnect(self): 94 """Perform GATT disconnect""" 95 cmd = "Disconnect GATT connection" 96 try: 97 disconnect_gatt_connection(self.dut, self.bluetooth_gatt, 98 self.gatt_callback) 99 except Exception as err: 100 self.log.info("Cmd {} failed with {}".format(cmd, err)) 101 try: 102 self.dut.droid.gattClientClose(self.bluetooth_gatt) 103 except Exception as err: 104 self.log.info("Cmd failed with {}".format(err)) 105 106 def _setup_discovered_services_index(self): 107 if not self.discovered_services_index: 108 self.dut.droid.gattClientDiscoverServices(self.bluetooth_gatt) 109 expected_event = gatt_cb_strings['gatt_serv_disc'].format( 110 self.gatt_callback) 111 event = self.dut.ed.pop_event(expected_event, 10) 112 self.discovered_services_index = event['data']['ServicesIndex'] 113 114 def read_char_by_uuid(self, line): 115 """GATT client read Characteristic by UUID.""" 116 uuid = line 117 if len(line) == 4: 118 uuid = self.generic_uuid.format(line) 119 self.dut.droid.gattClientReadUsingCharacteristicUuid( 120 self.bluetooth_gatt, uuid, 0x0001, 0xFFFF) 121 122 def request_mtu(self, mtu): 123 """Request MTU Change of input value""" 124 setup_gatt_mtu(self.dut, self.bluetooth_gatt, self.gatt_callback, 125 int(mtu)) 126 127 def list_all_uuids(self): 128 """From the GATT Client, discover services and list all services, 129 chars and descriptors 130 """ 131 self._setup_discovered_services_index() 132 log_gatt_server_uuids(self.dut, self.discovered_services_index, 133 self.bluetooth_gatt) 134 135 def discover_services(self): 136 """GATT Client discover services of GATT Server""" 137 self.dut.droid.gattClientDiscoverServices(self.bluetooth_gatt) 138 139 def refresh(self): 140 """Perform Gatt Client Refresh""" 141 self.dut.droid.gattClientRefresh(self.bluetooth_gatt) 142 143 def read_char_by_instance_id(self, id): 144 """From the GATT Client, discover services and list all services, 145 chars and descriptors 146 """ 147 if not id: 148 self.log.info("Invalid id") 149 return 150 self._setup_discovered_services_index() 151 self.dut.droid.gattClientReadCharacteristicByInstanceId( 152 self.bluetooth_gatt, self.discovered_services_index, int(id, 16)) 153 154 def write_char_by_instance_id(self, line): 155 """GATT Client Write to Characteristic by instance ID""" 156 args = line.split() 157 if len(args) != 2: 158 self.log.info("2 Arguments required: [InstanceId] [Size]") 159 return 160 instance_id = args[0] 161 size = args[1] 162 write_value = [] 163 for i in range(int(size)): 164 write_value.append(i % 256) 165 self._setup_discovered_services_index() 166 self.dut.droid.gattClientWriteCharacteristicByInstanceId( 167 self.bluetooth_gatt, self.discovered_services_index, 168 int(instance_id, 16), write_value) 169 170 def write_char_by_instance_id_value(self, line): 171 """GATT Client Write to Characteristic by instance ID""" 172 args = line.split() 173 if len(args) != 2: 174 self.log.info("2 Arguments required: [InstanceId] [Size]") 175 return 176 instance_id = args[0] 177 write_value = args[1] 178 self._setup_discovered_services_index() 179 self.dut.droid.gattClientWriteCharacteristicByInstanceId( 180 self.bluetooth_gatt, self.discovered_services_index, 181 int(instance_id, 16), [int(write_value)]) 182 183 def mod_write_char_by_instance_id(self, line): 184 """GATT Client Write to Char that doesn't have write permission""" 185 args = line.split() 186 if len(args) != 2: 187 self.log.info("2 Arguments required: [InstanceId] [Size]") 188 return 189 instance_id = args[0] 190 size = args[1] 191 write_value = [] 192 for i in range(int(size)): 193 write_value.append(i % 256) 194 self._setup_discovered_services_index() 195 self.dut.droid.gattClientModifyAccessAndWriteCharacteristicByInstanceId( 196 self.bluetooth_gatt, self.discovered_services_index, 197 int(instance_id, 16), write_value) 198 199 def write_invalid_char_by_instance_id(self, line): 200 """GATT Client Write to Char that doesn't exists""" 201 args = line.split() 202 if len(args) != 2: 203 self.log.info("2 Arguments required: [InstanceId] [Size]") 204 return 205 instance_id = args[0] 206 size = args[1] 207 write_value = [] 208 for i in range(int(size)): 209 write_value.append(i % 256) 210 self._setup_discovered_services_index() 211 self.dut.droid.gattClientWriteInvalidCharacteristicByInstanceId( 212 self.bluetooth_gatt, self.discovered_services_index, 213 int(instance_id, 16), write_value) 214 215 def mod_read_char_by_instance_id(self, line): 216 """GATT Client Read Char that doesn't have write permission""" 217 instance_id = line 218 self._setup_discovered_services_index() 219 self.dut.droid.gattClientModifyAccessAndReadCharacteristicByInstanceId( 220 self.bluetooth_gatt, self.discovered_services_index, 221 int(instance_id, 16)) 222 223 def read_invalid_char_by_instance_id(self, line): 224 """GATT Client Read Char that doesn't exists""" 225 instance_id = line 226 self.dut.droid.gattClientReadInvalidCharacteristicByInstanceId( 227 self.bluetooth_gatt, self.discovered_services_index, 228 int(instance_id, 16)) 229 230 def mod_write_desc_by_instance_id(self, line): 231 """GATT Client Write to Desc that doesn't have write permission""" 232 cmd = "" 233 args = line.split() 234 if len(args) != 2: 235 self.log.info("2 Arguments required: [InstanceId] [Size]") 236 return 237 instance_id = args[0] 238 size = args[1] 239 write_value = [] 240 for i in range(int(size)): 241 write_value.append(i % 256) 242 self._setup_discovered_services_index() 243 self.dut.droid.gattClientModifyAccessAndWriteDescriptorByInstanceId( 244 self.bluetooth_gatt, self.discovered_services_index, 245 int(instance_id, 16), write_value) 246 247 def write_invalid_desc_by_instance_id(self, line): 248 """GATT Client Write to Desc that doesn't exists""" 249 args = line.split() 250 if len(args) != 2: 251 self.log.info("2 Arguments required: [InstanceId] [Size]") 252 return 253 instance_id = args[0] 254 size = args[1] 255 write_value = [] 256 for i in range(int(size)): 257 write_value.append(i % 256) 258 self._setup_discovered_services_index() 259 self.dut.droid.gattClientWriteInvalidDescriptorByInstanceId( 260 self.bluetooth_gatt, self.discovered_services_index, 261 int(instance_id, 16), write_value) 262 263 def mod_read_desc_by_instance_id(self, line): 264 """GATT Client Read Desc that doesn't have write permission""" 265 cmd = "" 266 instance_id = line 267 self._setup_discovered_services_index() 268 self.dut.droid.gattClientModifyAccessAndReadDescriptorByInstanceId( 269 self.bluetooth_gatt, self.discovered_services_index, 270 int(instance_id, 16)) 271 272 def read_invalid_desc_by_instance_id(self, line): 273 """GATT Client Read Desc that doesn't exists""" 274 instance_id = line 275 self._setup_discovered_services_index() 276 self.dut.droid.gattClientReadInvalidDescriptorByInstanceId( 277 self.bluetooth_gatt, self.discovered_services_index, 278 int(instance_id, 16)) 279 280 def mod_read_char_by_uuid_and_instance_id(self, line): 281 """GATT Client Read Char that doesn't have write permission""" 282 args = line.split() 283 if len(args) != 2: 284 self.log.info("2 Arguments required: [uuid] [instance_id]") 285 return 286 uuid = args[0] 287 instance_id = args[1] 288 self._setup_discovered_services_index() 289 self.dut.droid.gattClientModifyAccessAndReadCharacteristicByUuidAndInstanceId( 290 self.bluetooth_gatt, self.discovered_services_index, 291 int(instance_id, 16), self.generic_uuid.format(uuid)) 292 293 def read_invalid_char_by_uuid(self, line): 294 """GATT Client Read Char that doesn't exists""" 295 uuid = line 296 self._setup_discovered_services_index() 297 self.dut.droid.gattClientReadInvalidCharacteristicByUuid( 298 self.bluetooth_gatt, self.discovered_services_index, 299 self.generic_uuid.format(uuid)) 300 301 def write_desc_by_instance_id(self, line): 302 """GATT Client Write to Descriptor by instance ID""" 303 args = line.split() 304 if len(args) != 2: 305 self.log.info("2 Arguments required: [instanceID] [size]") 306 return 307 instance_id = args[0] 308 size = args[1] 309 write_value = [] 310 for i in range(int(size)): 311 write_value.append(i % 256) 312 self._setup_discovered_services_index() 313 self.dut.droid.gattClientWriteDescriptorByInstanceId( 314 self.bluetooth_gatt, self.discovered_services_index, 315 int(instance_id, 16), write_value) 316 317 def write_desc_notification_by_instance_id(self, line): 318 """GATT Client Write to Descriptor by instance ID""" 319 args = line.split() 320 instance_id = args[0] 321 switch = int(args[1]) 322 write_value = [0x00, 0x00] 323 if switch == 2: 324 write_value = [0x02, 0x00] 325 self._setup_discovered_services_index() 326 self.dut.droid.gattClientWriteDescriptorByInstanceId( 327 self.bluetooth_gatt, self.discovered_services_index, 328 int(instance_id, 16), write_value) 329 330 def enable_notification_desc_by_instance_id(self, line): 331 """GATT Client Enable Notification on Descriptor by instance ID""" 332 instance_id = line 333 self._setup_discovered_services_index() 334 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 335 self.discovered_services_index) 336 for i in range(services_count): 337 characteristic_uuids = ( 338 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 339 self.discovered_services_index, i)) 340 for j in range(len(characteristic_uuids)): 341 descriptor_uuids = ( 342 self.dut.droid. 343 gattClientGetDiscoveredDescriptorUuidsByIndex( 344 self.discovered_services_index, i, j)) 345 for k in range(len(descriptor_uuids)): 346 desc_inst_id = self.dut.droid.gattClientGetDescriptorInstanceId( 347 self.bluetooth_gatt, self.discovered_services_index, i, 348 j, k) 349 if desc_inst_id == int(instance_id, 16): 350 self.dut.droid.gattClientDescriptorSetValueByIndex( 351 self.bluetooth_gatt, 352 self.discovered_services_index, i, j, k, 353 gatt_descriptor['enable_notification_value']) 354 time.sleep(2) #Necessary for PTS 355 self.dut.droid.gattClientWriteDescriptorByIndex( 356 self.bluetooth_gatt, 357 self.discovered_services_index, i, j, k) 358 time.sleep(2) #Necessary for PTS 359 self.dut.droid.gattClientSetCharacteristicNotificationByIndex( 360 self.bluetooth_gatt, 361 self.discovered_services_index, i, j, True) 362 363 def enable_indication_desc_by_instance_id(self, line): 364 """GATT Client Enable indication on Descriptor by instance ID""" 365 instance_id = line 366 self._setup_discovered_services_index() 367 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 368 self.discovered_services_index) 369 for i in range(services_count): 370 characteristic_uuids = ( 371 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 372 self.discovered_services_index, i)) 373 for j in range(len(characteristic_uuids)): 374 descriptor_uuids = ( 375 self.dut.droid. 376 gattClientGetDiscoveredDescriptorUuidsByIndex( 377 self.discovered_services_index, i, j)) 378 for k in range(len(descriptor_uuids)): 379 desc_inst_id = self.dut.droid.gattClientGetDescriptorInstanceId( 380 self.bluetooth_gatt, self.discovered_services_index, i, 381 j, k) 382 if desc_inst_id == int(instance_id, 16): 383 self.dut.droid.gattClientDescriptorSetValueByIndex( 384 self.bluetooth_gatt, 385 self.discovered_services_index, i, j, k, 386 gatt_descriptor['enable_indication_value']) 387 time.sleep(2) #Necessary for PTS 388 self.dut.droid.gattClientWriteDescriptorByIndex( 389 self.bluetooth_gatt, 390 self.discovered_services_index, i, j, k) 391 time.sleep(2) #Necessary for PTS 392 self.dut.droid.gattClientSetCharacteristicNotificationByIndex( 393 self.bluetooth_gatt, 394 self.discovered_services_index, i, j, True) 395 396 def char_enable_all_notifications(self): 397 self._setup_discovered_services_index() 398 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 399 self.discovered_services_index) 400 for i in range(services_count): 401 characteristic_uuids = ( 402 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 403 self.discovered_services_index, i)) 404 for j in range(len(characteristic_uuids)): 405 self.dut.droid.gattClientSetCharacteristicNotificationByIndex( 406 self.bluetooth_gatt, self.discovered_services_index, i, j, 407 True) 408 409 def read_char_by_invalid_instance_id(self, line): 410 self._setup_discovered_services_index() 411 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 412 self.discovered_services_index) 413 self.dut.droid.gattClientReadInvalidCharacteristicInstanceId( 414 self.bluetooth_gatt, self.discovered_services_index, 0, 415 int(line, 16)) 416 417 def begin_reliable_write(self): 418 """Begin a reliable write on the Bluetooth Gatt Client""" 419 self.dut.droid.gattClientBeginReliableWrite(self.bluetooth_gatt) 420 421 def abort_reliable_write(self): 422 """Abort a reliable write on the Bluetooth Gatt Client""" 423 self.dut.droid.gattClientAbortReliableWrite(self.bluetooth_gatt) 424 425 def execute_reliable_write(self): 426 """Execute a reliable write on the Bluetooth Gatt Client""" 427 self.dut.droid.gattExecuteReliableWrite(self.bluetooth_gatt) 428 429 def read_all_char(self): 430 """GATT Client read all Characteristic values""" 431 self._setup_discovered_services_index() 432 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 433 self.discovered_services_index) 434 for i in range(services_count): 435 characteristic_uuids = ( 436 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 437 self.discovered_services_index, i)) 438 for j in range(len(characteristic_uuids)): 439 char_inst_id = self.dut.droid.gattClientGetCharacteristicInstanceId( 440 self.bluetooth_gatt, self.discovered_services_index, i, j) 441 self.log.info("Reading characteristic {} {}".format( 442 hex(char_inst_id), characteristic_uuids[j])) 443 self.dut.droid.gattClientReadCharacteristicByIndex( 444 self.bluetooth_gatt, self.discovered_services_index, i, j) 445 time.sleep(1) # Necessary for PTS 446 447 def read_all_desc(self): 448 """GATT Client read all Descriptor values""" 449 self._setup_discovered_services_index() 450 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 451 self.discovered_services_index) 452 for i in range(services_count): 453 characteristic_uuids = ( 454 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 455 self.discovered_services_index, i)) 456 for j in range(len(characteristic_uuids)): 457 descriptor_uuids = ( 458 self.dut.droid. 459 gattClientGetDiscoveredDescriptorUuidsByIndex( 460 self.discovered_services_index, i, j)) 461 for k in range(len(descriptor_uuids)): 462 time.sleep(1) 463 try: 464 self.log.info("Reading descriptor {}".format( 465 descriptor_uuids[k])) 466 self.dut.droid.gattClientReadDescriptorByIndex( 467 self.bluetooth_gatt, 468 self.discovered_services_index, i, j, k) 469 except Exception as err: 470 self.log.info( 471 "Failed to read to descriptor: {}".format( 472 descriptor_uuids[k])) 473 474 def write_all_char(self, line): 475 """Write to every Characteristic on the GATT server""" 476 args = line.split() 477 write_value = [] 478 for i in range(int(line)): 479 write_value.append(i % 256) 480 self._setup_discovered_services_index() 481 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 482 self.discovered_services_index) 483 for i in range(services_count): 484 characteristic_uuids = ( 485 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 486 self.discovered_services_index, i)) 487 for j in range(len(characteristic_uuids)): 488 char_inst_id = self.dut.droid.gattClientGetCharacteristicInstanceId( 489 self.bluetooth_gatt, self.discovered_services_index, i, j) 490 self.log.info("Writing to {} {}".format( 491 hex(char_inst_id), characteristic_uuids[j])) 492 try: 493 self.dut.droid.gattClientCharacteristicSetValueByIndex( 494 self.bluetooth_gatt, self.discovered_services_index, i, 495 j, write_value) 496 self.dut.droid.gattClientWriteCharacteristicByIndex( 497 self.bluetooth_gatt, self.discovered_services_index, i, 498 j) 499 time.sleep(1) 500 except Exception as err: 501 self.log.info( 502 "Failed to write to characteristic: {}".format( 503 characteristic_uuids[j])) 504 505 def write_all_desc(self, line): 506 """ Write to every Descriptor on the GATT server """ 507 args = line.split() 508 write_value = [] 509 for i in range(int(line)): 510 write_value.append(i % 256) 511 self._setup_discovered_services_index() 512 services_count = self.dut.droid.gattClientGetDiscoveredServicesCount( 513 self.discovered_services_index) 514 for i in range(services_count): 515 characteristic_uuids = ( 516 self.dut.droid.gattClientGetDiscoveredCharacteristicUuids( 517 self.discovered_services_index, i)) 518 for j in range(len(characteristic_uuids)): 519 descriptor_uuids = ( 520 self.dut.droid. 521 gattClientGetDiscoveredDescriptorUuidsByIndex( 522 self.discovered_services_index, i, j)) 523 for k in range(len(descriptor_uuids)): 524 time.sleep(1) 525 desc_inst_id = self.dut.droid.gattClientGetDescriptorInstanceId( 526 self.bluetooth_gatt, self.discovered_services_index, i, 527 j, k) 528 self.log.info("Writing to {} {}".format( 529 hex(desc_inst_id), descriptor_uuids[k])) 530 try: 531 self.dut.droid.gattClientDescriptorSetValueByIndex( 532 self.bluetooth_gatt, 533 self.discovered_services_index, i, j, k, 534 write_value) 535 self.dut.droid.gattClientWriteDescriptorByIndex( 536 self.bluetooth_gatt, 537 self.discovered_services_index, i, j, k) 538 except Exception as err: 539 self.log.info( 540 "Failed to write to descriptor: {}".format( 541 descriptor_uuids[k])) 542 543 def discover_service_by_uuid(self, line): 544 """ Discover service by UUID """ 545 uuid = line 546 if len(line) == 4: 547 uuid = self.generic_uuid.format(line) 548 self.dut.droid.gattClientDiscoverServiceByUuid(self.bluetooth_gatt, 549 uuid) 550 551 def request_le_connection_parameters(self): 552 le_min_ce_len = 0 553 le_max_ce_len = 0 554 le_connection_interval = 0 555 minInterval = default_le_connection_interval_ms / le_connection_interval_time_step_ms 556 maxInterval = default_le_connection_interval_ms / le_connection_interval_time_step_ms 557 return_status = self.dut.droid.gattClientRequestLeConnectionParameters( 558 self.bluetooth_gatt, minInterval, maxInterval, 0, 559 le_default_supervision_timeout, le_min_ce_len, le_max_ce_len) 560 self.log.info( 561 "Result of request le connection param: {}".format(return_status)) 562 563 def socket_conn_begin_connect_thread_psm(self, line): 564 args = line.split() 565 is_ble = bool(int(args[0])) 566 secured_conn = bool(int(args[1])) 567 psm_value = int(args[2]) # 1 568 self.dut.droid.bluetoothSocketConnBeginConnectThreadPsm( 569 self.target_mac_addr, is_ble, psm_value, secured_conn) 570 571 def socket_conn_begin_accept_thread_psm(self, line): 572 accept_timeout_ms = default_bluetooth_socket_timeout_ms 573 is_ble = True 574 secured_conn = False 575 self.dut.droid.bluetoothSocketConnBeginAcceptThreadPsm( 576 accept_timeout_ms, is_ble, secured_conn) 577