improve error handling and request timing
This commit is contained in:
parent
4a5a7e0f74
commit
0055db7445
|
@ -1,9 +1,11 @@
|
|||
use std::error::Error;
|
||||
|
||||
use b15f::B15F;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>>{
|
||||
let drv = B15F::new()?;
|
||||
|
||||
Ok(())
|
||||
fn main() {
|
||||
let _drv = match B15F::new() {
|
||||
Ok(val) => val,
|
||||
Err(error) => {
|
||||
eprintln!("{error}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
74
src/b15f.rs
74
src/b15f.rs
|
@ -5,6 +5,7 @@
|
|||
use std::{process::Command, time::Duration, fmt::Debug, thread::sleep};
|
||||
use rand::Rng;
|
||||
use serialport::SerialPort;
|
||||
use crate::error::Error;
|
||||
|
||||
use crate::{request::Request, build_request};
|
||||
|
||||
|
@ -44,7 +45,7 @@ impl B15F {
|
|||
///
|
||||
/// let drv = B15F::new().unwrap();
|
||||
/// ```
|
||||
pub fn new() -> Result<B15F, String> {
|
||||
pub fn new() -> Result<B15F, Error> {
|
||||
let port = B15F::init_connection()?;
|
||||
|
||||
let mut drv =B15F {
|
||||
|
@ -54,7 +55,7 @@ impl B15F {
|
|||
log_start!("Testing connection");
|
||||
let mut tries = 3;
|
||||
while tries > 0 {
|
||||
drv.discard();
|
||||
drv.discard()?;
|
||||
|
||||
match drv.test_connection() {
|
||||
Ok(()) => break,
|
||||
|
@ -65,12 +66,12 @@ impl B15F {
|
|||
}
|
||||
|
||||
if tries == 0 {
|
||||
panic!("Testing connection failed!");
|
||||
return Err("Connection test failed. Are you using the newest version?".into());
|
||||
}
|
||||
|
||||
log_end!("Ok!");
|
||||
|
||||
let info = drv.get_board_info();
|
||||
let info = drv.get_board_info()?;
|
||||
log!("AVR firmware version: {} built at {} ({})", info[0], info[1], info[2]);
|
||||
|
||||
// let avr_commit_hash = info[3];
|
||||
|
@ -82,7 +83,7 @@ impl B15F {
|
|||
Ok(drv)
|
||||
}
|
||||
|
||||
fn init_connection() -> Result<Box<dyn SerialPort>, String> {
|
||||
fn init_connection() -> Result<Box<dyn SerialPort>, Error> {
|
||||
let devices = B15F::get_devices();
|
||||
|
||||
let device = match devices.first() {
|
||||
|
@ -96,8 +97,7 @@ impl B15F {
|
|||
|
||||
let port = serialport::new(device, 57_600)
|
||||
.timeout(Duration::from_millis(1000))
|
||||
.open()
|
||||
.map_err(|err| err.to_string())?;
|
||||
.open()?;
|
||||
log_end!("Ok!");
|
||||
|
||||
Ok(port)
|
||||
|
@ -112,27 +112,28 @@ impl B15F {
|
|||
/// ```
|
||||
/// use b15f::B15F;
|
||||
///
|
||||
/// let drv = B15F::new().unwrap();
|
||||
/// let mut drv = B15F::new().unwrap();
|
||||
///
|
||||
/// // Print each bit of information on a new line
|
||||
/// drv.get_board_info()
|
||||
/// .unwrap()
|
||||
/// .iter()
|
||||
/// .for_each(|info| println!("{info}"));
|
||||
/// ```
|
||||
pub fn get_board_info(&mut self) -> Vec<String> {
|
||||
pub fn get_board_info(&mut self) -> Result<Vec<String>, Error> {
|
||||
let mut info: Vec<String> = vec![];
|
||||
|
||||
self.usart.write(build_request!(Request::Info)).unwrap();
|
||||
self.usart.write(build_request!(Request::Info))?;
|
||||
|
||||
let mut data_count: [u8; 1] = [0;1];
|
||||
self.usart.read(&mut data_count).unwrap();
|
||||
self.usart.read(&mut data_count)?;
|
||||
|
||||
while data_count[0] > 0 {
|
||||
let mut len: [u8; 1] = [0;1];
|
||||
self.usart.read(&mut len).unwrap();
|
||||
self.usart.read(&mut len)?;
|
||||
|
||||
let mut data: Vec<u8> = vec![0; len[0] as usize];
|
||||
self.usart.read(data.as_mut_slice()).unwrap();
|
||||
self.usart.read(data.as_mut_slice())?;
|
||||
|
||||
info.push(
|
||||
data.into_iter()
|
||||
|
@ -140,37 +141,62 @@ impl B15F {
|
|||
.collect::<String>()
|
||||
);
|
||||
|
||||
sleep(Duration::from_millis(4)); // Add delay to give the board time to catch up with our requests
|
||||
data_count[0] -= 1;
|
||||
}
|
||||
|
||||
info
|
||||
let mut aw: [u8; 1] = [0; 1];
|
||||
self.usart.read(&mut aw)?;
|
||||
|
||||
if aw[0] != B15F::MSG_OK {
|
||||
return Err(format!("Board info is faulty: code {}", aw[0]).into());
|
||||
}
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
/// Clears data in the USART buffers on this device and on the B15
|
||||
pub fn discard(&mut self) {
|
||||
// TODO: In general, unwrap() will cause panic on failure and crash the application.
|
||||
// It would be better to implement error handling
|
||||
self.usart.clear(serialport::ClearBuffer::Output).unwrap();
|
||||
pub fn discard(&mut self) -> Result<(), Error> {
|
||||
self.usart.clear(serialport::ClearBuffer::Output)?;
|
||||
|
||||
for _ in 0..16 {
|
||||
self.usart.write(build_request![Request::Discard]).unwrap();
|
||||
self.usart.write(build_request![Request::Discard])?;
|
||||
sleep(Duration::from_millis(4));
|
||||
}
|
||||
|
||||
self.usart.clear(serialport::ClearBuffer::Input).unwrap()
|
||||
self.usart.clear(serialport::ClearBuffer::Input)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests the connetion to the B15
|
||||
pub fn test_connection(&mut self) -> Result<(), String> {
|
||||
///
|
||||
/// To test the connection a `Request::Test` request will be sent
|
||||
/// to the board together with a randomly generated value. If the
|
||||
/// board returns that value the connection is working correctly.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// use b15f::B15F;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut drv = B15F::new().unwrap();
|
||||
///
|
||||
/// if let Err(err) = drv.test_connection() {
|
||||
/// panic!("Connection is not working: {err}");
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn test_connection(&mut self) -> Result<(), Error> {
|
||||
let dummy: u8 = rand::thread_rng().gen_range(0x00..=0xFF);
|
||||
|
||||
self.usart.write(build_request![Request::Test, dummy]).unwrap();
|
||||
self.usart.write(build_request![Request::Test, dummy])?;
|
||||
|
||||
let mut buffer: [u8; 2]= [0; 2];
|
||||
self.usart.read(&mut buffer).unwrap();
|
||||
self.usart.read(&mut buffer)?;
|
||||
|
||||
if buffer[0] != B15F::MSG_OK || buffer[1] != dummy {
|
||||
panic!("Test request failed");
|
||||
return Err("Test request failed".into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
42
src/error.rs
Normal file
42
src/error.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
message: String
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(what: &str) -> Error {
|
||||
Error { message: String::from(what) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error { message: err.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serialport::Error> for Error {
|
||||
fn from(err: serialport::Error) -> Self {
|
||||
Error { message: err.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Error {
|
||||
fn from(msg: &str) -> Self {
|
||||
Error::new(msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
fn from(msg: String) -> Self {
|
||||
Error { message: msg }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
|
@ -15,5 +15,6 @@
|
|||
|
||||
pub mod b15f;
|
||||
mod request;
|
||||
mod error;
|
||||
|
||||
pub use crate::b15f::B15F;
|
Loading…
Reference in a new issue