wasefire_cli_tools/action/
usb_serial.rs

1// Copyright 2025 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//     http://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
15use anyhow::{Result, bail};
16pub use serialport;
17use serialport::{SerialPort, SerialPortType};
18
19/// Options to connect to a USB serial.
20#[derive(Clone, clap::Args)]
21pub struct ConnectionOptions {
22    /// Filter the USB serial to connect using the platform serial number.
23    #[arg(long)]
24    serial: Option<String>,
25
26    /// Timeout to send or receive with the USB serial.
27    #[arg(long, default_value = "1s")]
28    timeout: humantime::Duration,
29}
30
31impl ConnectionOptions {
32    /// Establishes a connection.
33    pub fn connect(&self) -> Result<Box<dyn SerialPort>> {
34        let ConnectionOptions { serial, timeout } = self;
35        for info in serialport::available_ports()? {
36            let path = info.port_name;
37            let SerialPortType::UsbPort(info) = info.port_type else { continue };
38            if info.vid != 0x18d1 || info.pid != 0x0239 {
39                continue;
40            }
41            match (serial, &info.serial_number) {
42                (None, _) => (),
43                (Some(expected), Some(actual)) if actual == expected => (),
44                _ => continue,
45            }
46            return Ok(serialport::new(path, 19200).timeout(**timeout).open()?);
47        }
48        bail!("no available port");
49    }
50}