Fix UART timeout issues 1. Fix timeout detection for the verilator UART. 2. Add timeout detection for the common-case UART. 3. Print backtraces if available. Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/host/opentitanlib/Cargo.toml b/sw/host/opentitanlib/Cargo.toml index b547ab2..ee522f2 100644 --- a/sw/host/opentitanlib/Cargo.toml +++ b/sw/host/opentitanlib/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2018" [dependencies] -anyhow = "1.0" +anyhow = {version="1.0", features=["backtrace"]} thiserror = "1.0" lazy_static = "1.4.0" regex = "1"
diff --git a/sw/host/opentitanlib/src/transport/common/uart.rs b/sw/host/opentitanlib/src/transport/common/uart.rs index 9bb2c51..a562e2b 100644 --- a/sw/host/opentitanlib/src/transport/common/uart.rs +++ b/sw/host/opentitanlib/src/transport/common/uart.rs
@@ -4,6 +4,7 @@ use serialport::SerialPort; use std::cell::RefCell; +use std::io::ErrorKind; use std::time::Duration; use crate::io::uart::{Uart, UartError}; @@ -64,7 +65,11 @@ fn read_timeout(&self, buf: &mut [u8], timeout: Duration) -> Result<usize> { let mut port = self.port.borrow_mut(); port.set_timeout(timeout).wrap(UartError::ReadError)?; - let len = port.read(buf); + let result = port.read(buf); + let len = match result { + Err(ioerr) if ioerr.kind() == ErrorKind::TimedOut => Ok(0), + _ => result, + }; port.set_timeout(Self::FOREVER).wrap(UartError::ReadError)?; Ok(len.wrap(UartError::ReadError)?) }
diff --git a/sw/host/opentitanlib/src/transport/verilator/uart.rs b/sw/host/opentitanlib/src/transport/verilator/uart.rs index a85923a..1319435 100644 --- a/sw/host/opentitanlib/src/transport/verilator/uart.rs +++ b/sw/host/opentitanlib/src/transport/verilator/uart.rs
@@ -52,7 +52,7 @@ // If we got a timeout from the uart, return 0 as per convention. // Let all other errors propagate (wrapped in TransportError). if let Some(ioerr) = e.downcast_ref::<io::Error>() { - if ioerr.kind() != ErrorKind::TimedOut { + if ioerr.kind() == ErrorKind::TimedOut { return Ok(0); } }
diff --git a/sw/host/opentitantool/Cargo.toml b/sw/host/opentitantool/Cargo.toml index 44f0b80..eafa9b9 100644 --- a/sw/host/opentitantool/Cargo.toml +++ b/sw/host/opentitantool/Cargo.toml
@@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] -anyhow = "1.0" +anyhow = {version="1.0", features=["backtrace"]} hex = "0.4" thiserror = "1.0" opentitanlib = {path="../opentitanlib"}
diff --git a/sw/host/opentitantool/src/main.rs b/sw/host/opentitantool/src/main.rs index a72ca67..d19c6d7 100644 --- a/sw/host/opentitantool/src/main.rs +++ b/sw/host/opentitantool/src/main.rs
@@ -4,6 +4,7 @@ use anyhow::Result; use directories::ProjectDirs; +use erased_serde::Serialize; use log::LevelFilter; use std::env::{args_os, ArgsOs}; use std::ffi::OsString; @@ -123,6 +124,22 @@ Ok(opts) } +// Print the result of a command. +// If there is an error and `RUST_BACKTRACE=1` _and_ `--logging=debug`, print a backtrace. +fn print_command_result(result: Result<Option<Box<dyn Serialize>>>) -> Result<()> { + match result { + Ok(Some(value)) => { + println!("{}", serde_json::to_string_pretty(&value)?); + Ok(()) + } + Ok(None) => Ok(()), + Err(e) => { + log::debug!("{:?}", e); + Err(e) + } + } +} + // Execute is a convenience function for taking a list of strings, // parsing them into a command, executing the command and printing the result. fn execute<I>(args: I, opts: &Opts, transport: &TransportWrapper) -> Result<()> @@ -132,9 +149,7 @@ let command = RootCommandHierarchy::from_iter( std::iter::once(OsString::from("opentitantool")).chain(args), ); - if let Some(value) = command.run(opts, transport)? { - println!("{}", serde_json::to_string_pretty(&value)?); - } + print_command_result(command.run(opts, &transport))?; Ok(()) } @@ -150,9 +165,6 @@ &transport, )?; } - - if let Some(value) = opts.command.run(&opts, &transport)? { - println!("{}", serde_json::to_string_pretty(&value)?); - } + print_command_result(opts.command.run(&opts, &transport))?; Ok(()) }