Move printer communication to separate function

This commit is contained in:
Frederik Menke 2023-11-26 18:00:12 +01:00
parent d676be5d73
commit 4d30463a87
3 changed files with 80 additions and 59 deletions

View file

@ -1,3 +1,4 @@
#![warn(missing_docs)]
pub mod gamepad; pub mod gamepad;
pub mod jogger; pub mod jogger;
pub mod printer; pub mod printer;

View file

@ -1,4 +1,5 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![warn(missing_docs)]
use futures::never::Never; use futures::never::Never;
use i2c_linux::I2c; use i2c_linux::I2c;
use red::gamepad; use red::gamepad;
@ -33,7 +34,6 @@ const I2C_REGISTER_SPINDLE_SPEED: u8 = 0;
// SMBUS_WORD_DATA // SMBUS_WORD_DATA
// SMBUS_I2C_BLOCK // SMBUS_I2C_BLOCK
// SMBUS_EMUL // SMBUS_EMUL
#[tokio::main] #[tokio::main]
async fn main() -> Never { async fn main() -> Never {
println!("Entering App"); println!("Entering App");

View file

@ -8,7 +8,7 @@ use std::{fmt::Write, io, rc::Rc, str};
use tokio; use tokio;
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::time::timeout; use tokio::time::timeout;
use tokio_serial::SerialPortBuilderExt; use tokio_serial::{SerialPortBuilderExt, SerialStream};
use tokio_util::codec::{Decoder, Encoder}; use tokio_util::codec::{Decoder, Encoder};
pub use gcode::{GcodeCommand, GcodeReply}; pub use gcode::{GcodeCommand, GcodeReply};
@ -58,66 +58,16 @@ impl Printer {
port.set_exclusive(false) port.set_exclusive(false)
.expect("Unable to set serial port exclusive to 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::<Box<dyn GcodeCommand>>(32); let (printer_in_tx, mut printer_in_rx) = channel::<Box<dyn GcodeCommand>>(32);
// replies that come from the printer
let (printer_out_tx, printer_out_rx) = channel::<Result<GcodeReply, PrinterError>>(32); let (printer_out_tx, printer_out_rx) = channel::<Result<GcodeReply, PrinterError>>(32);
tokio::spawn(async move { tokio::spawn(printer_communication_task(
let (mut serial_tx, mut serial_rx) = connection.split(); port,
printer_in_rx,
// The printer will send some info after connecting. We need to wait for this printer_out_tx,
// 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);
}
}
}
});
Ok(Printer { Ok(Printer {
printer_in: printer_in_tx, 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<Box<dyn GcodeCommand>>,
printer_replies: Sender<Result<GcodeReply, PrinterError>>,
) {
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; struct LineCodec;
impl Decoder for LineCodec { impl Decoder for LineCodec {