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_CONNECT_TIMEOUT = 15.0 17 18 19class ChameleonBluetoothAudioError(Exception): 20 """Error in this module.""" 21 pass 22 23 24def connect_bluetooth_module_full_flow(bt_adapter, target_mac_address, 25 timeout=_SEARCH_TIMEOUT): 26 """Controls Cros device to connect to bluetooth module on audio board. 27 28 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 29 on Cros device. 30 @param target_mac_address: The MAC address of bluetooth module to be 31 connected. 32 @param timeout: Timeout in seconds to search for bluetooth module. 33 34 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 35 bluetooth module on audio board. 36 37 """ 38 # Resets bluetooth adapter on Cros device. 39 if not bt_adapter.reset_on(): 40 raise ChameleonBluetoothAudioError( 41 'Failed to reset bluetooth adapter on Cros host.' 42 ' You should check if controller is available on Cros host' 43 ' using bluetoothctl.') 44 45 # Starts discovery mode of bluetooth adapter. 46 if not bt_adapter.start_discovery(): 47 raise ChameleonBluetoothAudioError( 48 'Failed to start discovery on bluetooth adapter on Cros host') 49 50 def _find_device(): 51 """Controls bluetooth adapter to search for bluetooth module. 52 53 @returns: True if there is a bluetooth device with MAC address 54 matches target_mac_address. False otherwise. 55 56 """ 57 return bt_adapter.has_device(target_mac_address) 58 59 # Searches for bluetooth module with given MAC address. 60 found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout) 61 62 if not found_device: 63 raise ChameleonBluetoothAudioError( 64 'Can not find bluetooth module with MAC address %s' % 65 target_mac_address) 66 67 pair_legacy_bluetooth_module(bt_adapter, target_mac_address) 68 69 # Disconnects from bluetooth module to clean up the state. 70 if not bt_adapter.disconnect_device(target_mac_address): 71 raise ChameleonBluetoothAudioError( 72 'Failed to let Cros device disconnect from bluetooth module %s' % 73 target_mac_address) 74 75 # Connects to bluetooth module. 76 connect_bluetooth_module(bt_adapter, target_mac_address) 77 78 logging.info('Bluetooth module at %s is connected', target_mac_address) 79 80 81def connect_bluetooth_module(bt_adapter, target_mac_address, 82 timeout=_CONNECT_TIMEOUT): 83 """Controls Cros device to connect to bluetooth module on audio board. 84 85 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 86 on Cros device. 87 @param target_mac_address: The MAC address of bluetooth module to be 88 connected. 89 @param timeout: Timeout in seconds to connect bluetooth module. 90 91 @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 92 bluetooth module on audio board. 93 94 """ 95 def _connect_device(): 96 success = bt_adapter.connect_device(target_mac_address) 97 if not success: 98 logging.debug('Can not connect device, retry in 1 second.') 99 time.sleep(1) 100 return False 101 logging.debug('Connection established.') 102 return True 103 104 # Connects bluetooth module with given MAC address. 105 connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) 106 if not connected: 107 raise ChameleonBluetoothAudioError( 108 'Failed to let Cros device connect to bluetooth module %s' % 109 target_mac_address) 110 111 112def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, 113 pairing_timeout=_PAIRING_TIMEOUT, retries=3): 114 """Pairs Cros device bluetooth adapter with legacy bluetooth module. 115 116 @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 117 on Cros device. 118 @param target_mac_address: The MAC address of bluetooth module to be 119 paired. 120 @param pin: The pin for legacy pairing. 121 @param timeout: Timeout in seconds to pair bluetooth module in a trial. 122 @param retries: Number of retries if pairing fails. 123 124 @raises: ChameleonBluetoothAudioError if Cros device fails to pair 125 bluetooth module on audio board after all the retries. 126 127 """ 128 # Pairs the bluetooth adapter with bluetooth module. 129 for trial in xrange(retries): 130 if bt_adapter.pair_legacy_device( 131 target_mac_address, pin, pairing_timeout): 132 logging.debug('Pairing to %s succeeded', target_mac_address) 133 return 134 elif trial == retries - 1: 135 raise ChameleonBluetoothAudioError( 136 'Failed to pair Cros device and bluetooth module %s' % 137 target_mac_address) 138 139 logging.debug('Retry for pairing...') 140