Handle temperature auto-reports
This commit is contained in:
parent
df88b5a40c
commit
13d716924d
4 changed files with 104 additions and 44 deletions
|
@ -39,6 +39,7 @@ fn jog() -> Result<()> {
|
|||
.with_context(|| anyhow!("Initializing printer connection"))?;
|
||||
|
||||
printer.set_position_auto_report(AutoReportSetting::EverySeconds(1))?;
|
||||
printer.set_temperature_auto_report(AutoReportSetting::EverySeconds(1))?;
|
||||
|
||||
jogger::jog(&mut gamepad, printer).with_context(|| anyhow!("Running jog mode"))
|
||||
}
|
||||
|
|
19
red/src/printer/gcode/m155.rs
Normal file
19
red/src/printer/gcode/m155.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use super::*;
|
||||
|
||||
/// Set up auto reporting of axis positions
|
||||
#[derive(Debug, Default)]
|
||||
pub struct M155Command {
|
||||
/// Seconds between the auto reports. Disable auto report by setting this to 0
|
||||
pub interval: u64,
|
||||
}
|
||||
|
||||
impl GcodeCommand for M155Command {
|
||||
type Reply = ();
|
||||
fn command(&self) -> String {
|
||||
format!("M155 S{}", self.interval)
|
||||
}
|
||||
|
||||
fn parse_reply(&self, reply: &str) -> Result<Self::Reply> {
|
||||
super::parse_empty_reply(self.command(), reply)
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ mod g90;
|
|||
mod g91;
|
||||
mod m114;
|
||||
mod m154;
|
||||
mod m155;
|
||||
mod m997;
|
||||
|
||||
use crate::printer::PrinterPosition;
|
||||
|
@ -25,6 +26,7 @@ pub use g91::G91Command;
|
|||
use lazy_static::lazy_static;
|
||||
pub use m114::M114Command;
|
||||
pub use m154::M154Command;
|
||||
pub use m155::M155Command;
|
||||
pub use m997::M997Command;
|
||||
use regex::Regex;
|
||||
use std::fmt::Debug;
|
||||
|
@ -88,9 +90,15 @@ pub fn parse_autoreport_line(line: &str) -> AutoReport {
|
|||
|
||||
/// Can the line be interpreted as an auto-report by the printer
|
||||
fn is_auto_report(line: &str) -> bool {
|
||||
matches!(parse_autoreport_line(line), AutoReport::NotRecognized)
|
||||
matches!(parse_autoreport_line(line), AutoReport::NotRecognized) && is_temperature_report(line)
|
||||
}
|
||||
|
||||
pub fn is_temperature_report(line: &str) -> bool {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r" T:(-?\d+(?:\.\d+)) /").unwrap();
|
||||
}
|
||||
RE.is_match(line)
|
||||
}
|
||||
fn parse_position_line(line: &str) -> Result<(Option<f64>, Option<f64>, Option<f64>)> {
|
||||
lazy_static! {
|
||||
static ref RE_SET: Vec<Regex> = vec![
|
||||
|
@ -114,7 +122,7 @@ fn parse_position_line(line: &str) -> Result<(Option<f64>, Option<f64>, Option<f
|
|||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
if fields.iter().all(|r| r.is_err()) {
|
||||
return Err(fields[0].clone().unwrap_err());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
pub mod gcode;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::printer::gcode::{AutoReport, G91Command, M114Command};
|
||||
use self::gcode::{
|
||||
G0Command, G28Command, G90Command, GcodeReplyError, M154Command, parse_autoreport_line,
|
||||
};
|
||||
use crate::printer::gcode::{
|
||||
AutoReport, G91Command, M114Command, M155Command, is_temperature_report,
|
||||
};
|
||||
pub use gcode::GcodeCommand;
|
||||
use regex::Regex;
|
||||
use serialport::SerialPort;
|
||||
|
@ -15,12 +20,11 @@ use std::sync::Arc;
|
|||
use std::sync::Mutex;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::sync::mpsc::RecvTimeoutError;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{io, str};
|
||||
use std::sync::mpsc::RecvTimeoutError;
|
||||
use self::gcode::{G0Command, G28Command, G90Command, GcodeReplyError, M154Command, parse_autoreport_line};
|
||||
|
||||
/// Recv buffer string will be initialized with this capacity.
|
||||
/// This should fit a simple "OK Pnn Bn" reply for GCODE commands that
|
||||
|
@ -111,9 +115,7 @@ impl Printer {
|
|||
Err(RecvTimeoutError::Timeout) => {
|
||||
Err(PrinterError::NoResponseFromPrinter(command_text))
|
||||
}
|
||||
Err(RecvTimeoutError::Disconnected) => {
|
||||
Err(PrinterError::OutputChannelDropped)
|
||||
}
|
||||
Err(RecvTimeoutError::Disconnected) => Err(PrinterError::OutputChannelDropped),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +353,22 @@ impl Printer {
|
|||
|
||||
/// Set an interval at which to report the printer position or disable automatic position
|
||||
/// updates
|
||||
pub fn set_position_auto_report(&mut self, report: AutoReportSetting) -> Result<(), PrinterError> {
|
||||
pub fn set_temperature_auto_report(
|
||||
&mut self,
|
||||
report: AutoReportSetting,
|
||||
) -> Result<(), PrinterError> {
|
||||
match report {
|
||||
AutoReportSetting::Disabled => self.send_gcode(M155Command { interval: 0 }),
|
||||
AutoReportSetting::EverySeconds(n) => self.send_gcode(M155Command { interval: n }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an interval at which to report the printer position or disable automatic position
|
||||
/// updates
|
||||
pub fn set_position_auto_report(
|
||||
&mut self,
|
||||
report: AutoReportSetting,
|
||||
) -> Result<(), PrinterError> {
|
||||
match report {
|
||||
AutoReportSetting::Disabled => self.send_gcode(M154Command { interval: 0 }),
|
||||
AutoReportSetting::EverySeconds(n) => self.send_gcode(M154Command { interval: n }),
|
||||
|
@ -381,38 +398,9 @@ impl Printer {
|
|||
to_user_thread.clone(),
|
||||
),
|
||||
Err(TryRecvError::Disconnected) => break,
|
||||
Err(TryRecvError::Empty) => handle_printer_autoreport(&mut port, &mut partial_reads, state.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for auto-report messages coming in from the printer and update the `state` accordingly
|
||||
fn handle_printer_autoreport(port: &mut TTYPort, partial_reads: &mut Vec<u8>, state: Arc<Mutex<State>>) {
|
||||
return;
|
||||
if port
|
||||
.bytes_to_read()
|
||||
.expect("`handle_printer_autoreport`: Failed to check for available data")
|
||||
> 0
|
||||
{
|
||||
let mut buf = [0; BUF_SIZE_READ_LINE];
|
||||
let bytes_read = port
|
||||
.read(&mut buf)
|
||||
.expect("`handle_printer_autoreport`: Failed to read data");
|
||||
assert!(
|
||||
bytes_read > 0,
|
||||
"The port returned 0 bytes after a read. Is the port closed?"
|
||||
);
|
||||
match String::from_utf8(buf[..bytes_read].to_vec()) {
|
||||
Ok(s) => {
|
||||
println!("Received autoreport:");
|
||||
println!("<< {}", s);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"`handle_printer_autoreport` Failed to parse received bytes `{}` as UTF8: {}",
|
||||
bytes_read, e
|
||||
);
|
||||
Err(TryRecvError::Empty) => {
|
||||
handle_printer_autoreport(&mut port, &mut partial_reads, state.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -466,6 +454,48 @@ fn read_line(
|
|||
))
|
||||
}
|
||||
|
||||
/// Check for auto-report messages coming in from the printer and update the `state` accordingly
|
||||
fn handle_printer_autoreport(
|
||||
port: &mut TTYPort,
|
||||
partial_reads: &mut Vec<u8>,
|
||||
state: Arc<Mutex<State>>,
|
||||
) {
|
||||
if port
|
||||
.bytes_to_read()
|
||||
.expect("Unable to read available byte count")
|
||||
== 0
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have any byte available, we should also get a whole line
|
||||
let line = read_line(port, partial_reads, DEFAULT_COMMAND_TIMEOUT)
|
||||
.expect("Failed to read from printer");
|
||||
let str_line = String::from_utf8(line.clone()).expect("Read line was no valid utf8");
|
||||
println!("<< {:?}", str_line);
|
||||
|
||||
if is_temperature_report(&str_line) {
|
||||
// Temperature reports are not handled
|
||||
// If you need this, implement it analogous to `parse_autoreport_line`
|
||||
} else if let AutoReport::Position(x, y, z) = parse_autoreport_line(&str_line) {
|
||||
let mut position_guard = state.lock().unwrap();
|
||||
if let Some(x) = x {
|
||||
position_guard.position.x = x;
|
||||
}
|
||||
if let Some(y) = y {
|
||||
position_guard.position.y = y;
|
||||
}
|
||||
if let Some(z) = z {
|
||||
position_guard.position.z = z;
|
||||
}
|
||||
} else {
|
||||
eprintln!(
|
||||
"ERROR: Got line from printer outside of command!: {}",
|
||||
str_line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_user_command(
|
||||
port: &mut TTYPort,
|
||||
user_command: String,
|
||||
|
@ -491,7 +521,10 @@ fn handle_user_command(
|
|||
let str_line = String::from_utf8(line.clone()).expect("Read line was no valid utf8");
|
||||
println!("<< {:?}", str_line);
|
||||
|
||||
if let AutoReport::Position(x, y, z) = parse_autoreport_line(&str_line) {
|
||||
if is_temperature_report(&str_line) {
|
||||
// Temperature reports are not handled
|
||||
// If you need this, implement it analogous to `parse_autoreport_line`
|
||||
} else if let AutoReport::Position(x, y, z) = parse_autoreport_line(&str_line) {
|
||||
let mut position_guard = state.lock().unwrap();
|
||||
if let Some(x) = x {
|
||||
position_guard.position.x = x;
|
||||
|
@ -502,8 +535,7 @@ fn handle_user_command(
|
|||
if let Some(z) = z {
|
||||
position_guard.position.z = z;
|
||||
}
|
||||
}
|
||||
else if str_line.starts_with("ok") {
|
||||
} else 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
|
||||
|
|
Loading…
Add table
Reference in a new issue