| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """This module provides the utilities for bluetooth audio using chameleon.""" |
| |
| import logging |
| import time |
| |
| from autotest_lib.client.bin import utils |
| |
| |
| _PIN = '0000' |
| _SEARCH_TIMEOUT = 30.0 |
| _PAIRING_TIMEOUT = 5.0 |
| _SLEEP_AFTER_DISCONNECT = 20.0 |
| # When device is busy, a trial may take more than 15 seconds. |
| # Set the timeout to 90 seconds so device can take more trials to reconnect. |
| _CONNECT_TIMEOUT = 90.0 |
| |
| class ChameleonBluetoothAudioError(Exception): |
| """Error in this module.""" |
| pass |
| |
| |
| def connect_bluetooth_module_full_flow(bt_adapter, target_mac_address, |
| timeout=_SEARCH_TIMEOUT): |
| """Controls Cros device to connect to bluetooth module on audio board. |
| |
| @param bt_adapter: A BluetoothDevice object to control bluetooth adapter |
| on Cros device. |
| @param target_mac_address: The MAC address of bluetooth module to be |
| connected. |
| @param timeout: Timeout in seconds to search for bluetooth module. |
| |
| @raises: ChameleonBluetoothAudioError if Cros device fails to connect to |
| bluetooth module on audio board. |
| |
| """ |
| # Resets bluetooth adapter on Cros device. |
| if not bt_adapter.reset_on(): |
| raise ChameleonBluetoothAudioError( |
| 'Failed to reset bluetooth adapter on Cros host.' |
| ' You should check if controller is available on Cros host' |
| ' using bluetoothctl.') |
| |
| # Starts discovery mode of bluetooth adapter. |
| if not bt_adapter.start_discovery(): |
| raise ChameleonBluetoothAudioError( |
| 'Failed to start discovery on bluetooth adapter on Cros host') |
| |
| def _find_device(): |
| """Controls bluetooth adapter to search for bluetooth module. |
| |
| @returns: True if there is a bluetooth device with MAC address |
| matches target_mac_address. False otherwise. |
| |
| """ |
| return bt_adapter.has_device(target_mac_address) |
| |
| # Searches for bluetooth module with given MAC address. |
| found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout) |
| if not bt_adapter.stop_discovery(): |
| raise ChameleonBluetoothAudioError( |
| 'Failed to stop discovery on bluetooth adapter on Cros host') |
| |
| if not found_device: |
| raise ChameleonBluetoothAudioError( |
| 'Can not find bluetooth module with MAC address %s' % |
| target_mac_address) |
| |
| pair_legacy_bluetooth_module(bt_adapter, target_mac_address) |
| |
| # Disconnects from bluetooth module to clean up the state. |
| if not bt_adapter.disconnect_device(target_mac_address): |
| raise ChameleonBluetoothAudioError( |
| 'Failed to let Cros device disconnect from bluetooth module %s' % |
| target_mac_address) |
| time.sleep(_SLEEP_AFTER_DISCONNECT) |
| |
| # Connects to bluetooth module. |
| connect_bluetooth_module(bt_adapter, target_mac_address) |
| |
| logging.info('Bluetooth module at %s is connected', target_mac_address) |
| |
| |
| def connect_bluetooth_module(bt_adapter, target_mac_address, |
| timeout=_CONNECT_TIMEOUT): |
| """Controls Cros device to connect to bluetooth module on audio board. |
| |
| @param bt_adapter: A BluetoothDevice object to control bluetooth adapter |
| on Cros device. |
| @param target_mac_address: The MAC address of bluetooth module to be |
| connected. |
| @param timeout: Timeout in seconds to connect bluetooth module. |
| |
| @raises: ChameleonBluetoothAudioError if Cros device fails to connect to |
| bluetooth module on audio board. |
| |
| """ |
| def _connect_device(): |
| logging.info('Try to connect to device') |
| success = bt_adapter.connect_device(target_mac_address) |
| if not success: |
| logging.debug('Can not connect device, retry in 1 second.') |
| time.sleep(1) |
| return False |
| logging.debug('Connection established.') |
| return True |
| |
| # Connects bluetooth module with given MAC address. |
| connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout) |
| if not connected: |
| raise ChameleonBluetoothAudioError( |
| 'Failed to let Cros device connect to bluetooth module %s' % |
| target_mac_address) |
| |
| |
| def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN, |
| pairing_timeout=_PAIRING_TIMEOUT, retries=3): |
| """Pairs Cros device bluetooth adapter with legacy bluetooth module. |
| |
| @param bt_adapter: A BluetoothDevice object to control bluetooth adapter |
| on Cros device. |
| @param target_mac_address: The MAC address of bluetooth module to be |
| paired. |
| @param pin: The pin for legacy pairing. |
| @param timeout: Timeout in seconds to pair bluetooth module in a trial. |
| @param retries: Number of retries if pairing fails. |
| |
| @raises: ChameleonBluetoothAudioError if Cros device fails to pair |
| bluetooth module on audio board after all the retries. |
| |
| """ |
| # Pairs the bluetooth adapter with bluetooth module. |
| for trial in xrange(retries): |
| if bt_adapter.pair_legacy_device( |
| target_mac_address, pin, False, pairing_timeout): |
| logging.debug('Pairing to %s succeeded', target_mac_address) |
| return |
| elif trial == retries - 1: |
| raise ChameleonBluetoothAudioError( |
| 'Failed to pair Cros device and bluetooth module %s' % |
| target_mac_address) |
| |
| logging.debug('Retry for pairing...') |
| |
| |
| class BluetoothRefController(object): |
| """ |
| An abstraction of bluetooth module on Fizz. |
| Analogous to BluetoothController defined in audio_board.py for |
| Chameleon hardware. |
| |
| """ |
| def __init__(self, chameleon_connection): |
| """Constructs a BluetoothController. |
| |
| @param chameleon_connection: A ChameleonConnection object. |
| |
| """ |
| self._chameleond_proxy = chameleon_connection.chameleond_proxy |
| |
| |
| def reset(self): |
| """Resets the bluetooth Ref.""" |
| self._chameleond_proxy.ResetBluetoothRef() |
| logging.info('Resets bluetooth Ref.') |
| |
| |
| def enable(self): |
| """Disables the bluetooth Ref.""" |
| self._chameleond_proxy.EnableBluetoothRef() |
| logging.info('Disables bluetooth Ref.') |
| |
| def disable(self): |
| """Disables the bluetooth Ref.""" |
| self._chameleond_proxy.DisableBluetoothRef() |
| logging.info('Disables bluetooth Ref.') |
| |
| |
| def is_enabled(self): |
| """Checks if the bluetooth Ref is enabled. |
| |
| @returns: True if bluetooth module is enabled. False otherwise. |
| |
| """ |
| """ |
| TODO (npoojary): |
| return self._chameleond_proxy.IsBluetoothRefEnabled() |
| """ |
| return True |