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 status, _ = bt_adapter.start_discovery() 49 if not status: 50 raise ChameleonBluetoothAudioError( 51 'Failed to start discovery on bluetooth adapter on Cros host') 52 53 def _find_device(): 54 """Controls bluetooth adapter to search for bluetooth module. 55 56 @returns: True if there is a bluetooth device with MAC address 57 matches target_mac_address. False otherwise. 58 59 """ 60 return bt_adapter.has_device(target_mac_address) 61 62 # Searches for bluetooth module with given MAC address. 63 found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout) 64 status, _ = bt_adapter.stop_discovery() 65 if not status: 66 raise ChameleonBluetoothAudioError( 67 'Failed to stop discovery on bluetooth adapter on Cros host') 68 69 if not found_device: 70 raise ChameleonBluetoothAudioError( 71 'Can not find bluetooth module with MAC address %s' % 72 target_mac_address) 73 74 pair_legacy_bluetooth_module(bt_adapter, target_mac_address) 75 76 # Disconnects from bluetooth module to clean up the state. 77 if not bt_adapter.disconnect_device(target_mac_address): 78 raise ChameleonBluetoothAudioError( 79 'Failed to let Cros device disconnect from bluetooth module %s' % 80 target_mac_address) 81 time.sleep(_SLEEP_AFTER_DISCONNECT) 82 83 # Connects to bluetooth module. 84 connect_bluetooth_module(bt_adapter, target_mac_address) 85 86 logging.info('Bluetooth module at %s is connected', target_mac_address) 87 88 89def connect_bluetooth_module(bt_adapter, target_mac_address, 90 timeout=_CONNECT_TIMEOUT): 91 """Controls Cros device to connect to bluetooth module on audio board. 92 93 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 94 on Cros device. 95 @param target_mac_address: The MAC address of bluetooth module to be 96 connected. 97 @param timeout: Timeout in seconds to connect bluetooth module. 98 99 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 100 bluetooth module on audio board. 101 102 """ 103 def _connect_device(): 104 logging.info('Try to connect to device') 105 success = bt_adapter.connect_device(target_mac_address) 106 if not success: 107 logging.debug('Can not connect device, retry in 1 second.') 108 time.sleep(1) 109 return False 110 logging.debug('Connection established.') 111 return True 112 113 # Connects bluetooth module with given MAC address. 114 connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) 115 if not connected: 116 raise ChameleonBluetoothAudioError( 117 'Failed to let Cros device connect to bluetooth module %s' % 118 target_mac_address) 119 120 121def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, 122 pairing_timeout=_PAIRING_TIMEOUT, retries=3): 123 """Pairs Cros device bluetooth adapter with legacy bluetooth module. 124 125 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 126 on Cros device. 127 @param target_mac_address: The MAC address of bluetooth module to be 128 paired. 129 @param pin: The pin for legacy pairing. 130 @param timeout: Timeout in seconds to pair bluetooth module in a trial. 131 @param retries: Number of retries if pairing fails. 132 133 @raises: ChameleonBluetoothAudioError if Cros device fails to pair 134 bluetooth module on audio board after all the retries. 135 136 """ 137 # Pairs the bluetooth adapter with bluetooth module. 138 for trial in xrange(retries): 139 if bt_adapter.pair_legacy_device( 140 target_mac_address, pin, False, pairing_timeout): 141 logging.debug('Pairing to %s succeeded', target_mac_address) 142 return 143 elif trial == retries - 1: 144 raise ChameleonBluetoothAudioError( 145 'Failed to pair Cros device and bluetooth module %s' % 146 target_mac_address) 147 148 logging.debug('Retry for pairing...') 149 150 151class BluetoothRefController(object): 152 """ 153 An abstraction of bluetooth module on Fizz. 154 Analogous to BluetoothController defined in audio_board.py for 155 Chameleon hardware. 156 157 """ 158 def __init__(self, chameleon_connection): 159 """Constructs a BluetoothController. 160 161 @param chameleon_connection: A ChameleonConnection object. 162 163 """ 164 self._chameleond_proxy = chameleon_connection 165 166 167 def reset(self): 168 """Resets the bluetooth Ref.""" 169 self._chameleond_proxy.ResetBluetoothRef() 170 logging.info('Resets bluetooth Ref.') 171 172 173 def enable(self): 174 """Disables the bluetooth Ref.""" 175 self._chameleond_proxy.EnableBluetoothRef() 176 logging.info('Disables bluetooth Ref.') 177 178 def disable(self): 179 """Disables the bluetooth Ref.""" 180 self._chameleond_proxy.DisableBluetoothRef() 181 logging.info('Disables bluetooth Ref.') 182 183 184 def is_enabled(self): 185 """Checks if the bluetooth Ref is enabled. 186 187 @returns: True if bluetooth module is enabled. False otherwise. 188 189 """ 190 """ 191 TODO (npoojary): 192 return self._chameleond_proxy.IsBluetoothRefEnabled() 193 """ 194 return True 195