断行续打功能优化

This commit is contained in:
魏瑞鹏 2025-04-30 11:49:31 +08:00
parent 46e033ccc5
commit 567d7ee7e8
28 changed files with 373 additions and 139 deletions

View File

@ -376,7 +376,7 @@ gcode:
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor|default("") == ""
else True if not printer[client.filament_sensor].enabled
else printer[client.filament_sensor].filament_detected|default(False) %}
else printer[client.filament_sensor].filament_detected|default(False) %}
{% set printing = printer.print_stats.state == "printing" %}
{% if filament_insert or printing == False %}
SET_SERVO SERVO=switch_nozzle angle=135
@ -406,7 +406,7 @@ gcode:
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor1|default("") == ""
else True if not printer[client.filament_sensor1].enabled
else printer[client.filament_sensor1].filament_detected|default(False) %}
else printer[client.filament_sensor1].filament_detected|default(False) %}
{% set printing = (printer.print_stats.state == "printing") %}
{% if filament_insert or printing == False %}
SET_SERVO SERVO=switch_nozzle angle=135
@ -841,7 +841,7 @@ gcode:
{% set sv = printer.save_variables.variables %}
{% set door_function = sv.door_detect|default("Disabled") %}
{% set door_state = printer['gcode_button _door_detection'].state|default('released')|lower %}
{% if door_function == 'Pause Print' and door_state == 'released' %}
RESPOND TYPE=command MSG="action:prompt_begin"
RESPOND TYPE=command MSG="action:prompt_text Please close the door and click Resume to proceed."
@ -974,9 +974,9 @@ gcode:
RUN_SHELL_COMMAND CMD=_CLEAR_PLR
SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
{% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
{% set zero_vars = ['power_resume_position', 'power_resume_line'] %}
{% for var in zero_vars %}
SAVE_VARIABLE VARIABLE={var} VALUE=0
SAVE_VARIABLE VARIABLE={var} VALUE=0
{% endfor %}
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False
@ -992,9 +992,9 @@ gcode:
{% set park_dz = client.custom_park_dz|default(2.0)|abs %}
RESPOND TYPE=command MSG="action:prompt_end"
SET_GCODE_OFFSET Z=0 MOVE=0
{% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
{% set is_paused = sv.power_loss_paused|default(False) %}
{% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
{% set filepath = params.GCODE_FILE|default(sv.filepath)|string %}
{% set last_file = filepath.split('/')[-1] %}
{% set hotend = sv.power_resume_extruder|default("extruder")%}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set z_offset_total = park_dz if is_paused else 0 %}
@ -1004,7 +1004,7 @@ gcode:
SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
G4 P300
M118 Recovery in progress, please wait
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_offset_total}"
SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

View File

@ -308,7 +308,7 @@ gcode:
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor|default("") == ""
else True if not printer[client.filament_sensor].enabled
else printer[client.filament_sensor].filament_detected|default(False) %}
else printer[client.filament_sensor].filament_detected|default(False) %}
{% set printing = printer.print_stats.state == "printing" %}
{% if filament_insert or printing == False %}
SET_SERVO SERVO=switch_nozzle angle=135
@ -338,7 +338,7 @@ gcode:
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor1|default("") == ""
else True if not printer[client.filament_sensor1].enabled
else printer[client.filament_sensor1].filament_detected|default(False) %}
else printer[client.filament_sensor1].filament_detected|default(False) %}
{% set printing = (printer.print_stats.state == "printing") %}
{% if filament_insert or printing == False %}
SET_SERVO SERVO=switch_nozzle angle=135
@ -887,9 +887,9 @@ gcode:
RUN_SHELL_COMMAND CMD=_CLEAR_PLR
SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
{% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
{% set zero_vars = ['power_resume_position', 'power_resume_line'] %}
{% for var in zero_vars %}
SAVE_VARIABLE VARIABLE={var} VALUE=0
SAVE_VARIABLE VARIABLE={var} VALUE=0
{% endfor %}
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False
@ -905,9 +905,9 @@ gcode:
{% set park_dz = client.custom_park_dz|default(2.0)|abs %}
RESPOND TYPE=command MSG="action:prompt_end"
SET_GCODE_OFFSET Z=0 MOVE=0
{% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
{% set is_paused = sv.power_loss_paused|default(False) %}
{% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
{% set filepath = params.GCODE_FILE|default(sv.filepath)|string %}
{% set last_file = filepath.split('/')[-1] %}
{% set hotend = sv.power_resume_extruder|default("extruder")%}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set z_offset_total = park_dz if is_paused else 0 %}
@ -917,7 +917,7 @@ gcode:
SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
G4 P300
M118 Recovery in progress, please wait
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_offset_total}"
SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

View File

@ -843,7 +843,7 @@ gcode:
{% set sv = printer.save_variables.variables %}
{% set door_function = sv.door_detect|default("Disabled") %}
{% set door_state = printer['gcode_button _door_detection'].state|default('released')|lower %}
{% if door_function == 'Pause Print' and door_state == 'released' %}
RESPOND TYPE=command MSG="action:prompt_begin"
RESPOND TYPE=command MSG="action:prompt_text Please close the door and click Resume to proceed."
@ -976,9 +976,9 @@ gcode:
RUN_SHELL_COMMAND CMD=_CLEAR_PLR
SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
{% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
{% set zero_vars = ['power_resume_position', 'power_resume_line'] %}
{% for var in zero_vars %}
SAVE_VARIABLE VARIABLE={var} VALUE=0
SAVE_VARIABLE VARIABLE={var} VALUE=0
{% endfor %}
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False
@ -994,9 +994,9 @@ gcode:
{% set park_dz = client.custom_park_dz|default(2.0)|abs %}
RESPOND TYPE=command MSG="action:prompt_end"
SET_GCODE_OFFSET Z=0 MOVE=0
{% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
{% set is_paused = sv.power_loss_paused|default(False) %}
{% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
{% set filepath = params.GCODE_FILE|default(sv.filepath)|string %}
{% set last_file = filepath.split('/')[-1] %}
{% set hotend = sv.power_resume_extruder|default("extruder")%}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set z_offset_total = park_dz if is_paused else 0 %}
@ -1006,7 +1006,7 @@ gcode:
SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
G4 P300
M118 Recovery in progress, please wait
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_offset_total}"
SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

View File

@ -335,7 +335,7 @@ gcode:
{% set x_offset = sv.nozzle_x_offset_val|default(0)|float %}
{% set y_offset = sv.nozzle_y_offset_val|default(0)|float %}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set x_offset = x_offset - 59 %}
{% set x_offset = x_offset - 59 %}
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor1|default("") == ""
else True if not printer[client.filament_sensor1].enabled
@ -882,9 +882,9 @@ gcode:
RUN_SHELL_COMMAND CMD=_CLEAR_PLR
SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
{% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
{% set zero_vars = ['power_resume_position', 'power_resume_line'] %}
{% for var in zero_vars %}
SAVE_VARIABLE VARIABLE={var} VALUE=0
SAVE_VARIABLE VARIABLE={var} VALUE=0
{% endfor %}
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False
@ -900,9 +900,9 @@ gcode:
{% set park_dz = client.custom_park_dz|default(2.0)|abs %}
RESPOND TYPE=command MSG="action:prompt_end"
SET_GCODE_OFFSET Z=0 MOVE=0
{% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
{% set is_paused = sv.power_loss_paused|default(False) %}
{% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
{% set filepath = params.GCODE_FILE|default(sv.filepath)|string %}
{% set last_file = filepath.split('/')[-1] %}
{% set hotend = sv.power_resume_extruder|default("extruder")%}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set z_offset_total = park_dz if is_paused else 0 %}
@ -912,7 +912,7 @@ gcode:
SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
G4 P300
M118 Recovery in progress, please wait
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_offset_total}"
SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

View File

@ -206,7 +206,7 @@ kick_start_time: 1.0
pin: PC6
max_power: 0.8
heater:
stepper: stepper_x, stepper_z, dual_carriage
stepper: stepper_x, stepper_z, dual_carriage
idle_speed: 0.5
[delayed_gcode INIT_LIGHT]
@ -501,7 +501,7 @@ gcode:
{% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %}
{% set filament_insert = True if client.filament_sensor1|default("") == ""
else True if not printer[client.filament_sensor1].enabled
else printer[client.filament_sensor1].filament_detected|default(False) %}
else printer[client.filament_sensor1].filament_detected|default(False) %}
{% set printing = (printer.print_stats.state == "printing") %}
{% if filament_insert or printing == False %}
{% if "x" not in printer.toolhead.homed_axes %}
@ -1157,9 +1157,9 @@ gcode:
RUN_SHELL_COMMAND CMD=_CLEAR_PLR
SAVE_VARIABLE VARIABLE=last_file VALUE='"{ filename }"'
SAVE_VARIABLE VARIABLE=filepath VALUE='"{ filepath }"'
{% set zero_vars = ['power_resume_x', 'power_resume_y', 'power_resume_z'] %}
{% set zero_vars = ['power_resume_position', 'power_resume_line'] %}
{% for var in zero_vars %}
SAVE_VARIABLE VARIABLE={var} VALUE=0
SAVE_VARIABLE VARIABLE={var} VALUE=0
{% endfor %}
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False
@ -1175,9 +1175,9 @@ gcode:
{% set park_dz = client.custom_park_dz|default(2.0)|abs %}
RESPOND TYPE=command MSG="action:prompt_end"
SET_GCODE_OFFSET Z=0 MOVE=0
{% set z_height = params.Z_HEIGHT|default(sv.power_resume_z)|float %}
{% set is_paused = sv.power_loss_paused|default(False) %}
{% set last_file = params.GCODE_FILE|default(sv.last_file)|string %}
{% set filepath = params.GCODE_FILE|default(sv.filepath)|string %}
{% set last_file = filepath.split('/')[-1] %}
{% set hotend = sv.power_resume_extruder|default("extruder")%}
{% set z_offset = sv.nozzle_z_offset_val|default(0)|float %}
{% set z_offset_total = park_dz if is_paused else 0 %}
@ -1187,7 +1187,7 @@ gcode:
SET_STEPPER_ENABLE STEPPER=stepper_z ENABLE=1
G4 P300
M118 Recovery in progress, please wait
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_height} \"{last_file}\" \"{z_offset_total}\""
RUN_SHELL_COMMAND CMD=_POWER_LOSS_RECOVERY PARAMS="{z_offset_total}"
SDCARD_PRINT_FILE FILENAME=.plr/"{last_file}"
SAVE_VARIABLE VARIABLE=was_interrupted VALUE=False

View File

@ -94,7 +94,7 @@ defs_trapq = """
, double accel_t, double cruise_t, double decel_t
, double start_pos_x, double start_pos_y, double start_pos_z
, double axes_r_x, double axes_r_y, double axes_r_z
, double start_v, double cruise_v, double accel);
, double start_v, double cruise_v, double accel, double taskline);
void trapq_finalize_moves(struct trapq *tq, double print_time
, double clear_history_time);
void trapq_set_position(struct trapq *tq, double print_time

View File

@ -41,6 +41,7 @@ itersolve_gen_steps_range(struct stepper_kinematics *sk, struct move *m
int is_dir_change = 0, have_bracket = 0, check_oscillate = 0;
double target = sk->commanded_pos + (sdir ? half_step : -half_step);
double last_time=start, low_time=start, high_time=start + SEEK_TIME_RESET;
stepcompress_set_taskline(sk->sc, m->taskline);
if (high_time > end)
high_time = end;
for (;;) {

View File

@ -38,6 +38,7 @@ struct stepcompress {
uint64_t last_step_clock;
struct list_head msg_queue;
uint32_t oid;
uint32_t taskline;
int32_t queue_step_msgtag, set_next_step_dir_msgtag;
int sdir, invert_sdir;
// Step+dir+step filter
@ -52,13 +53,14 @@ struct step_move {
uint32_t interval;
uint16_t count;
int16_t add;
uint32_t taskline;
};
struct history_steps {
struct list_node node;
uint64_t first_clock, last_clock;
int64_t start_position;
int step_count, interval, add;
int step_count, interval, add, taskline;
};
@ -113,6 +115,7 @@ compress_bisect_add(struct stepcompress *sc)
int32_t add = 0, minadd = -0x8000, maxadd = 0x7fff;
int32_t bestinterval = 0, bestcount = 1, bestadd = 1, bestreach = INT32_MIN;
int32_t zerointerval = 0, zerocount = 0;
int32_t taskline = sc->taskline;
for (;;) {
// Find longest valid sequence with the given 'add'
@ -124,7 +127,7 @@ compress_bisect_add(struct stepcompress *sc)
nextcount++;
if (&sc->queue_pos[nextcount-1] >= qlast) {
int32_t count = nextcount - 1;
return (struct step_move){ interval, count, add };
return (struct step_move){ interval, count, add, taskline };
}
nextpoint = minmax_point(sc, sc->queue_pos + nextcount - 1);
int32_t nextaddfactor = nextcount*(nextcount-1)/2;
@ -192,8 +195,8 @@ compress_bisect_add(struct stepcompress *sc)
}
if (zerocount + zerocount/16 >= bestcount)
// Prefer add=0 if it's similar to the best found sequence
return (struct step_move){ zerointerval, zerocount, 0 };
return (struct step_move){ bestinterval, bestcount, bestadd };
return (struct step_move){ zerointerval, zerocount, 0, taskline };
return (struct step_move){ bestinterval, bestcount, bestadd, taskline };
}
@ -276,6 +279,13 @@ stepcompress_set_invert_sdir(struct stepcompress *sc, uint32_t invert_sdir)
}
}
void __visible
stepcompress_set_taskline(struct stepcompress *sc, uint32_t taskline)
{
if (taskline != sc->taskline)
sc->taskline = taskline;
}
// Helper to free items from the history_list
static void
free_history(struct stepcompress *sc, uint64_t end_clock)
@ -321,6 +331,12 @@ stepcompress_get_step_dir(struct stepcompress *sc)
return sc->next_step_dir;
}
uint32_t
stepcompress_get_taskline(struct stepcompress *sc)
{
return sc->taskline;
}
// Determine the "print time" of the last_step_clock
static void
calc_last_step_print_time(struct stepcompress *sc)
@ -351,10 +367,10 @@ add_move(struct stepcompress *sc, uint64_t first_clock, struct step_move *move)
uint64_t last_clock = first_clock + ticks;
// Create and queue a queue_step command
uint32_t msg[5] = {
sc->queue_step_msgtag, sc->oid, move->interval, move->count, move->add
uint32_t msg[6] = {
sc->queue_step_msgtag, sc->oid, move->interval, move->count, move->add, move->taskline
};
struct queue_message *qm = message_alloc_and_encode(msg, 5);
struct queue_message *qm = message_alloc_and_encode(msg, 6);
qm->min_clock = qm->req_clock = sc->last_step_clock;
if (move->count == 1 && first_clock >= sc->last_step_clock + CLOCK_DIFF_MAX)
qm->req_clock = first_clock;
@ -368,6 +384,7 @@ add_move(struct stepcompress *sc, uint64_t first_clock, struct step_move *move)
hs->start_position = sc->last_position;
hs->interval = move->interval;
hs->add = move->add;
hs->taskline = move->taskline;
hs->step_count = sc->sdir ? move->count : -move->count;
sc->last_position += hs->step_count;
list_add_head(&hs->node, &sc->history_list);
@ -401,7 +418,7 @@ queue_flush(struct stepcompress *sc, uint64_t move_clock)
static int
stepcompress_flush_far(struct stepcompress *sc, uint64_t abs_step_clock)
{
struct step_move move = { abs_step_clock - sc->last_step_clock, 1, 0 };
struct step_move move = { abs_step_clock - sc->last_step_clock, 1, 0, 0 };
add_move(sc, abs_step_clock, &move);
calc_last_step_print_time(sc);
return 0;

View File

@ -17,6 +17,8 @@ void stepcompress_fill(struct stepcompress *sc, uint32_t max_error
, int32_t set_next_step_dir_msgtag);
void stepcompress_set_invert_sdir(struct stepcompress *sc
, uint32_t invert_sdir);
void stepcompress_set_taskline(struct stepcompress *sc
, uint32_t taskline);
void stepcompress_free(struct stepcompress *sc);
uint32_t stepcompress_get_oid(struct stepcompress *sc);
int stepcompress_get_step_dir(struct stepcompress *sc);

View File

@ -103,6 +103,7 @@ trapq_add_move(struct trapq *tq, struct move *m)
// Add a null move to fill time gap
struct move *null_move = move_alloc();
null_move->start_pos = m->start_pos;
null_move->taskline = m->taskline;
if (!prev->print_time && m->print_time > MAX_NULL_MOVE)
// Limit the first null move to improve numerical stability
null_move->print_time = m->print_time - MAX_NULL_MOVE;
@ -121,7 +122,7 @@ trapq_append(struct trapq *tq, double print_time
, double accel_t, double cruise_t, double decel_t
, double start_pos_x, double start_pos_y, double start_pos_z
, double axes_r_x, double axes_r_y, double axes_r_z
, double start_v, double cruise_v, double accel)
, double start_v, double cruise_v, double accel, double taskline)
{
struct coord start_pos = { .x=start_pos_x, .y=start_pos_y, .z=start_pos_z };
struct coord axes_r = { .x=axes_r_x, .y=axes_r_y, .z=axes_r_z };
@ -133,6 +134,7 @@ trapq_append(struct trapq *tq, double print_time
m->half_accel = .5 * accel;
m->start_pos = start_pos;
m->axes_r = axes_r;
m->taskline = taskline;
trapq_add_move(tq, m);
print_time += accel_t;
@ -146,6 +148,7 @@ trapq_append(struct trapq *tq, double print_time
m->half_accel = 0.;
m->start_pos = start_pos;
m->axes_r = axes_r;
m->taskline = taskline;
trapq_add_move(tq, m);
print_time += cruise_t;
@ -159,6 +162,7 @@ trapq_append(struct trapq *tq, double print_time
m->half_accel = -.5 * accel;
m->start_pos = start_pos;
m->axes_r = axes_r;
m->taskline = taskline;
trapq_add_move(tq, m);
}
}

View File

@ -13,6 +13,7 @@ struct coord {
};
struct move {
double taskline;
double print_time, move_t;
double start_v, half_accel;
struct coord start_pos, axes_r;
@ -42,7 +43,7 @@ void trapq_append(struct trapq *tq, double print_time
, double accel_t, double cruise_t, double decel_t
, double start_pos_x, double start_pos_y, double start_pos_z
, double axes_r_x, double axes_r_y, double axes_r_z
, double start_v, double cruise_v, double accel);
, double start_v, double cruise_v, double accel, double taskline);
void trapq_finalize_moves(struct trapq *tq, double print_time
, double clear_history_time);
void trapq_set_position(struct trapq *tq, double print_time

View File

@ -204,7 +204,7 @@ class BedMesh:
final_z_adj = factor * z_adj + self.fade_target
self.last_position[:] = [x, y, z - final_z_adj, e]
return list(self.last_position)
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
factor = self.get_z_factor(newpos[2])
if self.z_mesh is None or not factor:
# No mesh calibrated, or mesh leveling phased out.
@ -214,13 +214,13 @@ class BedMesh:
logging.info(
"bed_mesh fade complete: Current Z: %.4f fade_target: %.4f "
% (z, self.fade_target))
self.toolhead.move([x, y, z + self.fade_target, e], speed)
self.toolhead.move([x, y, z + self.fade_target, e], speed, taskline)
else:
self.splitter.build_move(self.last_position, newpos, factor)
while not self.splitter.traverse_complete:
split_move = self.splitter.split()
if split_move:
self.toolhead.move(split_move, speed)
self.toolhead.move(split_move, speed, taskline)
else:
raise self.gcode.error(
"Mesh Leveling: Error splitting move ")

View File

@ -41,7 +41,7 @@ class BedScrews:
self.state = None
self.current_screw = 0
self.accepted_screws = 0
def move(self, coord, speed):
def move(self, coord, speed, taskline=0):
try:
self.printer.lookup_object('toolhead').manual_move(coord, speed)
except self.printer.command_error as e:

View File

@ -26,10 +26,10 @@ class BedTilt:
def get_position(self):
x, y, z, e = self.toolhead.get_position()
return [x, y, z - x*self.x_adjust - y*self.y_adjust - self.z_adjust, e]
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
x, y, z, e = newpos
self.toolhead.move([x, y, z + x*self.x_adjust + y*self.y_adjust
+ self.z_adjust, e], speed)
+ self.z_adjust, e], speed, taskline)
def update_adjust(self, x_adjust, y_adjust, z_adjust):
self.x_adjust = x_adjust
self.y_adjust = y_adjust

View File

@ -177,7 +177,7 @@ class ExcludeObject:
}
return status
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
move_in_excluded_region = self._test_in_excluded_region()
self.last_speed = speed

View File

@ -83,7 +83,7 @@ class ForceMove:
axis_r, accel_t, cruise_t, cruise_v = calc_move_time(dist, speed, accel)
print_time = toolhead.get_last_move_time()
self.trapq_append(self.trapq, print_time, accel_t, cruise_t, accel_t,
0., 0., 0., axis_r, 0., 0., 0., cruise_v, accel)
0., 0., 0., axis_r, 0., 0., 0., cruise_v, accel, 0.)
print_time = print_time + accel_t + cruise_t + accel_t
stepper.generate_steps(print_time)
self.trapq_finalize_moves(self.trapq, print_time + 99999.9,

View File

@ -113,6 +113,7 @@ class GCodeMove:
def cmd_G1(self, gcmd):
# Move
params = gcmd.get_command_parameters()
line = gcmd.get_taskline()
try:
for pos, axis in enumerate('XYZ'):
if axis in params:
@ -140,7 +141,7 @@ class GCodeMove:
except ValueError as e:
raise gcmd.error("Unable to parse move '%s'"
% (gcmd.get_commandline(),))
self.move_with_transform(self.last_position, self.speed)
self.move_with_transform(self.last_position, self.speed, line)
# G-Code coordinate manipulation
def cmd_G20(self, gcmd):
# Set units to inches

View File

@ -64,7 +64,7 @@ class ManualStepper:
self.trapq_append(self.trapq, self.next_cmd_time,
accel_t, cruise_t, accel_t,
cp, 0., 0., axis_r, 0., 0.,
0., cruise_v, accel)
0., cruise_v, accel, 0.)
self.next_cmd_time = self.next_cmd_time + accel_t + cruise_t + accel_t
self.rail.generate_steps(self.next_cmd_time)
self.trapq_finalize_moves(self.trapq, self.next_cmd_time + 99999.9,

View File

@ -67,9 +67,9 @@ class PrinterSkew:
return [skewed_x, skewed_y, pos[2], pos[3]]
def get_position(self):
return self.calc_unskew(self.next_transform.get_position())
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
corrected_pos = self.calc_skew(newpos)
self.next_transform.move(corrected_pos, speed)
self.next_transform.move(corrected_pos, speed, taskline)
def _update_skew(self, xy_factor, xz_factor, yz_factor):
self.xy_factor = xy_factor
self.xz_factor = xz_factor

View File

@ -74,7 +74,7 @@ class TuningTower:
if self.band:
z = (math.floor(z / self.band) + .5) * self.band
return self.start + z * self.factor
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
normal_transform = self.normal_transform
if (newpos[3] > self.last_position[3] and newpos[2] != self.last_z
and newpos[:3] != self.last_position[:3]):
@ -94,7 +94,7 @@ class TuningTower:
% (newval,))
# Forward move to actual handler
self.last_position[:] = newpos
normal_transform.move(newpos, speed)
normal_transform.move(newpos, speed, taskline)
def end_test(self):
self.gcode.respond_info("Ending tuning test mode")
self.gcode_move.set_move_transform(self.normal_transform, force=True)

View File

@ -29,6 +29,9 @@ class VirtualSD:
self.reactor = self.printer.get_reactor()
self.must_pause_work = self.cmd_from_sd = False
self.next_file_position = 0
self.file_line = 0
self.file_runline = 0
self.linfo = ""
self.work_timer = None
# Error handling
gcode_macro = self.printer.load_object(config, 'gcode_macro')
@ -46,6 +49,8 @@ class VirtualSD:
self.gcode.register_command(
"SDCARD_PRINT_FILE", self.cmd_SDCARD_PRINT_FILE,
desc=self.cmd_SDCARD_PRINT_FILE_help)
self.gcode.register_command(
'GET_TASKLINE', self.cmd_GET_TASKLINE, False)
def handle_shutdown(self):
if self.work_timer is not None:
self.must_pause_work = True
@ -95,6 +100,7 @@ class VirtualSD:
'progress': self.progress(),
'is_active': self.is_active(),
'file_position': self.file_position,
'file_line': self.file_runline,
'file_size': self.file_size,
}
def file_path(self):
@ -111,6 +117,7 @@ class VirtualSD:
def do_pause(self):
if self.work_timer is not None:
self.must_pause_work = True
self._get_runline()
while self.work_timer is not None and not self.cmd_from_sd:
self.reactor.pause(self.reactor.monotonic() + .001)
def do_resume(self):
@ -126,6 +133,7 @@ class VirtualSD:
self.current_file = None
self.print_stats.note_cancel()
self.file_position = self.file_size = 0
self.file_line = self.file_runline = 0
# G-Code commands
def cmd_error(self, gcmd):
raise gcmd.error("SD write not supported")
@ -135,10 +143,28 @@ class VirtualSD:
self.current_file.close()
self.current_file = None
self.file_position = self.file_size = 0
self.file_line = self.file_runline = 0
self.print_stats.reset()
self.printer.send_event("virtual_sdcard:reset_file")
cmd_SDCARD_RESET_FILE_help = "Clears a loaded SD File. Stops the print "\
"if necessary"
def _get_runline(self):
toolhead = self.printer.lookup_object('toolhead', None)
if toolhead is None:
raise self.gcode.error("Printer not ready")
kin = toolhead.get_kinematics()
steppers = kin.get_steppers()
linfo = [(s.get_name(), s.get_stepper_taskline()) for s in steppers if s.get_name() != "stepper_z"]
max_position = max(position for _, position in linfo)
self.linfo = linfo
self.file_runline = max_position
def cmd_GET_TASKLINE(self, gcmd):
if not self.must_pause_work:
self._get_runline()
formatted_pairs = [f"{key}:{value}" for key, value in self.linfo]
formatted_line = " ".join(formatted_pairs)
gcmd.respond_info(f"stepper line: {formatted_line}")
def cmd_SDCARD_RESET_FILE(self, gcmd):
if self.cmd_from_sd:
raise gcmd.error(
@ -217,6 +243,8 @@ class VirtualSD:
% (self.file_position, self.file_size))
def get_file_position(self):
return self.next_file_position
def get_file_line(self):
return self.file_line
def set_file_position(self, pos):
self.next_file_position = pos
def is_cmd_from_sd(self):
@ -264,6 +292,7 @@ class VirtualSD:
# Dispatch command
self.cmd_from_sd = True
line = lines.pop()
self.file_line += 1
if sys.version_info.major >= 3:
next_file_position = self.file_position + len(line.encode()) + 1
else:

View File

@ -122,15 +122,15 @@ class ZThermalAdjuster:
self.last_position = self.calc_adjust(position)
return position
def move(self, newpos, speed):
def move(self, newpos, speed, taskline=0):
# don't apply to extrude only moves or when disabled
if (newpos[0:2] == self.last_position[0:2]) or not self.adjust_enable:
z = newpos[2] + self.last_z_adjust_mm
adjusted_pos = [newpos[0], newpos[1], z, newpos[3]]
self.next_transform.move(adjusted_pos, speed)
self.next_transform.move(adjusted_pos, speed, taskline)
else:
adjusted_pos = self.calc_adjust(newpos)
self.next_transform.move(adjusted_pos, speed)
self.next_transform.move(adjusted_pos, speed, taskline)
self.last_position[:] = newpos
def temperature_callback(self, read_time, temp):

View File

@ -12,14 +12,17 @@ Coord = collections.namedtuple('Coord', ('x', 'y', 'z', 'e'))
class GCodeCommand:
error = CommandError
def __init__(self, gcode, command, commandline, params, need_ack):
def __init__(self, gcode, command, commandline, params, need_ack, taskline):
self._command = command
self._commandline = commandline
self._params = params
self._need_ack = need_ack
self.taskline = taskline
# Method wrappers
self.respond_info = gcode.respond_info
self.respond_raw = gcode.respond_raw
def get_taskline(self):
return self.taskline
def get_command(self):
return self._command
def get_commandline(self):
@ -189,6 +192,11 @@ class GCodeDispatch:
# Parse input into commands
args_r = re.compile('([A-Z_]+|[A-Z*])')
def _process_commands(self, commands, need_ack=True):
sdcard = self.printer.lookup_object('virtual_sdcard', None)
if sdcard is not None:
taskline = sdcard.file_line
else:
taskline = 0
for line in commands:
# Ignore comments and leading/trailing spaces
line = origline = line.strip()
@ -205,7 +213,7 @@ class GCodeDispatch:
# Build gcode "params" dictionary
params = { parts[i]: parts[i+1].strip()
for i in range(1, len(parts), 2) }
gcmd = GCodeCommand(self, cmd, origline, params, need_ack)
gcmd = GCodeCommand(self, cmd, origline, params, need_ack, taskline)
# Invoke handler for command
handler = self.gcode_handlers.get(cmd, self.cmd_default)
try:
@ -231,7 +239,7 @@ class GCodeDispatch:
def get_mutex(self):
return self.mutex
def create_gcode_command(self, command, commandline, params):
return GCodeCommand(self, command, commandline, params, False)
return GCodeCommand(self, command, commandline, params, False, 0)
# Response handling
def respond_raw(self, msg):
for cb in self.output_callbacks:

View File

@ -233,7 +233,7 @@ class PrinterExtruder:
if diff_r:
return (self.instant_corner_v / abs(diff_r))**2
return move.max_cruise_v2
def move(self, print_time, move):
def move(self, print_time, move, taskline=0):
axis_r = move.axes_r[3]
accel = move.accel * axis_r
start_v = move.start_v * axis_r
@ -246,7 +246,7 @@ class PrinterExtruder:
move.accel_t, move.cruise_t, move.decel_t,
move.start_pos[3], 0., 0.,
1., can_pressure_advance, 0.,
start_v, cruise_v, accel)
start_v, cruise_v, accel, taskline)
self.last_position = move.end_pos[3]
def find_past_position(self, print_time):
if self.extruder_stepper is None:

View File

@ -39,6 +39,7 @@ class MCU_stepper:
self._invert_dir = self._orig_invert_dir = dir_pin_params['invert']
self._step_both_edge = self._req_step_both_edge = False
self._mcu_position_offset = 0.
self.taskline = 0
self._reset_cmd_tag = self._get_position_cmd = None
self._active_callbacks = []
ffi_main, ffi_lib = chelper.get_ffi()
@ -90,7 +91,7 @@ class MCU_stepper:
self._mcu.add_config_cmd("reset_step_clock oid=%d clock=0"
% (self._oid,), on_restart=True)
step_cmd_tag = self._mcu.lookup_command(
"queue_step oid=%c interval=%u count=%hu add=%hi").get_command_tag()
"queue_step oid=%c interval=%u count=%hu add=%hi taskline=%u").get_command_tag()
dir_cmd_tag = self._mcu.lookup_command(
"set_next_step_dir oid=%c dir=%c").get_command_tag()
self._reset_cmd_tag = self._mcu.lookup_command(
@ -98,6 +99,9 @@ class MCU_stepper:
self._get_position_cmd = self._mcu.lookup_query_command(
"stepper_get_position oid=%c",
"stepper_position oid=%c pos=%i", oid=self._oid)
self._get_taskline_cmd = self._mcu.lookup_query_command(
"stepper_get_taskline oid=%c",
"stepper_taskline line=%u")
max_error = self._mcu.get_max_stepper_error()
max_error_ticks = self._mcu.seconds_to_clock(max_error)
ffi_main, ffi_lib = chelper.get_ffi()
@ -164,6 +168,11 @@ class MCU_stepper:
return (data, count)
def get_stepper_kinematics(self):
return self._stepper_kinematics
def get_stepper_taskline(self):
if self._mcu.is_fileoutput():
return 0
params = self._get_taskline_cmd.send([self._oid])
return int(params['line'])
def set_stepper_kinematics(self, sk):
old_sk = self._stepper_kinematics
mcu_pos = 0

View File

@ -12,7 +12,7 @@ import mcu, chelper, kinematics.extruder
# Class to track each move request
class Move:
def __init__(self, toolhead, start_pos, end_pos, speed):
def __init__(self, toolhead, start_pos, end_pos, speed, taskline):
self.toolhead = toolhead
self.start_pos = tuple(start_pos)
self.end_pos = tuple(end_pos)
@ -23,6 +23,7 @@ class Move:
self.is_kinematic_move = True
self.axes_d = axes_d = [end_pos[i] - start_pos[i] for i in (0, 1, 2, 3)]
self.move_d = move_d = math.sqrt(sum([d*d for d in axes_d[:3]]))
self.taskline = taskline
if move_d < .000000001:
# Extrude only move
self.end_pos = (start_pos[0], start_pos[1], start_pos[2],
@ -351,7 +352,7 @@ class ToolHead:
move.accel_t, move.cruise_t, move.decel_t,
move.start_pos[0], move.start_pos[1], move.start_pos[2],
move.axes_r[0], move.axes_r[1], move.axes_r[2],
move.start_v, move.cruise_v, move.accel)
move.start_v, move.cruise_v, move.accel, move.taskline)
if move.axes_d[3]:
self.extruder.move(next_move_time, move)
next_move_time = (next_move_time + move.accel_t
@ -469,8 +470,8 @@ class ToolHead:
last_move = self.lookahead.get_last()
if last_move is not None:
last_move.limit_next_junction_speed(speed)
def move(self, newpos, speed):
move = Move(self, self.commanded_pos, newpos, speed)
def move(self, newpos, speed, taskline=0):
move = Move(self, self.commanded_pos, newpos, speed, taskline)
if not move.move_d:
return
if move.is_kinematic_move:

View File

@ -1,34 +1,114 @@
#!/bin/bash
# $1 z_height $2 filename $3 z_offset
PLR_DIR="/home/klipper/printer_data/gcodes/.plr"
CONFIG_FILE="/home/klipper/printer_data/config/config_variables.cfg"
LOG_FILE="/home/klipper/printer_data/logs/moonraker.log"
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [$(date '+%F %T')] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> "$LOG_FILE"
mkdir -p ~/printer_data/gcodes/.plr
filepath=$(sed -n "s/.*filepath *= *'\([^']*\)'.*/\1/p" /home/klipper/printer_data/config/config_variables.cfg)
filepath=$(printf "$filepath")
echo "$filepath"
z_offset="$1"
last_file=$(sed -n "s/.*last_file *= *'\([^']*\)'.*/\1/p" /home/klipper/printer_data/config/config_variables.cfg)
last_file=$(printf "$last_file")
echo "$last_file"
plr=$last_file
echo "plr=$plr"
PLR_PATH=~/printer_data/gcodes/.plr
mkdir -p "$PLR_DIR" || {
echo "[$(date '+%F %T')] ERROR: Unable to create the directory: $PLR_DIR" >> "$LOG_FILE"
exit 2
}
file_content=$(cat "${filepath}" | awk '/; thumbnail begin/{flag=1;next}/; thumbnail end/{flag=0} !flag' | grep -v "^;simage:\|^;gimage:")
filepath=$(sed -n "s/.*filepath *= *'\([^']*\)'.*/\1/p" "$CONFIG_FILE")
cp "${filepath}" "/home/klipper/plrtmpA.$$"
sourcefile="/home/klipper/plrtmpA.$$"
echo "$file_content" | sed 's/\r$//' | awk -F"Z" 'BEGIN{OFS="Z"} {if ($2 ~ /^[0-9]+$/) $2=$2".0"} 1' > /home/klipper/plrtmpA.$$
sed -i 's/Z\./Z0\./g' /home/klipper/plrtmpA.$$
z_pos=$(echo "${1} + ${3}" | bc)
cat /home/klipper/plrtmpA.$$ | sed -e '1,/Z'${1}'/ d' | sed -ne '/ Z/,$ p' | grep -m 1 ' Z' | sed -ne "s/.* Z\([^ ]*\).*/SET_KINEMATIC_POSITION Z=${z_pos}/p" > ${PLR_PATH}/"${plr}"
raw_value=$(sed -n -E "s/^[[:space:]]*power_loss_paused[[:space:]]*=[[:space:]]*(True|False)[[:space:]]*(;.*)?$/\1/p" "$CONFIG_FILE" | tail -n1)
is_pause=False
[[ "${raw_value,,}" == "true" ]] && is_pause=True
cat /home/klipper/plrtmpA.$$ | sed '/ Z'${1}'/q' | sed -ne '/\(M104\|M140\|M109\|M190\)/p' >> ${PLR_PATH}/"${plr}"
raw_line=$(sed -n -E "s/power_resume_line[[:space:]]*=[[:space:]]*([1-9][0-9]*)['\"]?[[:space:]]*(;.*)?$/\1/p" "$CONFIG_FILE")
run_line=$(tr -cd '0-9' <<< "$raw_line")
if [[ ! "$run_line" =~ ^[1-9][0-9]*$ ]]; then
echo "ERROR: power_resume_line, It must be a valid positive integer" >> "$LOG_FILE"
echo "Current configuration value:'$run_line'" >> "$LOG_FILE"
exit 1
fi
echo "When power outage, the printer is executing $run_line line of the file." >> "$LOG_FILE"
line=$(cat /home/klipper/plrtmpA.$$ | sed '/ Z'${1}'/q' | sed -n '/START_PRINT/p')
raw_position=$(sed -n -E "s/power_resume_position[[:space:]]*=[[:space:]]*([1-9][0-9]*)['\"]?[[:space:]]*(;.*)?$/\1/p" "$CONFIG_FILE")
target_pos=$(tr -cd '0-9' <<< "$raw_position")
if [[ ! "$target_pos" =~ ^[1-9][0-9]*$ ]]; then
echo "ERROR: power_resume_position, It must be a valid positive integer" >> "$LOG_FILE"
echo "Current configuration value:'$target_pos'" >> "$LOG_FILE"
exit 1
fi
if [ -n "$line" ]; then
EXTRUDER=$(echo "$line" | sed -n 's/.*EXTRUDER=\([0-9]*\).*/\1/p')
EXTRUDER1=$(echo "$line" | sed -n 's/.*EXTRUDER1=\([0-9]*\).*/\1/p')
BED=$(echo "$line" | sed -n 's/.*BED=\([0-9]*\).*/\1/p')
CHAMBER=$(echo "$line" | sed -n 's/.*CHAMBER=\([0-9]*\).*/\1/p')
last_file="${filepath##*/}"
echo "Power-off recovery file path: $filepath" >> "$LOG_FILE"
echo "Last printed file name: $last_file" >> "$LOG_FILE"
plr="$last_file"
cat "${sourcefile}" | awk '
{
sub(/\r$/, "")
if ($0 ~ /^;/ || $0 ~ /^[[:space:]]*$/) {
print
} else {
exit
}
}' > "${PLR_DIR}/${plr}"
line=$(awk -v target="$target_pos" '
BEGIN { current_pos = 0; line_number = 1 }
{
line_length = length($0) + 1 # +1 对应换行符(Linux: \n, Windows: \r\n)
if (current_pos <= target && target < current_pos + line_length) {
print line_number
exit
}
current_pos += line_length
line_number++
}
' "$sourcefile")
echo "When power outage, it was parsing the $target_pos byte and the $line line" >> "$LOG_FILE"
line="$run_line"
z_height=$(awk -v target_line="$line" '
BEGIN { found = 0 }
NR <= target_line {
if ($0 ~ /^;[[:space:]]*Z:/) {
split($0, parts, /:[[:space:]]*/)
z_val = parts[2]
found = 1
}
}
NR == target_line {
if (found) {
print z_val
}
exit
}
' "$sourcefile")
echo "When power outage, the printing height: $z_height, the offset value: $z_offset" >> "$LOG_FILE"
z_pos=$(echo "${z_height} + ${z_offset}" | bc)
echo "Assign the Z height as: $z_pos" >> "$LOG_FILE"
echo "SET_KINEMATIC_POSITION Z=${z_pos}" >> "${PLR_DIR}/${plr}"
echo ";Z:${z_pos}" >> "${PLR_DIR}/${plr}"
awk -v end_line="$line" '
NR > end_line { exit }
/M104|M140|M109|M190/ { print }
' "$sourcefile" >> "${PLR_DIR}/${plr}"
start_info=$(awk -v max_line="$line" '
NR > max_line { exit }
$0 ~ /^(START_PRINT|PRINT_START)/ {
print
exit
}
' "$sourcefile")
if [ -n "$start_info" ]; then
EXTRUDER=$(echo "$start_info" | sed -n 's/.*EXTRUDER=\([0-9]*\).*/\1/p')
EXTRUDER1=$(echo "$start_info" | sed -n 's/.*EXTRUDER1=\([0-9]*\).*/\1/p')
BED=$(echo "$start_info" | sed -n 's/.*BED=\([0-9]*\).*/\1/p')
CHAMBER=$(echo "$start_info" | sed -n 's/.*CHAMBER=\([0-9]*\).*/\1/p')
EXTRUDER=${EXTRUDER:-0}
EXTRUDER1=${EXTRUDER1:-0}
BED=${BED:-0}
@ -39,56 +119,112 @@ if [ -n "$line" ]; then
for i in "${!temps[@]}"; do
if [ "${temps[$i]}" != "0" ]; then
echo "${temp_cmds[$i]} ${temps[$i]}" >> "${PLR_PATH}/${plr}"
echo "${temp_cmds[$i]} ${temps[$i]}" >> "${PLR_DIR}/${plr}"
fi
done
fi
cat /home/klipper/plrtmpA.$$ | sed -ne '/;End of Gcode/,$ p' | tr '\n' ' ' | sed -ne 's/ ;[^ ]* //gp' | sed -ne 's/\\\\n/;/gp' | tr ';' '\n' | grep material_bed_temperature | sed -ne 's/.* = /M140 S/p' | head -1 >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -ne '/;End of Gcode/,$ p' | tr '\n' ' ' | sed -ne 's/ ;[^ ]* //gp' | sed -ne 's/\\\\n/;/gp' | tr ';' '\n' | grep material_print_temperature | sed -ne 's/.* = /M104 S/p' | head -1 >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -ne '/;End of Gcode/,$ p' | tr '\n' ' ' | sed -ne 's/ ;[^ ]* //gp' | sed -ne 's/\\\\n/;/gp' | tr ';' '\n' | grep material_bed_temperature | sed -ne 's/.* = /M190 S/p' | head -1 >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -ne '/;End of Gcode/,$ p' | tr '\n' ' ' | sed -ne 's/ ;[^ ]* //gp' | sed -ne 's/\\\\n/;/gp' | tr ';' '\n' | grep material_print_temperature | sed -ne 's/.* = /M109 S/p' | head -1 >> ${PLR_PATH}/"${plr}"
awk -v plr="${PLR_DIR}/${plr}" '
BEGIN {
bed_temp = 0
print_temp = 0
cmd_generated = 0
}
$0 ~ /;End of Gcode/,0 {
gsub(/\r?\n/, " ")
gsub(/;/, "\n")
gsub(/[ \t]+/, " ")
if (match($0, /material_bed_temperature[ =]+([0-9]+)/, m))
bed_temp = m[1]
if (match($0, /material_print_temperature[ =]+([0-9]+)/, m))
print_temp = m[1]
BG_EX=`tac /home/klipper/plrtmpA.$$ | sed -e '/ Z'${1}'[^0-9]*$/q' | tac | tail -n+2 | sed -e '/ Z[0-9]/ q' | tac | sed -e '/ E[0-9]/ q' | sed -ne 's/.* E\([^ ]*\)/G92 E\1/p'`
# If we failed to match an extrusion command (allowing us to correctly set the E axis) prior to the matched layer height, then simply set the E axis to the first E value present in the resemued gcode. This avoids extruding a huge blod on resume, and/or max extrusion errors.
if [ "${BG_EX}" = "" ]; then
BG_EX=`tac /home/klipper/plrtmpA.$$ | sed -e '/ Z'${1}'[^0-9]*$/q' | tac | tail -n+2 | sed -ne '/ Z/,$ p' | sed -e '/ E[0-9]/ q' | sed -ne 's/.* E\([^ ]*\)/G92 E\1/p'`
fi
M83=$(cat /home/klipper/plrtmpA.$$ | sed '/ Z'${1}'/q' | sed -ne '/\(M83\)/p')
if [ -n "${M83}" ];then
echo 'G92 E0' >> ${PLR_PATH}/"${plr}"
echo ${M83} >> ${PLR_PATH}/"${plr}"
else
echo ${BG_EX} >> ${PLR_PATH}/"${plr}"
fi
echo 'G91' >> ${PLR_PATH}/"${plr}"
echo 'G1 Z10' >> ${PLR_PATH}/"${plr}"
echo 'G90' >> ${PLR_PATH}/"${plr}"
echo 'G28 X Y' >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed '/ Z'${1}'/q' | sed -ne '/\(ACTIVATE_COPY_MODE\|ACTIVATE_MIRROR_MODE\)/p' >> ${PLR_PATH}/"${plr}"
echo 'G1 X5' >> ${PLR_PATH}/"${plr}"
echo 'G1 Y5' >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -n '1,/Z'"${1}"'/p'| tac | grep -m 1 -o '^[T][01]' >> ${PLR_PATH}/"${plr}"
echo 'G91' >> ${PLR_PATH}/"${plr}"
echo 'G1 Z-5' >> ${PLR_PATH}/"${plr}"
echo 'G90' >> ${PLR_PATH}/"${plr}"
echo 'M106 S204' >> ${PLR_PATH}/"${plr}"
if (bed_temp > 0 || print_temp > 0) {
if (!cmd_generated) {
print "; 温度控制指令"
cmd_generated = 1
}
if (bed_temp > 0) {
printf "M140 S%d\nM190 S%d\n", bed_temp, bed_temp
}
if (print_temp > 0) {
printf "M104 S%d\nM109 S%d\n", print_temp, print_temp
}
exit
}
}
' "$sourcefile" >> "${PLR_DIR}/${plr}"
first_line=$(cat /home/klipper/plrtmpA.$$ |sed -e '1,/Z'${1}'/ d' | sed -ne '/ Z/,$ p' | grep -m 1 ' Z' | grep -E 'F[0-9]+' | sed -E 's/F[0-9]+/F3000/g')
if [ "${first_line}" = "" ];then
cat /home/klipper/plrtmpA.$$ | sed -e '1,/Z'${1}'/ d' | sed -ne '/ Z/,$ p' >> ${PLR_PATH}/"${plr}"
else
line=$(cat /home/klipper/plrtmpA.$$ | sed -e '1,/Z'${1}'/ d' | sed -ne '/ Z/,$ p' | grep -m 1 ' Z')
z_pos=$(echo "$line" | sed -n 's/.*Z\([0-9.]*\).*/\1/p')
if [[ ${1} != $z_pos ]]; then
first_line=$(cat /home/klipper/plrtmpA.$$ |sed -e '1,/Z'${1}'/ { /Z'${1}'/!d }' | sed -ne '/ Z/,$ p' | grep -m 1 ' Z' | grep -E 'F[0-9]+' | sed -E 's/F[0-9]+/F3000/g')
echo ${first_line} >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -e '1,/Z'${1}'/ { /Z'${1}'/!d }' | sed -ne '/ Z/,$ p' | tail -n +2 >> ${PLR_PATH}/"${plr}"
else
echo ${first_line} >> ${PLR_PATH}/"${plr}"
cat /home/klipper/plrtmpA.$$ | sed -e '1,/Z'${1}'/ d' | sed -ne '/ Z/,$ p' | tail -n +2 >> ${PLR_PATH}/"${plr}"
awk -v end_line="$line" '
BEGIN { last_mode = ""; e_value = "" }
# 跳过注释行
$0 ~ /^;/ { next }
# 只处理到end_line行
NR > end_line { exit }
# 记录最后出现的模式
/M83/ { last_mode = "M83" }
/M82/ { last_mode = "M82" }
# 捕获end_line行的E值
NR == end_line {
if (match($0, /E[0-9.]+/)) {
e_value = substr($0, RSTART+1, RLENGTH-1)
}
}
# 最终决策
END {
if (last_mode == "M83") {
print "G92 E0"
print "M83"
}
else if (last_mode == "M82") {
print "M82"
print (e_value != "") ? "G92 E" e_value : "G92 E0"
}
}
' "$sourcefile" >> "${PLR_DIR}/${plr}"
target_position=$(awk -v line_num="$line" 'NR == line_num { gsub(/E[0-9.]+/, ""); print }' "$sourcefile")
{
echo 'G91'
echo 'G1 Z10'
echo 'G90'
echo 'G28 X Y'
awk -v end_line="$line" '
NR > end_line { exit }
/ACTIVATE_COPY_MODE|ACTIVATE_MIRROR_MODE/ { print }
' "$sourcefile"
echo 'G1 X5'
echo 'G1 Y5'
awk -v end_line="$line" '
NR > end_line {
if (found) {
print last_match
}
exit
}
/^T[01]/ {
last_match = $0
found = 1
}
END {
if (found) {
print last_match
}
}
' "$sourcefile"
if [ -n "$target_position" ]; then
echo "$target_position"
fi
fi
echo 'M106 S204'
} >> "${PLR_DIR}/${plr}"
echo "G1 Z${z_height} F3000" >> "${PLR_DIR}/${plr}"
sed -n "${line},$ p" "${sourcefile}" >> "${PLR_DIR}/${plr}"
echo "Append the file from ${line} line to ${PLR_DIR}/${plr}" >> "$LOG_FILE"
rm /home/klipper/plrtmpA.$$
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [$(date '+%F %T')] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> "$LOG_FILE"

View File

@ -32,6 +32,7 @@
struct stepper_move {
struct move_node node;
uint32_t interval;
uint32_t taskline;
int16_t add;
uint16_t count;
uint8_t flags;
@ -227,6 +228,7 @@ command_queue_step(uint32_t *args)
if (!m->count)
shutdown("Invalid count parameter");
m->add = args[3];
m->taskline = args[4];
m->flags = 0;
irq_disable();
@ -249,7 +251,7 @@ command_queue_step(uint32_t *args)
irq_enable();
}
DECL_COMMAND(command_queue_step,
"queue_step oid=%c interval=%u count=%hu add=%hi");
"queue_step oid=%c interval=%u count=%hu add=%hi taskline=%u");
// Set the direction of the next queued step
void
@ -307,6 +309,29 @@ command_stepper_get_position(uint32_t *args)
}
DECL_COMMAND(command_stepper_get_position, "stepper_get_position oid=%c");
// Report the current line of the stepper
void
command_stepper_get_taskline(uint32_t *args)
{
uint8_t oid = args[0];
struct stepper *s = stepper_oid_lookup(oid);
uint32_t max_taskline = 0;
irq_disable();
struct move_node *mn = s->mq.first;
while (mn) {
struct stepper_move *m = container_of(mn, struct stepper_move, node);
if(m->taskline){
if (m->taskline > max_taskline)
max_taskline = m->taskline;
break;
}
mn = mn->next;
}
irq_enable();
sendf("stepper_taskline line=%u", max_taskline);
}
DECL_COMMAND(command_stepper_get_taskline, "stepper_get_taskline oid=%c");
// Stop all moves for a given stepper (caller must disable IRQs)
static void
stepper_stop(struct trsync_signal *tss, uint8_t reason)