Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions hil/src/boot.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::time::Duration;

use crate::ftdi::{FtdiGpio, OutputState};
use crate::ftdi::{FtdiGpio, FtdiId, OutputState};
use color_eyre::{eyre::WrapErr as _, Result};
use tracing::info;
use tracing::{debug, info};

pub const BUTTON_PIN: crate::ftdi::Pin = FtdiGpio::CTS_PIN;
pub const RECOVERY_PIN: crate::ftdi::Pin = FtdiGpio::RTS_PIN;
Expand All @@ -17,17 +17,34 @@ pub fn is_recovery_mode_detected() -> Result<bool> {
}

// Note: we are calling some blocking code from async here, but its probably fine.
/// If `device` is `None`, will get the first available device.
#[tracing::instrument]
pub async fn reboot(recovery: bool) -> Result<()> {
fn make_ftdi() -> Result<FtdiGpio> {
FtdiGpio::builder()
.with_default_device()
pub async fn reboot(recovery: bool, device: Option<&FtdiId>) -> Result<()> {
fn make_ftdi(device: Option<FtdiId>) -> Result<FtdiGpio> {
let builder = FtdiGpio::builder();
let builder = match &device {
Some(FtdiId::Description(desc)) => builder.with_description(desc),
Some(FtdiId::SerialNumber(serial)) => builder.with_serial_number(serial),
Some(FtdiId::Index(idx)) => builder.with_index(*idx),
None => builder.with_default_device(),
};
builder
.and_then(|b| b.configure())
.wrap_err("failed to create ftdi device")
}

info!("Turning off");
let device_clone = device.cloned();
let ftdi = tokio::task::spawn_blocking(|| -> Result<_, color_eyre::Report> {
let mut ftdi = make_ftdi()?;
FtdiGpio::detach_all(None, None)
.wrap_err("failed to detach all ftdi devices")?;
for d in FtdiGpio::list_devices().wrap_err("failed to list ftdi devices")? {
debug!(
"ftdi device - desc:{}, serial:{}, vid:{}, pid:{}",
d.description, d.serial_number, d.vendor_id, d.product_id,
);
}
let mut ftdi = make_ftdi(device_clone)?;
ftdi.set_pin(BUTTON_PIN, OutputState::Low)?;
ftdi.set_pin(RECOVERY_PIN, OutputState::High)?;
Ok(ftdi)
Expand All @@ -41,8 +58,9 @@ pub async fn reboot(recovery: bool) -> Result<()> {
tokio::time::sleep(Duration::from_secs(4)).await;

info!("Turning on");
let device_clone = device.cloned();
let ftdi = tokio::task::spawn_blocking(move || -> Result<_, color_eyre::Report> {
let mut ftdi = make_ftdi()?;
let mut ftdi = make_ftdi(device_clone)?;
let recovery_state = if recovery {
OutputState::Low
} else {
Expand Down
33 changes: 27 additions & 6 deletions hil/src/commands/reboot.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
use clap::Parser;
use color_eyre::{eyre::WrapErr as _, Result};

use crate::ftdi::FtdiId;

#[derive(Debug, Parser)]
pub struct Reboot {
#[arg(short)]
recovery: bool,
/// The serial number of the FTDI device to use
#[arg(long, group = "id")]
serial_num: Option<String>,
/// The description of the FTDI device to use
#[arg(long, group = "id")]
desc: Option<String>,
/// The index of the FTDI device to use
#[arg(long, group = "id")]
index: Option<u8>,
}

impl Reboot {
pub async fn run(self) -> Result<()> {
crate::boot::reboot(self.recovery).await.wrap_err_with(|| {
format!(
"failed to reboot into {} mode",
if self.recovery { "recovery" } else { "normal" }
)
})
let device = match (self.serial_num, self.desc, self.index) {
(Some(serial), None, None) => Some(FtdiId::SerialNumber(serial)),
(None, Some(desc), None) => Some(FtdiId::Description(desc)),
(None, None, Some(index)) => Some(FtdiId::Index(index)),
(None, None, None) => None,
_ => unreachable!(),
};

crate::boot::reboot(self.recovery, device.as_ref())
.await
.wrap_err_with(|| {
format!(
"failed to reboot into {} mode",
if self.recovery { "recovery" } else { "normal" }
)
})
}
}
Loading