Implement handle_user_command
This commit is contained in:
parent
62816b749e
commit
c616279c12
1 changed files with 56 additions and 51 deletions
|
@ -1,14 +1,14 @@
|
|||
pub mod gcode;
|
||||
use futures::AsyncWriteExt;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use bytes::BytesMut;
|
||||
use core::panic;
|
||||
use regex::Regex;
|
||||
use serialport::SerialPort;
|
||||
use serialport::TTYPort;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::ops::{Deref, DerefMut, Index};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::fd::{FromRawFd, RawFd};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
|
@ -18,7 +18,6 @@ use std::sync::Arc;
|
|||
use std::sync::Mutex;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{io, str};
|
||||
use tokio;
|
||||
|
||||
pub use gcode::{GcodeCommand, GcodeReply};
|
||||
|
||||
|
@ -65,6 +64,7 @@ pub struct PrinterPosition {
|
|||
pub z: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum MovementMode {
|
||||
AbsoluteMovements,
|
||||
RelativeMovements,
|
||||
|
@ -87,12 +87,7 @@ pub struct Printer {
|
|||
|
||||
impl Printer {
|
||||
/// Send gcode to the printer and parse its reply
|
||||
fn send_gcode<T: GcodeCommand>(
|
||||
&mut self,
|
||||
command: T,
|
||||
ignore_pos: bool,
|
||||
timeout: Duration,
|
||||
) -> Result<T::Reply, PrinterError> {
|
||||
fn send_gcode<T: GcodeCommand>(&mut self, command: T) -> Result<T::Reply, PrinterError> {
|
||||
let command_text = command.command() + "\n";
|
||||
self.to_io_thread
|
||||
.send(command_text.clone())
|
||||
|
@ -146,7 +141,6 @@ impl Printer {
|
|||
last_buffer_capacity: 0, // this is updated on the next call to `send_gcode()`
|
||||
}));
|
||||
|
||||
//TODO: Spawn IO-Thread
|
||||
let state_for_io = state.clone();
|
||||
std::thread::spawn(move || {
|
||||
Self::io_thread_work(to_user_thread, from_user_thread, port, state_for_io)
|
||||
|
@ -281,15 +275,14 @@ impl Printer {
|
|||
e: None, // Machine has no e
|
||||
velocity,
|
||||
};
|
||||
if let MovementMode::AbsoluteMovements =
|
||||
self.state.lock().unwrap().deref_mut().movement_mode
|
||||
{
|
||||
let movement_mode = self.state.lock().unwrap().deref_mut().movement_mode;
|
||||
if let MovementMode::AbsoluteMovements = movement_mode {
|
||||
self.use_relative_movements()?;
|
||||
let res = self.send_gcode(command, true, DEFAULT_COMMAND_TIMEOUT);
|
||||
let res = self.send_gcode(command);
|
||||
self.use_absolute_movements()?;
|
||||
res
|
||||
} else {
|
||||
self.send_gcode(command, true, DEFAULT_COMMAND_TIMEOUT)
|
||||
self.send_gcode(command)
|
||||
}?;
|
||||
|
||||
self.state.lock().unwrap().deref_mut().position.x += x;
|
||||
|
@ -321,13 +314,14 @@ impl Printer {
|
|||
e: None, // Machine has no e
|
||||
velocity,
|
||||
};
|
||||
if let MovementMode::RelativeMovements = self.state.lock().unwrap().deref().movement_mode {
|
||||
let movement_mode = self.state.lock().unwrap().deref().movement_mode;
|
||||
if let MovementMode::RelativeMovements = movement_mode {
|
||||
self.use_absolute_movements()?;
|
||||
let res = self.send_gcode(command, true, DEFAULT_COMMAND_TIMEOUT);
|
||||
let res = self.send_gcode(command);
|
||||
self.use_relative_movements()?;
|
||||
res
|
||||
} else {
|
||||
self.send_gcode(command, true, DEFAULT_COMMAND_TIMEOUT)
|
||||
self.send_gcode(command)
|
||||
}?;
|
||||
|
||||
self.state.lock().unwrap().deref_mut().position.x = x;
|
||||
|
@ -350,7 +344,12 @@ impl Printer {
|
|||
) {
|
||||
loop {
|
||||
match from_user_thread.try_recv() {
|
||||
Ok(user_command) => handle_user_command(&mut port, user_command, state.clone()),
|
||||
Ok(user_command) => handle_user_command(
|
||||
&mut port,
|
||||
user_command,
|
||||
state.clone(),
|
||||
to_user_thread.clone(),
|
||||
),
|
||||
Err(TryRecvError::Disconnected) => break,
|
||||
Err(TryRecvError::Empty) => handle_printer_autoreport(&mut port, state.clone()),
|
||||
}
|
||||
|
@ -368,21 +367,21 @@ fn handle_printer_autoreport(port: &mut TTYPort, state: Arc<Mutex<State>>) {
|
|||
/// Parameters
|
||||
/// * `port` - The port to read from
|
||||
/// * `already_read` - Read bytes from a previous call. May not contain `\n`
|
||||
/// * `timeout` - Time to wait before raising a timeout error
|
||||
/// * `timeout` - Time to wait for new bytes from the `port` before raising a timeout error
|
||||
///
|
||||
/// Returns
|
||||
/// `(potential_line, rest)`, where
|
||||
/// - `potential_line` is `None` if no complete line was read or `Some(line)` if a whole
|
||||
/// line was received from the port
|
||||
/// - `rest` contains the bytes that were read since the last occurence of `\n`
|
||||
///
|
||||
/// * `Ok(Some(line))` if a complete line was read from the port
|
||||
/// * `Ok(None)` if there was no `\n` received
|
||||
/// * `Err(e)` in case reading failed
|
||||
fn read_line(
|
||||
port: &mut TTYPort,
|
||||
mut already_read: Vec<u8>,
|
||||
already_read: &mut Vec<u8>,
|
||||
timeout: Duration,
|
||||
) -> io::Result<(Option<Vec<u8>>, Vec<u8>)> {
|
||||
) -> io::Result<Option<Vec<u8>>> {
|
||||
let deadline = Instant::now() + timeout;
|
||||
while Instant::now() < deadline {
|
||||
match port.read(&mut already_read) {
|
||||
match port.read(already_read) {
|
||||
Err(e) => {
|
||||
if let io::ErrorKind::TimedOut = e.kind() {
|
||||
continue;
|
||||
|
@ -393,10 +392,7 @@ fn read_line(
|
|||
Ok(0) => panic!("TTYPort returned 0 bytes!"),
|
||||
Ok(n) => {
|
||||
if let Some(line_break_idx) = already_read[..n].iter().position(|x| *x == b'\n') {
|
||||
return Ok((
|
||||
Some(already_read[..line_break_idx].into()),
|
||||
already_read[line_break_idx..].into(),
|
||||
));
|
||||
return Ok(Some(already_read[..line_break_idx].into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,32 +403,41 @@ fn read_line(
|
|||
))
|
||||
}
|
||||
|
||||
fn handle_user_command(port: &mut TTYPort, user_command: String, state: Arc<Mutex<State>>) {
|
||||
fn handle_user_command(
|
||||
port: &mut TTYPort,
|
||||
user_command: String,
|
||||
state: Arc<Mutex<State>>,
|
||||
to_user_thread: Sender<Vec<u8>>,
|
||||
) {
|
||||
port.write(user_command.as_bytes())
|
||||
.expect("Printer IO-Thread hung up its incoming mpsc");
|
||||
.expect("Failed to write to printer serial port");
|
||||
port.flush().unwrap();
|
||||
let ignore_pos = false;
|
||||
let mut reply = String::with_capacity(RECV_BUFFER_CAPACITY);
|
||||
let mut already_read = Vec::new();
|
||||
|
||||
let mut already_read_lines = Vec::new();
|
||||
let mut rest = Vec::new();
|
||||
loop {
|
||||
let (mut line, mut rest) = read_line(port, Vec::new(), DEFAULT_COMMAND_TIMEOUT).unwrap();
|
||||
let timeout = Instant::now() + DEFAULT_COMMAND_TIMEOUT;
|
||||
while line.is_none() && Instant::now() < timeout {
|
||||
let buf = Vec::new();
|
||||
_ = port.read(&mut buf);
|
||||
if line.is_none() {
|
||||
let mut line;
|
||||
loop {
|
||||
line = read_line(port, &mut rest, DEFAULT_COMMAND_TIMEOUT)
|
||||
.expect("Failed to read from printer");
|
||||
if line.is_some() {
|
||||
break;
|
||||
} else {
|
||||
std::thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
}
|
||||
if let Some(line) = line {
|
||||
let line = String::from_utf8(line).unwrap();
|
||||
if line.starts_with("ok") {
|
||||
(*state.lock().unwrap()).last_buffer_capacity = Printer::parse_ok(&line)?;
|
||||
let reply = command_parser(&reply);
|
||||
return reply.map_err(PrinterError::GcodeReply);
|
||||
} else {
|
||||
reply.push_str(&line);
|
||||
}
|
||||
let line = line.expect("Line must be set as otherwise we don't leave the loop");
|
||||
|
||||
let str_line = String::from_utf8(line.clone()).expect("Read line was no valid utf8");
|
||||
|
||||
if str_line.starts_with("ok") {
|
||||
(*state.lock().unwrap()).last_buffer_capacity =
|
||||
Printer::parse_ok(&str_line).expect("Couldn't parse line as 'ok'-message");
|
||||
to_user_thread
|
||||
.send(already_read_lines.join(&b'\n'))
|
||||
.expect("Failed to send read bytes to user thread");
|
||||
} else {
|
||||
already_read_lines.push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue