gcode_serial/
gcode_serial.rs1use crate::models::action::{Action, Command, PrinterAction, PrinterStatus, TelemetryData};
2use crate::models::file::{FinishedPrint, GcodeFile};
3use crate::models::serial_connector::SerialConnector;
4use crate::serial::serial::Serial;
5use event_listener::Event;
6use lazy_static::lazy_static;
7use log::debug;
8use regex::Regex;
9use std::collections::VecDeque;
10use std::fs::File;
11use std::io::{BufRead, BufReader};
12use std::sync::{Arc, Mutex};
13use std::time::{SystemTime, UNIX_EPOCH};
14use tokio::sync::broadcast::Sender;
15
16lazy_static! {
17 static ref RE_MAX_Z_POS: Regex = Regex::new(r";\s*max_layer_z\s*=\s*([\d.]+)").unwrap();
18}
19
20pub struct GcodeSerial {
21 tx: Sender<Action>,
22 que: Arc<Mutex<VecDeque<String>>>,
23 event: Arc<Mutex<Event>>,
24 active_file: Option<GcodeFile>,
25}
26
27impl GcodeSerial {
28 pub fn new(tx: Sender<Action>) -> Self {
29 let q = Arc::new(Mutex::new(VecDeque::new()));
30 let event = Arc::new(Mutex::new(Event::new()));
31 GcodeSerial {
32 tx: tx.clone(),
33 que: q,
34 event,
35 active_file: None,
36 }
37 }
38
39 pub async fn start(&mut self, serial_connector: SerialConnector) {
41 let mut rx = self.tx.subscribe();
42
43 let que = self.que.clone();
44 let event = self.event.clone();
45 let tx = self.tx.clone();
46 tokio::spawn(async move {
47 let mut serial = Serial::new(tx, serial_connector, que, event).await;
48 serial.start_temp_interval();
49 serial.start_event_loop().await;
50 });
51
52 while let Ok(v) = rx.recv().await {
53 match v {
54 Action::Telemetry(_) => {}
55 Action::StateChange(s) => {
56 match s {
57 PrinterStatus::Disconnected => {}
58 PrinterStatus::Active => {}
59 PrinterStatus::Idle => {
60 if self.active_file.is_some() {
61 let f = self.active_file.clone().unwrap();
62
63 let _ = self.tx.send(Action::Telemetry(
64 TelemetryData::PrintFinished(FinishedPrint {
65 name: f.name,
66 size: f.size,
67 last_modified: f.last_modified,
68 start_time: f.start_time,
69 finish_time: SystemTime::now()
70 .duration_since(UNIX_EPOCH)
71 .unwrap()
72 .as_millis(),
73 }),
74 ));
75 self.active_file = None;
76 }
77 }
78 PrinterStatus::Errored => {}
79 }
80 debug!("Printer State change: {}", s);
81 }
82 Action::PrinterAction(a) => match a {
83 PrinterAction::Cancel => {
84 self.stop_print();
85 }
86 PrinterAction::Pause => {
87 todo!()
88 }
89 PrinterAction::Resume => {
90 todo!()
91 }
92 },
93 Action::Command(c) => match c {
94 Command::SetTemps(b, c) => {
95 self.set_temps(b, c);
96 }
97 Command::StartPrint(n) => {
98 self.start_print(n);
99 }
100 Command::StopPrint => {
101 self.stop_print();
102 }
103 },
104 }
105 }
106 }
107
108 pub fn set_temps(&mut self, bed_temp: u16, extruder_temp: u16) {
110 self.que
111 .lock()
112 .unwrap()
113 .push_back(format!("M140 S{}", bed_temp));
114 self.que
115 .lock()
116 .unwrap()
117 .push_back(format!("M104 S{}", extruder_temp));
118 }
119
120 pub fn start_print(&mut self, file_path: String) {
123 if self.que.lock().unwrap().len() > 10 {
125 return;
126 }
127
128 let file = File::open(file_path.to_string()).unwrap();
129
130 let unix_timestamp = file
131 .metadata()
132 .unwrap()
133 .modified()
134 .unwrap()
135 .duration_since(UNIX_EPOCH)
136 .unwrap()
137 .as_millis();
138 let size = file.metadata().unwrap().len();
139
140 let reader = BufReader::new(file);
141
142 let active_file = GcodeFile {
143 name: file_path,
144 size,
145 last_modified: unix_timestamp,
146 start_time: SystemTime::now()
147 .duration_since(UNIX_EPOCH)
148 .unwrap()
149 .as_millis(),
150 };
151 self.active_file = Some(active_file.clone());
152
153 let _ = self
154 .tx
155 .send(Action::Telemetry(TelemetryData::ActiveFileChange(Some(
156 active_file,
157 ))));
158
159 for line in reader.lines() {
160 let mut command = line.unwrap();
161
162 match RE_MAX_Z_POS.captures(command.as_str()) {
164 None => {}
165 Some(c) => {
166 let h1: f32 = c
167 .get(1)
168 .map_or("0.0", |m| m.as_str())
169 .parse()
170 .unwrap_or(0.0);
171 let _ = self
172 .tx
173 .send(Action::Telemetry(TelemetryData::MaxZHeight(h1)));
174 }
175 }
176
177 if command.trim().starts_with(";") || command.trim().is_empty() {
179 continue;
180 }
181
182 if command.trim().contains(";") {
184 command = command.trim().split(";").collect::<Vec<&str>>()[0].to_string();
185 }
186
187 self.que.lock().unwrap().push_back(command);
188 }
189
190 let _ = self
191 .tx
192 .send(Action::Telemetry(TelemetryData::TotalCommandCount(
193 self.que.lock().unwrap().len() as u32,
194 )));
195 let _ = self.tx.send(Action::StateChange(PrinterStatus::Active));
196 self.event.lock().unwrap().notify(42);
197 }
198
199 pub fn stop_print(&self) {
201 let mut que = self.que.lock().unwrap();
202 que.clear();
203 que.push_back("G1 X0 Y200 F3600".to_string()); que.push_back("G4".to_string()); que.push_back("M221 S100".to_string()); que.push_back("M900 K0".to_string()); que.push_back("M104 S0".to_string()); que.push_back("M140 S0".to_string()); que.push_back("M107".to_string()); que.push_back("M84".to_string()); let _ = self
214 .tx
215 .send(Action::Telemetry(TelemetryData::TotalCommandCount(0)));
216 let _ = self.tx.send(Action::StateChange(PrinterStatus::Idle));
217 self.event.lock().unwrap().notify(42);
218 }
219}