1*cf78ab8cSAndroid Build Coastguard Worker"""BLE test utils for netsim.""" 2*cf78ab8cSAndroid Build Coastguard Worker 3*cf78ab8cSAndroid Build Coastguard Workerimport logging 4*cf78ab8cSAndroid Build Coastguard Workerimport time 5*cf78ab8cSAndroid Build Coastguard Workerfrom typing import Any 6*cf78ab8cSAndroid Build Coastguard Worker 7*cf78ab8cSAndroid Build Coastguard Workerfrom mobly import asserts 8*cf78ab8cSAndroid Build Coastguard Workerfrom mobly import utils 9*cf78ab8cSAndroid Build Coastguard Workerfrom mobly.controllers import android_device 10*cf78ab8cSAndroid Build Coastguard Workerfrom mobly.snippet import callback_event 11*cf78ab8cSAndroid Build Coastguard Worker 12*cf78ab8cSAndroid Build Coastguard Worker 13*cf78ab8cSAndroid Build Coastguard Worker# Number of seconds for the target to stay BLE advertising. 14*cf78ab8cSAndroid Build Coastguard WorkerADVERTISING_TIME = 120 15*cf78ab8cSAndroid Build Coastguard Worker# Number of seconds for the target to start BLE advertising. 16*cf78ab8cSAndroid Build Coastguard WorkerADVERTISING_START_TIME = 30 17*cf78ab8cSAndroid Build Coastguard Worker# The number of seconds to wait for receiving scan results. 18*cf78ab8cSAndroid Build Coastguard WorkerSCAN_TIMEOUT = 20 19*cf78ab8cSAndroid Build Coastguard Worker# The number of seconds to wair for connection established. 20*cf78ab8cSAndroid Build Coastguard WorkerCONNECTION_TIMEOUT = 60 21*cf78ab8cSAndroid Build Coastguard Worker# The number of seconds to wait before cancel connection. 22*cf78ab8cSAndroid Build Coastguard WorkerCANCEL_CONNECTION_WAIT_TIME = 0.1 23*cf78ab8cSAndroid Build Coastguard Worker# UUID for test service. 24*cf78ab8cSAndroid Build Coastguard WorkerTEST_BLE_SERVICE_UUID = '0000fe23-0000-1000-8000-00805f9b34fb' 25*cf78ab8cSAndroid Build Coastguard Worker# UUID for write characteristic. 26*cf78ab8cSAndroid Build Coastguard WorkerTEST_WRITE_UUID = '0000e632-0000-1000-8000-00805f9b34fb' 27*cf78ab8cSAndroid Build Coastguard Worker# UUID for second write characteristic. 28*cf78ab8cSAndroid Build Coastguard WorkerTEST_SECOND_WRITE_UUID = '0000e633-0000-1000-8000-00805f9b34fb' 29*cf78ab8cSAndroid Build Coastguard Worker# UUID for read test. 30*cf78ab8cSAndroid Build Coastguard WorkerTEST_READ_UUID = '0000e631-0000-1000-8000-00805f9b34fb' 31*cf78ab8cSAndroid Build Coastguard Worker# UUID for second read characteristic. 32*cf78ab8cSAndroid Build Coastguard WorkerTEST_SECOND_READ_UUID = '0000e634-0000-1000-8000-00805f9b34fb' 33*cf78ab8cSAndroid Build Coastguard Worker# UUID for third read characteristic. 34*cf78ab8cSAndroid Build Coastguard WorkerTEST_THIRD_READ_UUID = '0000e635-0000-1000-8000-00805f9b34fb' 35*cf78ab8cSAndroid Build Coastguard Worker# UUID for scan response. 36*cf78ab8cSAndroid Build Coastguard WorkerTEST_SCAN_RESPONSE_UUID = '0000e639-0000-1000-8000-00805f9b34fb' 37*cf78ab8cSAndroid Build Coastguard Worker# Advertise settings in json format for Ble Advertise. 38*cf78ab8cSAndroid Build Coastguard WorkerADVERTISE_SETTINGS = { 39*cf78ab8cSAndroid Build Coastguard Worker 'AdvertiseMode': 'ADVERTISE_MODE_LOW_LATENCY', 40*cf78ab8cSAndroid Build Coastguard Worker 'Timeout': ADVERTISING_TIME * 1000, 41*cf78ab8cSAndroid Build Coastguard Worker 'Connectable': True, 42*cf78ab8cSAndroid Build Coastguard Worker 'TxPowerLevel': 'ADVERTISE_TX_POWER_ULTRA_LOW', 43*cf78ab8cSAndroid Build Coastguard Worker} 44*cf78ab8cSAndroid Build Coastguard Worker# Ramdom data to represent device stored in advertise data. 45*cf78ab8cSAndroid Build Coastguard WorkerDATA = utils.rand_ascii_str(16) 46*cf78ab8cSAndroid Build Coastguard Worker# Random data for scan response. 47*cf78ab8cSAndroid Build Coastguard WorkerSCAN_RESPONSE_DATA = utils.rand_ascii_str(16) 48*cf78ab8cSAndroid Build Coastguard Worker# Random data for read operation. 49*cf78ab8cSAndroid Build Coastguard WorkerREAD_DATA = utils.rand_ascii_str(8) 50*cf78ab8cSAndroid Build Coastguard Worker# Random data for second read operation. 51*cf78ab8cSAndroid Build Coastguard WorkerSECOND_READ_DATA = utils.rand_ascii_str(8) 52*cf78ab8cSAndroid Build Coastguard Worker# Random data for third read operation. 53*cf78ab8cSAndroid Build Coastguard WorkerTHIRD_READ_DATA = utils.rand_ascii_str(8) 54*cf78ab8cSAndroid Build Coastguard Worker# Random data for write operation. 55*cf78ab8cSAndroid Build Coastguard WorkerWRITE_DATA = utils.rand_ascii_str(8) 56*cf78ab8cSAndroid Build Coastguard Worker# Random data for second write operation. 57*cf78ab8cSAndroid Build Coastguard WorkerSECOND_WRITE_DATA = utils.rand_ascii_str(8) 58*cf78ab8cSAndroid Build Coastguard Worker# Advertise data in json format for BLE advertise. 59*cf78ab8cSAndroid Build Coastguard WorkerADVERTISE_DATA = { 60*cf78ab8cSAndroid Build Coastguard Worker 'IncludeDeviceName': False, 61*cf78ab8cSAndroid Build Coastguard Worker 'ServiceData': [{'UUID': TEST_BLE_SERVICE_UUID, 'Data': DATA}], 62*cf78ab8cSAndroid Build Coastguard Worker} 63*cf78ab8cSAndroid Build Coastguard Worker# Advertise data in json format representing scan response for BLE advertise. 64*cf78ab8cSAndroid Build Coastguard WorkerSCAN_RESPONSE = { 65*cf78ab8cSAndroid Build Coastguard Worker 'IncludeDeviceName': False, 66*cf78ab8cSAndroid Build Coastguard Worker 'ServiceData': [{ 67*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_SCAN_RESPONSE_UUID, 68*cf78ab8cSAndroid Build Coastguard Worker 'Data': SCAN_RESPONSE_DATA, 69*cf78ab8cSAndroid Build Coastguard Worker }], 70*cf78ab8cSAndroid Build Coastguard Worker} 71*cf78ab8cSAndroid Build Coastguard Worker# Scan filter in json format for BLE scan. 72*cf78ab8cSAndroid Build Coastguard WorkerSCAN_FILTER = {'ServiceUuid': TEST_BLE_SERVICE_UUID} 73*cf78ab8cSAndroid Build Coastguard Worker# Scan settings in json format for BLE scan. 74*cf78ab8cSAndroid Build Coastguard WorkerSCAN_SETTINGS = {'ScanMode': 'SCAN_MODE_LOW_LATENCY'} 75*cf78ab8cSAndroid Build Coastguard Worker# Characteristics for write in json format. 76*cf78ab8cSAndroid Build Coastguard WorkerWRITE_CHARACTERISTIC = { 77*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_WRITE_UUID, 78*cf78ab8cSAndroid Build Coastguard Worker 'Property': 'PROPERTY_WRITE', 79*cf78ab8cSAndroid Build Coastguard Worker 'Permission': 'PERMISSION_WRITE', 80*cf78ab8cSAndroid Build Coastguard Worker} 81*cf78ab8cSAndroid Build Coastguard WorkerSECOND_WRITE_CHARACTERISTIC = { 82*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_SECOND_WRITE_UUID, 83*cf78ab8cSAndroid Build Coastguard Worker 'Property': 'PROPERTY_WRITE', 84*cf78ab8cSAndroid Build Coastguard Worker 'Permission': 'PERMISSION_WRITE', 85*cf78ab8cSAndroid Build Coastguard Worker} 86*cf78ab8cSAndroid Build Coastguard Worker# Characteristics for read in json format. 87*cf78ab8cSAndroid Build Coastguard WorkerREAD_CHARACTERISTIC = { 88*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_READ_UUID, 89*cf78ab8cSAndroid Build Coastguard Worker 'Property': 'PROPERTY_READ', 90*cf78ab8cSAndroid Build Coastguard Worker 'Permission': 'PERMISSION_READ', 91*cf78ab8cSAndroid Build Coastguard Worker 'Data': READ_DATA, 92*cf78ab8cSAndroid Build Coastguard Worker} 93*cf78ab8cSAndroid Build Coastguard WorkerSECOND_READ_CHARACTERISTIC = { 94*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_SECOND_READ_UUID, 95*cf78ab8cSAndroid Build Coastguard Worker 'Property': 'PROPERTY_READ', 96*cf78ab8cSAndroid Build Coastguard Worker 'Permission': 'PERMISSION_READ', 97*cf78ab8cSAndroid Build Coastguard Worker 'Data': SECOND_READ_DATA, 98*cf78ab8cSAndroid Build Coastguard Worker} 99*cf78ab8cSAndroid Build Coastguard WorkerTHIRD_READ_CHARACTERISTIC = { 100*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_THIRD_READ_UUID, 101*cf78ab8cSAndroid Build Coastguard Worker 'Property': 'PROPERTY_READ', 102*cf78ab8cSAndroid Build Coastguard Worker 'Permission': 'PERMISSION_READ', 103*cf78ab8cSAndroid Build Coastguard Worker 'Data': THIRD_READ_DATA, 104*cf78ab8cSAndroid Build Coastguard Worker} 105*cf78ab8cSAndroid Build Coastguard Worker# Service data in json format for Ble Server. 106*cf78ab8cSAndroid Build Coastguard WorkerSERVICE = { 107*cf78ab8cSAndroid Build Coastguard Worker 'UUID': TEST_BLE_SERVICE_UUID, 108*cf78ab8cSAndroid Build Coastguard Worker 'Type': 'SERVICE_TYPE_PRIMARY', 109*cf78ab8cSAndroid Build Coastguard Worker 'Characteristics': [ 110*cf78ab8cSAndroid Build Coastguard Worker WRITE_CHARACTERISTIC, 111*cf78ab8cSAndroid Build Coastguard Worker SECOND_WRITE_CHARACTERISTIC, 112*cf78ab8cSAndroid Build Coastguard Worker READ_CHARACTERISTIC, 113*cf78ab8cSAndroid Build Coastguard Worker SECOND_READ_CHARACTERISTIC, 114*cf78ab8cSAndroid Build Coastguard Worker THIRD_READ_CHARACTERISTIC, 115*cf78ab8cSAndroid Build Coastguard Worker ], 116*cf78ab8cSAndroid Build Coastguard Worker} 117*cf78ab8cSAndroid Build Coastguard Worker# Macros for literal string. 118*cf78ab8cSAndroid Build Coastguard WorkerUUID = 'UUID' 119*cf78ab8cSAndroid Build Coastguard WorkerGATT_SUCCESS = 'GATT_SUCCESS' 120*cf78ab8cSAndroid Build Coastguard WorkerSTATE = 'newState' 121*cf78ab8cSAndroid Build Coastguard WorkerSTATUS = 'status' 122*cf78ab8cSAndroid Build Coastguard Worker 123*cf78ab8cSAndroid Build Coastguard Worker 124*cf78ab8cSAndroid Build Coastguard Workerdef IsRequiredScanResult(scan_result: callback_event.CallbackEvent) -> bool: 125*cf78ab8cSAndroid Build Coastguard Worker result = scan_result.data['result'] 126*cf78ab8cSAndroid Build Coastguard Worker for service in result['ScanRecord']['Services']: 127*cf78ab8cSAndroid Build Coastguard Worker if service[UUID] == TEST_BLE_SERVICE_UUID and service['Data'] == DATA: 128*cf78ab8cSAndroid Build Coastguard Worker return True 129*cf78ab8cSAndroid Build Coastguard Worker return False 130*cf78ab8cSAndroid Build Coastguard Worker 131*cf78ab8cSAndroid Build Coastguard Worker 132*cf78ab8cSAndroid Build Coastguard Workerdef Discover( 133*cf78ab8cSAndroid Build Coastguard Worker scanner: android_device.AndroidDevice, 134*cf78ab8cSAndroid Build Coastguard Worker advertiser: android_device.AndroidDevice, 135*cf78ab8cSAndroid Build Coastguard Worker) -> dict[str, Any]: 136*cf78ab8cSAndroid Build Coastguard Worker """Logic for BLE scan and advertising. 137*cf78ab8cSAndroid Build Coastguard Worker 138*cf78ab8cSAndroid Build Coastguard Worker Steps: 139*cf78ab8cSAndroid Build Coastguard Worker 1. Advertiser starts advertising and gets a startSuccess callback. 140*cf78ab8cSAndroid Build Coastguard Worker 2. Scanner starts scanning and finds advertiser from scan results. 141*cf78ab8cSAndroid Build Coastguard Worker 142*cf78ab8cSAndroid Build Coastguard Worker Verifies: 143*cf78ab8cSAndroid Build Coastguard Worker Advertiser is discovered within 5s by scanner. 144*cf78ab8cSAndroid Build Coastguard Worker 145*cf78ab8cSAndroid Build Coastguard Worker Args: 146*cf78ab8cSAndroid Build Coastguard Worker scanner: AndroidDevice. The device that starts BLE scan to find target. 147*cf78ab8cSAndroid Build Coastguard Worker advertiser: AndroidDevice. The device that keeps advertising so other 148*cf78ab8cSAndroid Build Coastguard Worker devices acknowledge it. 149*cf78ab8cSAndroid Build Coastguard Worker 150*cf78ab8cSAndroid Build Coastguard Worker Returns: 151*cf78ab8cSAndroid Build Coastguard Worker dict. Scan results. 152*cf78ab8cSAndroid Build Coastguard Worker 153*cf78ab8cSAndroid Build Coastguard Worker Raises: 154*cf78ab8cSAndroid Build Coastguard Worker TimeoutError: The expected event does not occur within the time limit. 155*cf78ab8cSAndroid Build Coastguard Worker """ 156*cf78ab8cSAndroid Build Coastguard Worker # Retry initial command in case command is lost after triggering a reset 157*cf78ab8cSAndroid Build Coastguard Worker max_attempts = 2 158*cf78ab8cSAndroid Build Coastguard Worker for attempt_num in range(max_attempts): 159*cf78ab8cSAndroid Build Coastguard Worker advertiser.advertise_callback = advertiser.mbs.bleStartAdvertising( 160*cf78ab8cSAndroid Build Coastguard Worker ADVERTISE_SETTINGS, ADVERTISE_DATA, SCAN_RESPONSE 161*cf78ab8cSAndroid Build Coastguard Worker ) 162*cf78ab8cSAndroid Build Coastguard Worker scanner.scan_callback = scanner.mbs.bleStartScan( 163*cf78ab8cSAndroid Build Coastguard Worker [SCAN_FILTER], SCAN_SETTINGS 164*cf78ab8cSAndroid Build Coastguard Worker ) 165*cf78ab8cSAndroid Build Coastguard Worker success = False 166*cf78ab8cSAndroid Build Coastguard Worker for _ in range(ADVERTISING_START_TIME): 167*cf78ab8cSAndroid Build Coastguard Worker failure = advertiser.advertise_callback.getAll('onStartFailure') 168*cf78ab8cSAndroid Build Coastguard Worker if failure: 169*cf78ab8cSAndroid Build Coastguard Worker logging.warning( 170*cf78ab8cSAndroid Build Coastguard Worker "'onStartFailure' event detected after bleStartAdvertising" 171*cf78ab8cSAndroid Build Coastguard Worker ) 172*cf78ab8cSAndroid Build Coastguard Worker success = advertiser.advertise_callback.getAll('onStartSuccess') 173*cf78ab8cSAndroid Build Coastguard Worker if success: 174*cf78ab8cSAndroid Build Coastguard Worker break 175*cf78ab8cSAndroid Build Coastguard Worker time.sleep(1) 176*cf78ab8cSAndroid Build Coastguard Worker else: 177*cf78ab8cSAndroid Build Coastguard Worker logging.error( 178*cf78ab8cSAndroid Build Coastguard Worker 'Timed out after %ss waiting for an "onStartSuccess" event ', 179*cf78ab8cSAndroid Build Coastguard Worker ADVERTISING_START_TIME, 180*cf78ab8cSAndroid Build Coastguard Worker ) 181*cf78ab8cSAndroid Build Coastguard Worker if not success: 182*cf78ab8cSAndroid Build Coastguard Worker if attempt_num < max_attempts - 1: 183*cf78ab8cSAndroid Build Coastguard Worker logging.warning( 184*cf78ab8cSAndroid Build Coastguard Worker "'onStartSuccess' event was not received after " 185*cf78ab8cSAndroid Build Coastguard Worker 'bleStartAdvertising. Retrying... (%d)', 186*cf78ab8cSAndroid Build Coastguard Worker attempt_num + 1, 187*cf78ab8cSAndroid Build Coastguard Worker ) 188*cf78ab8cSAndroid Build Coastguard Worker else: 189*cf78ab8cSAndroid Build Coastguard Worker raise TimeoutError( 190*cf78ab8cSAndroid Build Coastguard Worker f'Timed out after {max_attempts} retries of ' 191*cf78ab8cSAndroid Build Coastguard Worker f'{ADVERTISING_START_TIME}s waiting for an ' 192*cf78ab8cSAndroid Build Coastguard Worker '"onStartSuccess" event ' 193*cf78ab8cSAndroid Build Coastguard Worker ) 194*cf78ab8cSAndroid Build Coastguard Worker 195*cf78ab8cSAndroid Build Coastguard Worker advertiser.log.info('BLE advertising started') 196*cf78ab8cSAndroid Build Coastguard Worker time.sleep(SCAN_TIMEOUT) 197*cf78ab8cSAndroid Build Coastguard Worker scan_result = scanner.scan_callback.waitForEvent( 198*cf78ab8cSAndroid Build Coastguard Worker 'onScanResult', IsRequiredScanResult, SCAN_TIMEOUT 199*cf78ab8cSAndroid Build Coastguard Worker ) 200*cf78ab8cSAndroid Build Coastguard Worker scan_success = False 201*cf78ab8cSAndroid Build Coastguard Worker scan_response_found = False 202*cf78ab8cSAndroid Build Coastguard Worker result = scan_result.data['result'] 203*cf78ab8cSAndroid Build Coastguard Worker scan_start_to_result_time_ms = scan_result.data['StartToResultTimeDeltaMs'] 204*cf78ab8cSAndroid Build Coastguard Worker for service in result['ScanRecord']['Services']: 205*cf78ab8cSAndroid Build Coastguard Worker if service[UUID] == TEST_BLE_SERVICE_UUID and service['Data'] == DATA: 206*cf78ab8cSAndroid Build Coastguard Worker scanner.connect_to_address = result['Device']['Address'] 207*cf78ab8cSAndroid Build Coastguard Worker scan_success = True 208*cf78ab8cSAndroid Build Coastguard Worker if ( 209*cf78ab8cSAndroid Build Coastguard Worker service[UUID] == TEST_SCAN_RESPONSE_UUID 210*cf78ab8cSAndroid Build Coastguard Worker and service['Data'] == SCAN_RESPONSE_DATA 211*cf78ab8cSAndroid Build Coastguard Worker ): 212*cf78ab8cSAndroid Build Coastguard Worker scan_response_found = True 213*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 214*cf78ab8cSAndroid Build Coastguard Worker scan_success, 'Advertiser is not found inside %d seconds' % SCAN_TIMEOUT 215*cf78ab8cSAndroid Build Coastguard Worker ) 216*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true(scan_response_found, 'Scan response is not found') 217*cf78ab8cSAndroid Build Coastguard Worker logging.info('Discovery metrics: %d', scan_start_to_result_time_ms) 218*cf78ab8cSAndroid Build Coastguard Worker return result 219*cf78ab8cSAndroid Build Coastguard Worker 220*cf78ab8cSAndroid Build Coastguard Worker 221*cf78ab8cSAndroid Build Coastguard Workerdef StartScanning( 222*cf78ab8cSAndroid Build Coastguard Worker scanner: android_device.AndroidDevice, scan_duration: int 223*cf78ab8cSAndroid Build Coastguard Worker) -> list[dict[str, Any]]: 224*cf78ab8cSAndroid Build Coastguard Worker """Logic for BLE scanning for advertisers. 225*cf78ab8cSAndroid Build Coastguard Worker 226*cf78ab8cSAndroid Build Coastguard Worker Steps: 227*cf78ab8cSAndroid Build Coastguard Worker 1. Scanner starts scanning with retries 228*cf78ab8cSAndroid Build Coastguard Worker 2. Retrieves the ScanResult 229*cf78ab8cSAndroid Build Coastguard Worker 230*cf78ab8cSAndroid Build Coastguard Worker Verifies: 231*cf78ab8cSAndroid Build Coastguard Worker Advertiser is discovered within timeout by scanner. 232*cf78ab8cSAndroid Build Coastguard Worker 233*cf78ab8cSAndroid Build Coastguard Worker Args: 234*cf78ab8cSAndroid Build Coastguard Worker scanner: AndroidDevice. The device that starts BLE scan to find advertisers. 235*cf78ab8cSAndroid Build Coastguard Worker scan_duration: Number of seconds for each scan attempt 236*cf78ab8cSAndroid Build Coastguard Worker 237*cf78ab8cSAndroid Build Coastguard Worker Returns: 238*cf78ab8cSAndroid Build Coastguard Worker List of dicts containing Scan results. 239*cf78ab8cSAndroid Build Coastguard Worker 240*cf78ab8cSAndroid Build Coastguard Worker Raises: 241*cf78ab8cSAndroid Build Coastguard Worker TimeoutError: The expected event does not occur within the time limit. 242*cf78ab8cSAndroid Build Coastguard Worker """ 243*cf78ab8cSAndroid Build Coastguard Worker # Retry initial command in case command is lost after triggering a reset 244*cf78ab8cSAndroid Build Coastguard Worker max_attempts = 3 245*cf78ab8cSAndroid Build Coastguard Worker scan_success = False 246*cf78ab8cSAndroid Build Coastguard Worker result = [] 247*cf78ab8cSAndroid Build Coastguard Worker scan_result = None 248*cf78ab8cSAndroid Build Coastguard Worker for attempt_num in range(max_attempts): 249*cf78ab8cSAndroid Build Coastguard Worker scanner.scan_callback = scanner.mbs.bleStartScan() 250*cf78ab8cSAndroid Build Coastguard Worker scanner.log.info('BLE scanning started') 251*cf78ab8cSAndroid Build Coastguard Worker failure = scanner.scan_callback.getAll('onScanFailed') 252*cf78ab8cSAndroid Build Coastguard Worker if failure: 253*cf78ab8cSAndroid Build Coastguard Worker logging.warning("'onScanFailed' event detected after bleStartScan") 254*cf78ab8cSAndroid Build Coastguard Worker continue 255*cf78ab8cSAndroid Build Coastguard Worker success = False 256*cf78ab8cSAndroid Build Coastguard Worker for _ in range(int(SCAN_TIMEOUT / scan_duration)): 257*cf78ab8cSAndroid Build Coastguard Worker time.sleep(scan_duration) 258*cf78ab8cSAndroid Build Coastguard Worker scan_result = scanner.scan_callback.getAll('onScanResult') 259*cf78ab8cSAndroid Build Coastguard Worker if scan_result: 260*cf78ab8cSAndroid Build Coastguard Worker success = True 261*cf78ab8cSAndroid Build Coastguard Worker break 262*cf78ab8cSAndroid Build Coastguard Worker else: 263*cf78ab8cSAndroid Build Coastguard Worker logging.error( 264*cf78ab8cSAndroid Build Coastguard Worker 'Timed out after %ss waiting for an "onScanResult" event ', 265*cf78ab8cSAndroid Build Coastguard Worker SCAN_TIMEOUT, 266*cf78ab8cSAndroid Build Coastguard Worker ) 267*cf78ab8cSAndroid Build Coastguard Worker if success: 268*cf78ab8cSAndroid Build Coastguard Worker break 269*cf78ab8cSAndroid Build Coastguard Worker if attempt_num < max_attempts - 1: 270*cf78ab8cSAndroid Build Coastguard Worker logging.warning( 271*cf78ab8cSAndroid Build Coastguard Worker "'onScanResult' event was not received after " 272*cf78ab8cSAndroid Build Coastguard Worker 'bleStartScan. Retrying... (%d)', 273*cf78ab8cSAndroid Build Coastguard Worker attempt_num + 1, 274*cf78ab8cSAndroid Build Coastguard Worker ) 275*cf78ab8cSAndroid Build Coastguard Worker else: 276*cf78ab8cSAndroid Build Coastguard Worker raise TimeoutError( 277*cf78ab8cSAndroid Build Coastguard Worker f'Timed out after {max_attempts} retries of ' 278*cf78ab8cSAndroid Build Coastguard Worker f'{SCAN_TIMEOUT}s waiting for an ' 279*cf78ab8cSAndroid Build Coastguard Worker '"onScanResult" event ' 280*cf78ab8cSAndroid Build Coastguard Worker ) 281*cf78ab8cSAndroid Build Coastguard Worker 282*cf78ab8cSAndroid Build Coastguard Worker if scan_result: 283*cf78ab8cSAndroid Build Coastguard Worker scan_success = True 284*cf78ab8cSAndroid Build Coastguard Worker result = [result.data['result'] for result in scan_result] 285*cf78ab8cSAndroid Build Coastguard Worker 286*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 287*cf78ab8cSAndroid Build Coastguard Worker scan_success, 'Advertiser is not found inside %d seconds' % SCAN_TIMEOUT 288*cf78ab8cSAndroid Build Coastguard Worker ) 289*cf78ab8cSAndroid Build Coastguard Worker return result 290*cf78ab8cSAndroid Build Coastguard Worker 291*cf78ab8cSAndroid Build Coastguard Worker 292*cf78ab8cSAndroid Build Coastguard Workerdef StopDiscover( 293*cf78ab8cSAndroid Build Coastguard Worker scanner: android_device.AndroidDevice, 294*cf78ab8cSAndroid Build Coastguard Worker advertiser: android_device.AndroidDevice, 295*cf78ab8cSAndroid Build Coastguard Worker) -> None: 296*cf78ab8cSAndroid Build Coastguard Worker """Logic for stopping BLE scan and advertising. 297*cf78ab8cSAndroid Build Coastguard Worker 298*cf78ab8cSAndroid Build Coastguard Worker Steps: 299*cf78ab8cSAndroid Build Coastguard Worker 1. Scanner stops scanning. 300*cf78ab8cSAndroid Build Coastguard Worker 2. Advertiser stops advertising. 301*cf78ab8cSAndroid Build Coastguard Worker 302*cf78ab8cSAndroid Build Coastguard Worker Args: 303*cf78ab8cSAndroid Build Coastguard Worker scanner: AndroidDevice. The device that starts BLE scan to find target. 304*cf78ab8cSAndroid Build Coastguard Worker advertiser: AndroidDevice. The device that keeps advertising so other 305*cf78ab8cSAndroid Build Coastguard Worker devices acknowledge it. 306*cf78ab8cSAndroid Build Coastguard Worker """ 307*cf78ab8cSAndroid Build Coastguard Worker scanner.mbs.bleStopScan(scanner.scan_callback.callback_id) 308*cf78ab8cSAndroid Build Coastguard Worker scanner.log.info('BLE scanning stopped') 309*cf78ab8cSAndroid Build Coastguard Worker advertiser.mbs.bleStopAdvertising(advertiser.advertise_callback.callback_id) 310*cf78ab8cSAndroid Build Coastguard Worker advertiser.log.info('BLE advertising stopped') 311*cf78ab8cSAndroid Build Coastguard Worker 312*cf78ab8cSAndroid Build Coastguard Worker 313*cf78ab8cSAndroid Build Coastguard Workerdef StopScanning(scanner: android_device.AndroidDevice) -> None: 314*cf78ab8cSAndroid Build Coastguard Worker """Logic for stopping BLE scan. 315*cf78ab8cSAndroid Build Coastguard Worker 316*cf78ab8cSAndroid Build Coastguard Worker Steps: 317*cf78ab8cSAndroid Build Coastguard Worker 1. Scanner stops scanning. 318*cf78ab8cSAndroid Build Coastguard Worker 319*cf78ab8cSAndroid Build Coastguard Worker Args: 320*cf78ab8cSAndroid Build Coastguard Worker scanner: AndroidDevice. The device that starts BLE scan to find target. 321*cf78ab8cSAndroid Build Coastguard Worker """ 322*cf78ab8cSAndroid Build Coastguard Worker scanner.mbs.bleStopScan(scanner.scan_callback.callback_id) 323*cf78ab8cSAndroid Build Coastguard Worker scanner.log.info('BLE scanning stopped') 324*cf78ab8cSAndroid Build Coastguard Worker 325*cf78ab8cSAndroid Build Coastguard Worker 326*cf78ab8cSAndroid Build Coastguard Workerdef Connect( 327*cf78ab8cSAndroid Build Coastguard Worker client: android_device.AndroidDevice, server: android_device.AndroidDevice 328*cf78ab8cSAndroid Build Coastguard Worker) -> None: 329*cf78ab8cSAndroid Build Coastguard Worker """Logic for create a Gatt connection between a client and a server. 330*cf78ab8cSAndroid Build Coastguard Worker 331*cf78ab8cSAndroid Build Coastguard Worker Steps: 332*cf78ab8cSAndroid Build Coastguard Worker 1. Server starts and service added properly. 333*cf78ab8cSAndroid Build Coastguard Worker 2. Client connects to server via Gatt, connection completes with 334*cf78ab8cSAndroid Build Coastguard Worker GATT_SUCCESS within TIMEOUT, onConnectionStateChange/STATE_CONNECTED is 335*cf78ab8cSAndroid Build Coastguard Worker called EXACTLY once. 336*cf78ab8cSAndroid Build Coastguard Worker 337*cf78ab8cSAndroid Build Coastguard Worker Verifies: 338*cf78ab8cSAndroid Build Coastguard Worker Both the client and the server consider themselves connected to each other. 339*cf78ab8cSAndroid Build Coastguard Worker 340*cf78ab8cSAndroid Build Coastguard Worker Args: 341*cf78ab8cSAndroid Build Coastguard Worker client: AndroidDevice. The device that behaves as GATT client. 342*cf78ab8cSAndroid Build Coastguard Worker server: AndroidDevice. The device that behaves as GATT server. 343*cf78ab8cSAndroid Build Coastguard Worker """ 344*cf78ab8cSAndroid Build Coastguard Worker server.server_callback = server.mbs.bleStartServer([SERVICE]) 345*cf78ab8cSAndroid Build Coastguard Worker start_server_result = server.server_callback.waitAndGet('onServiceAdded', 30) 346*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(start_server_result.data[STATUS], GATT_SUCCESS) 347*cf78ab8cSAndroid Build Coastguard Worker uuids = [ 348*cf78ab8cSAndroid Build Coastguard Worker characteristic[UUID] 349*cf78ab8cSAndroid Build Coastguard Worker for characteristic in start_server_result.data['Service'][ 350*cf78ab8cSAndroid Build Coastguard Worker 'Characteristics' 351*cf78ab8cSAndroid Build Coastguard Worker ] 352*cf78ab8cSAndroid Build Coastguard Worker ] 353*cf78ab8cSAndroid Build Coastguard Worker for uuid in [ 354*cf78ab8cSAndroid Build Coastguard Worker characteristic[UUID] for characteristic in SERVICE['Characteristics'] 355*cf78ab8cSAndroid Build Coastguard Worker ]: 356*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true(uuid in uuids, 'Failed to find uuid %s.' % uuid) 357*cf78ab8cSAndroid Build Coastguard Worker server.log.info('BLE server started') 358*cf78ab8cSAndroid Build Coastguard Worker client.client_callback = client.mbs.bleConnectGatt(client.connect_to_address) 359*cf78ab8cSAndroid Build Coastguard Worker start_client_result = client.client_callback.waitAndGet( 360*cf78ab8cSAndroid Build Coastguard Worker 'onConnectionStateChange', CONNECTION_TIMEOUT 361*cf78ab8cSAndroid Build Coastguard Worker ) 362*cf78ab8cSAndroid Build Coastguard Worker extra_events = client.client_callback.getAll('onConnectionStateChange') 363*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_false( 364*cf78ab8cSAndroid Build Coastguard Worker extra_events, 365*cf78ab8cSAndroid Build Coastguard Worker 'Got unexpected onConnectionStateChange events: %s', 366*cf78ab8cSAndroid Build Coastguard Worker extra_events, 367*cf78ab8cSAndroid Build Coastguard Worker ) 368*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(start_client_result.data[STATUS], GATT_SUCCESS) 369*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(start_client_result.data[STATE], 'STATE_CONNECTED') 370*cf78ab8cSAndroid Build Coastguard Worker client.log.info('BLE client connected') 371*cf78ab8cSAndroid Build Coastguard Worker # Verify that the server side also considers itself connected. 372*cf78ab8cSAndroid Build Coastguard Worker server_event = server.server_callback.waitAndGet('onConnectionStateChange') 373*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(server_event.data[STATUS], GATT_SUCCESS) 374*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal( 375*cf78ab8cSAndroid Build Coastguard Worker server_event.data[STATE], 376*cf78ab8cSAndroid Build Coastguard Worker 'STATE_CONNECTED', 377*cf78ab8cSAndroid Build Coastguard Worker 'The server side does not consider itself connected, error!', 378*cf78ab8cSAndroid Build Coastguard Worker ) 379*cf78ab8cSAndroid Build Coastguard Worker logging.info('Gatt connection complete.') 380*cf78ab8cSAndroid Build Coastguard Worker logging.info( 381*cf78ab8cSAndroid Build Coastguard Worker 'Connection metrics: %d', start_client_result.data['gattConnectionTimeMs'] 382*cf78ab8cSAndroid Build Coastguard Worker ) 383*cf78ab8cSAndroid Build Coastguard Worker 384*cf78ab8cSAndroid Build Coastguard Worker 385*cf78ab8cSAndroid Build Coastguard Workerdef Disconnect( 386*cf78ab8cSAndroid Build Coastguard Worker client: android_device.AndroidDevice, server: android_device.AndroidDevice 387*cf78ab8cSAndroid Build Coastguard Worker) -> None: 388*cf78ab8cSAndroid Build Coastguard Worker """Logic for stopping BLE client and server. 389*cf78ab8cSAndroid Build Coastguard Worker 390*cf78ab8cSAndroid Build Coastguard Worker Steps: 391*cf78ab8cSAndroid Build Coastguard Worker 1. Client calls disconnect, gets a callback with STATE_DISCONNECTED and 392*cf78ab8cSAndroid Build Coastguard Worker GATT_SUCCESS. 393*cf78ab8cSAndroid Build Coastguard Worker 2. Server closes. 394*cf78ab8cSAndroid Build Coastguard Worker 395*cf78ab8cSAndroid Build Coastguard Worker Verifies: Client gets corresponding callback. 396*cf78ab8cSAndroid Build Coastguard Worker 397*cf78ab8cSAndroid Build Coastguard Worker Args: 398*cf78ab8cSAndroid Build Coastguard Worker client: AndroidDevice. The device that behaves as GATT client. 399*cf78ab8cSAndroid Build Coastguard Worker server: AndroidDevice. The device that behaves as GATT server. 400*cf78ab8cSAndroid Build Coastguard Worker """ 401*cf78ab8cSAndroid Build Coastguard Worker client.mbs.bleDisconnect() 402*cf78ab8cSAndroid Build Coastguard Worker stop_client_result = client.client_callback.waitAndGet( 403*cf78ab8cSAndroid Build Coastguard Worker 'onConnectionStateChange', 30 404*cf78ab8cSAndroid Build Coastguard Worker ) 405*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(stop_client_result.data[STATUS], GATT_SUCCESS) 406*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(stop_client_result.data[STATE], 'STATE_DISCONNECTED') 407*cf78ab8cSAndroid Build Coastguard Worker client.log.info('BLE client disconnected') 408*cf78ab8cSAndroid Build Coastguard Worker server.mbs.bleStopServer() 409*cf78ab8cSAndroid Build Coastguard Worker server.log.info('BLE server stopped') 410*cf78ab8cSAndroid Build Coastguard Worker 411*cf78ab8cSAndroid Build Coastguard Worker 412*cf78ab8cSAndroid Build Coastguard Workerdef DiscoverServices(client: android_device.AndroidDevice) -> None: 413*cf78ab8cSAndroid Build Coastguard Worker """Logic for BLE services discovery. 414*cf78ab8cSAndroid Build Coastguard Worker 415*cf78ab8cSAndroid Build Coastguard Worker Steps: 416*cf78ab8cSAndroid Build Coastguard Worker 1. Client successfully completes service discovery & gets 417*cf78ab8cSAndroid Build Coastguard Worker onServicesDiscovered callback within some TIMEOUT, onServicesDiscovered/ 418*cf78ab8cSAndroid Build Coastguard Worker GATT_SUCCESS is called EXACTLY once. 419*cf78ab8cSAndroid Build Coastguard Worker 2. Client discovers the readable and writable characteristics. 420*cf78ab8cSAndroid Build Coastguard Worker 421*cf78ab8cSAndroid Build Coastguard Worker Verifies: 422*cf78ab8cSAndroid Build Coastguard Worker Client gets corresponding callback. 423*cf78ab8cSAndroid Build Coastguard Worker 424*cf78ab8cSAndroid Build Coastguard Worker Args: 425*cf78ab8cSAndroid Build Coastguard Worker client: AndroidDevice. The device that behaves as GATT client. 426*cf78ab8cSAndroid Build Coastguard Worker """ 427*cf78ab8cSAndroid Build Coastguard Worker client.mbs.bleDiscoverServices() 428*cf78ab8cSAndroid Build Coastguard Worker time.sleep(CONNECTION_TIMEOUT) 429*cf78ab8cSAndroid Build Coastguard Worker discover_services_results = client.client_callback.getAll( 430*cf78ab8cSAndroid Build Coastguard Worker 'onServiceDiscovered' 431*cf78ab8cSAndroid Build Coastguard Worker ) 432*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(len(discover_services_results), 1) 433*cf78ab8cSAndroid Build Coastguard Worker service_discovered = False 434*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(discover_services_results[0].data[STATUS], GATT_SUCCESS) 435*cf78ab8cSAndroid Build Coastguard Worker for service in discover_services_results[0].data['Services']: 436*cf78ab8cSAndroid Build Coastguard Worker if service['UUID'] == TEST_BLE_SERVICE_UUID: 437*cf78ab8cSAndroid Build Coastguard Worker service_discovered = True 438*cf78ab8cSAndroid Build Coastguard Worker uuids = [ 439*cf78ab8cSAndroid Build Coastguard Worker characteristic[UUID] for characteristic in service['Characteristics'] 440*cf78ab8cSAndroid Build Coastguard Worker ] 441*cf78ab8cSAndroid Build Coastguard Worker for uuid in [ 442*cf78ab8cSAndroid Build Coastguard Worker characteristic[UUID] for characteristic in SERVICE['Characteristics'] 443*cf78ab8cSAndroid Build Coastguard Worker ]: 444*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true(uuid in uuids, 'Failed to find uuid %s.' % uuid) 445*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 446*cf78ab8cSAndroid Build Coastguard Worker service_discovered, 'Failed to discover the customize service' 447*cf78ab8cSAndroid Build Coastguard Worker ) 448*cf78ab8cSAndroid Build Coastguard Worker client.log.info('BLE discover services finished') 449*cf78ab8cSAndroid Build Coastguard Worker 450*cf78ab8cSAndroid Build Coastguard Worker 451*cf78ab8cSAndroid Build Coastguard Workerdef ReadCharacteristic(client: android_device.AndroidDevice) -> None: 452*cf78ab8cSAndroid Build Coastguard Worker """Logic for BLE characteristic retrieval. 453*cf78ab8cSAndroid Build Coastguard Worker 454*cf78ab8cSAndroid Build Coastguard Worker Steps: 455*cf78ab8cSAndroid Build Coastguard Worker 1. Client reads a characteristic from server & gets true. 456*cf78ab8cSAndroid Build Coastguard Worker 2. Server calls sendResponse & client gets onCharacteristicRead. 457*cf78ab8cSAndroid Build Coastguard Worker 458*cf78ab8cSAndroid Build Coastguard Worker Verifies: 459*cf78ab8cSAndroid Build Coastguard Worker Client gets corresponding callback. 460*cf78ab8cSAndroid Build Coastguard Worker 461*cf78ab8cSAndroid Build Coastguard Worker Args: 462*cf78ab8cSAndroid Build Coastguard Worker client: AndroidDevice. The device that behaves as GATT client. 463*cf78ab8cSAndroid Build Coastguard Worker """ 464*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.mbs.bleReadOperation( 465*cf78ab8cSAndroid Build Coastguard Worker TEST_BLE_SERVICE_UUID, TEST_READ_UUID 466*cf78ab8cSAndroid Build Coastguard Worker ) 467*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 468*cf78ab8cSAndroid Build Coastguard Worker read_operation_result, 'BLE read operation failed to start' 469*cf78ab8cSAndroid Build Coastguard Worker ) 470*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.client_callback.waitAndGet( 471*cf78ab8cSAndroid Build Coastguard Worker 'onCharacteristicRead', 30 472*cf78ab8cSAndroid Build Coastguard Worker ) 473*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data[STATUS], GATT_SUCCESS) 474*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data['Data'], READ_DATA) 475*cf78ab8cSAndroid Build Coastguard Worker client.log.info('Read operation finished') 476*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.mbs.bleReadOperation( 477*cf78ab8cSAndroid Build Coastguard Worker TEST_BLE_SERVICE_UUID, TEST_SECOND_READ_UUID 478*cf78ab8cSAndroid Build Coastguard Worker ) 479*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 480*cf78ab8cSAndroid Build Coastguard Worker read_operation_result, 'BLE read operation failed to start' 481*cf78ab8cSAndroid Build Coastguard Worker ) 482*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.client_callback.waitAndGet( 483*cf78ab8cSAndroid Build Coastguard Worker 'onCharacteristicRead', 30 484*cf78ab8cSAndroid Build Coastguard Worker ) 485*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data[STATUS], GATT_SUCCESS) 486*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data['Data'], SECOND_READ_DATA) 487*cf78ab8cSAndroid Build Coastguard Worker client.log.info('Second read operation finished') 488*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.mbs.bleReadOperation( 489*cf78ab8cSAndroid Build Coastguard Worker TEST_BLE_SERVICE_UUID, TEST_THIRD_READ_UUID 490*cf78ab8cSAndroid Build Coastguard Worker ) 491*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 492*cf78ab8cSAndroid Build Coastguard Worker read_operation_result, 'BLE read operation failed to start' 493*cf78ab8cSAndroid Build Coastguard Worker ) 494*cf78ab8cSAndroid Build Coastguard Worker read_operation_result = client.client_callback.waitAndGet( 495*cf78ab8cSAndroid Build Coastguard Worker 'onCharacteristicRead', 30 496*cf78ab8cSAndroid Build Coastguard Worker ) 497*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data[STATUS], GATT_SUCCESS) 498*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(read_operation_result.data['Data'], THIRD_READ_DATA) 499*cf78ab8cSAndroid Build Coastguard Worker client.log.info('Third read operation finished') 500*cf78ab8cSAndroid Build Coastguard Worker 501*cf78ab8cSAndroid Build Coastguard Worker 502*cf78ab8cSAndroid Build Coastguard Workerdef WriteCharacteristic( 503*cf78ab8cSAndroid Build Coastguard Worker client: android_device.AndroidDevice, server: android_device.AndroidDevice 504*cf78ab8cSAndroid Build Coastguard Worker) -> None: 505*cf78ab8cSAndroid Build Coastguard Worker """Logic for BLE characteristic write. 506*cf78ab8cSAndroid Build Coastguard Worker 507*cf78ab8cSAndroid Build Coastguard Worker Steps: 508*cf78ab8cSAndroid Build Coastguard Worker 1. Client writes a characteristic to server & gets true. 509*cf78ab8cSAndroid Build Coastguard Worker 2. Server calls sendResponse & client gets onCharacteristicWrite. 510*cf78ab8cSAndroid Build Coastguard Worker 511*cf78ab8cSAndroid Build Coastguard Worker Verifies: 512*cf78ab8cSAndroid Build Coastguard Worker Client gets corresponding callback. 513*cf78ab8cSAndroid Build Coastguard Worker 514*cf78ab8cSAndroid Build Coastguard Worker Args: 515*cf78ab8cSAndroid Build Coastguard Worker client: AndroidDevice. The device that behaves as GATT client. 516*cf78ab8cSAndroid Build Coastguard Worker server: AndroidDevice. The device that behaves as GATT server. 517*cf78ab8cSAndroid Build Coastguard Worker """ 518*cf78ab8cSAndroid Build Coastguard Worker write_operation_result = client.mbs.bleWriteOperation( 519*cf78ab8cSAndroid Build Coastguard Worker TEST_BLE_SERVICE_UUID, TEST_WRITE_UUID, WRITE_DATA 520*cf78ab8cSAndroid Build Coastguard Worker ) 521*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 522*cf78ab8cSAndroid Build Coastguard Worker write_operation_result, 'BLE write operation failed to start' 523*cf78ab8cSAndroid Build Coastguard Worker ) 524*cf78ab8cSAndroid Build Coastguard Worker server_write_operation_result = server.server_callback.waitAndGet( 525*cf78ab8cSAndroid Build Coastguard Worker 'onCharacteristicWriteRequest', 30 526*cf78ab8cSAndroid Build Coastguard Worker ) 527*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal(server_write_operation_result.data['Data'], WRITE_DATA) 528*cf78ab8cSAndroid Build Coastguard Worker client.client_callback.waitAndGet('onCharacteristicWrite', 30) 529*cf78ab8cSAndroid Build Coastguard Worker client.log.info('Write operation finished') 530*cf78ab8cSAndroid Build Coastguard Worker write_operation_result = client.mbs.bleWriteOperation( 531*cf78ab8cSAndroid Build Coastguard Worker TEST_BLE_SERVICE_UUID, TEST_SECOND_WRITE_UUID, SECOND_WRITE_DATA 532*cf78ab8cSAndroid Build Coastguard Worker ) 533*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_true( 534*cf78ab8cSAndroid Build Coastguard Worker write_operation_result, 'BLE write operation failed to start' 535*cf78ab8cSAndroid Build Coastguard Worker ) 536*cf78ab8cSAndroid Build Coastguard Worker server_write_operation_result = server.server_callback.waitAndGet( 537*cf78ab8cSAndroid Build Coastguard Worker 'onCharacteristicWriteRequest', 30 538*cf78ab8cSAndroid Build Coastguard Worker ) 539*cf78ab8cSAndroid Build Coastguard Worker asserts.assert_equal( 540*cf78ab8cSAndroid Build Coastguard Worker server_write_operation_result.data['Data'], SECOND_WRITE_DATA 541*cf78ab8cSAndroid Build Coastguard Worker ) 542*cf78ab8cSAndroid Build Coastguard Worker client.client_callback.waitAndGet('onCharacteristicWrite', 30) 543*cf78ab8cSAndroid Build Coastguard Worker client.log.info('Second write operation finished') 544