diff --git a/config.h b/config.h index ae48023..dca6c86 100755 --- a/config.h +++ b/config.h @@ -164,7 +164,7 @@ // and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may // be stored and executed in order. These startup blocks would typically be used to set the g-code // parser state depending on user preferences. -#define N_STARTUP_LINE 1 // Integer (1-5) +#define N_STARTUP_LINE 3 // Integer (1-5) // --------------------------------------------------------------------------------------- // FOR ADVANCED USERS ONLY: diff --git a/gcode.c b/gcode.c index b56e241..56e29fb 100755 --- a/gcode.c +++ b/gcode.c @@ -410,9 +410,7 @@ uint8_t gc_execute_line(char *line) break; case MOTION_MODE_SEEK: if (!axis_words) { FAIL(STATUS_INVALID_STATEMENT);} - else { - mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], gc.seek_rate, false); - } + else { mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], gc.seek_rate, false); } break; case MOTION_MODE_LINEAR: // TODO: Inverse time requires F-word with each statement. Need to do a check. Also need diff --git a/main.c b/main.c index 43abb64..5e9ecb3 100755 --- a/main.c +++ b/main.c @@ -51,7 +51,7 @@ int main(void) memset(&sys, 0, sizeof(sys)); // Clear all system variables sys.abort = true; // Set abort to complete initialization - sys.state = STATE_LOST; // Set state to indicate unknown initial position + sys.state = STATE_ALARM; // Set alarm state to indicate unknown initial position for(;;) { @@ -59,11 +59,6 @@ int main(void) // Once here, it is safe to re-initialize the system. At startup, the system will automatically // reset to finish the initialization process. if (sys.abort) { - // If a critical event has occurred, set the position lost system state. For example, a - // hard limit event can cause the stepper to lose steps and position due to an immediate - // stop, not with a controlled deceleration. Or, if an abort was issued while a cycle - // was active, the immediate stop can also cause lost steps. - if (sys.state == STATE_ALARM) { sys.state = STATE_LOST; } // Reset system. serial_reset_read_buffer(); // Clear serial read buffer @@ -84,11 +79,15 @@ int main(void) // resume. sys_sync_current_position(); - // Reset system variables + // Reset system variables. sys.abort = false; sys.execute = 0; - if (sys.state == STATE_LOST && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { - report_feedback_message(MESSAGE_POSITION_LOST); + if (sys.state == STATE_ALARM && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { + // If a critical event has occurred, set the position lost system state. For example, a + // hard limit event can cause the stepper to lose steps and position due to an immediate + // stop, not with a controlled deceleration. Or, if an abort was issued while a cycle + // was active, the immediate stop can also cause lost steps. + report_feedback_message(MESSAGE_HOMING_ALARM); } else { sys.state = STATE_IDLE; } diff --git a/motion_control.c b/motion_control.c index a7d4295..995d27c 100755 --- a/motion_control.c +++ b/motion_control.c @@ -215,7 +215,7 @@ void mc_go_home() limits_go_home(); // Perform homing routine. if (sys.abort) { - sys.state = STATE_LOST; // Homing routine did not complete. + sys.state = STATE_ALARM; // Homing routine did not complete. return; } @@ -253,7 +253,8 @@ void mc_alarm() // Only this function can set the system alarm. This is done to prevent multiple kill calls // by different processes. if (bit_isfalse(sys.execute, EXEC_ALARM)) { - // Set system alarm flag. + // Set system alarm flag to have the main program check for anything wrong with shutting + // down the system. sys.execute |= EXEC_ALARM; // Immediately force stepper, spindle, and coolant to stop. st_go_idle(); diff --git a/nuts_bolts.h b/nuts_bolts.h index 7438660..7b00210 100755 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -75,9 +75,8 @@ #define STATE_HOLD 3 // Executing feed hold #define STATE_HOMING 4 // Performing homing cycle #define STATE_JOG 5 // Jogging mode is unique like homing. -#define STATE_ALARM 6 // In alarm state. Locks out all but reset -#define STATE_LOST 7 // Used to message position may be lost upon startup or event -#define STATE_LIMIT 8 // Used to message hard limit triggered. +#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes and messages position lost +#define STATE_LIMIT 7 // Used to message hard limit triggered. // Define global system variables typedef struct { diff --git a/protocol.c b/protocol.c index cae64cb..aa84bfc 100755 --- a/protocol.c +++ b/protocol.c @@ -102,22 +102,25 @@ void protocol_execute_runtime() if (sys.execute) { // Enter only if any bit flag is true uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times - // System alarm. Something has gone wrong. Disable everything by entering an infinite - // loop until system reset/abort. + // System alarm. Everything has shutdown by either something that has gone wrong or issuing + // the Grbl soft-reset/abort. Check the system states to report any critical error found. + // If critical, disable Grbl by entering an infinite loop until system reset/abort. + // NOTE: The system alarm state is also used to set if (rt_exec & EXEC_ALARM) { - // Report the cause of the alarm here in the main program. - if (sys.state == STATE_LIMIT) { report_status_message(STATUS_HARD_LIMIT); } - if (sys.state == STATE_CYCLE) { // Pick up abort during active cycle. - report_status_message(STATUS_ABORT_CYCLE); - sys.state = STATE_LOST; - } - // Ignore loop if reset is already issued. In other words, a normal system abort/reset - // will not enter this loop, only a critical event not controlled by the user will. - if (bit_isfalse(rt_exec,EXEC_RESET)) { + // Limit switch critical event. Lock out Grbl until reset. + if (sys.state == STATE_LIMIT) { + report_status_message(STATUS_HARD_LIMIT); sys.state = STATE_ALARM; - report_feedback_message(MESSAGE_SYSTEM_ALARM); + report_feedback_message(MESSAGE_CRITICAL_EVENT); while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); } } + + // Check if a runtime abort command was issued during a cycle. If so, message the user + // that position may have been lost and set alarm state to force re-homing, if enabled. + if (sys.state == STATE_CYCLE) { + report_status_message(STATUS_ABORT_CYCLE); + sys.state = STATE_ALARM; + } bit_false(sys.execute,EXEC_ALARM); } @@ -193,8 +196,8 @@ uint8_t protocol_execute_line(char *line) case 'H' : // Perform homing cycle if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { // Only perform homing if Grbl is idle or lost. - if ( sys.state==STATE_IDLE || sys.state==STATE_LOST ) { mc_go_home(); } - else { return(STATUS_HOMING_ERROR); } + if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) { mc_go_home(); } + else { return(STATUS_IDLE_ERROR); } } else { return(STATUS_SETTING_DISABLED); } break; // case 'J' : break; // Jogging methods @@ -210,49 +213,47 @@ uint8_t protocol_execute_line(char *line) // block buffer without having the planner plan them. It would need to manage de/ac-celerations // on its own carefully. This approach could be effective and possibly size/memory efficient. case 'S' : // Switch modes - if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } // Set helper_var as switch bitmask or clearing flag switch (line[++char_counter]) { - case '0' : - helper_var = BITFLAG_CHECK_GCODE; - // If check mode is being disabled, automatically soft reset Grbl to ensure the user starts - // fresh with the g-code modes in their default, known state. - if (bit_istrue(gc.switches,helper_var)) { sys.execute |= EXEC_RESET; } - break; - case '1' : - helper_var = BITFLAG_DRY_RUN; - // If dry run is being disabled, automatically soft reset Grbl as with check g-code mode - if (bit_istrue(gc.switches,helper_var)) { - // If disabled while in cycle, immediately stop everything and notify user that stopping - // mid-cycle likely lost position. - if (bit_istrue(sys.state,STATE_CYCLE)) { mc_alarm(); } - sys.execute |= EXEC_RESET; // Soft-reset Grbl. - } - break; + case '0' : helper_var = BITFLAG_CHECK_GCODE; break; + case '1' : helper_var = BITFLAG_DRY_RUN; break; case '2' : helper_var = BITFLAG_BLOCK_DELETE; break; case '3' : helper_var = BITFLAG_SINGLE_BLOCK; break; case '4' : helper_var = BITFLAG_OPT_STOP; break; default : return(STATUS_INVALID_STATEMENT); } - gc.switches ^= helper_var; - if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_SWITCH_ON); } - else { report_feedback_message(MESSAGE_SWITCH_OFF); } - break; - case 'P' : // Purge system if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } - if (sys.state == STATE_CYCLE) { return(STATUS_PURGE_CYCLE); } // Also prevents position error - plan_reset_buffer(); - if (sys.state == STATE_LOST) { - report_feedback_message(MESSAGE_PURGE_AXES_LOCK); - sys_sync_current_position(); // Any motion commands during a lock can unsync position vectors. + if ( helper_var & (BITFLAG_CHECK_GCODE | BITFLAG_DRY_RUN) ) { + if ( bit_istrue(gc.switches,helper_var) ) { + // Perform reset and check for cycle when toggling off. If disabled while in cycle, + // immediately stop everything and notify user that stopping mid-cycle and likely + // lost position. In check g-code mode, there is never a cycle. + if (sys.state == STATE_CYCLE) { mc_alarm(); } + sys.execute |= EXEC_RESET; // Soft-reset Grbl. + } else { + // Check if Grbl is idle and ready or if the other mode is enabled. + if (sys.state) { return(STATUS_IDLE_ERROR); } + if ((gc.switches & (BITFLAG_CHECK_GCODE | BITFLAG_DRY_RUN)) & ~(helper_var)) { return(STATUS_INVALID_STATEMENT); } + } + } + gc.switches ^= helper_var; + if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); } + else { report_feedback_message(MESSAGE_DISABLED); } + break; + case 'U' : // Disable homing lock + if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } + if (sys.state == STATE_ALARM) { + report_feedback_message(MESSAGE_HOMING_UNLOCK); + sys.state = STATE_IDLE; + } else { + return(STATUS_SETTING_DISABLED); } - sys.state = STATE_IDLE; break; case 'N' : // Startup lines. if ( line[++char_counter] == 0 ) { // Print startup lines for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { if (!(settings_read_startup_line(helper_var, line))) { - report_status_message(STATUS_SETTING_READ_FAIL); + report_status_message(STATUS_SETTING_READ_FAIL); } else { report_startup_line(helper_var,line); } @@ -287,12 +288,17 @@ uint8_t protocol_execute_line(char *line) return(STATUS_OK); // If '$' command makes it to here, then everything's ok. } else { - - return(gc_execute_line(line)); // Everything else is gcode - // TODO: Install option to set system alarm upon any error code received back from the - // the g-code parser. This is a common safety feature on CNCs to help prevent crashes - // if the g-code doesn't perform as intended. - + + // If homing is enabled and position is lost, lock out all g-code commands. + if (sys.state != STATE_ALARM) { + return(gc_execute_line(line)); // Everything else is gcode + // TODO: Install option to set system alarm upon any error code received back from the + // the g-code parser. This is a common safety feature on CNCs to help prevent crashes + // if the g-code doesn't perform as intended. + } else { + return(STATUS_HOMING_LOCK); + } + } } diff --git a/report.c b/report.c index d336677..1407a7f 100644 --- a/report.c +++ b/report.c @@ -63,7 +63,7 @@ void report_status_message(uint8_t status_code) case STATUS_INVALID_STATEMENT: printPgmString(PSTR("Invalid statement")); break; case STATUS_HARD_LIMIT: - printPgmString(PSTR("Limit triggered")); break; + printPgmString(PSTR("Limit triggered. MPos lost?")); break; case STATUS_SETTING_DISABLED: printPgmString(PSTR("Setting disabled")); break; case STATUS_SETTING_VALUE_NEG: @@ -72,12 +72,12 @@ void report_status_message(uint8_t status_code) printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break; case STATUS_SETTING_READ_FAIL: printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break; - case STATUS_HOMING_ERROR: - printPgmString(PSTR("Must be idle to home")); break; + case STATUS_IDLE_ERROR: + printPgmString(PSTR("Must be idle to execute")); break; case STATUS_ABORT_CYCLE: - printPgmString(PSTR("Abort during cycle. Position maybe lost")); break; - case STATUS_PURGE_CYCLE: - printPgmString(PSTR("Can't purge buffer during cycle")); break; + printPgmString(PSTR("Abort during cycle. MPos lost?")); break; + case STATUS_HOMING_LOCK: + printPgmString(PSTR("Locked until homed")); break; } printPgmString(PSTR("\r\n")); } @@ -94,18 +94,16 @@ void report_feedback_message(int8_t message_code) { printPgmString(PSTR("[")); switch(message_code) { - case MESSAGE_SYSTEM_ALARM: - printPgmString(PSTR("ALARM: Check and reset Grbl")); break; - case MESSAGE_POSITION_LOST: - printPgmString(PSTR("'$H' to home and enable axes")); break; - case MESSAGE_HOMING_ENABLE: - printPgmString(PSTR("WARNING: All limit switches must be installed before homing")); break; - case MESSAGE_SWITCH_ON: - printPgmString(PSTR("Switch enabled")); break; - case MESSAGE_SWITCH_OFF: - printPgmString(PSTR("Switch disabled")); break; - case MESSAGE_PURGE_AXES_LOCK: - printPgmString(PSTR("WARNING: Motion lock disabled. Position unknown.")); break; + case MESSAGE_CRITICAL_EVENT: + printPgmString(PSTR("ALARM: Check and reset")); break; + case MESSAGE_HOMING_ALARM: + printPgmString(PSTR("'$H' to home and unlock")); break; + case MESSAGE_ENABLED: + printPgmString(PSTR("Enabled")); break; + case MESSAGE_DISABLED: + printPgmString(PSTR("Disabled")); break; + case MESSAGE_HOMING_UNLOCK: + printPgmString(PSTR("Unlocked. MPos lost?")); break; } printPgmString(PSTR("]\r\n")); } @@ -131,7 +129,7 @@ void report_grbl_help() { "$S2 (toggle block delete)\r\n" "$S3 (toggle single block)\r\n" "$S4 (toggle optional stop)\r\n" - "$P (purge buffer and locks)\r\n" + "$U (disable homing lock)\r\n" "$H (perform homing cycle)\r\n" "~ (cycle start)\r\n" "! (feed hold)\r\n" diff --git a/report.h b/report.h index 810d199..4d8c471 100644 --- a/report.h +++ b/report.h @@ -34,17 +34,16 @@ #define STATUS_SETTING_VALUE_NEG 9 #define STATUS_SETTING_STEP_PULSE_MIN 10 #define STATUS_SETTING_READ_FAIL 11 -#define STATUS_HOMING_ERROR 12 +#define STATUS_IDLE_ERROR 12 #define STATUS_ABORT_CYCLE 13 -#define STATUS_PURGE_CYCLE 14 +#define STATUS_HOMING_LOCK 14 // Define Grbl feedback message codes. Less than zero to distinguish message from error. -#define MESSAGE_SYSTEM_ALARM -1 -#define MESSAGE_POSITION_LOST -2 -#define MESSAGE_HOMING_ENABLE -3 -#define MESSAGE_SWITCH_ON -4 -#define MESSAGE_SWITCH_OFF -5 -#define MESSAGE_PURGE_AXES_LOCK -6 +#define MESSAGE_CRITICAL_EVENT -1 +#define MESSAGE_HOMING_ALARM -2 +#define MESSAGE_ENABLED -3 +#define MESSAGE_DISABLED -4 +#define MESSAGE_HOMING_UNLOCK -5 // Prints system status messages. void report_status_message(uint8_t status_code); diff --git a/settings.c b/settings.c index 1deb732..2e22ea6 100644 --- a/settings.c +++ b/settings.c @@ -202,9 +202,8 @@ uint8_t settings_store_global_setting(int parameter, float value) { case 14: if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; - sys.state = STATE_LOST; - report_feedback_message(MESSAGE_POSITION_LOST); - report_feedback_message(MESSAGE_HOMING_ENABLE); + sys.state = STATE_ALARM; + report_feedback_message(MESSAGE_HOMING_ALARM); } else { settings.flags &= ~BITFLAG_HOMING_ENABLE; } break; case 15: settings.homing_dir_mask = trunc(value); break;