1# Copyright 2021-2022 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# -----------------------------------------------------------------------------
16# Imports
17# -----------------------------------------------------------------------------
18import asyncio
19import sys
20import os
21import logging
22from bumble.colors import color
23from bumble.device import Device
24from bumble.hci import Address
25from bumble.transport import open_transport_or_link
26from bumble.core import DeviceClass
27
28
29# -----------------------------------------------------------------------------
30class DiscoveryListener(Device.Listener):
31    def on_inquiry_result(self, address, class_of_device, data, rssi):
32        (
33            service_classes,
34            major_device_class,
35            minor_device_class,
36        ) = DeviceClass.split_class_of_device(class_of_device)
37        separator = '\n  '
38        print(f'>>> {color(address, "yellow")}:')
39        print(f'  Device Class (raw): {class_of_device:06X}')
40        major_class_name = DeviceClass.major_device_class_name(major_device_class)
41        print('  Device Major Class: ' f'{major_class_name}')
42        minor_class_name = DeviceClass.minor_device_class_name(
43            major_device_class, minor_device_class
44        )
45        print('  Device Minor Class: ' f'{minor_class_name}')
46        print(
47            '  Device Services: '
48            f'{", ".join(DeviceClass.service_class_labels(service_classes))}'
49        )
50        print(f'  RSSI: {rssi}')
51        if data.ad_structures:
52            print(f'  {data.to_string(separator)}')
53
54
55# -----------------------------------------------------------------------------
56async def main() -> None:
57    if len(sys.argv) != 2:
58        print('Usage: run_classic_discovery.py <transport-spec>')
59        print('example: run_classic_discovery.py usb:04b4:f901')
60        return
61
62    print('<<< connecting to HCI...')
63    async with await open_transport_or_link(sys.argv[1]) as hci_transport:
64        print('<<< connected')
65
66        device = Device.with_hci(
67            'Bumble',
68            Address('F0:F1:F2:F3:F4:F5'),
69            hci_transport.source,
70            hci_transport.sink,
71        )
72        device.listener = DiscoveryListener()
73        await device.power_on()
74        await device.start_discovery()
75
76        await hci_transport.source.wait_for_termination()
77
78
79# -----------------------------------------------------------------------------
80logging.basicConfig(level=os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper())
81asyncio.run(main())
82