diff --git a/g2core/alarm.cpp b/g2core/alarm.cpp index f257b508..1949e6b5 100644 --- a/g2core/alarm.cpp +++ b/g2core/alarm.cpp @@ -178,7 +178,7 @@ stat_t cm_alarm(const stat_t status, const char *msg) (cm->machine_state == MACHINE_PANIC)) { return (STAT_OK); // don't alarm if already in an alarm state } - cm_request_feedhold(FEEDHOLD_TYPE_SKIP, FEEDHOLD_EXIT_ALARM); // fast stop and alarm + cm_request_feedhold(FEEDHOLD_TYPE_HOLD, FEEDHOLD_EXIT_ALARM); // fast stop and alarm rpt_exception(status, msg); // send alarm message sr_request_status_report(SR_REQUEST_TIMED); return (status); @@ -206,12 +206,11 @@ stat_t cm_shutdown(const stat_t status, const char *msg) if ((cm->machine_state == MACHINE_SHUTDOWN) || (cm->machine_state == MACHINE_PANIC)) { return (STAT_OK); // don't shutdown if shutdown or panic'd } - cm_request_feedhold(FEEDHOLD_TYPE_SKIP, FEEDHOLD_EXIT_SHUTDOWN); // fast stop and shutdown + cm_request_feedhold(FEEDHOLD_TYPE_HOLD, FEEDHOLD_EXIT_SHUTDOWN); // fast stop and shutdown spindle_reset(); // stop spindle immediately and set speed to 0 RPM coolant_reset(); // stop coolant immediately temperature_reset(); // turn off heaters and fans - // cm_queue_flush(&cm1); // flush all queues and reset positions for (uint8_t i = 0; i < HOMING_AXES; i++) { // unhome axes and the machine cm->homed[i] = false; diff --git a/g2core/canonical_machine.h b/g2core/canonical_machine.h index c3957ae4..c71b4852 100644 --- a/g2core/canonical_machine.h +++ b/g2core/canonical_machine.h @@ -550,11 +550,14 @@ bool cm_has_hold(void); // has hold in p stat_t cm_homing_cycle_start(const float axes[], const bool flags[]); // G28.2 stat_t cm_homing_cycle_start_no_set(const float axes[], const bool flags[]); // G28.4 stat_t cm_homing_cycle_callback(void); // G28.2/.4 main loop callback +void cm_abort_homing(cmMachine_t *_cm); // called from the queue flush sequence to clean up // Probe cycles stat_t cm_straight_probe(float target[], bool flags[], // G38.x bool trip_sense, bool alarm_flag); stat_t cm_probing_cycle_callback(void); // G38.x main loop callback +void cm_abort_probing(cmMachine_t *_cm); // called from the queue flush sequence to clean up + stat_t cm_get_prbr(nvObj_t *nv); // enable/disable probe report stat_t cm_set_prbr(nvObj_t *nv); diff --git a/g2core/cycle_feedhold.cpp b/g2core/cycle_feedhold.cpp index f1d793b7..dffdca4f 100644 --- a/g2core/cycle_feedhold.cpp +++ b/g2core/cycle_feedhold.cpp @@ -322,14 +322,24 @@ static stat_t _run_reset_position() return (STAT_OK); } -static stat_t _run_alarm() { +stat_t _run_job_kill(); + +stat_t _run_alarm() { + if (cm1.hold_state == FEEDHOLD_HOLD) { + _run_job_kill(); + } else { + return (STAT_EAGAIN); + } cm1.machine_state = MACHINE_ALARM; - cm1.hold_exit = FEEDHOLD_EXIT_END; return (STAT_OK); } -static stat_t _run_shutdown() { +stat_t _run_shutdown() { + if (cm1.hold_state == FEEDHOLD_HOLD) { + _run_job_kill(); + } else { + return (STAT_EAGAIN); + } cm1.machine_state = MACHINE_SHUTDOWN; - cm1.hold_exit = FEEDHOLD_EXIT_END; return (STAT_OK); } #ifdef ENABLE_INTERLOCK_AND_ESTOP @@ -451,6 +461,8 @@ static void _start_queue_flush() static stat_t _run_queue_flush() // typically runs from cm1 planner { cm_abort_arc(cm); // kill arcs so they don't just create more alines + cm_abort_homing(cm); // kill homing so it can reset cleanly + cm_abort_probing(cm); // kill probing so it can exit cleanly planner_reset((mpPlanner_t *)cm->mp); // reset primary planner. also resets the mr under the planner cm_reset_position_to_absolute_position(cm); cm1.queue_flush_state = QUEUE_FLUSH_OFF; @@ -503,12 +515,6 @@ static stat_t _run_job_kill() _run_queue_flush(); -#ifdef ENABLE_INTERLOCK_AND_ESTOP - if ((cm1.safety_state & (SAFETY_ESC_MASK | SAFETY_INTERLOCK_MASK)) != 0 && spindle.state != SPINDLE_OFF) { - return STAT_EAGAIN; - } -#endif - coolant_control_immediate(COOLANT_OFF, COOLANT_BOTH); // stop coolant spindle_control_immediate(SPINDLE_OFF); // stop spindle @@ -573,8 +579,8 @@ void cm_request_feedhold(cmFeedholdType type, cmFeedholdExit exit) cm1.hold_type = type; cm1.hold_exit = exit; - cm1.hold_profile = ((type == FEEDHOLD_TYPE_ACTIONS) || (type == FEEDHOLD_TYPE_HOLD)) ? - PROFILE_NORMAL : PROFILE_FAST; + cm1.hold_profile = + ((type == FEEDHOLD_TYPE_ACTIONS) || (type == FEEDHOLD_TYPE_HOLD)) ? PROFILE_NORMAL : PROFILE_FAST; switch (cm1.hold_type) { case FEEDHOLD_TYPE_HOLD: { op.add_action(_feedhold_no_actions); break; } diff --git a/g2core/cycle_homing.cpp b/g2core/cycle_homing.cpp index d2ac53f1..6bb19362 100644 --- a/g2core/cycle_homing.cpp +++ b/g2core/cycle_homing.cpp @@ -190,6 +190,7 @@ stat_t cm_homing_cycle_start(const float axes[], const bool flags[]) { cm_set_coord_system(ABSOLUTE_COORDS); // homing is done in machine coordinates cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); hm.set_coordinates = true; + hm.waiting_for_motion_end = false; // clear rotation matrix canonical_machine_reset_rotation(cm); @@ -217,11 +218,43 @@ stat_t cm_homing_cycle_callback(void) { return (STAT_NOOP); } if (hm.waiting_for_motion_end) { // sync to planner move ends (using callback) + // check for alarm or shutdown and recover + // expect the alarm or shutdown to flush the queue, so don't worry about that + if (cm->machine_state == MACHINE_ALARM || cm->machine_state == MACHINE_SHUTDOWN) { + cm_abort_homing(cm); + return (STAT_OK); + } return (STAT_EAGAIN); } return (hm.func(hm.axis)); // execute the current homing move } +/*********************************************************************************** + * cm_abort_homing() - something big happened, the queue is flushing, reset to non-homing state + * + * Note: No need to worry about resetting states we saved (if we are actually homig), since + * when this is called everything is being reset anyway. + * + * The task here is to stop sending homing moves to the planner, and ensure we can re-enter + * homing fresh without issue. + * + */ + +void cm_abort_homing(cmMachine_t *_cm) { + // The queue has been emptied, the callback is lost, and all of the states we saved are reset + hm.waiting_for_motion_end = false; + + // The cycle_type may have already been changed, but if it hasn't do so now + if (_cm->cycle_type == CYCLE_HOMING) { + _cm->cycle_type = CYCLE_NONE; + } + + // This is idempotent - if it's not there, no worries + din_handlers[INPUT_ACTION_INTERNAL].deregisterHandler(&_homing_handler); // end homing mode + + hm.func = nullptr; +} + /*********************************************************************************** * Homing axis moves and helpers - these execute in sequence for each axis ***********************************************************************************/ diff --git a/g2core/cycle_probing.cpp b/g2core/cycle_probing.cpp index cbb0a94a..e0b40c63 100644 --- a/g2core/cycle_probing.cpp +++ b/g2core/cycle_probing.cpp @@ -248,11 +248,49 @@ uint8_t cm_probing_cycle_callback(void) return (STAT_NOOP); // exit if not in a probing cycle } if (pb.waiting_for_motion_complete) { // sync to planner move ends (using callback) - return (STAT_EAGAIN); + // check for alarm or shutdown and recover + // expect the alarm or shutdown to flush the queue, so don't worry about that + if (cm->machine_state == MACHINE_ALARM || cm->machine_state == MACHINE_SHUTDOWN) { + cm_abort_probing(cm); + return (STAT_OK); + } + return (STAT_EAGAIN); } return (pb.func()); // execute the current probing move } +/*********************************************************************************** + * cm_abort_probing() - something big happened, the queue is flushing, reset to non-probing state + * + * Note: No need to worry about resetting states we saved (if we are actually probing), since + * when this is called everything is being reset anyway. + * + * The task here is to stop sending homing moves to the planner, and ensure we can re-enter + * homing fresh without issue. + * + */ + +void cm_abort_probing(cmMachine_t *_cm) { + // The queue has been emptied, the callback is lost, and all of the states we saved are reset + pb.waiting_for_motion_complete = false; + + // The cycle_type may have already been changed, but if it hasn't do so now + if (_cm->cycle_type == CYCLE_PROBE) { + _cm->cycle_type = CYCLE_NONE; + } + + // Also clean up the latest probe record + if (cm->probe_state[0] == PROBE_WAITING) { + // we can stop waiting + cm->probe_state[0] = PROBE_FAILED; + } + + // This is idempotent - if it's not there, no worries + din_handlers[INPUT_ACTION_INTERNAL].deregisterHandler(&_probing_handler); + + pb.func = nullptr; +} + /*********************************************************************************** * _probe_move() - function to execute probing moves * _motion_end_callback() - callback completes when motion has stopped