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;
|
use b15f::B15F;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>>{
|
fn main() {
|
||||||
let drv = B15F::new()?;
|
let _drv = match B15F::new() {
|
||||||
|
Ok(val) => val,
|
||||||
Ok(())
|
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 std::{process::Command, time::Duration, fmt::Debug, thread::sleep};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serialport::SerialPort;
|
use serialport::SerialPort;
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
use crate::{request::Request, build_request};
|
use crate::{request::Request, build_request};
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ impl B15F {
|
||||||
///
|
///
|
||||||
/// let drv = B15F::new().unwrap();
|
/// let drv = B15F::new().unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new() -> Result<B15F, String> {
|
pub fn new() -> Result<B15F, Error> {
|
||||||
let port = B15F::init_connection()?;
|
let port = B15F::init_connection()?;
|
||||||
|
|
||||||
let mut drv =B15F {
|
let mut drv =B15F {
|
||||||
|
@ -54,7 +55,7 @@ impl B15F {
|
||||||
log_start!("Testing connection");
|
log_start!("Testing connection");
|
||||||
let mut tries = 3;
|
let mut tries = 3;
|
||||||
while tries > 0 {
|
while tries > 0 {
|
||||||
drv.discard();
|
drv.discard()?;
|
||||||
|
|
||||||
match drv.test_connection() {
|
match drv.test_connection() {
|
||||||
Ok(()) => break,
|
Ok(()) => break,
|
||||||
|
@ -65,12 +66,12 @@ impl B15F {
|
||||||
}
|
}
|
||||||
|
|
||||||
if tries == 0 {
|
if tries == 0 {
|
||||||
panic!("Testing connection failed!");
|
return Err("Connection test failed. Are you using the newest version?".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
log_end!("Ok!");
|
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]);
|
log!("AVR firmware version: {} built at {} ({})", info[0], info[1], info[2]);
|
||||||
|
|
||||||
// let avr_commit_hash = info[3];
|
// let avr_commit_hash = info[3];
|
||||||
|
@ -82,7 +83,7 @@ impl B15F {
|
||||||
Ok(drv)
|
Ok(drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_connection() -> Result<Box<dyn SerialPort>, String> {
|
fn init_connection() -> Result<Box<dyn SerialPort>, Error> {
|
||||||
let devices = B15F::get_devices();
|
let devices = B15F::get_devices();
|
||||||
|
|
||||||
let device = match devices.first() {
|
let device = match devices.first() {
|
||||||
|
@ -96,8 +97,7 @@ impl B15F {
|
||||||
|
|
||||||
let port = serialport::new(device, 57_600)
|
let port = serialport::new(device, 57_600)
|
||||||
.timeout(Duration::from_millis(1000))
|
.timeout(Duration::from_millis(1000))
|
||||||
.open()
|
.open()?;
|
||||||
.map_err(|err| err.to_string())?;
|
|
||||||
log_end!("Ok!");
|
log_end!("Ok!");
|
||||||
|
|
||||||
Ok(port)
|
Ok(port)
|
||||||
|
@ -112,27 +112,28 @@ impl B15F {
|
||||||
/// ```
|
/// ```
|
||||||
/// use b15f::B15F;
|
/// use b15f::B15F;
|
||||||
///
|
///
|
||||||
/// let drv = B15F::new().unwrap();
|
/// let mut drv = B15F::new().unwrap();
|
||||||
///
|
///
|
||||||
/// // Print each bit of information on a new line
|
/// // Print each bit of information on a new line
|
||||||
/// drv.get_board_info()
|
/// drv.get_board_info()
|
||||||
|
/// .unwrap()
|
||||||
/// .iter()
|
/// .iter()
|
||||||
/// .for_each(|info| println!("{info}"));
|
/// .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![];
|
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];
|
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 {
|
while data_count[0] > 0 {
|
||||||
let mut len: [u8; 1] = [0;1];
|
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];
|
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(
|
info.push(
|
||||||
data.into_iter()
|
data.into_iter()
|
||||||
|
@ -140,37 +141,62 @@ impl B15F {
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(4)); // Add delay to give the board time to catch up with our requests
|
||||||
data_count[0] -= 1;
|
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
|
/// Clears data in the USART buffers on this device and on the B15
|
||||||
pub fn discard(&mut self) {
|
pub fn discard(&mut self) -> Result<(), Error> {
|
||||||
// TODO: In general, unwrap() will cause panic on failure and crash the application.
|
self.usart.clear(serialport::ClearBuffer::Output)?;
|
||||||
// It would be better to implement error handling
|
|
||||||
self.usart.clear(serialport::ClearBuffer::Output).unwrap();
|
|
||||||
|
|
||||||
for _ in 0..16 {
|
for _ in 0..16 {
|
||||||
self.usart.write(build_request![Request::Discard]).unwrap();
|
self.usart.write(build_request![Request::Discard])?;
|
||||||
sleep(Duration::from_millis(4));
|
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
|
/// 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);
|
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];
|
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 {
|
if buffer[0] != B15F::MSG_OK || buffer[1] != dummy {
|
||||||
panic!("Test request failed");
|
return Err("Test request failed".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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;
|
pub mod b15f;
|
||||||
mod request;
|
mod request;
|
||||||
|
mod error;
|
||||||
|
|
||||||
pub use crate::b15f::B15F;
|
pub use crate::b15f::B15F;
|
Loading…
Reference in a new issue