1#!/usr/bin/env python3 2# 3# Copyright 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of 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, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import logging 18import time 19import statistics 20from queue import Empty 21from concurrent.futures import ThreadPoolExecutor 22 23from acts.test_utils.bt.bt_gatt_utils import close_gatt_client 24from acts.test_utils.bt.bt_coc_test_utils import do_multi_connection_throughput 25from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection 26from acts.test_utils.bt.bt_constants import gatt_cb_err 27from acts.test_utils.bt.bt_constants import gatt_cb_strings 28from acts.test_utils.bt.bt_constants import l2cap_coc_header_size 29from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError 30from acts.test_utils.bt.bt_coc_test_utils import orchestrate_coc_connection 31from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection 32 33default_event_timeout = 10 34rssi_read_duration = 25 35 36 37def establish_ble_connection(client_ad, server_ad): 38 """Function to establish BLE connection between two BLE devices. 39 40 Args: 41 client_ad: the Android device performing the connection. 42 server_ad: the Android device accepting the connection. 43 Returns: 44 bluetooth_gatt: GATT object 45 gatt_callback: Gatt callback object 46 adv_callback: advertisement callback object 47 gatt_server: the gatt server 48 """ 49 gatt_server_cb = server_ad.droid.gattServerCreateGattServerCallback() 50 gatt_server = server_ad.droid.gattServerOpenGattServer(gatt_server_cb) 51 try: 52 bluetooth_gatt, gatt_callback, adv_callback = ( 53 orchestrate_gatt_connection(client_ad, server_ad)) 54 except GattTestUtilsError as err: 55 logging.error(err) 56 return False 57 return bluetooth_gatt, gatt_callback, adv_callback, gatt_server 58 59 60def read_ble_rssi(client_ad, gatt_server, gatt_callback): 61 """Function to Read BLE RSSI of the remote BLE device. 62 Args: 63 client_ad: the Android device performing the connection. 64 gatt_server: the gatt server 65 gatt_callback:the gatt connection call back object 66 Returns: 67 ble_rssi: RSSI value of the remote BLE device 68 """ 69 AVG_RSSI = [] 70 end_time = time.time() + rssi_read_duration 71 logging.info("Reading BLE RSSI for {} sec".format(rssi_read_duration)) 72 while time.time() < end_time: 73 expected_event = gatt_cb_strings['rd_remote_rssi'].format( 74 gatt_callback) 75 read_rssi = client_ad.droid.gattClientReadRSSI(gatt_server) 76 if read_rssi: 77 try: 78 event = client_ad.ed.pop_event(expected_event, 79 default_event_timeout) 80 except Empty: 81 logging.error( 82 gatt_cb_err['rd_remote_rssi_err'].format(expected_event)) 83 return False 84 rssi_value = event['data']['Rssi'] 85 AVG_RSSI.append(rssi_value) 86 logging.debug("First & Last reading of RSSI :{:03d} & {:03d}".format( 87 AVG_RSSI[0], AVG_RSSI[-1])) 88 ble_rssi = statistics.mean(AVG_RSSI) 89 ble_rssi = round(ble_rssi, 2) 90 91 return ble_rssi 92 93 94def ble_coc_connection(client_ad, server_ad): 95 """Sets up the CoC connection between two Android devices. 96 97 Args: 98 client_ad: the Android device performing the connection. 99 server_ad: the Android device accepting the connection. 100 101 Returns: 102 True if connection was successful or false if unsuccessful, 103 gatt_callback: GATT callback object 104 client connection ID: Client connection ID 105 and server connection ID : server connection ID 106 """ 107 #secured_conn: True if using secured connection 108 #le_connection_interval: LE Connection interval. 0 means use default. 109 #buffer_size : is the number of bytes per L2CAP data buffer 110 #le_tx_data_length: LE Data Length used by BT Controller to transmit. 111 is_secured = False 112 le_connection_interval = 30 113 buffer_size = 240 114 le_tx_data_length = buffer_size + l2cap_coc_header_size 115 gatt_server_cb = server_ad.droid.gattServerCreateGattServerCallback() 116 gatt_server = server_ad.droid.gattServerOpenGattServer(gatt_server_cb) 117 118 logging.info( 119 "orchestrate_ble_coc_connection. is_secured={}, Connection Interval={}msec, " 120 "buffer_size={}bytes".format(is_secured, le_connection_interval, 121 buffer_size)) 122 try: 123 status, client_conn_id, server_conn_id, bluetooth_gatt, gatt_callback = orchestrate_coc_connection( 124 client_ad, 125 server_ad, 126 True, 127 is_secured, 128 le_connection_interval, 129 le_tx_data_length, 130 gatt_disconnection=False) 131 except Exception as err: 132 logging.info("Failed to esatablish COC connection".format(err)) 133 return 0 134 return True, gatt_callback, gatt_server, bluetooth_gatt, client_conn_id 135 136 137def run_ble_throughput(server_ad, client_conn_id, client_ad, 138 num_iterations=30): 139 """Function to measure Throughput from one client to one-or-many servers 140 141 Args: 142 server_ad: the Android device accepting the connection. 143 client_conn_id: the client connection ID. 144 client_ad: the Android device performing the connection. 145 num_iterations: The num_iterations is that number of repetitions of each 146 set of buffers r/w. 147 Returns: 148 data_rate: Throughput in terms of bytes per second, 0 if test failed. 149 """ 150 # number_buffers is the total number of data buffers to transmit per 151 # set of buffers r/w. 152 # buffer_size is the number of bytes per L2CAP data buffer. 153 number_buffers = 100 154 buffer_size = 240 155 list_server_ad = [server_ad] 156 list_client_conn_id = [client_conn_id] 157 data_rate = do_multi_connection_throughput(client_ad, list_server_ad, 158 list_client_conn_id, 159 num_iterations, number_buffers, 160 buffer_size) 161 if data_rate <= 0: 162 return False 163 data_rate = data_rate * 8 164 logging.info( 165 "run_ble_coc_connection_throughput: throughput=%d bites per sec", 166 data_rate) 167 return data_rate 168 169 170def run_ble_throughput_and_read_rssi(client_ad, server_ad, client_conn_id, 171 gatt_server, gatt_callback): 172 """Function to measure ble rssi while sendinng data from client to server 173 174 Args: 175 client_ad: the Android device performing the connection. 176 server_ad: the Android device accepting the connection. 177 client_conn_id: the client connection ID. 178 gatt_server: the gatt server 179 gatt_callback: Gatt callback object 180 Returns: 181 ble_rssi: RSSI value of the remote BLE device. 182 """ 183 executor = ThreadPoolExecutor(2) 184 ble_throughput = executor.submit(run_ble_throughput, client_ad, 185 client_conn_id, server_ad) 186 ble_rssi = executor.submit(read_ble_rssi, server_ad, gatt_server, 187 gatt_callback) 188 logging.info("BLE RSSI is:{} dBm with data rate={} bites per sec ".format( 189 ble_rssi.result(), ble_throughput.result())) 190 return ble_rssi.result() 191 192 193def ble_gatt_disconnection(client_ad, bluetooth_gatt, gatt_callback): 194 """Function to disconnect GATT connection between client and server. 195 196 Args: 197 client_ad: the Android device performing the connection. 198 bluetooth_gatt: GATT object 199 gatt_callback:the gatt connection call back object 200 Returns: 201 ble_rssi: RSSI value of the remote BLE device 202 """ 203 logging.info("Disconnecting from peripheral device.") 204 try: 205 disconnect_gatt_connection(client_ad, bluetooth_gatt, gatt_callback) 206 close_gatt_client(client_ad, bluetooth_gatt) 207 except GattTestUtilsError as err: 208 logging.error(err) 209 return False 210 return True 211