Enforce full-loop handling of aborted commands
After calling planner_abort_hard() no motion command can be scheduled until we return to the main loop since the call can potentially be scheduled inside a nested process_command call. Despite previous fixes, bugs keep creeping in due to nested calls not being obvious to detect at all. Stop allowing motion _completely_ for the entire processing loop by default. That is, instead of aborting the current plan_buffer_line call, abort the entire command until we can actually schedule motion safely again. This benefits handling of pretty much all g/m-codes, since this flag (now "planner_aborted" for clarity) becomes a general "command aborted" call. This also now ensures that the flag prevents _any_ new block (including blocks partially planned while servicing an interrupt) are scheduled after planner_abort_hard is called. There are only two exceptions where it's safe to resume in this context: - Within uvlo_, where we never return to the main processing loop - When we're intentionally scheduling a new process_command loop for a MK3 filament recheck (which is *bad*) Handle those two cases as exceptions.
This commit is contained in:
parent
48c7c9d464
commit
5965572e88
|
|
@ -1843,6 +1843,9 @@ void host_keepalive() {
|
||||||
// Before loop(), the setup() function is called by the main() routine.
|
// Before loop(), the setup() function is called by the main() routine.
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
// Reset a previously aborted command, we can now start processing motion again
|
||||||
|
planner_aborted = false;
|
||||||
|
|
||||||
if(Stopped) {
|
if(Stopped) {
|
||||||
// Currently Stopped (possibly due to an error) and not accepting new serial commands.
|
// Currently Stopped (possibly due to an error) and not accepting new serial commands.
|
||||||
// Signal to the host that we're currently busy waiting for supervision.
|
// Signal to the host that we're currently busy waiting for supervision.
|
||||||
|
|
@ -2999,7 +3002,7 @@ static void gcode_G28(bool home_x_axis, bool home_y_axis, bool home_z_axis)
|
||||||
static void gcode_G80()
|
static void gcode_G80()
|
||||||
{
|
{
|
||||||
st_synchronize();
|
st_synchronize();
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted)
|
if (planner_aborted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mesh_bed_leveling_flag = true;
|
mesh_bed_leveling_flag = true;
|
||||||
|
|
@ -3093,7 +3096,7 @@ static void gcode_G80()
|
||||||
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
|
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
|
||||||
// Wait until the move is finished.
|
// Wait until the move is finished.
|
||||||
st_synchronize();
|
st_synchronize();
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted)
|
if (planner_aborted)
|
||||||
{
|
{
|
||||||
custom_message_type = custom_message_type_old;
|
custom_message_type = custom_message_type_old;
|
||||||
custom_message_state = custom_message_state_old;
|
custom_message_state = custom_message_state_old;
|
||||||
|
|
@ -3168,7 +3171,7 @@ static void gcode_G80()
|
||||||
//printf_P(PSTR("after clamping: [%f;%f]\n"), current_position[X_AXIS], current_position[Y_AXIS]);
|
//printf_P(PSTR("after clamping: [%f;%f]\n"), current_position[X_AXIS], current_position[Y_AXIS]);
|
||||||
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
|
plan_buffer_line_curposXYZE(XY_AXIS_FEEDRATE);
|
||||||
st_synchronize();
|
st_synchronize();
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted)
|
if (planner_aborted)
|
||||||
{
|
{
|
||||||
custom_message_type = custom_message_type_old;
|
custom_message_type = custom_message_type_old;
|
||||||
custom_message_state = custom_message_state_old;
|
custom_message_state = custom_message_state_old;
|
||||||
|
|
@ -9546,7 +9549,7 @@ void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const
|
||||||
current_position[Z_AXIS] + t * dz,
|
current_position[Z_AXIS] + t * dz,
|
||||||
current_position[E_AXIS] + t * de,
|
current_position[E_AXIS] + t * de,
|
||||||
feed_rate, extruder, gcode_target);
|
feed_rate, extruder, gcode_target);
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted)
|
if (planner_aborted)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10957,6 +10960,7 @@ void uvlo_()
|
||||||
|
|
||||||
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
|
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
|
||||||
// command queues are empty, SD card printing is disabled, usb is inhibited.
|
// command queues are empty, SD card printing is disabled, usb is inhibited.
|
||||||
|
planner_aborted = false;
|
||||||
sei();
|
sei();
|
||||||
|
|
||||||
// Retract
|
// Retract
|
||||||
|
|
@ -11089,6 +11093,7 @@ void uvlo_tiny()
|
||||||
|
|
||||||
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
|
// Enable stepper driver interrupt to move Z axis. This should be fine as the planner and
|
||||||
// command queues are empty, SD card printing is disabled, usb is inhibited.
|
// command queues are empty, SD card printing is disabled, usb is inhibited.
|
||||||
|
planner_aborted = false;
|
||||||
sei();
|
sei();
|
||||||
|
|
||||||
// The axis was moved: adjust Z as done on a regular UVLO.
|
// The axis was moved: adjust Z as done on a regular UVLO.
|
||||||
|
|
@ -11568,7 +11573,7 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
|
||||||
st_reset_timer();
|
st_reset_timer();
|
||||||
sei();
|
sei();
|
||||||
if ((z_move != 0) || (e_move != 0)) { // extruder or z move
|
if ((z_move != 0) || (e_move != 0)) { // extruder or z move
|
||||||
#if 1
|
|
||||||
// Rather than calling plan_buffer_line directly, push the move into the command queue so that
|
// Rather than calling plan_buffer_line directly, push the move into the command queue so that
|
||||||
// the caller can continue processing. This is used during powerpanic to save the state as we
|
// the caller can continue processing. This is used during powerpanic to save the state as we
|
||||||
// move away from the print.
|
// move away from the print.
|
||||||
|
|
@ -11600,13 +11605,6 @@ void stop_and_save_print_to_ram(float z_move, float e_move)
|
||||||
// If this call is invoked from the main Arduino loop() function, let the caller know that the command
|
// If this call is invoked from the main Arduino loop() function, let the caller know that the command
|
||||||
// in the command queue is not the original command, but a new one, so it should not be removed from the queue.
|
// in the command queue is not the original command, but a new one, so it should not be removed from the queue.
|
||||||
repeatcommand_front();
|
repeatcommand_front();
|
||||||
#else
|
|
||||||
plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS] + z_move, saved_pos[E_AXIS] + e_move, homing_feedrate[Z_AXIS], active_extruder);
|
|
||||||
st_synchronize(); //wait moving
|
|
||||||
memcpy(current_position, saved_pos, sizeof(saved_pos));
|
|
||||||
set_destination_to_current();
|
|
||||||
#endif
|
|
||||||
waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -11690,7 +11688,7 @@ void restore_print_from_ram_and_continue(float e_move)
|
||||||
lcd_setstatuspgm(MSG_WELCOME);
|
lcd_setstatuspgm(MSG_WELCOME);
|
||||||
saved_printing_type = PRINTING_TYPE_NONE;
|
saved_printing_type = PRINTING_TYPE_NONE;
|
||||||
saved_printing = false;
|
saved_printing = false;
|
||||||
waiting_inside_plan_buffer_line_print_aborted = true; //unroll the stack
|
planner_aborted = true; // unroll the stack
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel the state related to a currently saved print
|
// Cancel the state related to a currently saved print
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ void mc_arc(float* position, float* target, float* offset, float feed_rate, floa
|
||||||
// Insert the segment into the buffer
|
// Insert the segment into the buffer
|
||||||
plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder, position);
|
plan_buffer_line(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS], feed_rate, extruder, position);
|
||||||
// Handle the situation where the planner is aborted hard.
|
// Handle the situation where the planner is aborted hard.
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted)
|
if (planner_aborted)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,9 @@
|
||||||
#include "tmc2130.h"
|
#include "tmc2130.h"
|
||||||
#endif //TMC2130
|
#endif //TMC2130
|
||||||
|
|
||||||
|
#include <util/atomic.h>
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//=============================public variables ============================
|
//=============================public variables ============================
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
@ -593,17 +596,7 @@ void check_axes_activity()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool waiting_inside_plan_buffer_line_print_aborted = false;
|
bool planner_aborted = false;
|
||||||
/*
|
|
||||||
void planner_abort_soft()
|
|
||||||
{
|
|
||||||
// Empty the queue.
|
|
||||||
while (blocks_queued()) plan_discard_current_block();
|
|
||||||
// Relay to planner wait routine, that the current line shall be canceled.
|
|
||||||
waiting_inside_plan_buffer_line_print_aborted = true;
|
|
||||||
//current_position[i]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef PLANNER_DIAGNOSTICS
|
#ifdef PLANNER_DIAGNOSTICS
|
||||||
static inline void planner_update_queue_min_counter()
|
static inline void planner_update_queue_min_counter()
|
||||||
|
|
@ -665,6 +658,9 @@ void planner_abort_hard()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Relay to planner wait routine, that the current line shall be canceled.
|
||||||
|
planner_aborted = true;
|
||||||
|
|
||||||
// Clear the planner queue, reset and re-enable the stepper timer.
|
// Clear the planner queue, reset and re-enable the stepper timer.
|
||||||
quickStop();
|
quickStop();
|
||||||
|
|
||||||
|
|
@ -680,9 +676,6 @@ void planner_abort_hard()
|
||||||
|
|
||||||
plan_reset_next_e_queue = false;
|
plan_reset_next_e_queue = false;
|
||||||
plan_reset_next_e_sched = false;
|
plan_reset_next_e_sched = false;
|
||||||
|
|
||||||
// Relay to planner wait routine, that the current line shall be canceled.
|
|
||||||
waiting_inside_plan_buffer_line_print_aborted = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void plan_buffer_line_curposXYZE(float feed_rate) {
|
void plan_buffer_line_curposXYZE(float feed_rate) {
|
||||||
|
|
@ -706,9 +699,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
|
||||||
// Calculate the buffer head after we push this byte
|
// Calculate the buffer head after we push this byte
|
||||||
uint8_t next_buffer_head = next_block_index(block_buffer_head);
|
uint8_t next_buffer_head = next_block_index(block_buffer_head);
|
||||||
|
|
||||||
// TODO: shouldn't this be reset only in the outer marlin loop?
|
|
||||||
waiting_inside_plan_buffer_line_print_aborted = false;
|
|
||||||
|
|
||||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||||
// Rest here until there is room in the buffer.
|
// Rest here until there is room in the buffer.
|
||||||
if (block_buffer_tail == next_buffer_head) {
|
if (block_buffer_tail == next_buffer_head) {
|
||||||
|
|
@ -718,18 +708,14 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
|
||||||
manage_inactivity(false);
|
manage_inactivity(false);
|
||||||
lcd_update(0);
|
lcd_update(0);
|
||||||
} while (block_buffer_tail == next_buffer_head);
|
} while (block_buffer_tail == next_buffer_head);
|
||||||
if (waiting_inside_plan_buffer_line_print_aborted) {
|
|
||||||
// Inside the lcd_update(0) routine the print has been aborted.
|
|
||||||
// Cancel the print, do not plan the current line this routine is waiting on.
|
|
||||||
#ifdef PLANNER_DIAGNOSTICS
|
|
||||||
planner_update_queue_min_counter();
|
|
||||||
#endif /* PLANNER_DIAGNOSTICS */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#ifdef PLANNER_DIAGNOSTICS
|
#ifdef PLANNER_DIAGNOSTICS
|
||||||
planner_update_queue_min_counter();
|
planner_update_queue_min_counter();
|
||||||
#endif /* PLANNER_DIAGNOSTICS */
|
#endif /* PLANNER_DIAGNOSTICS */
|
||||||
|
if(planner_aborted) {
|
||||||
|
// avoid planning the block early if aborted
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare to set up new block
|
// Prepare to set up new block
|
||||||
block_t *block = &block_buffer[block_buffer_head];
|
block_t *block = &block_buffer[block_buffer_head];
|
||||||
|
|
@ -1334,8 +1320,12 @@ Having the real displacement of the head, we can calculate the total movement le
|
||||||
if (block->step_event_count.wide <= 32767)
|
if (block->step_event_count.wide <= 32767)
|
||||||
block->flag |= BLOCK_FLAG_DDA_LOWRES;
|
block->flag |= BLOCK_FLAG_DDA_LOWRES;
|
||||||
|
|
||||||
// Move the buffer head. From now the block may be picked up by the stepper interrupt controller.
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||||
block_buffer_head = next_buffer_head;
|
// Move the buffer head ensuring the current block hasn't been cancelled from an isr context
|
||||||
|
// (this is possible both during crash detection *and* uvlo, thus needing a global cli)
|
||||||
|
if(planner_aborted) return;
|
||||||
|
block_buffer_head = next_buffer_head;
|
||||||
|
}
|
||||||
|
|
||||||
// Update position
|
// Update position
|
||||||
memcpy(position, target, sizeof(target)); // position[] = target[]
|
memcpy(position, target, sizeof(target)); // position[] = target[]
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ FORCE_INLINE bool planner_queue_full() {
|
||||||
// wait for the steppers to stop,
|
// wait for the steppers to stop,
|
||||||
// update planner's current position and the current_position of the front end.
|
// update planner's current position and the current_position of the front end.
|
||||||
extern void planner_abort_hard();
|
extern void planner_abort_hard();
|
||||||
extern bool waiting_inside_plan_buffer_line_print_aborted;
|
extern bool planner_aborted;
|
||||||
|
|
||||||
#ifdef PREVENT_DANGEROUS_EXTRUDE
|
#ifdef PREVENT_DANGEROUS_EXTRUDE
|
||||||
extern int extrude_min_temp;
|
extern int extrude_min_temp;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue