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