From 430023e0998e9412700a3ded4fdf3a7a06ef1248 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Tue, 8 Apr 2025 15:33:16 +0200 Subject: [PATCH] wip --- common/protob/Makefile | 2 +- common/protob/messages-ble.proto | 8 + common/protob/messages-common.proto | 1 + core/src/trezor/enums/FailureType.py | 1 + core/src/trezor/enums/__init__.py | 1 + core/src/trezor/messages.py | 6 + pyproject.toml | 6 +- python/requirements.txt | 1 + python/setup.cfg | 2 +- python/src/trezorlib/ble.py | 12 + python/src/trezorlib/cli/__init__.py | 8 +- python/src/trezorlib/cli/ble.py | 57 +++- python/src/trezorlib/cli/trezorctl.py | 4 +- python/src/trezorlib/messages.py | 5 + python/src/trezorlib/transport/__init__.py | 4 + python/src/trezorlib/transport/ble.py | 291 ++++++++++++++++++ python/src/trezorlib/transport/protocol.py | 9 +- python/src/trezorlib/transport/webusb.py | 2 + .../src/protos/generated/messages_ble.rs | 111 ++++++- .../src/protos/generated/messages_common.rs | 89 +++--- 20 files changed, 562 insertions(+), 58 deletions(-) create mode 100644 python/src/trezorlib/transport/ble.py diff --git a/common/protob/Makefile b/common/protob/Makefile index f8df2d2d5d..c2feff5a84 100644 --- a/common/protob/Makefile +++ b/common/protob/Makefile @@ -1,4 +1,4 @@ -check: messages.pb messages-binance.pb messages-bitcoin.pb messages-bootloader.pb messages-cardano.pb messages-common.pb messages-crypto.pb messages-debug.pb messages-ethereum.pb messages-management.pb messages-monero.pb messages-nem.pb messages-ripple.pb messages-stellar.pb messages-tezos.pb messages-eos.pb +check: messages.pb messages-binance.pb messages-bitcoin.pb messages-ble.pb messages-bootloader.pb messages-cardano.pb messages-common.pb messages-crypto.pb messages-debug.pb messages-ethereum.pb messages-management.pb messages-monero.pb messages-nem.pb messages-ripple.pb messages-stellar.pb messages-tezos.pb messages-eos.pb %.pb: %.proto protoc -I/usr/include -I. $< -o $@ diff --git a/common/protob/messages-ble.proto b/common/protob/messages-ble.proto index ea34aa1ef0..f951725270 100644 --- a/common/protob/messages-ble.proto +++ b/common/protob/messages-ble.proto @@ -20,3 +20,11 @@ message BleUnpair { optional bool all = 1; // whether to erase bonds for all devices } +/** + * Request: disconnect + * @start + * @next Success + * @next Failure + */ +message BleDisconnect { +} diff --git a/common/protob/messages-common.proto b/common/protob/messages-common.proto index 3e8cb9537c..1e763455dc 100644 --- a/common/protob/messages-common.proto +++ b/common/protob/messages-common.proto @@ -39,6 +39,7 @@ message Failure { Failure_PinMismatch = 12; Failure_WipeCodeMismatch = 13; Failure_InvalidSession = 14; + Failure_DeviceIsBusy = 15; // FIXME: probably remove Failure_FirmwareError = 99; } } diff --git a/core/src/trezor/enums/FailureType.py b/core/src/trezor/enums/FailureType.py index fbb2001e54..625af7a461 100644 --- a/core/src/trezor/enums/FailureType.py +++ b/core/src/trezor/enums/FailureType.py @@ -16,4 +16,5 @@ NotInitialized = 11 PinMismatch = 12 WipeCodeMismatch = 13 InvalidSession = 14 +DeviceIsBusy = 15 FirmwareError = 99 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index b57b81bb0b..b6cc199e9a 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -39,6 +39,7 @@ if TYPE_CHECKING: PinMismatch = 12 WipeCodeMismatch = 13 InvalidSession = 14 + DeviceIsBusy = 15 FirmwareError = 99 class ButtonRequestType(IntEnum): diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index c35cc70092..44ac834c9d 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -1270,6 +1270,12 @@ if TYPE_CHECKING: def is_type_of(cls, msg: Any) -> TypeGuard["BleUnpair"]: return isinstance(msg, cls) + class BleDisconnect(protobuf.MessageType): + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["BleDisconnect"]: + return isinstance(msg, cls) + class CardanoBlockchainPointerType(protobuf.MessageType): block_index: "int" tx_index: "int" diff --git a/pyproject.toml b/pyproject.toml index 7990bb7679..1fec9ad140 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ package-mode = false [tool.poetry.dependencies] # all -python = "^3.9" +python = "<3.14,>=3.9" trezor = {path = "./python", develop = true} tvl = {path = "./vendor/ts-tvl", develop = true} scons = "*" @@ -80,6 +80,10 @@ flake8-annotations = "^3.1.1" pyelftools = "^0.32" pytest-retry = "^1.7.0" +# ble +#dbus-fast = "*" +bleak = "^0.22.3" + [tool.poetry.dev-dependencies] scan-build = "*" towncrier = "^23.6.0" diff --git a/python/requirements.txt b/python/requirements.txt index 7c2cfe8936..8597d8d107 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -9,3 +9,4 @@ construct>=2.9,!=2.10.55 typing_extensions>=4.7.1 construct-classes>=0.1.2 cryptography>=41 +bleak>=0.22 diff --git a/python/setup.cfg b/python/setup.cfg index 36533f528c..06791b49ec 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -29,7 +29,7 @@ per-file-ignores = helper-scripts/*:I tools/*:I tests/*:I -known-modules = libusb1:[usb1],hidapi:[hid],PyQt5:[PyQt5.QtWidgets,PyQt5.QtGui,PyQt5.QtCore] +known-modules = libusb1:[usb1],hidapi:[hid],PyQt5:[PyQt5.QtWidgets,PyQt5.QtGui,PyQt5.QtCore],dbus-next:[dbus_next] [isort] profile = black diff --git a/python/src/trezorlib/ble.py b/python/src/trezorlib/ble.py index d72f77b013..093645eec9 100644 --- a/python/src/trezorlib/ble.py +++ b/python/src/trezorlib/ble.py @@ -19,3 +19,15 @@ def unpair( return else: raise RuntimeError(f"Unexpected message {resp}") + + +@session +def disconnect( + client: "TrezorClient", +): + resp = client.call(messages.BleDisconnect()) + + if isinstance(resp, messages.Success): + return + else: + raise RuntimeError(f"Unexpected message {resp}") diff --git a/python/src/trezorlib/cli/__init__.py b/python/src/trezorlib/cli/__init__.py index 6db335a7ad..962c24d039 100644 --- a/python/src/trezorlib/cli/__init__.py +++ b/python/src/trezorlib/cli/__init__.py @@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional import click -from .. import exceptions, transport +from .. import exceptions, messages, transport from ..client import TrezorClient from ..ui import ClickUI, ScriptUI @@ -110,6 +110,12 @@ class TrezorConnection: except transport.DeviceIsBusy: click.echo("Device is in use by another process.") sys.exit(1) + except exceptions.TrezorFailure as e: + if e.code is messages.FailureType.DeviceIsBusy: + click.echo(str(e)) + sys.exit(1) + else: + raise e except Exception: click.echo("Failed to find a Trezor device.") if self.path is not None: diff --git a/python/src/trezorlib/cli/ble.py b/python/src/trezorlib/cli/ble.py index 3162d2d550..b5b964577c 100644 --- a/python/src/trezorlib/cli/ble.py +++ b/python/src/trezorlib/cli/ble.py @@ -15,16 +15,14 @@ # If not, see . import sys -from typing import TYPE_CHECKING import click from .. import ble, exceptions +from ..client import TrezorClient +from ..transport.ble import BleProxy from . import with_client -if TYPE_CHECKING: - from ..client import TrezorClient - @click.group(name="ble") def cli() -> None: @@ -53,3 +51,54 @@ def unpair( except exceptions.TrezorException as e: click.echo(f"Unpair failed: {e}") sys.exit(3) + + +@cli.command() +def connect() -> None: + """Connect to the device via BLE.""" + ble = BleProxy() + + click.echo("Scanning...") + devices = ble.scan() + + if len(devices) == 0: + click.echo("No BLE devices found") + return + else: + click.echo(f"Found {len(devices)} BLE device(s)") + + for address, name in devices: + click.echo(f"Device: {name}, {address}") + + device = devices[0] + click.echo(f"Connecting to {device[1]}...") + ble.connect(device[0]) + click.echo("Connected") + + +@with_client +def disconnect_device(client: "TrezorClient") -> None: + """Disconnect from device side.""" + try: + ble.disconnect(client) + except exceptions.Cancelled: + click.echo("Disconnect aborted on device.") + except exceptions.TrezorException as e: + click.echo(f"Disconnect failed: {e}") + sys.exit(3) + + +@cli.command() +@click.option("--device", is_flag=True, help="Disconnect from device side.") +def disconnect(device: bool) -> None: + + if device: + disconnect_device() + else: + ble_proxy = BleProxy() + devices = [d for d in ble_proxy.lookup() if d.connected] + if len(devices) == 0: + click.echo("No BLE devices found") + return + ble_proxy.connect(devices[0].address) + ble_proxy.disconnect() diff --git a/python/src/trezorlib/cli/trezorctl.py b/python/src/trezorlib/cli/trezorctl.py index 4b2c1eb533..926a1803fa 100755 --- a/python/src/trezorlib/cli/trezorctl.py +++ b/python/src/trezorlib/cli/trezorctl.py @@ -296,8 +296,8 @@ def list_devices(no_resolve: bool) -> Optional[Iterable["Transport"]]: client.end_session() except DeviceIsBusy: description = "Device is in use by another process" - except Exception: - description = "Failed to read details" + # except Exception: + # description = "Failed to read details" click.echo(f"{transport} - {description}") return None diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 13d9b42fd8..63f4bbc50a 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -43,6 +43,7 @@ class FailureType(IntEnum): PinMismatch = 12 WipeCodeMismatch = 13 InvalidSession = 14 + DeviceIsBusy = 15 FirmwareError = 99 @@ -2222,6 +2223,10 @@ class BleUnpair(protobuf.MessageType): self.all = all +class BleDisconnect(protobuf.MessageType): + MESSAGE_WIRE_TYPE = None + + class FirmwareErase(protobuf.MessageType): MESSAGE_WIRE_TYPE = 6 FIELDS = { diff --git a/python/src/trezorlib/transport/__init__.py b/python/src/trezorlib/transport/__init__.py index 8aa759b173..1890e8020a 100644 --- a/python/src/trezorlib/transport/__init__.py +++ b/python/src/trezorlib/transport/__init__.py @@ -110,6 +110,7 @@ class Transport: def all_transports() -> Iterable[type["Transport"]]: + from .ble import BleTransport from .bridge import BridgeTransport from .hid import HidTransport from .udp import UdpTransport @@ -120,7 +121,9 @@ def all_transports() -> Iterable[type["Transport"]]: HidTransport, UdpTransport, WebUsbTransport, + BleTransport, ) + print(f"transports {transports}") return set(t for t in transports if t.ENABLED) @@ -161,6 +164,7 @@ def get_transport(path: str | None = None, prefix_search: bool = False) -> Trans ) ) transports = [t for t in all_transports() if match_prefix(path, t.PATH_PREFIX)] + print(f"transports {transports}") if transports: return transports[0].find_by_path(path, prefix_search=prefix_search) diff --git a/python/src/trezorlib/transport/ble.py b/python/src/trezorlib/transport/ble.py new file mode 100644 index 0000000000..880b1aa5b9 --- /dev/null +++ b/python/src/trezorlib/transport/ble.py @@ -0,0 +1,291 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2025 SatoshiLabs and contributors +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the License along with this library. +# If not, see . +import asyncio +import atexit +import logging +from dataclasses import dataclass +from multiprocessing import Pipe, Process +from multiprocessing.connection import Connection +from typing import TYPE_CHECKING, Any, Iterable, Optional + +from . import Timeout, TransportException +from .protocol import ProtocolBasedTransport, ProtocolV1 + +if TYPE_CHECKING: + from ..models import TrezorModel + +LOG = logging.getLogger(__name__) + +TREZOR_SERVICE_UUID = "8c000001-a59b-4d58-a9ad-073df69fa1b1" +TREZOR_CHARACTERISTIC_RX = "8c000002-a59b-4d58-a9ad-073df69fa1b1" +TREZOR_CHARACTERISTIC_TX = "8c000003-a59b-4d58-a9ad-073df69fa1b1" + + + +class BleTransport(ProtocolBasedTransport): + ENABLED = True + PATH_PREFIX = "ble" + + _ble = None + + def __init__(self, mac_addr: str) -> None: + self.device = mac_addr + super().__init__(protocol=ProtocolV1(self, replen=244)) + + def get_path(self) -> str: + return "{}:{}".format(self.PATH_PREFIX, self.device) + + def find_debug(self) -> "BleTransport": + return BleTransport(self.device) # FIXME WebUsb + + @classmethod + def enumerate( + cls, _models: Optional[Iterable["TrezorModel"]] = None # FIXME models + ) -> Iterable["BleTransport"]: + devices = cls.ble().scan() + # FIXME we're dropping the name here + return [BleTransport(device[0]) for device in devices] + + @classmethod + def _try_path(cls, path: str) -> "BleTransport": + devices = cls.enumerate(None) + devices = [d for d in devices if d.device == path] + if len(devices) == 0: + raise TransportException(f"No BLE device: {path}") + return devices[0] + + @classmethod + def find_by_path(cls, path: str, prefix_search: bool = False) -> "BleTransport": + if not prefix_search: + raise TransportException + + if prefix_search: + return super().find_by_path(path, prefix_search) + else: + raise TransportException(f"No BLE device: {path}") + + def open(self) -> None: + self.ble().connect(self.device) + + def close(self) -> None: + pass # self.ble().disconnect() + + def write_chunk(self, chunk: bytes) -> None: + self.ble().write(self.device, chunk) + + def read_chunk(self, timeout: Optional[float] = None) -> bytes: + chunk = self.ble().read(self.device, timeout) + # LOG.log(DUMP_PACKETS, f"received packet: {chunk.hex()}") + if len(chunk) != 64: + raise TransportException(f"Unexpected chunk size: {len(chunk)}") + return bytearray(chunk) + + @classmethod + def ble(cls) -> "BleProxy": + if cls._ble is None: + cls._ble = BleProxy() + return cls._ble + + +class BleProxy: + pipe = None + process = None + + def __init__(self): + if self.pipe is not None: + return + + parent_pipe, child_pipe = Pipe() + self.pipe = parent_pipe + self.process = Process(target=BleAsync, args=(child_pipe,), daemon=True) + self.process.start() + + atexit.register(self._shutdown) + + def __getattr__(self, name: str): + def f(*args: Any, **kwargs: Any): + assert self.pipe is not None + self.pipe.send((name, args, kwargs)) + result = self.pipe.recv() + if isinstance(result, BaseException): + raise result + return result + + return f + + def _shutdown(self): + self.pipe.send(("shutdown", [], {})) + self.process.join(10) # is timeout + + +class BleAsync: + class Shutdown(Exception): + pass + +# @dataclass +# class Peripheral: +# device = None +# adv_data = None +# client = None +# queue = None + + def __init__(self, pipe: Connection): + asyncio.run(self.main(pipe)) + + async def main(self, pipe: Connection): + self.connected = {} + + # TODO: currently only one concurrent device is supported + self.current = None + self.devices = {} + self.queue = asyncio.Queue() + self.scanned = None + LOG.debug("async BLE process started") + # TODO: signal ready to main process? + + while True: + await ready(pipe) + cmd, args, kwargs = pipe.recv() + try: + result = await getattr(self, cmd)(*args, **kwargs) + except self.Shutdown: + LOG.debug("async BLE exit loop") + break + except Timeout as e: + await ready(pipe, write=True) + pipe.send(e) + except Exception as e: + LOG.exception("Error in async BLE process:") + await ready(pipe, write=True) + pipe.send(e) + break + else: + await ready(pipe, write=True) + pipe.send(result) + + await self.disconnect("FIXME") # TODO foreach + + async def scan(self) -> list[tuple[str, str]]: + LOG.debug("scanning BLE") + + from bleak import BleakScanner + + # NOTE BleakScanner.discover(service_uuids=[TREZOR_SERVICE_UUID]) is broken + # problem possibly on the bluez side + + devices = await BleakScanner.discover( + timeout=3, + return_adv=True, + ) + + self.scanned = [] + res = [] + for address, (dev, adv_data) in devices.items(): + if TREZOR_SERVICE_UUID not in adv_data.service_uuids: + continue + LOG.debug(f"scan: {dev.address}: {dev.name} rssi={adv_data.rssi} manufacturer_data={adv_data.manufacturer_data}") + self.scanned.append(dev) + res.append((dev.address, dev.name)) # FIXME + return res + + async def connect(self, address: str): + + from bleak import BleakClient + + # already connected? + # scanned? + # connect by addr + if self.current and self.current.address == address: + return + + ble_device = self.devices.get(address) + if ble_device: + LOG.debug(f"Already connected to {ble_device.address}") + self.current = ble_device + return + + if self.scanned is None: + await self.scan() + + for dev in self.scanned: + if dev.address == address: + break + else: + raise RuntimeError("device not found") + + LOG.debug(f"Connecting to {address}...") + ble_device = BleakClient(dev) # TODO: services, timeout + await ble_device.connect() + self.current = ble_device + + # import subprocess + # subprocess.run("gnome-control-center bluetooth") + + await ble_device.pair() + self.devices[address] = ble_device + + async def read_callback(characteristic, data): + await self.queue.put(data) + + await ble_device.start_notify(TREZOR_CHARACTERISTIC_TX, read_callback) + LOG.info(f"Connected to {ble_device.address}") + + async def disconnect(self, address: str): + if self.current is None: + return + ble_device = self.current + await ble_device.stop_notify(TREZOR_CHARACTERISTIC_TX) + await ble_device.disconnect() # throws EOFError sometimes + LOG.info(f"Disconnected from {ble_device.address}") + self.current = None + + async def read(self, address: str, timeout: float | None): + assert self.current + try: + return await asyncio.wait_for(self.queue.get(), timeout=timeout) + except (TimeoutError, asyncio.TimeoutError): + raise Timeout(f"Timeout reading BLE packet ({timeout}s)") + + async def write(self, address: str, chunk: bytes): + assert self.current + await self.current.write_gatt_char(TREZOR_CHARACTERISTIC_RX, chunk, response=False) + + async def shutdown(self): + raise self.Shutdown + + +async def ready(f: Any, write: bool = False): + """Asynchronously wait for file-like object to become ready for reading or writing.""" + fd = f.fileno() + loop = asyncio.get_event_loop() + event = asyncio.Event() + + if write: + + def callback(): + event.set() + loop.remove_writer(fd) + + loop.add_writer(fd, callback) + else: + + def callback(): + event.set() + loop.remove_reader(fd) + + loop.add_reader(fd, callback) + + await event.wait() diff --git a/python/src/trezorlib/transport/protocol.py b/python/src/trezorlib/transport/protocol.py index 25d8687a0c..6400f74a3e 100644 --- a/python/src/trezorlib/transport/protocol.py +++ b/python/src/trezorlib/transport/protocol.py @@ -78,8 +78,9 @@ class Protocol: its messages. """ - def __init__(self, handle: Handle) -> None: + def __init__(self, handle: Handle, replen: int = REPLEN) -> None: self.handle = handle + self.replen = replen self.session_counter = 0 # XXX we might be able to remove this now that TrezorClient does session handling @@ -144,10 +145,10 @@ class ProtocolV1(Protocol): while buffer: # Report ID, data padded to 63 bytes - chunk = b"?" + buffer[: REPLEN - 1] - chunk = chunk.ljust(REPLEN, b"\x00") + chunk = b"?" + buffer[: self.replen - 1] + chunk = chunk.ljust(self.replen, b"\x00") self.handle.write_chunk(chunk) - buffer = buffer[63:] + buffer = buffer[self.replen - 1 :] def read(self, timeout: float | None = None) -> MessagePayload: if timeout is None: diff --git a/python/src/trezorlib/transport/webusb.py b/python/src/trezorlib/transport/webusb.py index 6fa7868c0e..73783d1c60 100644 --- a/python/src/trezorlib/transport/webusb.py +++ b/python/src/trezorlib/transport/webusb.py @@ -68,6 +68,8 @@ class WebUsbHandle: self.handle.claimInterface(self.interface) except usb1.USBErrorAccess as e: raise DeviceIsBusy(self.device) from e + except usb1.USBErrorBusy as e: + raise DeviceIsBusy(self.device) from e def close(self) -> None: if self.handle is not None: diff --git a/rust/trezor-client/src/protos/generated/messages_ble.rs b/rust/trezor-client/src/protos/generated/messages_ble.rs index 832b7fecb7..8800302bc8 100644 --- a/rust/trezor-client/src/protos/generated/messages_ble.rs +++ b/rust/trezor-client/src/protos/generated/messages_ble.rs @@ -166,10 +166,114 @@ impl ::protobuf::reflect::ProtobufValue for BleUnpair { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } +// @@protoc_insertion_point(message:hw.trezor.messages.ble.BleDisconnect) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct BleDisconnect { + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.ble.BleDisconnect.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a BleDisconnect { + fn default() -> &'a BleDisconnect { + ::default_instance() + } +} + +impl BleDisconnect { + pub fn new() -> BleDisconnect { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(0); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "BleDisconnect", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for BleDisconnect { + const NAME: &'static str = "BleDisconnect"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> BleDisconnect { + BleDisconnect::new() + } + + fn clear(&mut self) { + self.special_fields.clear(); + } + + fn default_instance() -> &'static BleDisconnect { + static instance: BleDisconnect = BleDisconnect { + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for BleDisconnect { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("BleDisconnect").unwrap()).clone() + } +} + +impl ::std::fmt::Display for BleDisconnect { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for BleDisconnect { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + static file_descriptor_proto_data: &'static [u8] = b"\ \n\x12messages-ble.proto\x12\x16hw.trezor.messages.ble\x1a\roptions.prot\ - o\"\x1d\n\tBleUnpair\x12\x10\n\x03all\x18\x01\x20\x01(\x08R\x03allB;\n#c\ - om.satoshilabs.trezor.lib.protobufB\x10TrezorMessageBle\x80\xa6\x1d\x01\ + o\"\x1d\n\tBleUnpair\x12\x10\n\x03all\x18\x01\x20\x01(\x08R\x03all\"\x0f\ + \n\rBleDisconnectB;\n#com.satoshilabs.trezor.lib.protobufB\x10TrezorMess\ + ageBle\x80\xa6\x1d\x01\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -188,8 +292,9 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { let mut deps = ::std::vec::Vec::with_capacity(1); deps.push(super::options::file_descriptor().clone()); - let mut messages = ::std::vec::Vec::with_capacity(1); + let mut messages = ::std::vec::Vec::with_capacity(2); messages.push(BleUnpair::generated_message_descriptor_data()); + messages.push(BleDisconnect::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(0); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( file_descriptor_proto(), diff --git a/rust/trezor-client/src/protos/generated/messages_common.rs b/rust/trezor-client/src/protos/generated/messages_common.rs index 4fd72b22f0..8b6203c811 100644 --- a/rust/trezor-client/src/protos/generated/messages_common.rs +++ b/rust/trezor-client/src/protos/generated/messages_common.rs @@ -414,6 +414,8 @@ pub mod failure { Failure_WipeCodeMismatch = 13, // @@protoc_insertion_point(enum_value:hw.trezor.messages.common.Failure.FailureType.Failure_InvalidSession) Failure_InvalidSession = 14, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.common.Failure.FailureType.Failure_DeviceIsBusy) + Failure_DeviceIsBusy = 15, // @@protoc_insertion_point(enum_value:hw.trezor.messages.common.Failure.FailureType.Failure_FirmwareError) Failure_FirmwareError = 99, } @@ -441,6 +443,7 @@ pub mod failure { 12 => ::std::option::Option::Some(FailureType::Failure_PinMismatch), 13 => ::std::option::Option::Some(FailureType::Failure_WipeCodeMismatch), 14 => ::std::option::Option::Some(FailureType::Failure_InvalidSession), + 15 => ::std::option::Option::Some(FailureType::Failure_DeviceIsBusy), 99 => ::std::option::Option::Some(FailureType::Failure_FirmwareError), _ => ::std::option::Option::None } @@ -462,6 +465,7 @@ pub mod failure { "Failure_PinMismatch" => ::std::option::Option::Some(FailureType::Failure_PinMismatch), "Failure_WipeCodeMismatch" => ::std::option::Option::Some(FailureType::Failure_WipeCodeMismatch), "Failure_InvalidSession" => ::std::option::Option::Some(FailureType::Failure_InvalidSession), + "Failure_DeviceIsBusy" => ::std::option::Option::Some(FailureType::Failure_DeviceIsBusy), "Failure_FirmwareError" => ::std::option::Option::Some(FailureType::Failure_FirmwareError), _ => ::std::option::Option::None } @@ -482,6 +486,7 @@ pub mod failure { FailureType::Failure_PinMismatch, FailureType::Failure_WipeCodeMismatch, FailureType::Failure_InvalidSession, + FailureType::Failure_DeviceIsBusy, FailureType::Failure_FirmwareError, ]; } @@ -508,7 +513,8 @@ pub mod failure { FailureType::Failure_PinMismatch => 11, FailureType::Failure_WipeCodeMismatch => 12, FailureType::Failure_InvalidSession => 13, - FailureType::Failure_FirmwareError => 14, + FailureType::Failure_DeviceIsBusy => 14, + FailureType::Failure_FirmwareError => 15, }; Self::enum_descriptor().value_by_index(index) } @@ -2481,9 +2487,9 @@ impl ::protobuf::reflect::ProtobufValue for HDNodeType { static file_descriptor_proto_data: &'static [u8] = b"\ \n\x15messages-common.proto\x12\x19hw.trezor.messages.common\x1a\roption\ s.proto\"%\n\x07Success\x12\x1a\n\x07message\x18\x01\x20\x01(\t:\0R\x07m\ - essage\"\x8f\x04\n\x07Failure\x12B\n\x04code\x18\x01\x20\x01(\x0e2..hw.t\ + essage\"\xa9\x04\n\x07Failure\x12B\n\x04code\x18\x01\x20\x01(\x0e2..hw.t\ rezor.messages.common.Failure.FailureTypeR\x04code\x12\x18\n\x07message\ - \x18\x02\x20\x01(\tR\x07message\"\xa5\x03\n\x0bFailureType\x12\x1d\n\x19\ + \x18\x02\x20\x01(\tR\x07message\"\xbf\x03\n\x0bFailureType\x12\x1d\n\x19\ Failure_UnexpectedMessage\x10\x01\x12\x1a\n\x16Failure_ButtonExpected\ \x10\x02\x12\x15\n\x11Failure_DataError\x10\x03\x12\x1b\n\x17Failure_Act\ ionCancelled\x10\x04\x12\x17\n\x13Failure_PinExpected\x10\x05\x12\x18\n\ @@ -2492,44 +2498,45 @@ static file_descriptor_proto_data: &'static [u8] = b"\ essError\x10\t\x12\x1a\n\x16Failure_NotEnoughFunds\x10\n\x12\x1a\n\x16Fa\ ilure_NotInitialized\x10\x0b\x12\x17\n\x13Failure_PinMismatch\x10\x0c\ \x12\x1c\n\x18Failure_WipeCodeMismatch\x10\r\x12\x1a\n\x16Failure_Invali\ - dSession\x10\x0e\x12\x19\n\x15Failure_FirmwareError\x10c\"\xab\x06\n\rBu\ - ttonRequest\x12N\n\x04code\x18\x01\x20\x01(\x0e2:.hw.trezor.messages.com\ - mon.ButtonRequest.ButtonRequestTypeR\x04code\x12\x14\n\x05pages\x18\x02\ - \x20\x01(\rR\x05pages\x12\x12\n\x04name\x18\x04\x20\x01(\tR\x04name\"\ - \x99\x05\n\x11ButtonRequestType\x12\x17\n\x13ButtonRequest_Other\x10\x01\ - \x12\"\n\x1eButtonRequest_FeeOverThreshold\x10\x02\x12\x1f\n\x1bButtonRe\ - quest_ConfirmOutput\x10\x03\x12\x1d\n\x19ButtonRequest_ResetDevice\x10\ - \x04\x12\x1d\n\x19ButtonRequest_ConfirmWord\x10\x05\x12\x1c\n\x18ButtonR\ - equest_WipeDevice\x10\x06\x12\x1d\n\x19ButtonRequest_ProtectCall\x10\x07\ - \x12\x18\n\x14ButtonRequest_SignTx\x10\x08\x12\x1f\n\x1bButtonRequest_Fi\ - rmwareCheck\x10\t\x12\x19\n\x15ButtonRequest_Address\x10\n\x12\x1b\n\x17\ - ButtonRequest_PublicKey\x10\x0b\x12#\n\x1fButtonRequest_MnemonicWordCoun\ - t\x10\x0c\x12\x1f\n\x1bButtonRequest_MnemonicInput\x10\r\x120\n(_Depreca\ - ted_ButtonRequest_PassphraseType\x10\x0e\x1a\x02\x08\x01\x12'\n#ButtonRe\ - quest_UnknownDerivationPath\x10\x0f\x12\"\n\x1eButtonRequest_RecoveryHom\ - epage\x10\x10\x12\x19\n\x15ButtonRequest_Success\x10\x11\x12\x19\n\x15Bu\ - ttonRequest_Warning\x10\x12\x12!\n\x1dButtonRequest_PassphraseEntry\x10\ - \x13\x12\x1a\n\x16ButtonRequest_PinEntry\x10\x14J\x04\x08\x03\x10\x04\"\ - \x0b\n\tButtonAck\"\xbb\x02\n\x10PinMatrixRequest\x12T\n\x04type\x18\x01\ - \x20\x01(\x0e2@.hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequ\ - estTypeR\x04type\"\xd0\x01\n\x14PinMatrixRequestType\x12\x20\n\x1cPinMat\ - rixRequestType_Current\x10\x01\x12!\n\x1dPinMatrixRequestType_NewFirst\ - \x10\x02\x12\"\n\x1ePinMatrixRequestType_NewSecond\x10\x03\x12&\n\"PinMa\ - trixRequestType_WipeCodeFirst\x10\x04\x12'\n#PinMatrixRequestType_WipeCo\ - deSecond\x10\x05\"\x20\n\x0cPinMatrixAck\x12\x10\n\x03pin\x18\x01\x20\ - \x02(\tR\x03pin\"5\n\x11PassphraseRequest\x12\x20\n\n_on_device\x18\x01\ - \x20\x01(\x08R\x08OnDeviceB\x02\x18\x01\"g\n\rPassphraseAck\x12\x1e\n\np\ - assphrase\x18\x01\x20\x01(\tR\npassphrase\x12\x19\n\x06_state\x18\x02\ - \x20\x01(\x0cR\x05StateB\x02\x18\x01\x12\x1b\n\ton_device\x18\x03\x20\ - \x01(\x08R\x08onDevice\"=\n!Deprecated_PassphraseStateRequest\x12\x14\n\ - \x05state\x18\x01\x20\x01(\x0cR\x05state:\x02\x18\x01\"#\n\x1dDeprecated\ - _PassphraseStateAck:\x02\x18\x01\"\xc0\x01\n\nHDNodeType\x12\x14\n\x05de\ - pth\x18\x01\x20\x02(\rR\x05depth\x12\x20\n\x0bfingerprint\x18\x02\x20\ - \x02(\rR\x0bfingerprint\x12\x1b\n\tchild_num\x18\x03\x20\x02(\rR\x08chil\ - dNum\x12\x1d\n\nchain_code\x18\x04\x20\x02(\x0cR\tchainCode\x12\x1f\n\ - \x0bprivate_key\x18\x05\x20\x01(\x0cR\nprivateKey\x12\x1d\n\npublic_key\ - \x18\x06\x20\x02(\x0cR\tpublicKeyB>\n#com.satoshilabs.trezor.lib.protobu\ - fB\x13TrezorMessageCommon\x80\xa6\x1d\x01\ + dSession\x10\x0e\x12\x18\n\x14Failure_DeviceIsBusy\x10\x0f\x12\x19\n\x15\ + Failure_FirmwareError\x10c\"\xab\x06\n\rButtonRequest\x12N\n\x04code\x18\ + \x01\x20\x01(\x0e2:.hw.trezor.messages.common.ButtonRequest.ButtonReques\ + tTypeR\x04code\x12\x14\n\x05pages\x18\x02\x20\x01(\rR\x05pages\x12\x12\n\ + \x04name\x18\x04\x20\x01(\tR\x04name\"\x99\x05\n\x11ButtonRequestType\ + \x12\x17\n\x13ButtonRequest_Other\x10\x01\x12\"\n\x1eButtonRequest_FeeOv\ + erThreshold\x10\x02\x12\x1f\n\x1bButtonRequest_ConfirmOutput\x10\x03\x12\ + \x1d\n\x19ButtonRequest_ResetDevice\x10\x04\x12\x1d\n\x19ButtonRequest_C\ + onfirmWord\x10\x05\x12\x1c\n\x18ButtonRequest_WipeDevice\x10\x06\x12\x1d\ + \n\x19ButtonRequest_ProtectCall\x10\x07\x12\x18\n\x14ButtonRequest_SignT\ + x\x10\x08\x12\x1f\n\x1bButtonRequest_FirmwareCheck\x10\t\x12\x19\n\x15Bu\ + ttonRequest_Address\x10\n\x12\x1b\n\x17ButtonRequest_PublicKey\x10\x0b\ + \x12#\n\x1fButtonRequest_MnemonicWordCount\x10\x0c\x12\x1f\n\x1bButtonRe\ + quest_MnemonicInput\x10\r\x120\n(_Deprecated_ButtonRequest_PassphraseTyp\ + e\x10\x0e\x1a\x02\x08\x01\x12'\n#ButtonRequest_UnknownDerivationPath\x10\ + \x0f\x12\"\n\x1eButtonRequest_RecoveryHomepage\x10\x10\x12\x19\n\x15Butt\ + onRequest_Success\x10\x11\x12\x19\n\x15ButtonRequest_Warning\x10\x12\x12\ + !\n\x1dButtonRequest_PassphraseEntry\x10\x13\x12\x1a\n\x16ButtonRequest_\ + PinEntry\x10\x14J\x04\x08\x03\x10\x04\"\x0b\n\tButtonAck\"\xbb\x02\n\x10\ + PinMatrixRequest\x12T\n\x04type\x18\x01\x20\x01(\x0e2@.hw.trezor.message\ + s.common.PinMatrixRequest.PinMatrixRequestTypeR\x04type\"\xd0\x01\n\x14P\ + inMatrixRequestType\x12\x20\n\x1cPinMatrixRequestType_Current\x10\x01\ + \x12!\n\x1dPinMatrixRequestType_NewFirst\x10\x02\x12\"\n\x1ePinMatrixReq\ + uestType_NewSecond\x10\x03\x12&\n\"PinMatrixRequestType_WipeCodeFirst\ + \x10\x04\x12'\n#PinMatrixRequestType_WipeCodeSecond\x10\x05\"\x20\n\x0cP\ + inMatrixAck\x12\x10\n\x03pin\x18\x01\x20\x02(\tR\x03pin\"5\n\x11Passphra\ + seRequest\x12\x20\n\n_on_device\x18\x01\x20\x01(\x08R\x08OnDeviceB\x02\ + \x18\x01\"g\n\rPassphraseAck\x12\x1e\n\npassphrase\x18\x01\x20\x01(\tR\n\ + passphrase\x12\x19\n\x06_state\x18\x02\x20\x01(\x0cR\x05StateB\x02\x18\ + \x01\x12\x1b\n\ton_device\x18\x03\x20\x01(\x08R\x08onDevice\"=\n!Depreca\ + ted_PassphraseStateRequest\x12\x14\n\x05state\x18\x01\x20\x01(\x0cR\x05s\ + tate:\x02\x18\x01\"#\n\x1dDeprecated_PassphraseStateAck:\x02\x18\x01\"\ + \xc0\x01\n\nHDNodeType\x12\x14\n\x05depth\x18\x01\x20\x02(\rR\x05depth\ + \x12\x20\n\x0bfingerprint\x18\x02\x20\x02(\rR\x0bfingerprint\x12\x1b\n\t\ + child_num\x18\x03\x20\x02(\rR\x08childNum\x12\x1d\n\nchain_code\x18\x04\ + \x20\x02(\x0cR\tchainCode\x12\x1f\n\x0bprivate_key\x18\x05\x20\x01(\x0cR\ + \nprivateKey\x12\x1d\n\npublic_key\x18\x06\x20\x02(\x0cR\tpublicKeyB>\n#\ + com.satoshilabs.trezor.lib.protobufB\x13TrezorMessageCommon\x80\xa6\x1d\ + \x01\ "; /// `FileDescriptorProto` object which was a source for this generated file