1 #/usr/bin/env python3.4 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 """ 17 Ble libraries 18 """ 19 20 from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes 21 from acts.test_utils.bt.bt_constants import ble_advertise_settings_tx_powers 22 from acts.test_utils.bt.bt_constants import ble_scan_settings_modes 23 from acts.test_utils.bt.bt_constants import small_timeout 24 from acts.test_utils.bt.bt_test_utils import adv_fail 25 from acts.test_utils.bt.bt_constants import adv_succ 26 from acts.test_utils.bt.bt_test_utils import advertising_set_on_own_address_read 27 from acts.test_utils.bt.bt_test_utils import advertising_set_started 28 from acts.test_utils.bt.bt_test_utils import generate_ble_advertise_objects 29 30 import time 31 import os 32 33 34 class BleLib(): 35 def __init__(self, log, mac_addr, dut): 36 self.advertisement_list = [] 37 self.dut = dut 38 self.log = log 39 self.mac_addr = mac_addr 40 self.default_timeout = 5 41 self.set_advertisement_list = [] 42 self.generic_uuid = "0000{}-0000-1000-8000-00805f9b34fb" 43 44 def _verify_ble_adv_started(self, advertise_callback): 45 """Helper for verifying if an advertisment started or not""" 46 regex = "({}|{})".format( 47 adv_succ.format(advertise_callback), 48 adv_fail.format(advertise_callback)) 49 try: 50 event = self.dut.ed.pop_events(regex, 5, small_timeout) 51 except Empty: 52 self.dut.log.error("Failed to get success or failed event.") 53 return 54 if event[0]["name"] == adv_succ.format(advertise_callback): 55 self.dut.log.info("Advertisement started successfully.") 56 return True 57 else: 58 self.dut.log.info("Advertisement failed to start.") 59 return False 60 61 def start_generic_connectable_advertisement(self, line): 62 """Start a connectable LE advertisement""" 63 scan_response = None 64 if line: 65 scan_response = bool(line) 66 self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode( 67 ble_advertise_settings_modes['low_latency']) 68 self.dut.droid.bleSetAdvertiseSettingsIsConnectable(True) 69 advertise_callback, advertise_data, advertise_settings = ( 70 generate_ble_advertise_objects(self.dut.droid)) 71 if scan_response: 72 self.dut.droid.bleStartBleAdvertisingWithScanResponse( 73 advertise_callback, advertise_data, advertise_settings, 74 advertise_data) 75 else: 76 self.dut.droid.bleStartBleAdvertising( 77 advertise_callback, advertise_data, advertise_settings) 78 if self._verify_ble_adv_started(advertise_callback): 79 self.log.info("Tracking Callback ID: {}".format( 80 advertise_callback)) 81 self.advertisement_list.append(advertise_callback) 82 self.log.info(self.advertisement_list) 83 84 def start_connectable_advertisement_set(self, line): 85 """Start Connectable Advertisement Set""" 86 adv_callback = self.dut.droid.bleAdvSetGenCallback() 87 adv_data = {"includeDeviceName": True, } 88 self.dut.droid.bleAdvSetStartAdvertisingSet({ 89 "connectable": True, 90 "legacyMode": False, 91 "primaryPhy": "PHY_LE_1M", 92 "secondaryPhy": "PHY_LE_1M", 93 "interval": 320 94 }, adv_data, None, None, None, 0, 0, adv_callback) 95 evt = self.dut.ed.pop_event( 96 advertising_set_started.format(adv_callback), self.default_timeout) 97 set_id = evt['data']['setId'] 98 self.log.error("did not receive the set started event!") 99 evt = self.dut.ed.pop_event( 100 advertising_set_on_own_address_read.format(set_id), 101 self.default_timeout) 102 address = evt['data']['address'] 103 self.log.info("Advertiser address is: {}".format(str(address))) 104 self.set_advertisement_list.append(adv_callback) 105 106 def stop_all_advertisement_set(self, line): 107 """Stop all Advertisement Sets""" 108 for adv in self.set_advertisement_list: 109 try: 110 self.dut.droid.bleAdvSetStopAdvertisingSet(adv) 111 except Exception as err: 112 self.log.error("Failed to stop advertisement: {}".format(err)) 113 114 def adv_add_service_uuid_list(self, line): 115 """Add service UUID to the LE advertisement inputs: 116 [uuid1 uuid2 ... uuidN]""" 117 uuids = line.split() 118 uuid_list = [] 119 for uuid in uuids: 120 if len(uuid) == 4: 121 uuid = self.generic_uuid.format(line) 122 uuid_list.append(uuid) 123 self.dut.droid.bleSetAdvertiseDataSetServiceUuids(uuid_list) 124 125 def adv_data_include_local_name(self, is_included): 126 """Include local name in the advertisement. inputs: [true|false]""" 127 self.dut.droid.bleSetAdvertiseDataIncludeDeviceName(bool(is_included)) 128 129 def adv_data_include_tx_power_level(self, is_included): 130 """Include tx power level in the advertisement. inputs: [true|false]""" 131 self.dut.droid.bleSetAdvertiseDataIncludeTxPowerLevel( 132 bool(is_included)) 133 134 def adv_data_add_manufacturer_data(self, line): 135 """Include manufacturer id and data to the advertisment: 136 [id data1 data2 ... dataN]""" 137 info = line.split() 138 manu_id = int(info[0]) 139 manu_data = [] 140 for data in info[1:]: 141 manu_data.append(int(data)) 142 self.dut.droid.bleAddAdvertiseDataManufacturerId(manu_id, manu_data) 143 144 def start_generic_nonconnectable_advertisement(self, line): 145 """Start a nonconnectable LE advertisement""" 146 self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode( 147 ble_advertise_settings_modes['low_latency']) 148 self.dut.droid.bleSetAdvertiseSettingsIsConnectable(False) 149 advertise_callback, advertise_data, advertise_settings = ( 150 generate_ble_advertise_objects(self.dut.droid)) 151 self.dut.droid.bleStartBleAdvertising( 152 advertise_callback, advertise_data, advertise_settings) 153 if self._verify_ble_adv_started(advertise_callback): 154 self.log.info("Tracking Callback ID: {}".format( 155 advertise_callback)) 156 self.advertisement_list.append(advertise_callback) 157 self.log.info(self.advertisement_list) 158 159 def stop_all_advertisements(self, line): 160 """Stop all LE advertisements""" 161 for callback_id in self.advertisement_list: 162 self.log.info("Stopping Advertisement {}".format(callback_id)) 163 self.dut.droid.bleStopBleAdvertising(callback_id) 164 time.sleep(1) 165 self.advertisement_list = [] 166 167 def ble_stop_advertisement(self, callback_id): 168 """Stop an LE advertisement""" 169 if not callback_id: 170 self.log.info("Need a callback ID") 171 return 172 callback_id = int(callback_id) 173 if callback_id not in self.advertisement_list: 174 self.log.info("Callback not in list of advertisements.") 175 return 176 self.dut.droid.bleStopBleAdvertising(callback_id) 177 self.advertisement_list.remove(callback_id) 178