Use Error type for reply parsing

This commit is contained in:
Frederik Menke 2022-10-22 20:57:57 +02:00
parent c6c0f65f7a
commit 65bab91e8b
3 changed files with 39 additions and 17 deletions

View file

@ -7,7 +7,10 @@ const DEFAULT_TTY: &str = "/dev/ttyUSB0";
#[tokio::main] #[tokio::main]
async fn main() -> tokio_serial::Result<()> { async fn main() -> tokio_serial::Result<()> {
let printer = Printer::connect(DEFAULT_TTY).await.unwrap(); let printer = Printer::connect(DEFAULT_TTY).await.unwrap();
printer.printer_in.send(Box::new(red::printer::M114Command::new())).await; printer
.printer_in
.send(Box::new(red::printer::M114Command::new()))
.await;
tokio::time::sleep(std::time::Duration::from_secs(15)).await; tokio::time::sleep(std::time::Duration::from_secs(15)).await;
Ok(()) Ok(())
} }

View file

@ -3,9 +3,28 @@ use std::fmt::Debug;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
type Result<T> = std::result::Result<T, GcodeReplyError>;
#[derive(Debug, Clone)]
pub struct GcodeReplyError {
sent_command: String,
parsed_input: String,
problem: String,
}
impl std::fmt::Display for GcodeReplyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Failed to parse response `{}` to command {}: {}",
self.parsed_input, self.sent_command, self.problem
)
}
}
pub trait GcodeCommand: Debug + Send { pub trait GcodeCommand: Debug + Send {
fn command(&self) -> &str; fn command(&self) -> &str;
fn parse_reply(&self, reply: &str) -> GcodeReply; fn parse_reply(&self, reply: &str) -> Result<GcodeReply>;
} }
#[derive(Debug)] #[derive(Debug)]
@ -13,12 +32,7 @@ pub struct M114Command;
#[derive(Debug)] #[derive(Debug)]
pub enum GcodeReply { pub enum GcodeReply {
M114Reply { M114Reply { x: f64, y: f64, z: f64, e: f64 },
x: Option<f64>,
y: Option<f64>,
z: Option<f64>,
e: Option<f64>,
},
} }
impl M114Command { impl M114Command {
@ -31,7 +45,7 @@ impl GcodeCommand for M114Command {
fn command(&self) -> &'static str { fn command(&self) -> &'static str {
"M114" "M114"
} }
fn parse_reply(&self, reply: &str) -> GcodeReply { fn parse_reply(&self, reply: &str) -> Result<GcodeReply> {
lazy_static! { lazy_static! {
static ref RE_SET: Vec<Regex> = vec![ static ref RE_SET: Vec<Regex> = vec![
Regex::new(r"X:(\d+(?:\.\d+))").unwrap(), Regex::new(r"X:(\d+(?:\.\d+))").unwrap(),
@ -41,20 +55,25 @@ impl GcodeCommand for M114Command {
]; ];
} }
let fields: Vec<Option<f64>> = RE_SET let fields: Vec<Result<f64>> = RE_SET
.iter() .iter()
.map(|re| { .map(|re| {
re.captures(reply) re.captures(reply)
.and_then(|cpt| cpt.get(1).map(|mtch| mtch.as_str().to_string())) .and_then(|cpt| cpt.get(1).map(|mtch| mtch.as_str().to_string()))
.and_then(|s| s.parse().ok()) .and_then(|s| s.parse().ok())
.ok_or(GcodeReplyError {
parsed_input: reply.to_string(),
problem: format!("Failed to match to regex {}", re.as_str()),
sent_command: self.command().to_string(),
})
}) })
.collect(); .collect();
GcodeReply::M114Reply { Ok(GcodeReply::M114Reply {
x: fields[0], x: fields[0].clone()?,
y: fields[1], y: fields[1].clone()?,
z: fields[2], z: fields[2].clone()?,
e: fields[3], e: fields[3].clone()?,
} })
} }
} }

View file

@ -5,8 +5,8 @@ use futures::sink::SinkExt;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use std::{fmt::Write, io, rc::Rc, str}; use std::{fmt::Write, io, rc::Rc, str};
use tokio; use tokio;
use tokio::sync::mpsc::{channel, Sender};
use tokio_serial::SerialPortBuilderExt; use tokio_serial::SerialPortBuilderExt;
use tokio::sync::mpsc::{Sender, channel};
use tokio_util::codec::{Decoder, Encoder}; use tokio_util::codec::{Decoder, Encoder};
pub use gcode::{GcodeCommand, GcodeReply, M114Command}; pub use gcode::{GcodeCommand, GcodeReply, M114Command};