diff --git a/red/src/main.rs b/red/src/main.rs index 0ea495d..39e799a 100644 --- a/red/src/main.rs +++ b/red/src/main.rs @@ -7,7 +7,10 @@ const DEFAULT_TTY: &str = "/dev/ttyUSB0"; #[tokio::main] async fn main() -> tokio_serial::Result<()> { 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; Ok(()) } diff --git a/red/src/printer/gcode.rs b/red/src/printer/gcode.rs index d529f9f..5e808b4 100644 --- a/red/src/printer/gcode.rs +++ b/red/src/printer/gcode.rs @@ -3,9 +3,28 @@ use std::fmt::Debug; use lazy_static::lazy_static; use regex::Regex; +type Result = std::result::Result; + +#[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 { fn command(&self) -> &str; - fn parse_reply(&self, reply: &str) -> GcodeReply; + fn parse_reply(&self, reply: &str) -> Result; } #[derive(Debug)] @@ -13,12 +32,7 @@ pub struct M114Command; #[derive(Debug)] pub enum GcodeReply { - M114Reply { - x: Option, - y: Option, - z: Option, - e: Option, - }, + M114Reply { x: f64, y: f64, z: f64, e: f64 }, } impl M114Command { @@ -31,7 +45,7 @@ impl GcodeCommand for M114Command { fn command(&self) -> &'static str { "M114" } - fn parse_reply(&self, reply: &str) -> GcodeReply { + fn parse_reply(&self, reply: &str) -> Result { lazy_static! { static ref RE_SET: Vec = vec![ Regex::new(r"X:(\d+(?:\.\d+))").unwrap(), @@ -41,20 +55,25 @@ impl GcodeCommand for M114Command { ]; } - let fields: Vec> = RE_SET + let fields: Vec> = RE_SET .iter() .map(|re| { re.captures(reply) .and_then(|cpt| cpt.get(1).map(|mtch| mtch.as_str().to_string())) .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(); - GcodeReply::M114Reply { - x: fields[0], - y: fields[1], - z: fields[2], - e: fields[3], - } + Ok(GcodeReply::M114Reply { + x: fields[0].clone()?, + y: fields[1].clone()?, + z: fields[2].clone()?, + e: fields[3].clone()?, + }) } } diff --git a/red/src/printer/mod.rs b/red/src/printer/mod.rs index 83676cd..3685550 100644 --- a/red/src/printer/mod.rs +++ b/red/src/printer/mod.rs @@ -5,8 +5,8 @@ use futures::sink::SinkExt; use futures::stream::StreamExt; use std::{fmt::Write, io, rc::Rc, str}; use tokio; +use tokio::sync::mpsc::{channel, Sender}; use tokio_serial::SerialPortBuilderExt; -use tokio::sync::mpsc::{Sender, channel}; use tokio_util::codec::{Decoder, Encoder}; pub use gcode::{GcodeCommand, GcodeReply, M114Command};