Add gcode reply channel

This commit is contained in:
Frederik Menke 2022-10-27 21:54:01 +02:00
parent 6f92fae6c2
commit a9dcb7e517
2 changed files with 41 additions and 18 deletions

View file

@ -7,22 +7,19 @@ 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 mut printer = Printer::connect(DEFAULT_TTY).await.unwrap();
printer printer
.printer_in .send_gcode(Box::new(M114Command::new()))
.send(Box::new(M114Command::new()))
.await .await
.unwrap(); .unwrap();
printer printer
.printer_in .send_gcode(Box::new(G28Command::new(true, true, true)))
.send(Box::new(G28Command::new(true, true, true)))
.await .await
.unwrap(); .unwrap();
loop { loop {
tokio::time::sleep(std::time::Duration::from_secs(5)).await; tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer printer
.printer_in .send_gcode(Box::new(G0Command {
.send(Box::new(G0Command {
x: Some(50.0), x: Some(50.0),
y: Some(50.0), y: Some(50.0),
z: Some(5.0), z: Some(5.0),
@ -33,8 +30,7 @@ async fn main() -> tokio_serial::Result<()> {
.unwrap(); .unwrap();
tokio::time::sleep(std::time::Duration::from_secs(5)).await; tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer printer
.printer_in .send_gcode(Box::new(G0Command {
.send(Box::new(G0Command {
x: Some(25.0), x: Some(25.0),
y: Some(25.0), y: Some(25.0),
z: Some(5.0), z: Some(5.0),

View file

@ -5,15 +5,20 @@ 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::sync::mpsc::{channel, Receiver, Sender};
use tokio_serial::SerialPortBuilderExt; use tokio_serial::SerialPortBuilderExt;
use tokio_util::codec::{Decoder, Encoder}; use tokio_util::codec::{Decoder, Encoder};
pub use gcode::{GcodeCommand, GcodeReply}; pub use gcode::{GcodeCommand, GcodeReply};
use self::gcode::GcodeReplyError;
#[derive(Debug)] #[derive(Debug)]
pub enum PrinterError { pub enum PrinterError {
IO(std::io::Error), IO(std::io::Error),
PrinterTaskDown,
OutputChannelDropped,
GcodeReply(GcodeReplyError),
} }
pub struct State { pub struct State {
@ -21,11 +26,26 @@ pub struct State {
} }
pub struct Printer { pub struct Printer {
pub printer_in: Sender<Box<dyn GcodeCommand>>, printer_in: Sender<Box<dyn GcodeCommand>>,
printer_out: Receiver<Result<GcodeReply, PrinterError>>,
pub state: Rc<State>, pub state: Rc<State>,
} }
impl Printer { impl Printer {
pub async fn send_gcode(
&mut self,
gcode: Box<dyn GcodeCommand>,
) -> Result<GcodeReply, PrinterError> {
self.printer_in
.send(gcode)
.await
.map_err(|_| PrinterError::PrinterTaskDown)?;
self.printer_out
.recv()
.await
.unwrap_or(Err(PrinterError::PrinterTaskDown))
}
pub async fn connect(port_path: &str) -> Result<Self, PrinterError> { pub async fn connect(port_path: &str) -> Result<Self, PrinterError> {
let mut port = tokio_serial::new(port_path, 115200) let mut port = tokio_serial::new(port_path, 115200)
.open_native_async() .open_native_async()
@ -35,35 +55,42 @@ impl Printer {
.expect("Unable to set serial port exclusive to false"); .expect("Unable to set serial port exclusive to false");
let connection = LineCodec.framed(port); let connection = LineCodec.framed(port);
let (tx, mut rx) = channel::<Box<dyn GcodeCommand>>(32); let (printer_in_tx, mut printer_in_rx) = channel::<Box<dyn GcodeCommand>>(32);
let (printer_out_tx, printer_out_rx) = channel::<Result<GcodeReply, PrinterError>>(32);
tokio::spawn(async move { tokio::spawn(async move {
let (mut printer_tx, mut printer_rx) = connection.split(); let (mut serial_tx, mut serial_rx) = connection.split();
// The printer will send some info after connecting. We need to wait for this // 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: // to be received as it will otherwise stop responding for some reason:
while let Some(stuff) = printer_rx.next().await { while let Some(stuff) = serial_rx.next().await {
if stuff.map(|s| s.contains("Loaded")).unwrap_or(false) { if stuff.map(|s| s.contains("Loaded")).unwrap_or(false) {
break; break;
} }
} }
while let Some(command) = rx.recv().await { while let Some(command) = printer_in_rx.recv().await {
let command_text = format!("{}\n", command.command()); let command_text = format!("{}\n", command.command());
printer_tx.send(command_text).await.unwrap(); serial_tx.send(command_text).await.unwrap();
while let Some(reply) = printer_rx.next().await { while let Some(reply) = serial_rx.next().await {
let reply = reply.unwrap(); let reply = reply.unwrap();
if reply.contains("ok") { if reply.contains("ok") {
break; break;
} else { } else {
let reply = command.parse_reply(&reply); let reply = command.parse_reply(&reply);
println!("got reply: {:?}", reply); println!("got reply: {:?}", reply);
printer_out_tx
.send(reply.map_err(PrinterError::GcodeReply))
.await
.unwrap();
} }
} }
} }
}); });
Ok(Printer { Ok(Printer {
printer_in: tx, printer_in: printer_in_tx,
printer_out: printer_out_rx,
state: Rc::new(State { state: Rc::new(State {
position: (0.0, 0.0, 0.0, 0.0), position: (0.0, 0.0, 0.0, 0.0),
}), }),