1e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang# Copyright 2015 The Chromium OS Authors. All rights reserved. 2e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang# Use of this source code is governed by a BSD-style license that can be 3e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang# found in the LICENSE file. 4e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 5e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang"""This module provides the utilities for bluetooth audio using chameleon.""" 6e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 7e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiangimport logging 8d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiangimport time 9e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 10e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiangfrom autotest_lib.client.bin import utils 11e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 12e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 13e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang_PIN = '0000' 14e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang_SEARCH_TIMEOUT = 30.0 15e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang_PAIRING_TIMEOUT = 5.0 162070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang_SLEEP_AFTER_DISCONNECT = 20.0 172070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang# When device is busy, a trial may take more than 15 seconds. 182070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang# Set the timeout to 90 seconds so device can take more trials to reconnect. 192070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang_CONNECT_TIMEOUT = 90.0 20e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 21e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiangclass ChameleonBluetoothAudioError(Exception): 22e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang """Error in this module.""" 23e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang pass 24e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 25e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 26d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiangdef connect_bluetooth_module_full_flow(bt_adapter, target_mac_address, 27e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang timeout=_SEARCH_TIMEOUT): 28e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang """Controls Cros device to connect to bluetooth module on audio board. 29e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 30e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 31e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang on Cros device. 32e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang @param target_mac_address: The MAC address of bluetooth module to be 33e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang connected. 34e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang @param timeout: Timeout in seconds to search for bluetooth module. 35e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 36e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 37e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang bluetooth module on audio board. 38e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 39e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang """ 40e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang # Resets bluetooth adapter on Cros device. 4170d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang if not bt_adapter.reset_on(): 4270d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang raise ChameleonBluetoothAudioError( 4370d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang 'Failed to reset bluetooth adapter on Cros host.' 4470d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang ' You should check if controller is available on Cros host' 4570d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang ' using bluetoothctl.') 46e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 47e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang # Starts discovery mode of bluetooth adapter. 4870d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang if not bt_adapter.start_discovery(): 4970d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang raise ChameleonBluetoothAudioError( 5070d53c11268161c297a0a77228f789edba4a7b9bCheng-Yi Chiang 'Failed to start discovery on bluetooth adapter on Cros host') 51e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 52e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang def _find_device(): 53e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang """Controls bluetooth adapter to search for bluetooth module. 54e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 55e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang @returns: True if there is a bluetooth device with MAC address 56e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang matches target_mac_address. False otherwise. 57e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 58e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang """ 5987a919cdb8b8795a010e278b4da2085bb784264bCheng-Yi Chiang return bt_adapter.has_device(target_mac_address) 60e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 61e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang # Searches for bluetooth module with given MAC address. 62e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout) 63e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 64e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang if not found_device: 65e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang raise ChameleonBluetoothAudioError( 66e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 'Can not find bluetooth module with MAC address %s' % 67e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang target_mac_address) 68e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 69fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang pair_legacy_bluetooth_module(bt_adapter, target_mac_address) 70e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 71e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang # Disconnects from bluetooth module to clean up the state. 72e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang if not bt_adapter.disconnect_device(target_mac_address): 73e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang raise ChameleonBluetoothAudioError( 74e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 'Failed to let Cros device disconnect from bluetooth module %s' % 75e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang target_mac_address) 762070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang time.sleep(_SLEEP_AFTER_DISCONNECT) 77e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 78e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang # Connects to bluetooth module. 79d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang connect_bluetooth_module(bt_adapter, target_mac_address) 80d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 81d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang logging.info('Bluetooth module at %s is connected', target_mac_address) 82d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 83d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 84d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiangdef connect_bluetooth_module(bt_adapter, target_mac_address, 85d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang timeout=_CONNECT_TIMEOUT): 86d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang """Controls Cros device to connect to bluetooth module on audio board. 87d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 88d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 89d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang on Cros device. 90d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang @param target_mac_address: The MAC address of bluetooth module to be 91d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang connected. 92d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang @param timeout: Timeout in seconds to connect bluetooth module. 93d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 94d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang @raises: ChameleonBluetoothAudioError if Cros device fails to connect to 95d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang bluetooth module on audio board. 96d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 97d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang """ 98d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang def _connect_device(): 992070f4497322ba704738c9b59f73a03801800248Cheng-Yi Chiang logging.info('Try to connect to device') 100d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang success = bt_adapter.connect_device(target_mac_address) 101d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang if not success: 102d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang logging.debug('Can not connect device, retry in 1 second.') 103d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang time.sleep(1) 104d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang return False 105d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang logging.debug('Connection established.') 106d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang return True 107d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang 108d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang # Connects bluetooth module with given MAC address. 109d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) 110d357bed9c8d3adb8bb22113c551f085bcc4fa17dCheng-Yi Chiang if not connected: 111e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang raise ChameleonBluetoothAudioError( 112e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang 'Failed to let Cros device connect to bluetooth module %s' % 113e39f395b822adbc1a40e4e48f995efae29912c2dCheng-Yi Chiang target_mac_address) 114fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 115fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 116fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiangdef pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, 117fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang pairing_timeout=_PAIRING_TIMEOUT, retries=3): 118fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang """Pairs Cros device bluetooth adapter with legacy bluetooth module. 119fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 120fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @param bt_adapter: A BluetoothDevice object to control bluetooth adapter 121fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang on Cros device. 122fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @param target_mac_address: The MAC address of bluetooth module to be 123fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang paired. 124fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @param pin: The pin for legacy pairing. 125fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @param timeout: Timeout in seconds to pair bluetooth module in a trial. 126fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @param retries: Number of retries if pairing fails. 127fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 128fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang @raises: ChameleonBluetoothAudioError if Cros device fails to pair 129fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang bluetooth module on audio board after all the retries. 130fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 131fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang """ 132fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang # Pairs the bluetooth adapter with bluetooth module. 133fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang for trial in xrange(retries): 134fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang if bt_adapter.pair_legacy_device( 135cc1549a9cb023a187b23b26198662e9cf12ea93dCheng-Yi Chiang target_mac_address, pin, False, pairing_timeout): 136fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang logging.debug('Pairing to %s succeeded', target_mac_address) 137fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang return 138fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang elif trial == retries - 1: 139fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang raise ChameleonBluetoothAudioError( 140fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 'Failed to pair Cros device and bluetooth module %s' % 141fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang target_mac_address) 142fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang 143fcda92609c79581df1d34cd077b653619ea9b22fCheng-Yi Chiang logging.debug('Retry for pairing...') 144