• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import logging
8import time
9
10from 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
21class ChameleonBluetoothAudioError(Exception):
22    """Error in this module."""
23    pass
24
25
26def 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    status, _ = bt_adapter.start_discovery()
49    if not status:
50        raise ChameleonBluetoothAudioError(
51                'Failed to start discovery on bluetooth adapter on Cros host')
52
53    def _find_device():
54        """Controls bluetooth adapter to search for bluetooth module.
55
56        @returns: True if there is a bluetooth device with MAC address
57                  matches target_mac_address. False otherwise.
58
59        """
60        return bt_adapter.has_device(target_mac_address)
61
62    # Searches for bluetooth module with given MAC address.
63    found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout)
64    status, _ =  bt_adapter.stop_discovery()
65    if not status:
66        raise ChameleonBluetoothAudioError(
67            'Failed to stop discovery on bluetooth adapter on Cros host')
68
69    if not found_device:
70        raise ChameleonBluetoothAudioError(
71                'Can not find bluetooth module with MAC address %s' %
72                target_mac_address)
73
74    pair_legacy_bluetooth_module(bt_adapter, target_mac_address)
75
76    # Disconnects from bluetooth module to clean up the state.
77    if not bt_adapter.disconnect_device(target_mac_address):
78        raise ChameleonBluetoothAudioError(
79                'Failed to let Cros device disconnect from bluetooth module %s' %
80                target_mac_address)
81    time.sleep(_SLEEP_AFTER_DISCONNECT)
82
83    # Connects to bluetooth module.
84    connect_bluetooth_module(bt_adapter, target_mac_address)
85
86    logging.info('Bluetooth module at %s is connected', target_mac_address)
87
88
89def connect_bluetooth_module(bt_adapter, target_mac_address,
90                             timeout=_CONNECT_TIMEOUT):
91    """Controls Cros device to connect to bluetooth module on audio board.
92
93    @param bt_adapter: A BluetoothDevice object to control bluetooth adapter
94                       on Cros device.
95    @param target_mac_address: The MAC address of bluetooth module to be
96                               connected.
97    @param timeout: Timeout in seconds to connect bluetooth module.
98
99    @raises: ChameleonBluetoothAudioError if Cros device fails to connect to
100             bluetooth module on audio board.
101
102    """
103    def _connect_device():
104        logging.info('Try to connect to device')
105        success = bt_adapter.connect_device(target_mac_address)
106        if not success:
107            logging.debug('Can not connect device, retry in 1 second.')
108            time.sleep(1)
109            return False
110        logging.debug('Connection established.')
111        return True
112
113    # Connects bluetooth module with given MAC address.
114    connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout)
115    if not connected:
116        raise ChameleonBluetoothAudioError(
117                'Failed to let Cros device connect to bluetooth module %s' %
118                target_mac_address)
119
120
121def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN,
122                                 pairing_timeout=_PAIRING_TIMEOUT, retries=3):
123    """Pairs Cros device bluetooth adapter with legacy bluetooth module.
124
125    @param bt_adapter: A BluetoothDevice object to control bluetooth adapter
126                       on Cros device.
127    @param target_mac_address: The MAC address of bluetooth module to be
128                               paired.
129    @param pin: The pin for legacy pairing.
130    @param timeout: Timeout in seconds to pair bluetooth module in a trial.
131    @param retries: Number of retries if pairing fails.
132
133    @raises: ChameleonBluetoothAudioError if Cros device fails to pair
134             bluetooth module on audio board after all the retries.
135
136    """
137    # Pairs the bluetooth adapter with bluetooth module.
138    for trial in xrange(retries):
139        if bt_adapter.pair_legacy_device(
140            target_mac_address, pin, False, pairing_timeout):
141                logging.debug('Pairing to %s succeeded', target_mac_address)
142                return
143        elif trial == retries - 1:
144            raise ChameleonBluetoothAudioError(
145                    'Failed to pair Cros device and bluetooth module %s' %
146                    target_mac_address)
147
148        logging.debug('Retry for pairing...')
149
150
151class BluetoothRefController(object):
152    """
153    An abstraction of bluetooth module on Fizz.
154    Analogous to BluetoothController defined in audio_board.py for
155    Chameleon hardware.
156
157    """
158    def __init__(self, chameleon_connection):
159        """Constructs a BluetoothController.
160
161        @param chameleon_connection: A ChameleonConnection object.
162
163        """
164        self._chameleond_proxy = chameleon_connection
165
166
167    def reset(self):
168        """Resets the bluetooth Ref."""
169        self._chameleond_proxy.ResetBluetoothRef()
170        logging.info('Resets bluetooth Ref.')
171
172
173    def enable(self):
174        """Disables the bluetooth Ref."""
175        self._chameleond_proxy.EnableBluetoothRef()
176        logging.info('Disables bluetooth Ref.')
177
178    def disable(self):
179        """Disables the bluetooth Ref."""
180        self._chameleond_proxy.DisableBluetoothRef()
181        logging.info('Disables bluetooth Ref.')
182
183
184    def is_enabled(self):
185        """Checks if the bluetooth Ref is enabled.
186
187        @returns: True if bluetooth module is enabled. False otherwise.
188
189        """
190        """
191        TODO (npoojary):
192        return self._chameleond_proxy.IsBluetoothRefEnabled()
193        """
194        return True
195