blob: 08ea48bf24ab0af37fee6b1d49b3c83ce514347e [file] [log] [blame]
Luigi Santivetti69972f92019-11-12 22:55:40 +00001/*
2 protocol.c - controls Grbl execution protocol and procedures
3 Part of Grbl
4
5 Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
6 Copyright (c) 2009-2011 Simen Svale Skogsrud
7
8 Grbl is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Grbl is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Grbl. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "grbl.h"
23
24// Define line flags. Includes comment type tracking and line overflow detection.
25#define LINE_FLAG_OVERFLOW bit(0)
26#define LINE_FLAG_COMMENT_PARENTHESES bit(1)
27#define LINE_FLAG_COMMENT_SEMICOLON bit(2)
28
29
30static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
31
32static void protocol_exec_rt_suspend();
33
34
35/*
36 GRBL PRIMARY LOOP:
37*/
38void protocol_main_loop()
39{
40 // Perform some machine checks to make sure everything is good to go.
41 #ifdef CHECK_LIMITS_AT_INIT
42 if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
43 if (limits_get_state()) {
44 sys.state = STATE_ALARM; // Ensure alarm state is active.
45 report_feedback_message(MESSAGE_CHECK_LIMITS);
46 }
47 }
48 #endif
49 // Check for and report alarm state after a reset, error, or an initial power up.
50 // NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed.
51 // Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges.
52 if (sys.state & (STATE_ALARM | STATE_SLEEP)) {
53 report_feedback_message(MESSAGE_ALARM_LOCK);
54 sys.state = STATE_ALARM; // Ensure alarm state is set.
55 } else {
56 // Check if the safety door is open.
57 sys.state = STATE_IDLE;
58 if (system_check_safety_door_ajar()) {
59 bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
60 protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state.
61 }
62 // All systems go!
63 system_execute_startup(line); // Execute startup script.
64 }
65
66 // ---------------------------------------------------------------------------------
67 // Primary loop! Upon a system abort, this exits back to main() to reset the system.
68 // This is also where Grbl idles while waiting for something to do.
69 // ---------------------------------------------------------------------------------
70
71 uint8_t line_flags = 0;
72 uint8_t char_counter = 0;
73 uint8_t c;
74 for (;;) {
75
76 // Process one line of incoming serial data, as the data becomes available. Performs an
77 // initial filtering by removing spaces and comments and capitalizing all letters.
78 while((c = serial_read()) != SERIAL_NO_DATA) {
79 if ((c == '\n') || (c == '\r')) { // End of line reached
80
81 protocol_execute_realtime(); // Runtime command check point.
82 if (sys.abort) { return; } // Bail to calling function upon system abort
83
84 line[char_counter] = 0; // Set string termination character.
85 #ifdef REPORT_ECHO_LINE_RECEIVED
86 report_echo_line_received(line);
87 #endif
88
89 // Direct and execute one line of formatted input, and report status of execution.
90 if (line_flags & LINE_FLAG_OVERFLOW) {
91 // Report line overflow error.
92 report_status_message(STATUS_OVERFLOW);
93 } else if (line[0] == 0) {
94 // Empty or comment line. For syncing purposes.
95 report_status_message(STATUS_OK);
96 } else if (line[0] == '$') {
97 // Grbl '$' system command
98 report_status_message(system_execute_line(line));
99 } else if (sys.state & (STATE_ALARM | STATE_JOG)) {
100 // Everything else is gcode. Block if in alarm or jog mode.
101 report_status_message(STATUS_SYSTEM_GC_LOCK);
102 } else {
103 // Parse and execute g-code block.
104 report_status_message(gc_execute_line(line));
105 }
106
107 // Reset tracking data for next line.
108 line_flags = 0;
109 char_counter = 0;
110
111 } else {
112
113 if (line_flags) {
114 // Throw away all (except EOL) comment characters and overflow characters.
115 if (c == ')') {
116 // End of '()' comment. Resume line allowed.
117 if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) { line_flags &= ~(LINE_FLAG_COMMENT_PARENTHESES); }
118 }
119 } else {
120 if (c <= ' ') {
121 // Throw away whitepace and control characters
122 } else if (c == '/') {
123 // Block delete NOT SUPPORTED. Ignore character.
124 // NOTE: If supported, would simply need to check the system if block delete is enabled.
125 } else if (c == '(') {
126 // Enable comments flag and ignore all characters until ')' or EOL.
127 // NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
128 // In the future, we could simply remove the items within the comments, but retain the
129 // comment control characters, so that the g-code parser can error-check it.
130 line_flags |= LINE_FLAG_COMMENT_PARENTHESES;
131 } else if (c == ';') {
132 // NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
133 line_flags |= LINE_FLAG_COMMENT_SEMICOLON;
134 // TODO: Install '%' feature
135 // } else if (c == '%') {
136 // Program start-end percent sign NOT SUPPORTED.
137 // NOTE: This maybe installed to tell Grbl when a program is running vs manual input,
138 // where, during a program, the system auto-cycle start will continue to execute
139 // everything until the next '%' sign. This will help fix resuming issues with certain
140 // functions that empty the planner buffer to execute its task on-time.
141 } else if (char_counter >= (LINE_BUFFER_SIZE-1)) {
142 // Detect line buffer overflow and set flag.
143 line_flags |= LINE_FLAG_OVERFLOW;
144 } else if (c >= 'a' && c <= 'z') { // Upcase lowercase
145 line[char_counter++] = c-'a'+'A';
146 } else {
147 line[char_counter++] = c;
148 }
149 }
150
151 }
152 }
153
154 // If there are no more characters in the serial read buffer to be processed and executed,
155 // this indicates that g-code streaming has either filled the planner buffer or has
156 // completed. In either case, auto-cycle start, if enabled, any queued moves.
157 protocol_auto_cycle_start();
158
159 protocol_execute_realtime(); // Runtime command check point.
160 if (sys.abort) { return; } // Bail to main() program loop to reset system.
161 }
162
163 return; /* Never reached */
164}
165
166
167// Block until all buffered steps are executed or in a cycle state. Works with feed hold
168// during a synchronize call, if it should happen. Also, waits for clean cycle end.
169void protocol_buffer_synchronize()
170{
171 // If system is queued, ensure cycle resumes if the auto start flag is present.
172 protocol_auto_cycle_start();
173 do {
174 protocol_execute_realtime(); // Check and execute run-time commands
175 if (sys.abort) { return; } // Check for system abort
176 } while (plan_get_current_block() || (sys.state == STATE_CYCLE));
177}
178
179
180// Auto-cycle start triggers when there is a motion ready to execute and if the main program is not
181// actively parsing commands.
182// NOTE: This function is called from the main loop, buffer sync, and mc_line() only and executes
183// when one of these conditions exist respectively: There are no more blocks sent (i.e. streaming
184// is finished, single commands), a command that needs to wait for the motions in the buffer to
185// execute calls a buffer sync, or the planner buffer is full and ready to go.
186void protocol_auto_cycle_start()
187{
188 if (plan_get_current_block() != NULL) { // Check if there are any blocks in the buffer.
189 system_set_exec_state_flag(EXEC_CYCLE_START); // If so, execute them!
190 }
191}
192
193
194// This function is the general interface to Grbl's real-time command execution system. It is called
195// from various check points in the main program, primarily where there may be a while loop waiting
196// for a buffer to clear space or any point where the execution time from the last check point may
197// be more than a fraction of a second. This is a way to execute realtime commands asynchronously
198// (aka multitasking) with grbl's g-code parsing and planning functions. This function also serves
199// as an interface for the interrupts to set the system realtime flags, where only the main program
200// handles them, removing the need to define more computationally-expensive volatile variables. This
201// also provides a controlled way to execute certain tasks without having two or more instances of
202// the same task, such as the planner recalculating the buffer upon a feedhold or overrides.
203// NOTE: The sys_rt_exec_state variable flags are set by any process, step or serial interrupts, pinouts,
204// limit switches, or the main program.
205void protocol_execute_realtime()
206{
207 protocol_exec_rt_system();
208 if (sys.suspend) { protocol_exec_rt_suspend(); }
209}
210
211
212// Executes run-time commands, when required. This function primarily operates as Grbl's state
213// machine and controls the various real-time features Grbl has to offer.
214// NOTE: Do not alter this unless you know exactly what you are doing!
215void protocol_exec_rt_system()
216{
217 uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.
218 rt_exec = sys_rt_exec_alarm; // Copy volatile sys_rt_exec_alarm.
219 if (rt_exec) { // Enter only if any bit flag is true
220 // System alarm. Everything has shutdown by something that has gone severely wrong. Report
221 // the source of the error to the user. If critical, Grbl disables by entering an infinite
222 // loop until system reset/abort.
223 sys.state = STATE_ALARM; // Set system alarm state
224 report_alarm_message(rt_exec);
225 // Halt everything upon a critical event flag. Currently hard and soft limits flag this.
226 if ((rt_exec == EXEC_ALARM_HARD_LIMIT) || (rt_exec == EXEC_ALARM_SOFT_LIMIT)) {
227 report_feedback_message(MESSAGE_CRITICAL_EVENT);
228 system_clear_exec_state_flag(EXEC_RESET); // Disable any existing reset
229 do {
230 // Block everything, except reset and status reports, until user issues reset or power
231 // cycles. Hard limits typically occur while unattended or not paying attention. Gives
232 // the user and a GUI time to do what is needed before resetting, like killing the
233 // incoming stream. The same could be said about soft limits. While the position is not
234 // lost, continued streaming could cause a serious crash if by chance it gets executed.
235 } while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
236 }
237 system_clear_exec_alarm(); // Clear alarm
238 }
239
240 rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
241 if (rt_exec) {
242
243 // Execute system abort.
244 if (rt_exec & EXEC_RESET) {
245 sys.abort = true; // Only place this is set true.
246 return; // Nothing else to do but exit.
247 }
248
249 // Execute and serial print status
250 if (rt_exec & EXEC_STATUS_REPORT) {
251 report_realtime_status();
252 system_clear_exec_state_flag(EXEC_STATUS_REPORT);
253 }
254
255 // NOTE: Once hold is initiated, the system immediately enters a suspend state to block all
256 // main program processes until either reset or resumed. This ensures a hold completes safely.
257 if (rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP)) {
258
259 // State check for allowable states for hold methods.
260 if (!(sys.state & (STATE_ALARM | STATE_CHECK_MODE))) {
261
262 // If in CYCLE or JOG states, immediately initiate a motion HOLD.
263 if (sys.state & (STATE_CYCLE | STATE_JOG)) {
264 if (!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) { // Block, if already holding.
265 st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
266 sys.step_control = STEP_CONTROL_EXECUTE_HOLD; // Initiate suspend state with active flag.
267 if (sys.state == STATE_JOG) { // Jog cancelled upon any hold event, except for sleeping.
268 if (!(rt_exec & EXEC_SLEEP)) { sys.suspend |= SUSPEND_JOG_CANCEL; }
269 }
270 }
271 }
272 // If IDLE, Grbl is not in motion. Simply indicate suspend state and hold is complete.
273 if (sys.state == STATE_IDLE) { sys.suspend = SUSPEND_HOLD_COMPLETE; }
274
275 // Execute and flag a motion cancel with deceleration and return to idle. Used primarily by probing cycle
276 // to halt and cancel the remainder of the motion.
277 if (rt_exec & EXEC_MOTION_CANCEL) {
278 // MOTION_CANCEL only occurs during a CYCLE, but a HOLD and SAFETY_DOOR may been initiated beforehand
279 // to hold the CYCLE. Motion cancel is valid for a single planner block motion only, while jog cancel
280 // will handle and clear multiple planner block motions.
281 if (!(sys.state & STATE_JOG)) { sys.suspend |= SUSPEND_MOTION_CANCEL; } // NOTE: State is STATE_CYCLE.
282 }
283
284 // Execute a feed hold with deceleration, if required. Then, suspend system.
285 if (rt_exec & EXEC_FEED_HOLD) {
286 // Block SAFETY_DOOR, JOG, and SLEEP states from changing to HOLD state.
287 if (!(sys.state & (STATE_SAFETY_DOOR | STATE_JOG | STATE_SLEEP))) { sys.state = STATE_HOLD; }
288 }
289
290 // Execute a safety door stop with a feed hold and disable spindle/coolant.
291 // NOTE: Safety door differs from feed holds by stopping everything no matter state, disables powered
292 // devices (spindle/coolant), and blocks resuming until switch is re-engaged.
293 if (rt_exec & EXEC_SAFETY_DOOR) {
294 report_feedback_message(MESSAGE_SAFETY_DOOR_AJAR);
295 // If jogging, block safety door methods until jog cancel is complete. Just flag that it happened.
296 if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
297 // Check if the safety re-opened during a restore parking motion only. Ignore if
298 // already retracting, parked or in sleep state.
299 if (sys.state == STATE_SAFETY_DOOR) {
300 if (sys.suspend & SUSPEND_INITIATE_RESTORE) { // Actively restoring
301 #ifdef PARKING_ENABLE
302 // Set hold and reset appropriate control flags to restart parking sequence.
303 if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
304 st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
305 sys.step_control = (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION);
306 sys.suspend &= ~(SUSPEND_HOLD_COMPLETE);
307 } // else NO_MOTION is active.
308 #endif
309 sys.suspend &= ~(SUSPEND_RETRACT_COMPLETE | SUSPEND_INITIATE_RESTORE | SUSPEND_RESTORE_COMPLETE);
310 sys.suspend |= SUSPEND_RESTART_RETRACT;
311 }
312 }
313 if (sys.state != STATE_SLEEP) { sys.state = STATE_SAFETY_DOOR; }
314 }
315 // NOTE: This flag doesn't change when the door closes, unlike sys.state. Ensures any parking motions
316 // are executed if the door switch closes and the state returns to HOLD.
317 sys.suspend |= SUSPEND_SAFETY_DOOR_AJAR;
318 }
319
320 }
321
322 if (rt_exec & EXEC_SLEEP) {
323 if (sys.state == STATE_ALARM) { sys.suspend |= (SUSPEND_RETRACT_COMPLETE|SUSPEND_HOLD_COMPLETE); }
324 sys.state = STATE_SLEEP;
325 }
326
327 system_clear_exec_state_flag((EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP));
328 }
329
330 // Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
331 if (rt_exec & EXEC_CYCLE_START) {
332 // Block if called at same time as the hold commands: feed hold, motion cancel, and safety door.
333 // Ensures auto-cycle-start doesn't resume a hold without an explicit user-input.
334 if (!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR))) {
335 // Resume door state when parking motion has retracted and door has been closed.
336 if ((sys.state == STATE_SAFETY_DOOR) && !(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR)) {
337 if (sys.suspend & SUSPEND_RESTORE_COMPLETE) {
338 sys.state = STATE_IDLE; // Set to IDLE to immediately resume the cycle.
339 } else if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
340 // Flag to re-energize powered components and restore original position, if disabled by SAFETY_DOOR.
341 // NOTE: For a safety door to resume, the switch must be closed, as indicated by HOLD state, and
342 // the retraction execution is complete, which implies the initial feed hold is not active. To
343 // restore normal operation, the restore procedures must be initiated by the following flag. Once,
344 // they are complete, it will call CYCLE_START automatically to resume and exit the suspend.
345 sys.suspend |= SUSPEND_INITIATE_RESTORE;
346 }
347 }
348 // Cycle start only when IDLE or when a hold is complete and ready to resume.
349 if ((sys.state == STATE_IDLE) || ((sys.state & STATE_HOLD) && (sys.suspend & SUSPEND_HOLD_COMPLETE))) {
350 if (sys.state == STATE_HOLD && sys.spindle_stop_ovr) {
351 sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE_CYCLE; // Set to restore in suspend routine and cycle start after.
352 } else {
353 // Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
354 sys.step_control = STEP_CONTROL_NORMAL_OP; // Restore step control to normal operation
355 if (plan_get_current_block() && bit_isfalse(sys.suspend,SUSPEND_MOTION_CANCEL)) {
356 sys.suspend = SUSPEND_DISABLE; // Break suspend state.
357 sys.state = STATE_CYCLE;
358 st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
359 st_wake_up();
360 } else { // Otherwise, do nothing. Set and resume IDLE state.
361 sys.suspend = SUSPEND_DISABLE; // Break suspend state.
362 sys.state = STATE_IDLE;
363 }
364 }
365 }
366 }
367 system_clear_exec_state_flag(EXEC_CYCLE_START);
368 }
369
370 if (rt_exec & EXEC_CYCLE_STOP) {
371 // Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
372 // realtime command execution in the main program, ensuring that the planner re-plans safely.
373 // NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
374 // cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
375 // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
376 if ((sys.state & (STATE_HOLD|STATE_SAFETY_DOOR|STATE_SLEEP)) && !(sys.soft_limit) && !(sys.suspend & SUSPEND_JOG_CANCEL)) {
377 // Hold complete. Set to indicate ready to resume. Remain in HOLD or DOOR states until user
378 // has issued a resume command or reset.
379 plan_cycle_reinitialize();
380 if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { sys.suspend |= SUSPEND_HOLD_COMPLETE; }
381 bit_false(sys.step_control,(STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION));
382 } else {
383 // Motion complete. Includes CYCLE/JOG/HOMING states and jog cancel/motion cancel/soft limit events.
384 // NOTE: Motion and jog cancel both immediately return to idle after the hold completes.
385 if (sys.suspend & SUSPEND_JOG_CANCEL) { // For jog cancel, flush buffers and sync positions.
386 sys.step_control = STEP_CONTROL_NORMAL_OP;
387 plan_reset();
388 st_reset();
389 gc_sync_position();
390 plan_sync_position();
391 }
392 if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) { // Only occurs when safety door opens during jog.
393 sys.suspend &= ~(SUSPEND_JOG_CANCEL);
394 sys.suspend |= SUSPEND_HOLD_COMPLETE;
395 sys.state = STATE_SAFETY_DOOR;
396 } else {
397 sys.suspend = SUSPEND_DISABLE;
398 sys.state = STATE_IDLE;
399 }
400 }
401 system_clear_exec_state_flag(EXEC_CYCLE_STOP);
402 }
403 }
404
405 // Execute overrides.
406 rt_exec = sys_rt_exec_motion_override; // Copy volatile sys_rt_exec_motion_override
407 if (rt_exec) {
408 system_clear_exec_motion_overrides(); // Clear all motion override flags.
409
410 uint8_t new_f_override = sys.f_override;
411 if (rt_exec & EXEC_FEED_OVR_RESET) { new_f_override = DEFAULT_FEED_OVERRIDE; }
412 if (rt_exec & EXEC_FEED_OVR_COARSE_PLUS) { new_f_override += FEED_OVERRIDE_COARSE_INCREMENT; }
413 if (rt_exec & EXEC_FEED_OVR_COARSE_MINUS) { new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT; }
414 if (rt_exec & EXEC_FEED_OVR_FINE_PLUS) { new_f_override += FEED_OVERRIDE_FINE_INCREMENT; }
415 if (rt_exec & EXEC_FEED_OVR_FINE_MINUS) { new_f_override -= FEED_OVERRIDE_FINE_INCREMENT; }
416 new_f_override = min(new_f_override,MAX_FEED_RATE_OVERRIDE);
417 new_f_override = max(new_f_override,MIN_FEED_RATE_OVERRIDE);
418
419 uint8_t new_r_override = sys.r_override;
420 if (rt_exec & EXEC_RAPID_OVR_RESET) { new_r_override = DEFAULT_RAPID_OVERRIDE; }
421 if (rt_exec & EXEC_RAPID_OVR_MEDIUM) { new_r_override = RAPID_OVERRIDE_MEDIUM; }
422 if (rt_exec & EXEC_RAPID_OVR_LOW) { new_r_override = RAPID_OVERRIDE_LOW; }
423
424 if ((new_f_override != sys.f_override) || (new_r_override != sys.r_override)) {
425 sys.f_override = new_f_override;
426 sys.r_override = new_r_override;
427 sys.report_ovr_counter = 0; // Set to report change immediately
428 plan_update_velocity_profile_parameters();
429 plan_cycle_reinitialize();
430 }
431 }
432
433 rt_exec = sys_rt_exec_accessory_override;
434 if (rt_exec) {
435 system_clear_exec_accessory_overrides(); // Clear all accessory override flags.
436
437 // NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
438 uint8_t last_s_override = sys.spindle_speed_ovr;
439 if (rt_exec & EXEC_SPINDLE_OVR_RESET) { last_s_override = DEFAULT_SPINDLE_SPEED_OVERRIDE; }
440 if (rt_exec & EXEC_SPINDLE_OVR_COARSE_PLUS) { last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT; }
441 if (rt_exec & EXEC_SPINDLE_OVR_COARSE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT; }
442 if (rt_exec & EXEC_SPINDLE_OVR_FINE_PLUS) { last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT; }
443 if (rt_exec & EXEC_SPINDLE_OVR_FINE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT; }
444 last_s_override = min(last_s_override,MAX_SPINDLE_SPEED_OVERRIDE);
445 last_s_override = max(last_s_override,MIN_SPINDLE_SPEED_OVERRIDE);
446
447 if (last_s_override != sys.spindle_speed_ovr) {
448 sys.spindle_speed_ovr = last_s_override;
449 // NOTE: Spindle speed overrides during HOLD state are taken care of by suspend function.
450 if (sys.state == STATE_IDLE) { spindle_set_state(gc_state.modal.spindle, gc_state.spindle_speed); }
451 else { bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); }
452 sys.report_ovr_counter = 0; // Set to report change immediately
453 }
454
455 if (rt_exec & EXEC_SPINDLE_OVR_STOP) {
456 // Spindle stop override allowed only while in HOLD state.
457 // NOTE: Report counters are set in spindle_set_state() when spindle stop is executed.
458 if (sys.state == STATE_HOLD) {
459 if (!(sys.spindle_stop_ovr)) { sys.spindle_stop_ovr = SPINDLE_STOP_OVR_INITIATE; }
460 else if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_ENABLED) { sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE; }
461 }
462 }
463
464 // NOTE: Since coolant state always performs a planner sync whenever it changes, the current
465 // run state can be determined by checking the parser state.
466 // NOTE: Coolant overrides only operate during IDLE, CYCLE, HOLD, and JOG states. Ignored otherwise.
467 if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
468 if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_JOG))) {
469 uint8_t coolant_state = gc_state.modal.coolant;
470 #ifdef ENABLE_M7
471 if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
472 if (coolant_state & COOLANT_MIST_ENABLE) { bit_false(coolant_state,COOLANT_MIST_ENABLE); }
473 else { coolant_state |= COOLANT_MIST_ENABLE; }
474 }
475 if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE) {
476 if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
477 else { coolant_state |= COOLANT_FLOOD_ENABLE; }
478 }
479 #else
480 if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
481 else { coolant_state |= COOLANT_FLOOD_ENABLE; }
482 #endif
483 coolant_set_state(coolant_state); // Report counter set in coolant_set_state().
484 gc_state.modal.coolant = coolant_state;
485 }
486 }
487 }
488
489 #ifdef DEBUG
490 if (sys_rt_exec_debug) {
491 report_realtime_debug();
492 sys_rt_exec_debug = 0;
493 }
494 #endif
495
496 // Reload step segment buffer
497 if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG)) {
498 st_prep_buffer();
499 }
500
501}
502
503
504// Handles Grbl system suspend procedures, such as feed hold, safety door, and parking motion.
505// The system will enter this loop, create local variables for suspend tasks, and return to
506// whatever function that invoked the suspend, such that Grbl resumes normal operation.
507// This function is written in a way to promote custom parking motions. Simply use this as a
508// template
509static void protocol_exec_rt_suspend()
510{
511 #ifdef PARKING_ENABLE
512 // Declare and initialize parking local variables
513 float restore_target[N_AXIS];
514 float parking_target[N_AXIS];
515 float retract_waypoint = PARKING_PULLOUT_INCREMENT;
516 plan_line_data_t plan_data;
517 plan_line_data_t *pl_data = &plan_data;
518 memset(pl_data,0,sizeof(plan_line_data_t));
519 pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
520 #ifdef USE_LINE_NUMBERS
521 pl_data->line_number = PARKING_MOTION_LINE_NUMBER;
522 #endif
523 #endif
524
525 plan_block_t *block = plan_get_current_block();
526 uint8_t restore_condition;
527 #ifdef VARIABLE_SPINDLE
528 float restore_spindle_speed;
529 if (block == NULL) {
530 restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant);
531 restore_spindle_speed = gc_state.spindle_speed;
532 } else {
533 restore_condition = (block->condition & PL_COND_SPINDLE_MASK) | coolant_get_state();
534 restore_spindle_speed = block->spindle_speed;
535 }
536 #ifdef DISABLE_LASER_DURING_HOLD
537 if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
538 system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
539 }
540 #endif
541 #else
542 if (block == NULL) { restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant); }
543 else { restore_condition = (block->condition & PL_COND_SPINDLE_MASK) | coolant_get_state(); }
544 #endif
545
546 while (sys.suspend) {
547
548 if (sys.abort) { return; }
549
550 // Block until initial hold is complete and the machine has stopped motion.
551 if (sys.suspend & SUSPEND_HOLD_COMPLETE) {
552
553 // Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
554 // the safety door and sleep states.
555 if (sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP)) {
556
557 // Handles retraction motions and de-energizing.
558 if (bit_isfalse(sys.suspend,SUSPEND_RETRACT_COMPLETE)) {
559
560 // Ensure any prior spindle stop override is disabled at start of safety door routine.
561 sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED;
562
563 #ifndef PARKING_ENABLE
564
565 spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
566 coolant_set_state(COOLANT_DISABLE); // De-energize
567
568 #else
569
570 // Get current position and store restore location and spindle retract waypoint.
571 system_convert_array_steps_to_mpos(parking_target,sys_position);
572 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
573 memcpy(restore_target,parking_target,sizeof(parking_target));
574 retract_waypoint += restore_target[PARKING_AXIS];
575 retract_waypoint = min(retract_waypoint,PARKING_TARGET);
576 }
577
578 // Execute slow pull-out parking retract motion. Parking requires homing enabled, the
579 // current location not exceeding the parking target location, and laser mode disabled.
580 // NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
581 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
582 if ((bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) &&
583 (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
584 bit_isfalse(settings.flags,BITFLAG_LASER_MODE) &&
585 (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
586 #else
587 if ((bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) &&
588 (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
589 bit_isfalse(settings.flags,BITFLAG_LASER_MODE)) {
590 #endif
591 // Retract spindle by pullout distance. Ensure retraction motion moves away from
592 // the workpiece and waypoint motion doesn't exceed the parking target location.
593 if (parking_target[PARKING_AXIS] < retract_waypoint) {
594 parking_target[PARKING_AXIS] = retract_waypoint;
595 pl_data->feed_rate = PARKING_PULLOUT_RATE;
596 pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Retain accessory state
597 pl_data->spindle_speed = restore_spindle_speed;
598 mc_parking_motion(parking_target, pl_data);
599 }
600
601 // NOTE: Clear accessory state after retract and after an aborted restore motion.
602 pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
603 pl_data->spindle_speed = 0.0;
604 spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
605 coolant_set_state(COOLANT_DISABLE); // De-energize
606
607 // Execute fast parking retract motion to parking target location.
608 if (parking_target[PARKING_AXIS] < PARKING_TARGET) {
609 parking_target[PARKING_AXIS] = PARKING_TARGET;
610 pl_data->feed_rate = PARKING_RATE;
611 mc_parking_motion(parking_target, pl_data);
612 }
613
614 } else {
615
616 // Parking motion not possible. Just disable the spindle and coolant.
617 // NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
618 spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
619 coolant_set_state(COOLANT_DISABLE); // De-energize
620
621 }
622
623 #endif
624
625 sys.suspend &= ~(SUSPEND_RESTART_RETRACT);
626 sys.suspend |= SUSPEND_RETRACT_COMPLETE;
627
628 } else {
629
630
631 if (sys.state == STATE_SLEEP) {
632 report_feedback_message(MESSAGE_SLEEP_MODE);
633 // Spindle and coolant should already be stopped, but do it again just to be sure.
634 spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
635 coolant_set_state(COOLANT_DISABLE); // De-energize
636 st_go_idle(); // Disable steppers
637 while (!(sys.abort)) { protocol_exec_rt_system(); } // Do nothing until reset.
638 return; // Abort received. Return to re-initialize.
639 }
640
641 // Allows resuming from parking/safety door. Actively checks if safety door is closed and ready to resume.
642 if (sys.state == STATE_SAFETY_DOOR) {
643 if (!(system_check_safety_door_ajar())) {
644 sys.suspend &= ~(SUSPEND_SAFETY_DOOR_AJAR); // Reset door ajar flag to denote ready to resume.
645 }
646 }
647
648 // Handles parking restore and safety door resume.
649 if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
650
651 #ifdef PARKING_ENABLE
652 // Execute fast restore motion to the pull-out position. Parking requires homing enabled.
653 // NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
654 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
655 if (((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
656 (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
657 #else
658 if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
659 #endif
660 // Check to ensure the motion doesn't move below pull-out position.
661 if (parking_target[PARKING_AXIS] <= PARKING_TARGET) {
662 parking_target[PARKING_AXIS] = retract_waypoint;
663 pl_data->feed_rate = PARKING_RATE;
664 mc_parking_motion(parking_target, pl_data);
665 }
666 }
667 #endif
668
669 // Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle.
670 if (gc_state.modal.spindle != SPINDLE_DISABLE) {
671 // Block if safety door re-opened during prior restore actions.
672 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
673 if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
674 // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
675 bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
676 } else {
677 spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
678 delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
679 }
680 }
681 }
682 if (gc_state.modal.coolant != COOLANT_DISABLE) {
683 // Block if safety door re-opened during prior restore actions.
684 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
685 // NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin.
686 coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_MIST)));
687 delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND);
688 }
689 }
690
691 #ifdef PARKING_ENABLE
692 // Execute slow plunge motion from pull-out position to resume position.
693 #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
694 if (((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
695 (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
696 #else
697 if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
698 #endif
699 // Block if safety door re-opened during prior restore actions.
700 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
701 // Regardless if the retract parking motion was a valid/safe motion or not, the
702 // restore parking motion should logically be valid, either by returning to the
703 // original position through valid machine space or by not moving at all.
704 pl_data->feed_rate = PARKING_PULLOUT_RATE;
705 pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state
706 pl_data->spindle_speed = restore_spindle_speed;
707 mc_parking_motion(restore_target, pl_data);
708 }
709 }
710 #endif
711
712 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
713 sys.suspend |= SUSPEND_RESTORE_COMPLETE;
714 system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
715 }
716 }
717
718 }
719
720
721 } else {
722
723 // Feed hold manager. Controls spindle stop override states.
724 // NOTE: Hold ensured as completed by condition check at the beginning of suspend routine.
725 if (sys.spindle_stop_ovr) {
726 // Handles beginning of spindle stop
727 if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
728 if (gc_state.modal.spindle != SPINDLE_DISABLE) {
729 spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
730 sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
731 } else {
732 sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
733 }
734 // Handles restoring of spindle state
735 } else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) {
736 if (gc_state.modal.spindle != SPINDLE_DISABLE) {
737 report_feedback_message(MESSAGE_SPINDLE_RESTORE);
738 if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
739 // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
740 bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
741 } else {
742 spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
743 }
744 }
745 if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
746 system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
747 }
748 sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
749 }
750 } else {
751 // Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
752 // NOTE: STEP_CONTROL_UPDATE_SPINDLE_PWM is automatically reset upon resume in step generator.
753 if (bit_istrue(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
754 spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
755 bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
756 }
757 }
758
759 }
760 }
761
762 protocol_exec_rt_system();
763
764 }
765}