From 4d30463a87181a4bce0d852a30b769e571a1b2cf Mon Sep 17 00:00:00 2001 From: Frederik Menke Date: Sun, 26 Nov 2023 18:00:12 +0100 Subject: [PATCH] Move printer communication to separate function --- red/src/lib.rs | 1 + red/src/main.rs | 2 +- red/src/printer/mod.rs | 136 +++++++++++++++++++++++------------------ 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/red/src/lib.rs b/red/src/lib.rs index b3df052..cf3d96f 100644 --- a/red/src/lib.rs +++ b/red/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(missing_docs)] pub mod gamepad; pub mod jogger; pub mod printer; diff --git a/red/src/main.rs b/red/src/main.rs index c82dadb..4b8b757 100644 --- a/red/src/main.rs +++ b/red/src/main.rs @@ -1,4 +1,5 @@ #![warn(rust_2018_idioms)] +#![warn(missing_docs)] use futures::never::Never; use i2c_linux::I2c; use red::gamepad; @@ -33,7 +34,6 @@ const I2C_REGISTER_SPINDLE_SPEED: u8 = 0; // SMBUS_WORD_DATA // SMBUS_I2C_BLOCK // SMBUS_EMUL - #[tokio::main] async fn main() -> Never { println!("Entering App"); diff --git a/red/src/printer/mod.rs b/red/src/printer/mod.rs index bbc83fb..f56315a 100644 --- a/red/src/printer/mod.rs +++ b/red/src/printer/mod.rs @@ -8,7 +8,7 @@ use std::{fmt::Write, io, rc::Rc, str}; use tokio; use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::time::timeout; -use tokio_serial::SerialPortBuilderExt; +use tokio_serial::{SerialPortBuilderExt, SerialStream}; use tokio_util::codec::{Decoder, Encoder}; pub use gcode::{GcodeCommand, GcodeReply}; @@ -58,66 +58,16 @@ impl Printer { port.set_exclusive(false) .expect("Unable to set serial port exclusive to false"); - let connection = LineCodec.framed(port); + // commands that go to the printer let (printer_in_tx, mut printer_in_rx) = channel::>(32); + // replies that come from the printer let (printer_out_tx, printer_out_rx) = channel::>(32); - tokio::spawn(async move { - let (mut serial_tx, mut serial_rx) = connection.split(); - - // The printer will send some info after connecting. We need to wait for this - // to be received as it will otherwise stop responding for some reason: - loop { - if let Ok(message) = timeout(Duration::from_secs(10), serial_rx.next()).await { - match message { - Some(Ok(reply)) => { - println!("got stuff: {:?}", reply); - if reply.contains("Loaded") { - break; - } - if reply.contains("ok") { - break; - } - } - Some(Err(e)) => { - println!("Error reading from serial port: {:?}", e); - } - None => (), - } - } else { - // TODO: Check if port is good by sending some harmless gcode - println!( - "Reading from serial port timed out. Printer might already be initialized." - ); - println!("Sending G91 command"); - serial_tx - .send(G91Command.command() + "\n") - .await - .expect("Could not write to serial port!"); - } - } - - while let Some(command) = printer_in_rx.recv().await { - let command_text = format!("{}\n", command.command()); - println!("sending in: {:?}", command_text); - serial_tx.send(command_text).await.unwrap(); - let mut reply = "".to_string(); - while let Some(line) = serial_rx.next().await { - let line = line.unwrap(); - if line.contains("ok") { - let reply = command.parse_reply(&reply); - println!("got reply: {:?}", reply); - printer_out_tx - .send(reply.map_err(PrinterError::GcodeReply)) - .await - .unwrap(); - break; - } else { - reply.push_str(&line); - } - } - } - }); + tokio::spawn(printer_communication_task( + port, + printer_in_rx, + printer_out_tx, + )); Ok(Printer { printer_in: printer_in_tx, @@ -129,6 +79,76 @@ impl Printer { } } +/// Pull commands from `user_commands`, write them to the printer and send the reply back through +/// `printer_replies`. +/// +/// +/// Arguments: +/// +/// * `port`: Serial port that is connected to a printer running Marlin +/// * `user_commands`: Channel for the user to submit their GCODE +/// * `printer_replies`: Replies from the printer the the submitted GCODE. These always correspond +/// to the incoming commands in order that they were received. +async fn printer_communication_task( + port: SerialStream, + mut user_commands: Receiver>, + printer_replies: Sender>, +) { + let connection = LineCodec.framed(port); + let (mut serial_tx, mut serial_rx) = connection.split(); + + // The printer will send some info after connecting. We need to wait for this + // to be received as it will otherwise stop responding for some reason: + loop { + if let Ok(message) = timeout(Duration::from_secs(10), serial_rx.next()).await { + match message { + Some(Ok(reply)) => { + println!("got stuff: {:?}", reply); + if reply.contains("Loaded") { + break; + } + if reply.contains("ok") { + break; + } + } + Some(Err(e)) => { + println!("Error reading from serial port: {:?}", e); + } + None => (), + } + } else { + // TODO: Check if port is good by sending some harmless gcode + println!("Reading from serial port timed out. Printer might already be initialized."); + println!("Sending G91 command"); + serial_tx + .send(G91Command.command() + "\n") + .await + .expect("Could not write to serial port!"); + } + } + + while let Some(command) = user_commands.recv().await { + let command_text = format!("{}\n", command.command()); + println!("sending in: {:?}", command_text); + serial_tx.send(command_text).await.unwrap(); + let mut reply = "".to_string(); + while let Some(line) = serial_rx.next().await { + let line = line.unwrap(); + if line.contains("ok") { + let reply = command.parse_reply(&reply); + println!("got reply: {:?}", reply); + printer_replies + .send(reply.map_err(PrinterError::GcodeReply)) + .await + .unwrap(); + break; + } else { + reply.push_str(&line); + } + } + } +} + struct LineCodec; impl Decoder for LineCodec {