• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lint as: python2, python3
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This module provides the utilities for bluetooth audio using chameleon."""
7
8from __future__ import absolute_import
9from __future__ import division
10from __future__ import print_function
11
12import logging
13import time
14
15from autotest_lib.client.bin import utils
16from six.moves import range
17
18
19_PIN = '0000'
20_SEARCH_TIMEOUT = 30.0
21_PAIRING_TIMEOUT = 5.0
22_SLEEP_AFTER_DISCONNECT = 20.0
23# When device is busy, a trial may take more than 15 seconds.
24# Set the timeout to 90 seconds so device can take more trials to reconnect.
25_CONNECT_TIMEOUT = 90.0
26
27class ChameleonBluetoothAudioError(Exception):
28    """Error in this module."""
29    pass
30
31
32def connect_bluetooth_module_full_flow(bt_adapter, target_mac_address,
33                             timeout=_SEARCH_TIMEOUT):
34    """Controls Cros device to connect to bluetooth module on audio board.
35
36    @param bt_adapter: A BluetoothDevice object to control bluetooth adapter
37                       on Cros device.
38    @param target_mac_address: The MAC address of bluetooth module to be
39                               connected.
40    @param timeout: Timeout in seconds to search for bluetooth module.
41
42    @raises: ChameleonBluetoothAudioError if Cros device fails to connect to
43             bluetooth module on audio board.
44
45    """
46    # Resets bluetooth adapter on Cros device.
47    if not bt_adapter.reset_on():
48        raise ChameleonBluetoothAudioError(
49                'Failed to reset bluetooth adapter on Cros host.'
50                ' You should check if controller is available on Cros host'
51                ' using bluetoothctl.')
52
53    # Starts discovery mode of bluetooth adapter.
54    status, _ = bt_adapter.start_discovery()
55    if not status:
56        raise ChameleonBluetoothAudioError(
57                'Failed to start discovery on bluetooth adapter on Cros host')
58
59    def _find_device():
60        """Controls bluetooth adapter to search for bluetooth module.
61
62        @returns: True if there is a bluetooth device with MAC address
63                  matches target_mac_address. False otherwise.
64
65        """
66        return bt_adapter.has_device(target_mac_address)
67
68    # Searches for bluetooth module with given MAC address.
69    found_device = utils.wait_for_value(_find_device, True, timeout_sec=timeout)
70    status, _ =  bt_adapter.stop_discovery()
71    if not status:
72        raise ChameleonBluetoothAudioError(
73            'Failed to stop discovery on bluetooth adapter on Cros host')
74
75    if not found_device:
76        raise ChameleonBluetoothAudioError(
77                'Can not find bluetooth module with MAC address %s' %
78                target_mac_address)
79
80    pair_legacy_bluetooth_module(bt_adapter, target_mac_address)
81
82    # Disconnects from bluetooth module to clean up the state.
83    if not bt_adapter.disconnect_device(target_mac_address):
84        raise ChameleonBluetoothAudioError(
85                'Failed to let Cros device disconnect from bluetooth module %s' %
86                target_mac_address)
87    time.sleep(_SLEEP_AFTER_DISCONNECT)
88
89    # Connects to bluetooth module.
90    connect_bluetooth_module(bt_adapter, target_mac_address)
91
92    logging.info('Bluetooth module at %s is connected', target_mac_address)
93
94
95def connect_bluetooth_module(bt_adapter, target_mac_address,
96                             timeout=_CONNECT_TIMEOUT):
97    """Controls Cros device to connect to bluetooth module on audio board.
98
99    @param bt_adapter: A BluetoothDevice object to control bluetooth adapter
100                       on Cros device.
101    @param target_mac_address: The MAC address of bluetooth module to be
102                               connected.
103    @param timeout: Timeout in seconds to connect bluetooth module.
104
105    @raises: ChameleonBluetoothAudioError if Cros device fails to connect to
106             bluetooth module on audio board.
107
108    """
109    def _connect_device():
110        logging.info('Try to connect to device')
111        success = bt_adapter.connect_device(target_mac_address)
112        if not success:
113            logging.debug('Can not connect device, retry in 1 second.')
114            time.sleep(1)
115            return False
116        logging.debug('Connection established.')
117        return True
118
119    # Connects bluetooth module with given MAC address.
120    connected = utils.wait_for_value(_connect_device, True, timeout_sec=timeout)
121    if not connected:
122        raise ChameleonBluetoothAudioError(
123                'Failed to let Cros device connect to bluetooth module %s' %
124                target_mac_address)
125
126
127def pair_legacy_bluetooth_module(bt_adapter, target_mac_address, pin=_PIN,
128                                 pairing_timeout=_PAIRING_TIMEOUT, retries=3):
129    """Pairs Cros device bluetooth adapter with legacy bluetooth module.
130
131    @param bt_adapter: A BluetoothDevice object to control bluetooth adapter
132                       on Cros device.
133    @param target_mac_address: The MAC address of bluetooth module to be
134                               paired.
135    @param pin: The pin for legacy pairing.
136    @param timeout: Timeout in seconds to pair bluetooth module in a trial.
137    @param retries: Number of retries if pairing fails.
138
139    @raises: ChameleonBluetoothAudioError if Cros device fails to pair
140             bluetooth module on audio board after all the retries.
141
142    """
143    # Pairs the bluetooth adapter with bluetooth module.
144    for trial in range(retries):
145        if bt_adapter.pair_legacy_device(
146            target_mac_address, pin, False, pairing_timeout):
147                logging.debug('Pairing to %s succeeded', target_mac_address)
148                return
149        elif trial == retries - 1:
150            raise ChameleonBluetoothAudioError(
151                    'Failed to pair Cros device and bluetooth module %s' %
152                    target_mac_address)
153
154        logging.debug('Retry for pairing...')
155
156
157class BluetoothRefController(object):
158    """
159    An abstraction of bluetooth module on Fizz.
160    Analogous to BluetoothController defined in audio_board.py for
161    Chameleon hardware.
162
163    """
164    def __init__(self, chameleon_connection):
165        """Constructs a BluetoothController.
166
167        @param chameleon_connection: A ChameleonConnection object.
168
169        """
170        self._chameleond_proxy = chameleon_connection
171
172
173    def reset(self):
174        """Resets the bluetooth Ref."""
175        self._chameleond_proxy.ResetBluetoothRef()
176        logging.info('Resets bluetooth Ref.')
177
178
179    def enable(self):
180        """Disables the bluetooth Ref."""
181        self._chameleond_proxy.EnableBluetoothRef()
182        logging.info('Disables bluetooth Ref.')
183
184    def disable(self):
185        """Disables the bluetooth Ref."""
186        self._chameleond_proxy.DisableBluetoothRef()
187        logging.info('Disables bluetooth Ref.')
188
189
190    def is_enabled(self):
191        """Checks if the bluetooth Ref is enabled.
192
193        @returns: True if bluetooth module is enabled. False otherwise.
194
195        """
196        """
197        TODO (npoojary):
198        return self._chameleond_proxy.IsBluetoothRefEnabled()
199        """
200        return True
201