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(())
}