| # Copyright 2024 Google LLC | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # https://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| import asyncio | |
| # ----------------------------------------------------------------------------- | |
| # Imports | |
| # ----------------------------------------------------------------------------- | |
| import logging | |
| from typing import Any | |
| import click | |
| import bumble.logging | |
| from bumble import transport | |
| from bumble.colors import color | |
| from bumble.drivers import intel | |
| from bumble.host import Host | |
| # ----------------------------------------------------------------------------- | |
| # Logging | |
| # ----------------------------------------------------------------------------- | |
| logger = logging.getLogger(__name__) | |
| # ----------------------------------------------------------------------------- | |
| def print_device_info(device_info: dict[intel.ValueType, Any]) -> None: | |
| if (mode := device_info.get(intel.ValueType.CURRENT_MODE_OF_OPERATION)) is not None: | |
| print( | |
| color("MODE:", "yellow"), | |
| mode.name, | |
| ) | |
| print(color("DETAILS:", "yellow")) | |
| for key, value in device_info.items(): | |
| print(f" {color(key.name, 'green')}: {value}") | |
| # ----------------------------------------------------------------------------- | |
| async def get_driver(host: Host, force: bool) -> intel.Driver | None: | |
| # Create a driver | |
| driver = await intel.Driver.for_host(host, force) | |
| if driver is None: | |
| print("Device does not appear to be an Intel device") | |
| return None | |
| return driver | |
| # ----------------------------------------------------------------------------- | |
| async def do_info(usb_transport, force): | |
| async with await transport.open_transport(usb_transport) as ( | |
| hci_source, | |
| hci_sink, | |
| ): | |
| host = Host(hci_source, hci_sink) | |
| driver = await get_driver(host, force) | |
| if driver is None: | |
| return | |
| # Get and print the device info | |
| print_device_info(await driver.read_device_info()) | |
| # ----------------------------------------------------------------------------- | |
| async def do_load(usb_transport: str, force: bool) -> None: | |
| async with await transport.open_transport(usb_transport) as ( | |
| hci_source, | |
| hci_sink, | |
| ): | |
| host = Host(hci_source, hci_sink) | |
| driver = await get_driver(host, force) | |
| if driver is None: | |
| return | |
| # Reboot in bootloader mode | |
| await driver.load_firmware() | |
| # Get and print the device info | |
| print_device_info(await driver.read_device_info()) | |
| # ----------------------------------------------------------------------------- | |
| async def do_bootloader(usb_transport: str, force: bool) -> None: | |
| async with await transport.open_transport(usb_transport) as ( | |
| hci_source, | |
| hci_sink, | |
| ): | |
| host = Host(hci_source, hci_sink) | |
| driver = await get_driver(host, force) | |
| if driver is None: | |
| return | |
| # Reboot in bootloader mode | |
| await driver.reboot_bootloader() | |
| # ----------------------------------------------------------------------------- | |
| @click.group() | |
| def main(): | |
| bumble.logging.setup_basic_logging() | |
| @main.command | |
| @click.argument("usb_transport") | |
| @click.option( | |
| "--force", | |
| is_flag=True, | |
| default=False, | |
| help="Try to get the device info even if the USB info doesn't match", | |
| ) | |
| def info(usb_transport, force): | |
| """Get the firmware info.""" | |
| asyncio.run(do_info(usb_transport, force)) | |
| @main.command | |
| @click.argument("usb_transport") | |
| @click.option( | |
| "--force", | |
| is_flag=True, | |
| default=False, | |
| help="Load even if the USB info doesn't match", | |
| ) | |
| def load(usb_transport, force): | |
| """Load a firmware image.""" | |
| asyncio.run(do_load(usb_transport, force)) | |
| @main.command | |
| @click.argument("usb_transport") | |
| @click.option( | |
| "--force", | |
| is_flag=True, | |
| default=False, | |
| help="Attempt to reboot event if the USB info doesn't match", | |
| ) | |
| def bootloader(usb_transport, force): | |
| """Reboot in bootloader mode.""" | |
| asyncio.run(do_bootloader(usb_transport, force)) | |
| # ----------------------------------------------------------------------------- | |
| if __name__ == '__main__': | |
| main() |