diff --git a/src/bin/lpc55/main.rs b/src/bin/lpc55/main.rs index dc0fde1b..774a9052 100644 --- a/src/bin/lpc55/main.rs +++ b/src/bin/lpc55/main.rs @@ -4,7 +4,7 @@ use core::convert::TryFrom; use std::io::{self, Write as _}; use std::fs; -use anyhow::{anyhow}; +use anyhow::{Context as _, anyhow}; use delog::hex_str; use log::{info, warn, trace}; use uuid::Uuid; @@ -54,7 +54,7 @@ fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> { let uuid = args.value_of("UUID").map(Uuid::parse_str).transpose()?; - let bootloader = || Bootloader::try_find(vid, pid, uuid).ok_or(anyhow!("Could not attach to a bootloader")); + let bootloader = || Bootloader::try_find(vid, pid, uuid).context("Could not attach to a bootloader"); if let Some(command) = args.subcommand_matches("http") { let bootloader = bootloader()?; diff --git a/src/bootloader.rs b/src/bootloader.rs index ac2a47d2..26c945f1 100644 --- a/src/bootloader.rs +++ b/src/bootloader.rs @@ -3,6 +3,7 @@ //! Construct a `Bootloader` from a VID/PID pair (optionally a UUID to disambiguate), //! then call its methods. +use anyhow::anyhow; use enum_iterator::IntoEnumIterator; use hidapi::HidApi; use serde::{Deserialize, Serialize}; @@ -59,22 +60,29 @@ pub type Result = std::result::Result; impl Bootloader { - /// Select first available ROM bootloader with the given VID and PID. - /// - /// TODO: Open question is whether this is a good idea. - /// For instance, `write-flash` on the wrong device could wreak havoc. - pub fn try_new(vid: Option, pid: Option) -> Option { + /// Select a unique ROM bootloader with the given VID and PID. + pub fn try_new(vid: Option, pid: Option) -> anyhow::Result { Self::try_find(vid, pid, None) } - /// Attempt to find a ROM bootloader with the given VID, PID and UUID. - pub fn try_find(vid: Option, pid: Option, uuid: Option) -> Option { + /// Attempt to find a unique ROM bootloader with the given VID, PID and UUID. + pub fn try_find(vid: Option, pid: Option, uuid: Option) -> anyhow::Result { + let mut bootloaders = Self::find(vid, pid, uuid); + if bootloaders.len() > 1 { + Err(anyhow!("Muliple matching bootloaders found")) + } else { + bootloaders.pop().ok_or_else(|| anyhow!("No matching bootloader found")) + } + } + + /// Finds all ROM bootloader with the given VID, PID and UUID. + pub fn find(vid: Option, pid: Option, uuid: Option) -> Vec { Self::list() .into_iter() .filter(|bootloader| vid.map_or(true, |vid| vid == bootloader.vid)) .filter(|bootloader| pid.map_or(true, |pid| pid == bootloader.pid)) .filter(|bootloader| uuid.map_or(true, |uuid| uuid.as_u128() == bootloader.uuid)) - .next() + .collect() } /// Returns a vector of all HID devices that appear to be ROM bootloaders