201 lines
7.0 KiB
Python
201 lines
7.0 KiB
Python
# Lint as: python2, python3
|
|
# 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."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import logging
|
|
import time
|
|
|
|
from autotest_lib.client.bin import utils
|
|
from six.moves import range
|
|
|
|
|
|
_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.
|
|
status, _ = bt_adapter.start_discovery()
|
|
if not status:
|
|
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)
|
|
status, _ = bt_adapter.stop_discovery()
|
|
if not status:
|
|
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 range(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
|
|
|
|
|
|
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
|