Sergey Pastor / grbl1
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers protocol.c Source File

protocol.c

00001 /*
00002   protocol.c - controls Grbl execution protocol and procedures
00003   Part of Grbl
00004 
00005   Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
00006   Copyright (c) 2009-2011 Simen Svale Skogsrud
00007 
00008   Grbl is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012 
00013   Grbl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017 
00018   You should have received a copy of the GNU General Public License
00019   along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
00020 */
00021 
00022 #include "grbl.h"
00023 
00024 // Define line flags. Includes comment type tracking and line overflow detection.
00025 #define LINE_FLAG_OVERFLOW bit(0)
00026 #define LINE_FLAG_COMMENT_PARENTHESES bit(1)
00027 #define LINE_FLAG_COMMENT_SEMICOLON bit(2)
00028 
00029 
00030 static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
00031 #ifdef LEDBLINK
00032 void LedBlink(void);
00033 #endif
00034 
00035 static void protocol_exec_rt_suspend();
00036 
00037 
00038 /*
00039   GRBL PRIMARY LOOP:
00040 */
00041 void protocol_main_loop()
00042 {
00043   // Perform some machine checks to make sure everything is good to go.
00044   #ifdef CHECK_LIMITS_AT_INIT
00045     if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
00046       if (limits_get_state()) {
00047         sys.state = STATE_ALARM; // Ensure alarm state is active.
00048         report_feedback_message(MESSAGE_CHECK_LIMITS);
00049       }
00050     }
00051   #endif
00052   // Check for and report alarm state after a reset, error, or an initial power up.
00053   // NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed.
00054   // Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges.
00055   if (sys.state & (STATE_ALARM | STATE_SLEEP)) {
00056     report_feedback_message(MESSAGE_ALARM_LOCK);
00057     sys.state = STATE_ALARM; // Ensure alarm state is set.
00058   } else {
00059     // Check if the safety door is open.
00060     sys.state = STATE_IDLE;
00061     if (system_check_safety_door_ajar()) {
00062       bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
00063       protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state.
00064     }
00065     // All systems go!
00066     system_execute_startup(line); // Execute startup script.
00067   }
00068 
00069   // ---------------------------------------------------------------------------------
00070   // Primary loop! Upon a system abort, this exits back to main() to reset the system.
00071   // This is also where Grbl idles while waiting for something to do.
00072   // ---------------------------------------------------------------------------------
00073 
00074   uint8_t line_flags = 0;
00075   uint8_t char_counter = 0;
00076   uint8_t c;
00077   for (;;) {
00078 
00079     // Process one line of incoming serial data, as the data becomes available. Performs an
00080     // initial filtering by removing spaces and comments and capitalizing all letters.
00081     while((c = serial_read()) != SERIAL_NO_DATA) {
00082       if ((c == '\n') || (c == '\r')) { // End of line reached
00083 
00084         protocol_execute_realtime(); // Runtime command check point.
00085         if (sys.abort) { return; } // Bail to calling function upon system abort
00086 
00087         line[char_counter] = 0; // Set string termination character.
00088 #ifdef LEDBLINK
00089                 LedBlink();
00090 #endif
00091                 #ifdef REPORT_ECHO_LINE_RECEIVED
00092           report_echo_line_received(line);
00093         #endif
00094 
00095         // Direct and execute one line of formatted input, and report status of execution.
00096         if (line_flags & LINE_FLAG_OVERFLOW) {
00097           // Report line overflow error.
00098           report_status_message(STATUS_OVERFLOW);
00099         } else if (line[0] == 0) {
00100           // Empty or comment line. For syncing purposes.
00101           report_status_message(STATUS_OK);
00102         } else if (line[0] == '$') {
00103           // Grbl '$' system command
00104           report_status_message(system_execute_line(line));
00105         } else if (sys.state & (STATE_ALARM | STATE_JOG)) {
00106           // Everything else is gcode. Block if in alarm or jog mode.
00107           report_status_message(STATUS_SYSTEM_GC_LOCK);
00108         } else {
00109           // Parse and execute g-code block.
00110           report_status_message(gc_execute_line(line));
00111         }
00112 
00113         // Reset tracking data for next line.
00114         line_flags = 0;
00115         char_counter = 0;
00116 
00117       } else {
00118 
00119         if (line_flags) {
00120           // Throw away all (except EOL) comment characters and overflow characters.
00121           if (c == ')') {
00122             // End of '()' comment. Resume line allowed.
00123             if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) { line_flags &= ~(LINE_FLAG_COMMENT_PARENTHESES); }
00124           }
00125         } else {
00126           if (c <= ' ') {
00127             // Throw away whitepace and control characters
00128           } else if (c == '/') {
00129             // Block delete NOT SUPPORTED. Ignore character.
00130             // NOTE: If supported, would simply need to check the system if block delete is enabled.
00131           } else if (c == '(') {
00132             // Enable comments flag and ignore all characters until ')' or EOL.
00133             // NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
00134             // In the future, we could simply remove the items within the comments, but retain the
00135             // comment control characters, so that the g-code parser can error-check it.
00136             line_flags |= LINE_FLAG_COMMENT_PARENTHESES;
00137           } else if (c == ';') {
00138             // NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
00139             line_flags |= LINE_FLAG_COMMENT_SEMICOLON;
00140           // TODO: Install '%' feature
00141           // } else if (c == '%') {
00142             // Program start-end percent sign NOT SUPPORTED.
00143             // NOTE: This maybe installed to tell Grbl when a program is running vs manual input,
00144             // where, during a program, the system auto-cycle start will continue to execute
00145             // everything until the next '%' sign. This will help fix resuming issues with certain
00146             // functions that empty the planner buffer to execute its task on-time.
00147           } else if (char_counter >= (LINE_BUFFER_SIZE-1)) {
00148             // Detect line buffer overflow and set flag.
00149             line_flags |= LINE_FLAG_OVERFLOW;
00150           } else if (c >= 'a' && c <= 'z') { // Upcase lowercase
00151             line[char_counter++] = c-'a'+'A';
00152           } else {
00153             line[char_counter++] = c;
00154           }
00155         }
00156 
00157       }
00158     }
00159 
00160     // If there are no more characters in the serial read buffer to be processed and executed,
00161     // this indicates that g-code streaming has either filled the planner buffer or has
00162     // completed. In either case, auto-cycle start, if enabled, any queued moves.
00163     protocol_auto_cycle_start();
00164 
00165     protocol_execute_realtime();  // Runtime command check point.
00166     if (sys.abort) { return; } // Bail to main() program loop to reset system.
00167   }
00168 
00169   return; /* Never reached */
00170 }
00171 
00172 
00173 // Block until all buffered steps are executed or in a cycle state. Works with feed hold
00174 // during a synchronize call, if it should happen. Also, waits for clean cycle end.
00175 void protocol_buffer_synchronize()
00176 {
00177   // If system is queued, ensure cycle resumes if the auto start flag is present.
00178   protocol_auto_cycle_start();
00179   do {
00180     protocol_execute_realtime();   // Check and execute run-time commands
00181     if (sys.abort) { return; } // Check for system abort
00182   } while (plan_get_current_block() || (sys.state == STATE_CYCLE));
00183 }
00184 
00185 
00186 // Auto-cycle start triggers when there is a motion ready to execute and if the main program is not
00187 // actively parsing commands.
00188 // NOTE: This function is called from the main loop, buffer sync, and mc_line() only and executes
00189 // when one of these conditions exist respectively: There are no more blocks sent (i.e. streaming
00190 // is finished, single commands), a command that needs to wait for the motions in the buffer to
00191 // execute calls a buffer sync, or the planner buffer is full and ready to go.
00192 void protocol_auto_cycle_start()
00193 {
00194   if (plan_get_current_block() != NULL) { // Check if there are any blocks in the buffer.
00195     system_set_exec_state_flag(EXEC_CYCLE_START); // If so, execute them!
00196   }
00197 }
00198 
00199 
00200 // This function is the general interface to Grbl's real-time command execution system. It is called
00201 // from various check points in the main program, primarily where there may be a while loop waiting
00202 // for a buffer to clear space or any point where the execution time from the last check point may
00203 // be more than a fraction of a second. This is a way to execute realtime commands asynchronously
00204 // (aka multitasking) with grbl's g-code parsing and planning functions. This function also serves
00205 // as an interface for the interrupts to set the system realtime flags, where only the main program
00206 // handles them, removing the need to define more computationally-expensive volatile variables. This
00207 // also provides a controlled way to execute certain tasks without having two or more instances of
00208 // the same task, such as the planner recalculating the buffer upon a feedhold or overrides.
00209 // NOTE: The sys_rt_exec_state variable flags are set by any process, step or serial interrupts, pinouts,
00210 // limit switches, or the main program.
00211 void protocol_execute_realtime()
00212 {
00213   protocol_exec_rt_system();
00214   if (sys.suspend) { protocol_exec_rt_suspend(); }
00215 }
00216 
00217 
00218 // Executes run-time commands, when required. This function primarily operates as Grbl's state
00219 // machine and controls the various real-time features Grbl has to offer.
00220 // NOTE: Do not alter this unless you know exactly what you are doing!
00221 void protocol_exec_rt_system()
00222 {
00223   uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.
00224   rt_exec = sys_rt_exec_alarm; // Copy volatile sys_rt_exec_alarm.
00225   if (rt_exec) { // Enter only if any bit flag is true
00226     // System alarm. Everything has shutdown by something that has gone severely wrong. Report
00227     // the source of the error to the user. If critical, Grbl disables by entering an infinite
00228     // loop until system reset/abort.
00229     sys.state = STATE_ALARM; // Set system alarm state
00230     report_alarm_message(rt_exec);
00231     // Halt everything upon a critical event flag. Currently hard and soft limits flag this.
00232     if ((rt_exec == EXEC_ALARM_HARD_LIMIT) || (rt_exec == EXEC_ALARM_SOFT_LIMIT)) {
00233       report_feedback_message(MESSAGE_CRITICAL_EVENT);
00234       system_clear_exec_state_flag(EXEC_RESET); // Disable any existing reset
00235       do {
00236         // Block everything, except reset and status reports, until user issues reset or power
00237         // cycles. Hard limits typically occur while unattended or not paying attention. Gives
00238         // the user and a GUI time to do what is needed before resetting, like killing the
00239         // incoming stream. The same could be said about soft limits. While the position is not
00240         // lost, continued streaming could cause a serious crash if by chance it gets executed.
00241       } while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
00242     }
00243     system_clear_exec_alarm(); // Clear alarm
00244   }
00245 
00246   rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
00247   if (rt_exec) {
00248 
00249     // Execute system abort.
00250     if (rt_exec & EXEC_RESET) {
00251       sys.abort = true;  // Only place this is set true.
00252       return; // Nothing else to do but exit.
00253     }
00254 
00255     // Execute and serial print status
00256     if (rt_exec & EXEC_STATUS_REPORT) {
00257       report_realtime_status();
00258       system_clear_exec_state_flag(EXEC_STATUS_REPORT);
00259     }
00260 
00261     // NOTE: Once hold is initiated, the system immediately enters a suspend state to block all
00262     // main program processes until either reset or resumed. This ensures a hold completes safely.
00263     if (rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP)) {
00264 
00265       // State check for allowable states for hold methods.
00266       if (!(sys.state & (STATE_ALARM | STATE_CHECK_MODE))) {
00267       
00268         // If in CYCLE or JOG states, immediately initiate a motion HOLD.
00269         if (sys.state & (STATE_CYCLE | STATE_JOG)) {
00270           if (!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) { // Block, if already holding.
00271             st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
00272             sys.step_control = STEP_CONTROL_EXECUTE_HOLD; // Initiate suspend state with active flag.
00273             if (sys.state == STATE_JOG) { // Jog cancelled upon any hold event, except for sleeping.
00274               if (!(rt_exec & EXEC_SLEEP)) { sys.suspend |= SUSPEND_JOG_CANCEL; } 
00275             }
00276           }
00277         }
00278         // If IDLE, Grbl is not in motion. Simply indicate suspend state and hold is complete.
00279         if (sys.state == STATE_IDLE) { sys.suspend = SUSPEND_HOLD_COMPLETE; }
00280 
00281         // Execute and flag a motion cancel with deceleration and return to idle. Used primarily by probing cycle
00282         // to halt and cancel the remainder of the motion.
00283         if (rt_exec & EXEC_MOTION_CANCEL) {
00284           // MOTION_CANCEL only occurs during a CYCLE, but a HOLD and SAFETY_DOOR may been initiated beforehand
00285           // to hold the CYCLE. Motion cancel is valid for a single planner block motion only, while jog cancel
00286           // will handle and clear multiple planner block motions.
00287           if (!(sys.state & STATE_JOG)) { sys.suspend |= SUSPEND_MOTION_CANCEL; } // NOTE: State is STATE_CYCLE.
00288         }
00289 
00290         // Execute a feed hold with deceleration, if required. Then, suspend system.
00291         if (rt_exec & EXEC_FEED_HOLD) {
00292           // Block SAFETY_DOOR, JOG, and SLEEP states from changing to HOLD state.
00293           if (!(sys.state & (STATE_SAFETY_DOOR | STATE_JOG | STATE_SLEEP))) { sys.state = STATE_HOLD; }
00294         }
00295 
00296         // Execute a safety door stop with a feed hold and disable spindle/coolant.
00297         // NOTE: Safety door differs from feed holds by stopping everything no matter state, disables powered
00298         // devices (spindle/coolant), and blocks resuming until switch is re-engaged.
00299         if (rt_exec & EXEC_SAFETY_DOOR) {
00300           report_feedback_message(MESSAGE_SAFETY_DOOR_AJAR);
00301           // If jogging, block safety door methods until jog cancel is complete. Just flag that it happened.
00302           if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
00303             // Check if the safety re-opened during a restore parking motion only. Ignore if
00304             // already retracting, parked or in sleep state.
00305             if (sys.state == STATE_SAFETY_DOOR) {
00306               if (sys.suspend & SUSPEND_INITIATE_RESTORE) { // Actively restoring
00307                 #ifdef PARKING_ENABLE
00308                   // Set hold and reset appropriate control flags to restart parking sequence.
00309                   if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
00310                     st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
00311                     sys.step_control = (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION);
00312                     sys.suspend &= ~(SUSPEND_HOLD_COMPLETE);
00313                   } // else NO_MOTION is active.
00314                 #endif
00315                 sys.suspend &= ~(SUSPEND_RETRACT_COMPLETE | SUSPEND_INITIATE_RESTORE | SUSPEND_RESTORE_COMPLETE);
00316                 sys.suspend |= SUSPEND_RESTART_RETRACT;
00317               }
00318             }
00319             if (sys.state != STATE_SLEEP) { sys.state = STATE_SAFETY_DOOR; }
00320           }
00321           // NOTE: This flag doesn't change when the door closes, unlike sys.state. Ensures any parking motions
00322           // are executed if the door switch closes and the state returns to HOLD.
00323           sys.suspend |= SUSPEND_SAFETY_DOOR_AJAR;
00324         }
00325         
00326       }
00327 
00328       if (rt_exec & EXEC_SLEEP) {
00329         if (sys.state == STATE_ALARM) { sys.suspend |= (SUSPEND_RETRACT_COMPLETE|SUSPEND_HOLD_COMPLETE); }
00330         sys.state = STATE_SLEEP; 
00331       }
00332 
00333       system_clear_exec_state_flag((EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP));
00334     }
00335 
00336     // Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
00337     if (rt_exec & EXEC_CYCLE_START) {
00338       // Block if called at same time as the hold commands: feed hold, motion cancel, and safety door.
00339       // Ensures auto-cycle-start doesn't resume a hold without an explicit user-input.
00340       if (!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR))) {
00341         // Resume door state when parking motion has retracted and door has been closed.
00342         if ((sys.state == STATE_SAFETY_DOOR) && !(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR)) {
00343           if (sys.suspend & SUSPEND_RESTORE_COMPLETE) {
00344             sys.state = STATE_IDLE; // Set to IDLE to immediately resume the cycle.
00345           } else if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
00346             // Flag to re-energize powered components and restore original position, if disabled by SAFETY_DOOR.
00347             // NOTE: For a safety door to resume, the switch must be closed, as indicated by HOLD state, and
00348             // the retraction execution is complete, which implies the initial feed hold is not active. To
00349             // restore normal operation, the restore procedures must be initiated by the following flag. Once,
00350             // they are complete, it will call CYCLE_START automatically to resume and exit the suspend.
00351             sys.suspend |= SUSPEND_INITIATE_RESTORE;
00352           }
00353         }
00354         // Cycle start only when IDLE or when a hold is complete and ready to resume.
00355         if ((sys.state == STATE_IDLE) || ((sys.state & STATE_HOLD) && (sys.suspend & SUSPEND_HOLD_COMPLETE))) {
00356           if (sys.state == STATE_HOLD && sys.spindle_stop_ovr) {
00357             sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE_CYCLE; // Set to restore in suspend routine and cycle start after.
00358           } else {
00359             // Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
00360             sys.step_control = STEP_CONTROL_NORMAL_OP; // Restore step control to normal operation
00361             if (plan_get_current_block() && bit_isfalse(sys.suspend,SUSPEND_MOTION_CANCEL)) {
00362               sys.suspend = SUSPEND_DISABLE; // Break suspend state.
00363               sys.state = STATE_CYCLE;
00364               st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
00365               st_wake_up();
00366             } else { // Otherwise, do nothing. Set and resume IDLE state.
00367               sys.suspend = SUSPEND_DISABLE; // Break suspend state.
00368               sys.state = STATE_IDLE;
00369             }
00370           }
00371         }
00372       }
00373       system_clear_exec_state_flag(EXEC_CYCLE_START);
00374     }
00375 
00376     if (rt_exec & EXEC_CYCLE_STOP) {
00377       // Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
00378       // realtime command execution in the main program, ensuring that the planner re-plans safely.
00379       // NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
00380       // cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
00381       // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
00382       if ((sys.state & (STATE_HOLD|STATE_SAFETY_DOOR|STATE_SLEEP)) && !(sys.soft_limit) && !(sys.suspend & SUSPEND_JOG_CANCEL)) {
00383         // Hold complete. Set to indicate ready to resume.  Remain in HOLD or DOOR states until user
00384         // has issued a resume command or reset.
00385         plan_cycle_reinitialize();
00386         if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { sys.suspend |= SUSPEND_HOLD_COMPLETE; }
00387         bit_false(sys.step_control,(STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION));
00388       } else {
00389         // Motion complete. Includes CYCLE/JOG/HOMING states and jog cancel/motion cancel/soft limit events.
00390         // NOTE: Motion and jog cancel both immediately return to idle after the hold completes.
00391         if (sys.suspend & SUSPEND_JOG_CANCEL) {   // For jog cancel, flush buffers and sync positions.
00392           sys.step_control = STEP_CONTROL_NORMAL_OP;
00393           plan_reset();
00394           st_reset();
00395           gc_sync_position();
00396           plan_sync_position();
00397         }
00398         if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) { // Only occurs when safety door opens during jog.
00399           sys.suspend &= ~(SUSPEND_JOG_CANCEL);
00400           sys.suspend |= SUSPEND_HOLD_COMPLETE;
00401           sys.state = STATE_SAFETY_DOOR;
00402         } else {
00403           sys.suspend = SUSPEND_DISABLE;
00404           sys.state = STATE_IDLE;
00405         }
00406       }
00407       system_clear_exec_state_flag(EXEC_CYCLE_STOP);
00408     }
00409   }
00410 
00411   // Execute overrides.
00412   rt_exec = sys_rt_exec_motion_override; // Copy volatile sys_rt_exec_motion_override
00413   if (rt_exec) {
00414     system_clear_exec_motion_overrides(); // Clear all motion override flags.
00415 
00416     uint8_t new_f_override =  sys.f_override;
00417     if (rt_exec & EXEC_FEED_OVR_RESET) { new_f_override = DEFAULT_FEED_OVERRIDE; }
00418     if (rt_exec & EXEC_FEED_OVR_COARSE_PLUS) { new_f_override += FEED_OVERRIDE_COARSE_INCREMENT; }
00419     if (rt_exec & EXEC_FEED_OVR_COARSE_MINUS) { new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT; }
00420     if (rt_exec & EXEC_FEED_OVR_FINE_PLUS) { new_f_override += FEED_OVERRIDE_FINE_INCREMENT; }
00421     if (rt_exec & EXEC_FEED_OVR_FINE_MINUS) { new_f_override -= FEED_OVERRIDE_FINE_INCREMENT; }
00422     new_f_override = min(new_f_override,MAX_FEED_RATE_OVERRIDE);
00423     new_f_override = max(new_f_override,MIN_FEED_RATE_OVERRIDE);
00424 
00425     uint8_t new_r_override = sys.r_override;
00426     if (rt_exec & EXEC_RAPID_OVR_RESET) { new_r_override = DEFAULT_RAPID_OVERRIDE; }
00427     if (rt_exec & EXEC_RAPID_OVR_MEDIUM) { new_r_override = RAPID_OVERRIDE_MEDIUM; }
00428     if (rt_exec & EXEC_RAPID_OVR_LOW) { new_r_override = RAPID_OVERRIDE_LOW; }
00429 
00430     if ((new_f_override != sys.f_override) || (new_r_override != sys.r_override)) {
00431       sys.f_override = new_f_override;
00432       sys.r_override = new_r_override;
00433       sys.report_ovr_counter = 0; // Set to report change immediately
00434       plan_update_velocity_profile_parameters();
00435       plan_cycle_reinitialize();
00436     }
00437   }
00438 
00439   rt_exec = sys_rt_exec_accessory_override;
00440   if (rt_exec) {
00441     system_clear_exec_accessory_overrides(); // Clear all accessory override flags.
00442 
00443     // NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
00444     uint8_t last_s_override =  sys.spindle_speed_ovr;
00445     if (rt_exec & EXEC_SPINDLE_OVR_RESET) { last_s_override = DEFAULT_SPINDLE_SPEED_OVERRIDE; }
00446     if (rt_exec & EXEC_SPINDLE_OVR_COARSE_PLUS) { last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT; }
00447     if (rt_exec & EXEC_SPINDLE_OVR_COARSE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT; }
00448     if (rt_exec & EXEC_SPINDLE_OVR_FINE_PLUS) { last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT; }
00449     if (rt_exec & EXEC_SPINDLE_OVR_FINE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT; }
00450     last_s_override = min(last_s_override,MAX_SPINDLE_SPEED_OVERRIDE);
00451     last_s_override = max(last_s_override,MIN_SPINDLE_SPEED_OVERRIDE);
00452 
00453     if (last_s_override != sys.spindle_speed_ovr) {
00454       bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
00455       sys.spindle_speed_ovr = last_s_override;
00456       sys.report_ovr_counter = 0; // Set to report change immediately
00457     }
00458 
00459     if (rt_exec & EXEC_SPINDLE_OVR_STOP) {
00460       // Spindle stop override allowed only while in HOLD state.
00461       // NOTE: Report counters are set in spindle_set_state() when spindle stop is executed.
00462       if (sys.state == STATE_HOLD) {
00463         if (!(sys.spindle_stop_ovr)) { sys.spindle_stop_ovr = SPINDLE_STOP_OVR_INITIATE; }
00464         else if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_ENABLED) { sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE; }
00465       }
00466     }
00467 
00468     // NOTE: Since coolant state always performs a planner sync whenever it changes, the current
00469     // run state can be determined by checking the parser state.
00470     if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
00471       if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) {
00472         uint8_t coolant_state = gc_state.modal.coolant;
00473         #ifdef ENABLE_M7
00474           if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
00475             if (coolant_state & COOLANT_MIST_ENABLE) { bit_false(coolant_state,COOLANT_MIST_ENABLE); }
00476             else { coolant_state |= COOLANT_MIST_ENABLE; }
00477           }
00478           if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE) {
00479             if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
00480             else { coolant_state |= COOLANT_FLOOD_ENABLE; }
00481           }
00482         #else
00483           if (coolant_state & COOLANT_FLOOD_ENABLE) { bit_false(coolant_state,COOLANT_FLOOD_ENABLE); }
00484           else { coolant_state |= COOLANT_FLOOD_ENABLE; }
00485         #endif
00486         coolant_set_state(coolant_state); // Report counter set in coolant_set_state().
00487         gc_state.modal.coolant = coolant_state;
00488       }
00489     }
00490   }
00491 
00492   #ifdef DEBUG
00493     if (sys_rt_exec_debug) {
00494       report_realtime_debug();
00495       sys_rt_exec_debug = 0;
00496     }
00497   #endif
00498 
00499   // Reload step segment buffer
00500   if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG)) {
00501     st_prep_buffer();
00502   }
00503 
00504 }
00505 
00506 
00507 // Handles Grbl system suspend procedures, such as feed hold, safety door, and parking motion.
00508 // The system will enter this loop, create local variables for suspend tasks, and return to
00509 // whatever function that invoked the suspend, such that Grbl resumes normal operation.
00510 // This function is written in a way to promote custom parking motions. Simply use this as a
00511 // template
00512 static void protocol_exec_rt_suspend()
00513 {
00514   #ifdef PARKING_ENABLE
00515     // Declare and initialize parking local variables
00516     float restore_target[N_AXIS];
00517     float parking_target[N_AXIS];
00518     float retract_waypoint = PARKING_PULLOUT_INCREMENT;
00519     plan_line_data_t plan_data;
00520     plan_line_data_t *pl_data = &plan_data;
00521     memset(pl_data,0,sizeof(plan_line_data_t));
00522     pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
00523     #ifdef USE_LINE_NUMBERS
00524       pl_data->line_number = PARKING_MOTION_LINE_NUMBER;
00525     #endif
00526   #endif
00527 
00528   plan_block_t *block = plan_get_current_block();
00529   uint8_t restore_condition;
00530   #ifdef VARIABLE_SPINDLE
00531     float restore_spindle_speed;
00532     if (block == NULL) {
00533       restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant);
00534       restore_spindle_speed = gc_state.spindle_speed;
00535     } else {
00536       restore_condition = block->condition;
00537       restore_spindle_speed = block->spindle_speed;
00538     }
00539     #ifdef DISABLE_LASER_DURING_HOLD
00540       if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) {
00541         system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
00542       }
00543     #endif
00544   #else
00545     if (block == NULL) { restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant); }
00546     else { restore_condition = block->condition; }
00547   #endif
00548 
00549   while (sys.suspend) {
00550 
00551     if (sys.abort) { return; }
00552 
00553     // Block until initial hold is complete and the machine has stopped motion.
00554     if (sys.suspend & SUSPEND_HOLD_COMPLETE) {
00555 
00556       // Parking manager. Handles de/re-energizing, switch state checks, and parking motions for 
00557       // the safety door and sleep states.
00558       if (sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP)) {
00559       
00560         // Handles retraction motions and de-energizing.
00561         if (bit_isfalse(sys.suspend,SUSPEND_RETRACT_COMPLETE)) {
00562 
00563           // Ensure any prior spindle stop override is disabled at start of safety door routine.
00564           sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED;
00565 
00566           #ifndef PARKING_ENABLE
00567 
00568             spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
00569             coolant_set_state(COOLANT_DISABLE);     // De-energize
00570 
00571           #else
00572                     
00573             // Get current position and store restore location and spindle retract waypoint.
00574             system_convert_array_steps_to_mpos(parking_target,sys_position);
00575             if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
00576               memcpy(restore_target,parking_target,sizeof(parking_target));
00577               retract_waypoint += restore_target[PARKING_AXIS];
00578               retract_waypoint = min(retract_waypoint,PARKING_TARGET);
00579             }
00580 
00581             // Execute slow pull-out parking retract motion. Parking requires homing enabled, the
00582             // current location not exceeding the parking target location, and laser mode disabled.
00583             // NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
00584                         #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
00585                         if ((bit_istrue(settings.flags, BITFLAG_HOMING_ENABLE)) &&
00586                                                         (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
00587                                                         bit_isfalse(settings.flags, BITFLAG_LASER_MODE) &&
00588                                                         (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
00589                         #else
00590                         if ((bit_istrue(settings.flags, BITFLAG_HOMING_ENABLE)) &&
00591                                                         (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
00592                                                         bit_isfalse(settings.flags, BITFLAG_LASER_MODE)) {
00593                         #endif
00594                             // Retract spindle by pullout distance. Ensure retraction motion moves away from
00595               // the workpiece and waypoint motion doesn't exceed the parking target location.
00596               if (parking_target[PARKING_AXIS] < retract_waypoint) {
00597                 parking_target[PARKING_AXIS] = retract_waypoint;
00598                 pl_data->feed_rate = PARKING_PULLOUT_RATE;
00599                 pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Retain accessory state
00600                 pl_data->spindle_speed = restore_spindle_speed;
00601                 mc_parking_motion(parking_target, pl_data);
00602               }
00603 
00604               // NOTE: Clear accessory state after retract and after an aborted restore motion.
00605               pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
00606               pl_data->spindle_speed = 0.0f;
00607               spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
00608               coolant_set_state(COOLANT_DISABLE); // De-energize
00609 
00610               // Execute fast parking retract motion to parking target location.
00611               if (parking_target[PARKING_AXIS] < PARKING_TARGET) {
00612                 parking_target[PARKING_AXIS] = PARKING_TARGET;
00613                 pl_data->feed_rate = PARKING_RATE;
00614                 mc_parking_motion(parking_target, pl_data);
00615               }
00616 
00617             } else {
00618 
00619               // Parking motion not possible. Just disable the spindle and coolant.
00620               // NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
00621               spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
00622               coolant_set_state(COOLANT_DISABLE);     // De-energize
00623 
00624             }
00625 
00626           #endif
00627 
00628           sys.suspend &= ~(SUSPEND_RESTART_RETRACT);
00629           sys.suspend |= SUSPEND_RETRACT_COMPLETE;
00630 
00631         } else {
00632 
00633           
00634           if (sys.state == STATE_SLEEP) {
00635             report_feedback_message(MESSAGE_SLEEP_MODE);
00636             // Spindle and coolant should already be stopped, but do it again just to be sure.
00637             spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
00638             coolant_set_state(COOLANT_DISABLE); // De-energize
00639             st_go_idle(); // Disable steppers
00640             while (!(sys.abort)) { protocol_exec_rt_system(); } // Do nothing until reset.
00641             return; // Abort received. Return to re-initialize.
00642           }    
00643           
00644           // Allows resuming from parking/safety door. Actively checks if safety door is closed and ready to resume.
00645           if (sys.state == STATE_SAFETY_DOOR) {
00646             if (!(system_check_safety_door_ajar())) {
00647               sys.suspend &= ~(SUSPEND_SAFETY_DOOR_AJAR); // Reset door ajar flag to denote ready to resume.
00648             }
00649           }
00650 
00651           // Handles parking restore and safety door resume.
00652           if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
00653 
00654             #ifdef PARKING_ENABLE
00655               // Execute fast restore motion to the pull-out position. Parking requires homing enabled.
00656               // NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
00657                             #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
00658                             if (((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
00659                                      (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
00660                             #else
00661                             if ((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
00662                             #endif
00663                 // Check to ensure the motion doesn't move below pull-out position.
00664                 if (parking_target[PARKING_AXIS] <= PARKING_TARGET) {
00665                   parking_target[PARKING_AXIS] = retract_waypoint;
00666                   pl_data->feed_rate = PARKING_RATE;
00667                   mc_parking_motion(parking_target, pl_data);
00668                 }
00669               }
00670             #endif
00671 
00672             // Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle.
00673             if (gc_state.modal.spindle != SPINDLE_DISABLE) {
00674               // Block if safety door re-opened during prior restore actions.
00675               if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
00676                 if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
00677                   // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
00678                   bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
00679                 } else {
00680                   spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
00681                   delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
00682                 }
00683               }
00684             }
00685             if (gc_state.modal.coolant != COOLANT_DISABLE) {
00686               // Block if safety door re-opened during prior restore actions.
00687               if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
00688                 // NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin.
00689                 coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_FLOOD)));
00690                 delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND);
00691               }
00692             }
00693 
00694             #ifdef PARKING_ENABLE
00695               // Execute slow plunge motion from pull-out position to resume position.
00696                         #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
00697                         if (((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
00698                                     (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
00699                             #else
00700                             if ((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
00701                             #endif
00702                 // Block if safety door re-opened during prior restore actions.
00703                 if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
00704                   // Regardless if the retract parking motion was a valid/safe motion or not, the
00705                   // restore parking motion should logically be valid, either by returning to the
00706                   // original position through valid machine space or by not moving at all.
00707                   pl_data->feed_rate = PARKING_PULLOUT_RATE;
00708                                     pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state
00709                                     pl_data->spindle_speed = restore_spindle_speed;
00710                   mc_parking_motion(restore_target, pl_data);
00711                 }
00712               }
00713             #endif
00714 
00715             if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
00716               sys.suspend |= SUSPEND_RESTORE_COMPLETE;
00717               system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
00718             }
00719           }
00720 
00721         }
00722 
00723 
00724       } else {
00725 
00726         // Feed hold manager. Controls spindle stop override states.
00727         // NOTE: Hold ensured as completed by condition check at the beginning of suspend routine.
00728         if (sys.spindle_stop_ovr) {
00729           // Handles beginning of spindle stop
00730           if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
00731             if (gc_state.modal.spindle != SPINDLE_DISABLE) {
00732               spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
00733               sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
00734             } else {
00735               sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
00736             }
00737           // Handles restoring of spindle state
00738           } else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) {
00739             if (gc_state.modal.spindle != SPINDLE_DISABLE) {
00740               report_feedback_message(MESSAGE_SPINDLE_RESTORE);
00741               if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
00742                 // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
00743                 bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
00744               } else {
00745                 spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
00746               }
00747             }
00748             if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
00749               system_set_exec_state_flag(EXEC_CYCLE_START);  // Set to resume program.
00750             }
00751             sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
00752           }
00753         } else {
00754           // Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
00755           // NOTE: STEP_CONTROL_UPDATE_SPINDLE_PWM is automatically reset upon resume in step generator.
00756           if (bit_istrue(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
00757             spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
00758             bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
00759           }
00760         }
00761 
00762       }
00763     }
00764 
00765     protocol_exec_rt_system();
00766 
00767   }
00768 }