1# Lint as: python2, python3 2# Copyright 2015 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""This module provides the utilities for bluetooth audio using chameleon.""" 7 8from __future__ import absolute_import 9from __future__ import division 10from __future__ import print_function 11 12import logging 13import time 14 15from autotest_lib.client.bin import utils 16from six.moves import range 17 18 19_PIN = '0000' 20_SEARCH_TIMEOUT = 30.0 21_PAIRING_TIMEOUT = 5.0 22_SLEEP_AFTER_DISCONNECT = 20.0 23# When device is busy, a trial may take more than 15 seconds. 24# Set the timeout to 90 seconds so device can take more trials to reconnect. 25_CONNECT_TIMEOUT = 90.0 26 27class ChameleonBluetoothAudioError(Exception): 28 """Error in this module.""" 29 pass 30 31 32def connect_bluetooth_module_full_flow(bt_adapter, target_mac_address, 33 timeout=_SEARCH_TIMEOUT): 34 """Controls Cros device to connect to bluetooth module on audio board. 35 36 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 37 on Cros device. 38 @param target_mac_address: The MAC address of bluetooth module to be 39 connected. 40 @param timeout: Timeout in seconds to search for bluetooth module. 41 42 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 43 bluetooth module on audio board. 44 45 """ 46 # Resets bluetooth adapter on Cros device. 47 if not bt_adapter.reset_on(): 48 raise ChameleonBluetoothAudioError( 49 'Failed to reset bluetooth adapter on Cros host.' 50 ' You should check if controller is available on Cros host' 51 ' using bluetoothctl.') 52 53 # Starts discovery mode of bluetooth adapter. 54 status, _ = bt_adapter.start_discovery() 55 if not status: 56 raise ChameleonBluetoothAudioError( 57 'Failed to start discovery on bluetooth adapter on Cros host') 58 59 def _find_device(): 60 """Controls bluetooth adapter to search for bluetooth module. 61 62 @returns: True if there is a bluetooth device with MAC address 63 matches target_mac_address. False otherwise. 64 65 """ 66 return bt_adapter.has_device(target_mac_address) 67 68 # Searches for bluetooth module with given MAC address. 69 found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout) 70 status, _ = bt_adapter.stop_discovery() 71 if not status: 72 raise ChameleonBluetoothAudioError( 73 'Failed to stop discovery on bluetooth adapter on Cros host') 74 75 if not found_device: 76 raise ChameleonBluetoothAudioError( 77 'Can not find bluetooth module with MAC address %s' % 78 target_mac_address) 79 80 pair_legacy_bluetooth_module(bt_adapter, target_mac_address) 81 82 # Disconnects from bluetooth module to clean up the state. 83 if not bt_adapter.disconnect_device(target_mac_address): 84 raise ChameleonBluetoothAudioError( 85 'Failed to let Cros device disconnect from bluetooth module %s' % 86 target_mac_address) 87 time.sleep(_SLEEP_AFTER_DISCONNECT) 88 89 # Connects to bluetooth module. 90 connect_bluetooth_module(bt_adapter, target_mac_address) 91 92 logging.info('Bluetooth module at %s is connected', target_mac_address) 93 94 95def connect_bluetooth_module(bt_adapter, target_mac_address, 96 timeout=_CONNECT_TIMEOUT): 97 """Controls Cros device to connect to bluetooth module on audio board. 98 99 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 100 on Cros device. 101 @param target_mac_address: The MAC address of bluetooth module to be 102 connected. 103 @param timeout: Timeout in seconds to connect bluetooth module. 104 105 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 106 bluetooth module on audio board. 107 108 """ 109 def _connect_device(): 110 logging.info('Try to connect to device') 111 success = bt_adapter.connect_device(target_mac_address) 112 if not success: 113 logging.debug('Can not connect device, retry in 1 second.') 114 time.sleep(1) 115 return False 116 logging.debug('Connection established.') 117 return True 118 119 # Connects bluetooth module with given MAC address. 120 connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) 121 if not connected: 122 raise ChameleonBluetoothAudioError( 123 'Failed to let Cros device connect to bluetooth module %s' % 124 target_mac_address) 125 126 127def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, 128 pairing_timeout=_PAIRING_TIMEOUT, retries=3): 129 """Pairs Cros device bluetooth adapter with legacy bluetooth module. 130 131 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 132 on Cros device. 133 @param target_mac_address: The MAC address of bluetooth module to be 134 paired. 135 @param pin: The pin for legacy pairing. 136 @param timeout: Timeout in seconds to pair bluetooth module in a trial. 137 @param retries: Number of retries if pairing fails. 138 139 @raises: ChameleonBluetoothAudioError if Cros device fails to pair 140 bluetooth module on audio board after all the retries. 141 142 """ 143 # Pairs the bluetooth adapter with bluetooth module. 144 for trial in range(retries): 145 if bt_adapter.pair_legacy_device( 146 target_mac_address, pin, False, pairing_timeout): 147 logging.debug('Pairing to %s succeeded', target_mac_address) 148 return 149 elif trial == retries - 1: 150 raise ChameleonBluetoothAudioError( 151 'Failed to pair Cros device and bluetooth module %s' % 152 target_mac_address) 153 154 logging.debug('Retry for pairing...') 155 156 157class BluetoothRefController(object): 158 """ 159 An abstraction of bluetooth module on Fizz. 160 Analogous to BluetoothController defined in audio_board.py for 161 Chameleon hardware. 162 163 """ 164 def __init__(self, chameleon_connection): 165 """Constructs a BluetoothController. 166 167 @param chameleon_connection: A ChameleonConnection object. 168 169 """ 170 self._chameleond_proxy = chameleon_connection 171 172 173 def reset(self): 174 """Resets the bluetooth Ref.""" 175 self._chameleond_proxy.ResetBluetoothRef() 176 logging.info('Resets bluetooth Ref.') 177 178 179 def enable(self): 180 """Disables the bluetooth Ref.""" 181 self._chameleond_proxy.EnableBluetoothRef() 182 logging.info('Disables bluetooth Ref.') 183 184 def disable(self): 185 """Disables the bluetooth Ref.""" 186 self._chameleond_proxy.DisableBluetoothRef() 187 logging.info('Disables bluetooth Ref.') 188 189 190 def is_enabled(self): 191 """Checks if the bluetooth Ref is enabled. 192 193 @returns: True if bluetooth module is enabled. False otherwise. 194 195 """ 196 """ 197 TODO (npoojary): 198 return self._chameleond_proxy.IsBluetoothRefEnabled() 199 """ 200 return True 201