Home | History | Annotate | Download | only in chameleon
      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 
      7 import logging
      8 import time
      9 
     10 from 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 
     21 class ChameleonBluetoothAudioError(Exception):
     22     """Error in this module."""
     23     pass
     24 
     25 
     26 def 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 
     84 def 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 
    116 def 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