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 64 if not found_device: 65 raise ChameleonBluetoothAudioError( 66 'Can not find bluetooth module with MAC address %s' % 67 target_mac_address) 68 69 pair_legacy_bluetooth_module(bt_adapter, target_mac_address) 70 71 # Disconnects from bluetooth module to clean up the state. 72 if not bt_adapter.disconnect_device(target_mac_address): 73 raise ChameleonBluetoothAudioError( 74 'Failed to let Cros device disconnect from bluetooth module %s' % 75 target_mac_address) 76 time.sleep(_SLEEP_AFTER_DISCONNECT) 77 78 # Connects to bluetooth module. 79 connect_bluetooth_module(bt_adapter, target_mac_address) 80 81 logging.info('Bluetooth module at %s is connected', target_mac_address) 82 83 84def connect_bluetooth_module(bt_adapter, target_mac_address, 85 timeout=_CONNECT_TIMEOUT): 86 """Controls Cros device to connect to bluetooth module on audio board. 87 88 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 89 on Cros device. 90 @param target_mac_address: The MAC address of bluetooth module to be 91 connected. 92 @param timeout: Timeout in seconds to connect bluetooth module. 93 94 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 95 bluetooth module on audio board. 96 97 """ 98 def _connect_device(): 99 logging.info('Try to connect to device') 100 success = bt_adapter.connect_device(target_mac_address) 101 if not success: 102 logging.debug('Can not connect device, retry in 1 second.') 103 time.sleep(1) 104 return False 105 logging.debug('Connection established.') 106 return True 107 108 # Connects bluetooth module with given MAC address. 109 connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) 110 if not connected: 111 raise ChameleonBluetoothAudioError( 112 'Failed to let Cros device connect to bluetooth module %s' % 113 target_mac_address) 114 115 116def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, 117 pairing_timeout=_PAIRING_TIMEOUT, retries=3): 118 """Pairs Cros device bluetooth adapter with legacy bluetooth module. 119 120 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 121 on Cros device. 122 @param target_mac_address: The MAC address of bluetooth module to be 123 paired. 124 @param pin: The pin for legacy pairing. 125 @param timeout: Timeout in seconds to pair bluetooth module in a trial. 126 @param retries: Number of retries if pairing fails. 127 128 @raises: ChameleonBluetoothAudioError if Cros device fails to pair 129 bluetooth module on audio board after all the retries. 130 131 """ 132 # Pairs the bluetooth adapter with bluetooth module. 133 for trial in xrange(retries): 134 if bt_adapter.pair_legacy_device( 135 target_mac_address, pin, False, pairing_timeout): 136 logging.debug('Pairing to %s succeeded', target_mac_address) 137 return 138 elif trial == retries - 1: 139 raise ChameleonBluetoothAudioError( 140 'Failed to pair Cros device and bluetooth module %s' % 141 target_mac_address) 142 143 logging.debug('Retry for pairing...') 144