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