Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 20:45:31 by
 1.7.2
 1.7.2