Optimize Power-Loss Recovery (#12440)
This commit is contained in:
parent
ca21ac6b9b
commit
d97e31db4c
|
@ -924,11 +924,11 @@ void setup() {
|
|||
#endif
|
||||
|
||||
#if DO_SWITCH_EXTRUDER
|
||||
move_extruder_servo(0); // Initialize extruder servo
|
||||
move_extruder_servo(0); // Initialize extruder servo
|
||||
#endif
|
||||
|
||||
#if ENABLED(SWITCHING_NOZZLE)
|
||||
move_nozzle_servo(0); // Initialize nozzle servo
|
||||
move_nozzle_servo(0); // Initialize nozzle servo
|
||||
#endif
|
||||
|
||||
#if ENABLED(PARKING_EXTRUDER)
|
||||
|
@ -936,11 +936,11 @@ void setup() {
|
|||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
check_print_job_recovery();
|
||||
recovery.check();
|
||||
#endif
|
||||
|
||||
#if ENABLED(USE_WATCHDOG) // Reinit watchdog after HAL_get_reset_source call
|
||||
watchdog_init();
|
||||
#if ENABLED(USE_WATCHDOG)
|
||||
watchdog_init(); // Reinit watchdog after HAL_get_reset_source call
|
||||
#endif
|
||||
|
||||
#if ENABLED(EXTERNAL_CLOSED_LOOP_CONTROLLER)
|
||||
|
|
|
@ -29,247 +29,145 @@
|
|||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
|
||||
#include "power_loss_recovery.h"
|
||||
#include "../core/macros.h"
|
||||
|
||||
bool PrintJobRecovery::enabled; // Initialized by settings.load()
|
||||
|
||||
SdFile PrintJobRecovery::file;
|
||||
job_recovery_info_t PrintJobRecovery::info;
|
||||
|
||||
#include "../sd/cardreader.h"
|
||||
#include "../lcd/ultralcd.h"
|
||||
#include "../gcode/queue.h"
|
||||
#include "../gcode/gcode.h"
|
||||
#include "../module/motion.h"
|
||||
#include "../module/planner.h"
|
||||
#include "../module/printcounter.h"
|
||||
#include "../module/temperature.h"
|
||||
#include "../sd/cardreader.h"
|
||||
#include "../core/serial.h"
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
#include "fwretract.h"
|
||||
#endif
|
||||
|
||||
// Recovery data
|
||||
job_recovery_info_t job_recovery_info;
|
||||
JobRecoveryPhase job_recovery_phase = JOB_RECOVERY_IDLE;
|
||||
uint8_t job_recovery_commands_count; //=0
|
||||
char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
|
||||
PrintJobRecovery recovery;
|
||||
|
||||
extern uint8_t commands_in_queue, cmd_queue_index_r;
|
||||
/**
|
||||
* Clear the recovery info
|
||||
*/
|
||||
void PrintJobRecovery::init() { memset(&info, 0, sizeof(info)); }
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
void debug_print_job_recovery(const bool recovery) {
|
||||
SERIAL_PROTOCOLLNPGM("---- Job Recovery Info ----");
|
||||
SERIAL_PROTOCOLPAIR("valid_head:", int(job_recovery_info.valid_head));
|
||||
SERIAL_PROTOCOLLNPAIR(" valid_foot:", int(job_recovery_info.valid_foot));
|
||||
if (job_recovery_info.valid_head) {
|
||||
if (job_recovery_info.valid_head == job_recovery_info.valid_foot) {
|
||||
SERIAL_PROTOCOLPGM("current_position: ");
|
||||
LOOP_XYZE(i) {
|
||||
SERIAL_PROTOCOL(job_recovery_info.current_position[i]);
|
||||
if (i < E_AXIS) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
SERIAL_PROTOCOLLNPAIR("feedrate: ", job_recovery_info.feedrate);
|
||||
/**
|
||||
* Enable or disable then call changed()
|
||||
*/
|
||||
void PrintJobRecovery::enable(const bool onoff) {
|
||||
enabled = onoff;
|
||||
changed();
|
||||
}
|
||||
|
||||
#if HOTENDS > 1
|
||||
SERIAL_PROTOCOLLNPAIR("active_hotend: ", int(job_recovery_info.active_hotend));
|
||||
#endif
|
||||
|
||||
SERIAL_PROTOCOLPGM("target_temperature: ");
|
||||
HOTEND_LOOP() {
|
||||
SERIAL_PROTOCOL(job_recovery_info.target_temperature[e]);
|
||||
if (e < HOTENDS - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
SERIAL_PROTOCOLLNPAIR("target_temperature_bed: ", job_recovery_info.target_temperature_bed);
|
||||
#endif
|
||||
|
||||
#if FAN_COUNT
|
||||
SERIAL_PROTOCOLPGM("fan_speed: ");
|
||||
for (int8_t i = 0; i < FAN_COUNT; i++) {
|
||||
SERIAL_PROTOCOL(job_recovery_info.fan_speed[i]);
|
||||
if (i < FAN_COUNT - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
SERIAL_PROTOCOLPAIR("leveling: ", int(job_recovery_info.leveling));
|
||||
SERIAL_PROTOCOLLNPAIR(" fade: ", int(job_recovery_info.fade));
|
||||
#endif
|
||||
#if ENABLED(FWRETRACT)
|
||||
SERIAL_PROTOCOLPGM("retract: ");
|
||||
for (int8_t e = 0; e < EXTRUDERS; e++) {
|
||||
SERIAL_PROTOCOL(job_recovery_info.retract[e]);
|
||||
if (e < EXTRUDERS - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
SERIAL_PROTOCOLLNPAIR("retract_hop: ", job_recovery_info.retract_hop);
|
||||
#endif
|
||||
SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", int(job_recovery_info.cmd_queue_index_r));
|
||||
SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", int(job_recovery_info.commands_in_queue));
|
||||
if (recovery)
|
||||
for (uint8_t i = 0; i < job_recovery_commands_count; i++) SERIAL_PROTOCOLLNPAIR("> ", job_recovery_commands[i]);
|
||||
else
|
||||
for (uint8_t i = 0; i < job_recovery_info.commands_in_queue; i++) SERIAL_PROTOCOLLNPAIR("> ", job_recovery_info.command_queue[i]);
|
||||
SERIAL_PROTOCOLLNPAIR("sd_filename: ", job_recovery_info.sd_filename);
|
||||
SERIAL_PROTOCOLLNPAIR("sdpos: ", job_recovery_info.sdpos);
|
||||
SERIAL_PROTOCOLLNPAIR("print_job_elapsed: ", job_recovery_info.print_job_elapsed);
|
||||
}
|
||||
else
|
||||
SERIAL_PROTOCOLLNPGM("INVALID DATA");
|
||||
}
|
||||
SERIAL_PROTOCOLLNPGM("---------------------------");
|
||||
}
|
||||
#endif // DEBUG_POWER_LOSS_RECOVERY
|
||||
/**
|
||||
* The enabled state was changed:
|
||||
* - Enabled: Purge the job recovery file
|
||||
* - Disabled: Write the job recovery file
|
||||
*/
|
||||
void PrintJobRecovery::changed() {
|
||||
if (!enabled)
|
||||
purge();
|
||||
else if (IS_SD_PRINTING())
|
||||
save(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for Print Job Recovery during setup()
|
||||
*
|
||||
* If a saved state exists, populate job_recovery_commands with
|
||||
* commands to restore the machine state and continue the file.
|
||||
* If a saved state exists send 'M1000 S' to initiate job recovery.
|
||||
*/
|
||||
void check_print_job_recovery() {
|
||||
memset(&job_recovery_info, 0, sizeof(job_recovery_info));
|
||||
ZERO(job_recovery_commands);
|
||||
|
||||
if (!card.cardOK) card.initsd();
|
||||
|
||||
if (card.cardOK) {
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
SERIAL_PROTOCOLLNPAIR("Init job recovery info. Size: ", int(sizeof(job_recovery_info)));
|
||||
#endif
|
||||
|
||||
if (card.jobRecoverFileExists()) {
|
||||
card.openJobRecoveryFile(true);
|
||||
card.loadJobRecoveryInfo();
|
||||
card.closeJobRecoveryFile();
|
||||
//card.removeJobRecoveryFile();
|
||||
|
||||
if (job_recovery_info.valid_head && job_recovery_info.valid_head == job_recovery_info.valid_foot) {
|
||||
|
||||
uint8_t ind = 0;
|
||||
|
||||
#if HAS_LEVELING
|
||||
strcpy_P(job_recovery_commands[ind++], PSTR("M420 S0 Z0")); // Leveling off before G92 or G28
|
||||
#endif
|
||||
|
||||
strcpy_P(job_recovery_commands[ind++], PSTR("G92.0 Z0")); // Ensure Z is equal to 0
|
||||
strcpy_P(job_recovery_commands[ind++], PSTR("G1 Z2")); // Raise Z by 2mm (we hope!)
|
||||
strcpy_P(job_recovery_commands[ind++], PSTR("G28 R0"
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
" S"
|
||||
#elif !IS_KINEMATIC
|
||||
" X Y" // Home X and Y for Cartesian
|
||||
#endif
|
||||
));
|
||||
|
||||
char str_1[16], str_2[16];
|
||||
|
||||
#if HAS_LEVELING
|
||||
if (job_recovery_info.fade || job_recovery_info.leveling) {
|
||||
// Restore leveling state before G92 sets Z
|
||||
// This ensures the steppers correspond to the native Z
|
||||
dtostrf(job_recovery_info.fade, 1, 1, str_1);
|
||||
sprintf_P(job_recovery_commands[ind++], PSTR("M420 S%i Z%s"), int(job_recovery_info.leveling), str_1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
for (uint8_t e = 0; e < EXTRUDERS; e++) {
|
||||
if (job_recovery_info.retract[e] != 0.0)
|
||||
fwretract.current_retract[e] = job_recovery_info.retract[e];
|
||||
fwretract.retracted[e] = true;
|
||||
}
|
||||
fwretract.current_hop = job_recovery_info.retract_hop;
|
||||
#endif
|
||||
|
||||
dtostrf(job_recovery_info.current_position[Z_AXIS] + 2, 1, 3, str_1);
|
||||
dtostrf(job_recovery_info.current_position[E_AXIS]
|
||||
#if ENABLED(SAVE_EACH_CMD_MODE)
|
||||
- 5
|
||||
#endif
|
||||
, 1, 3, str_2
|
||||
);
|
||||
sprintf_P(job_recovery_commands[ind++], PSTR("G92.0 Z%s E%s"), str_1, str_2); // Current Z + 2 and E
|
||||
|
||||
uint8_t r = job_recovery_info.cmd_queue_index_r, c = job_recovery_info.commands_in_queue;
|
||||
while (c--) {
|
||||
strcpy(job_recovery_commands[ind++], job_recovery_info.command_queue[r]);
|
||||
r = (r + 1) % BUFSIZE;
|
||||
}
|
||||
|
||||
if (job_recovery_info.sd_filename[0] == '/') job_recovery_info.sd_filename[0] = ' ';
|
||||
sprintf_P(job_recovery_commands[ind++], PSTR("M23 %s"), job_recovery_info.sd_filename);
|
||||
sprintf_P(job_recovery_commands[ind++], PSTR("M24 S%ld T%ld"), job_recovery_info.sdpos, job_recovery_info.print_job_elapsed);
|
||||
|
||||
job_recovery_commands_count = ind;
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
debug_print_job_recovery(true);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (job_recovery_info.valid_head != job_recovery_info.valid_foot)
|
||||
LCD_ALERTMESSAGEPGM("INVALID DATA");
|
||||
memset(&job_recovery_info, 0, sizeof(job_recovery_info));
|
||||
}
|
||||
void PrintJobRecovery::check() {
|
||||
if (enabled) {
|
||||
if (!card.cardOK) card.initsd();
|
||||
if (card.cardOK) {
|
||||
load();
|
||||
if (!valid()) return purge();
|
||||
enqueue_and_echo_commands_P(PSTR("M1000 S"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the recovery file and clear the recovery data
|
||||
*/
|
||||
void PrintJobRecovery::purge() {
|
||||
init();
|
||||
card.removeJobRecoveryFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the recovery data, if it exists
|
||||
*/
|
||||
void PrintJobRecovery::load() {
|
||||
if (exists()) {
|
||||
open(true);
|
||||
(void)file.read(&info, sizeof(info));
|
||||
close();
|
||||
}
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
debug(PSTR("Load"));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current machine state to the power-loss recovery file
|
||||
*/
|
||||
void save_job_recovery_info() {
|
||||
void PrintJobRecovery::save(const bool force/*=false*/) {
|
||||
|
||||
#if SAVE_INFO_INTERVAL_MS > 0
|
||||
static millis_t next_save_ms; // = 0; // Init on reset
|
||||
static millis_t next_save_ms; // = 0
|
||||
millis_t ms = millis();
|
||||
#endif
|
||||
if (
|
||||
// Save on every command
|
||||
#if ENABLED(SAVE_EACH_CMD_MODE)
|
||||
true
|
||||
#else
|
||||
// Save if power loss pin is triggered
|
||||
#if PIN_EXISTS(POWER_LOSS)
|
||||
READ(POWER_LOSS_PIN) == POWER_LOSS_STATE ||
|
||||
|
||||
if (force
|
||||
#if DISABLED(SAVE_EACH_CMD_MODE) // Always save state when enabled
|
||||
#if PIN_EXISTS(POWER_LOSS) // Save if power loss pin is triggered
|
||||
|| READ(POWER_LOSS_PIN) == POWER_LOSS_STATE
|
||||
#endif
|
||||
// Save if interval is elapsed
|
||||
#if SAVE_INFO_INTERVAL_MS > 0
|
||||
ELAPSED(ms, next_save_ms) ||
|
||||
#if SAVE_INFO_INTERVAL_MS > 0 // Save if interval is elapsed
|
||||
|| ELAPSED(ms, next_save_ms)
|
||||
#endif
|
||||
// Save on every new Z height
|
||||
(current_position[Z_AXIS] > 0 && current_position[Z_AXIS] > job_recovery_info.current_position[Z_AXIS])
|
||||
// Save every time Z is higher than the last call
|
||||
|| current_position[Z_AXIS] > info.current_position[Z_AXIS]
|
||||
#endif
|
||||
) {
|
||||
|
||||
#if SAVE_INFO_INTERVAL_MS > 0
|
||||
next_save_ms = ms + SAVE_INFO_INTERVAL_MS;
|
||||
#endif
|
||||
|
||||
// Head and foot will match if valid data was saved
|
||||
if (!++job_recovery_info.valid_head) ++job_recovery_info.valid_head; // non-zero in sequence
|
||||
job_recovery_info.valid_foot = job_recovery_info.valid_head;
|
||||
// Set Head and Foot to matching non-zero values
|
||||
if (!++info.valid_head) ++info.valid_head; // non-zero in sequence
|
||||
//if (!IS_SD_PRINTING()) info.valid_head = 0;
|
||||
info.valid_foot = info.valid_head;
|
||||
|
||||
// Machine state
|
||||
COPY(job_recovery_info.current_position, current_position);
|
||||
job_recovery_info.feedrate = feedrate_mm_s;
|
||||
COPY(info.current_position, current_position);
|
||||
info.feedrate = uint16_t(feedrate_mm_s * 60.0f);
|
||||
|
||||
#if HOTENDS > 1
|
||||
job_recovery_info.active_hotend = active_extruder;
|
||||
info.active_hotend = active_extruder;
|
||||
#endif
|
||||
|
||||
COPY(job_recovery_info.target_temperature, thermalManager.target_temperature);
|
||||
COPY(info.target_temperature, thermalManager.target_temperature);
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
job_recovery_info.target_temperature_bed = thermalManager.target_temperature_bed;
|
||||
info.target_temperature_bed = thermalManager.target_temperature_bed;
|
||||
#endif
|
||||
|
||||
#if FAN_COUNT
|
||||
COPY(job_recovery_info.fan_speed, fan_speed);
|
||||
COPY(info.fan_speed, fan_speed);
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
job_recovery_info.leveling = planner.leveling_active;
|
||||
job_recovery_info.fade = (
|
||||
info.leveling = planner.leveling_active;
|
||||
info.fade = (
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
planner.z_fade_height
|
||||
#else
|
||||
|
@ -279,35 +177,238 @@ void save_job_recovery_info() {
|
|||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
COPY(job_recovery_info.retract, fwretract.current_retract);
|
||||
job_recovery_info.retract_hop = fwretract.current_hop;
|
||||
COPY(info.retract, fwretract.current_retract);
|
||||
info.retract_hop = fwretract.current_hop;
|
||||
#endif
|
||||
|
||||
// Commands in the queue
|
||||
job_recovery_info.cmd_queue_index_r = cmd_queue_index_r;
|
||||
job_recovery_info.commands_in_queue = commands_in_queue;
|
||||
COPY(job_recovery_info.command_queue, command_queue);
|
||||
info.cmd_queue_index_r = cmd_queue_index_r;
|
||||
info.commands_in_queue = commands_in_queue;
|
||||
COPY(info.command_queue, command_queue);
|
||||
|
||||
// Elapsed print job time
|
||||
job_recovery_info.print_job_elapsed = print_job_timer.duration();
|
||||
info.print_job_elapsed = print_job_timer.duration();
|
||||
|
||||
// SD file position
|
||||
card.getAbsFilename(job_recovery_info.sd_filename);
|
||||
job_recovery_info.sdpos = card.getIndex();
|
||||
card.getAbsFilename(info.sd_filename);
|
||||
info.sdpos = card.getIndex();
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
SERIAL_PROTOCOLLNPGM("Saving...");
|
||||
debug_print_job_recovery(false);
|
||||
#endif
|
||||
write();
|
||||
|
||||
card.openJobRecoveryFile(false);
|
||||
(void)card.saveJobRecoveryInfo();
|
||||
|
||||
// If power-loss pin was triggered, write just once then kill
|
||||
// KILL now if the power-loss pin was triggered
|
||||
#if PIN_EXISTS(POWER_LOSS)
|
||||
if (READ(POWER_LOSS_PIN) == POWER_LOSS_STATE) kill(MSG_POWER_LOSS_RECOVERY);
|
||||
if (READ(POWER_LOSS_PIN) == POWER_LOSS_STATE) kill(MSG_OUTAGE_RECOVERY);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the recovery info the recovery file
|
||||
*/
|
||||
void PrintJobRecovery::write() {
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
debug(PSTR("Write"));
|
||||
#endif
|
||||
|
||||
open(false);
|
||||
file.seekSet(0);
|
||||
const int16_t ret = file.write(&info, sizeof(info));
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
if (ret == -1) SERIAL_ECHOLNPGM("Power-loss file write failed.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume the saved print job
|
||||
*/
|
||||
void PrintJobRecovery::resume() {
|
||||
|
||||
#define RECOVERY_ZRAISE 2
|
||||
|
||||
#if HAS_LEVELING
|
||||
// Make sure leveling is off before any G92 and G28
|
||||
gcode.process_subcommands_now_P(PSTR("M420 S0 Z0"));
|
||||
#endif
|
||||
|
||||
// Set Z to 0, raise Z by 2mm, and Home (XY only for Cartesian) with no raise
|
||||
// (Only do simulated homing in Marlin Dev Mode.)
|
||||
gcode.process_subcommands_now_P(PSTR("G92.0 Z0|G1 Z" STRINGIFY(RECOVERY_ZRAISE) "|G28 R0"
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
" S"
|
||||
#elif !IS_KINEMATIC
|
||||
" X Y"
|
||||
#endif
|
||||
));
|
||||
|
||||
// Pretend that all axes are homed
|
||||
axis_homed = axis_known_position = xyz_bits;
|
||||
|
||||
char cmd[40], str_1[16], str_2[16];
|
||||
|
||||
// Select the previously active tool (with no_move)
|
||||
#if EXTRUDERS > 1
|
||||
sprintf_P(cmd, PSTR("T%i S"), info.active_hotend);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
#endif
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
const int16_t bt = info.target_temperature_bed;
|
||||
if (bt) {
|
||||
// Restore the bed temperature
|
||||
sprintf_P(cmd, PSTR("M190 S%i"), bt);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Restore all hotend temperatures
|
||||
HOTEND_LOOP() {
|
||||
const int16_t et = info.target_temperature[e];
|
||||
if (et) {
|
||||
#if HOTENDS > 1
|
||||
sprintf_P(cmd, PSTR("T%i"), e);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
#endif
|
||||
sprintf_P(cmd, PSTR("M109 S%i"), et);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore print cooling fan speeds
|
||||
for (uint8_t i = 0; i < FAN_COUNT; i++) {
|
||||
uint8_t f = info.fan_speed[i];
|
||||
if (f) {
|
||||
sprintf_P(cmd, PSTR("M106 P%i S%i"), i, f);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore retract and hop state
|
||||
#if ENABLED(FWRETRACT)
|
||||
for (uint8_t e = 0; e < EXTRUDERS; e++) {
|
||||
if (info.retract[e] != 0.0)
|
||||
fwretract.current_retract[e] = info.retract[e];
|
||||
fwretract.retracted[e] = true;
|
||||
}
|
||||
fwretract.current_hop = info.retract_hop;
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
// Restore leveling state before 'G92 Z' to ensure
|
||||
// the Z stepper count corresponds to the native Z.
|
||||
if (info.fade || info.leveling) {
|
||||
dtostrf(info.fade, 1, 1, str_1);
|
||||
sprintf_P(cmd, PSTR("M420 S%i Z%s"), int(info.leveling), str_1);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Restore Z (plus raise) and E positions with G92.0
|
||||
dtostrf(info.current_position[Z_AXIS] + RECOVERY_ZRAISE, 1, 3, str_1);
|
||||
dtostrf(info.current_position[E_AXIS]
|
||||
#if ENABLED(SAVE_EACH_CMD_MODE)
|
||||
- 5 // Extra extrusion on restart
|
||||
#endif
|
||||
, 1, 3, str_2
|
||||
);
|
||||
sprintf_P(cmd, PSTR("G92.0 Z%s E%s"), str_1, str_2);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
|
||||
// Move back to the saved XY
|
||||
dtostrf(info.current_position[X_AXIS], 1, 3, str_1);
|
||||
dtostrf(info.current_position[Y_AXIS], 1, 3, str_2);
|
||||
sprintf_P(cmd, PSTR("G1 X%s Y%s F3000"), str_1, str_2);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
|
||||
// Move back to the saved Z
|
||||
dtostrf(info.current_position[Z_AXIS], 1, 3, str_1);
|
||||
sprintf_P(cmd, PSTR("G1 Z%s F200"), str_1);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
|
||||
// Restore the feedrate
|
||||
sprintf_P(cmd, PSTR("G1 F%d"), info.feedrate);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
|
||||
// Process commands from the old pending queue
|
||||
uint8_t r = info.cmd_queue_index_r, c = info.commands_in_queue;
|
||||
for (; c--; r = (r + 1) % BUFSIZE)
|
||||
gcode.process_subcommands_now(info.command_queue[r]);
|
||||
|
||||
// Resume the SD file from the last position
|
||||
char *fn = info.sd_filename;
|
||||
while (*fn == '/') fn++;
|
||||
sprintf_P(cmd, PSTR("M23 %s"), fn);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
sprintf_P(cmd, PSTR("M24 S%ld T%ld"), info.sdpos, info.print_job_elapsed);
|
||||
gcode.process_subcommands_now(cmd);
|
||||
}
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
|
||||
void PrintJobRecovery::debug(PGM_P const prefix) {
|
||||
serialprintPGM(prefix);
|
||||
SERIAL_ECHOPAIR(" Job Recovery Info...\nvalid_head:", int(info.valid_head));
|
||||
SERIAL_ECHOLNPAIR(" valid_foot:", int(info.valid_foot));
|
||||
if (info.valid_head) {
|
||||
if (info.valid_head == info.valid_foot) {
|
||||
SERIAL_ECHOPGM("current_position: ");
|
||||
LOOP_XYZE(i) {
|
||||
SERIAL_ECHO(info.current_position[i]);
|
||||
if (i < E_AXIS) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
SERIAL_ECHOLNPAIR("feedrate: ", info.feedrate);
|
||||
|
||||
#if HOTENDS > 1
|
||||
SERIAL_ECHOLNPAIR("active_hotend: ", int(info.active_hotend));
|
||||
#endif
|
||||
|
||||
SERIAL_ECHOPGM("target_temperature: ");
|
||||
HOTEND_LOOP() {
|
||||
SERIAL_ECHO(info.target_temperature[e]);
|
||||
if (e < HOTENDS - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
SERIAL_ECHOLNPAIR("target_temperature_bed: ", info.target_temperature_bed);
|
||||
#endif
|
||||
|
||||
#if FAN_COUNT
|
||||
SERIAL_ECHOPGM("fan_speed: ");
|
||||
for (int8_t i = 0; i < FAN_COUNT; i++) {
|
||||
SERIAL_ECHO(int(info.fan_speed[i]));
|
||||
if (i < FAN_COUNT - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
SERIAL_ECHOPAIR("leveling: ", int(info.leveling));
|
||||
SERIAL_ECHOLNPAIR(" fade: ", int(info.fade));
|
||||
#endif
|
||||
#if ENABLED(FWRETRACT)
|
||||
SERIAL_ECHOPGM("retract: ");
|
||||
for (int8_t e = 0; e < EXTRUDERS; e++) {
|
||||
SERIAL_ECHO(info.retract[e]);
|
||||
if (e < EXTRUDERS - 1) SERIAL_CHAR(',');
|
||||
}
|
||||
SERIAL_EOL();
|
||||
SERIAL_ECHOLNPAIR("retract_hop: ", info.retract_hop);
|
||||
#endif
|
||||
SERIAL_ECHOLNPAIR("cmd_queue_index_r: ", int(info.cmd_queue_index_r));
|
||||
SERIAL_ECHOLNPAIR("commands_in_queue: ", int(info.commands_in_queue));
|
||||
for (uint8_t i = 0; i < info.commands_in_queue; i++) SERIAL_ECHOLNPAIR("> ", info.command_queue[i]);
|
||||
SERIAL_ECHOLNPAIR("sd_filename: ", info.sd_filename);
|
||||
SERIAL_ECHOLNPAIR("sdpos: ", info.sdpos);
|
||||
SERIAL_ECHOLNPAIR("print_job_elapsed: ", info.print_job_elapsed);
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("INVALID DATA");
|
||||
}
|
||||
SERIAL_ECHOLNPGM("---");
|
||||
}
|
||||
|
||||
#endif // DEBUG_POWER_LOSS_RECOVERY
|
||||
|
||||
#endif // POWER_LOSS_RECOVERY
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
*/
|
||||
|
||||
#include "../sd/cardreader.h"
|
||||
#include "../core/millis_t.h"
|
||||
#include "../inc/MarlinConfigPre.h"
|
||||
|
||||
#define SAVE_INFO_INTERVAL_MS 0
|
||||
|
@ -37,7 +36,9 @@ typedef struct {
|
|||
uint8_t valid_head;
|
||||
|
||||
// Machine state
|
||||
float current_position[NUM_AXIS], feedrate;
|
||||
float current_position[NUM_AXIS];
|
||||
|
||||
uint16_t feedrate;
|
||||
|
||||
#if HOTENDS > 1
|
||||
uint8_t active_hotend;
|
||||
|
@ -74,26 +75,45 @@ typedef struct {
|
|||
millis_t print_job_elapsed;
|
||||
|
||||
uint8_t valid_foot;
|
||||
|
||||
} job_recovery_info_t;
|
||||
|
||||
extern job_recovery_info_t job_recovery_info;
|
||||
class PrintJobRecovery {
|
||||
public:
|
||||
static SdFile file;
|
||||
static job_recovery_info_t info;
|
||||
|
||||
enum JobRecoveryPhase : unsigned char {
|
||||
JOB_RECOVERY_IDLE,
|
||||
JOB_RECOVERY_MAYBE,
|
||||
JOB_RECOVERY_YES,
|
||||
JOB_RECOVERY_DONE
|
||||
static void init();
|
||||
|
||||
static bool enabled;
|
||||
static void enable(const bool onoff);
|
||||
static void changed();
|
||||
|
||||
static void check();
|
||||
static void resume();
|
||||
|
||||
static inline bool exists() { return card.jobRecoverFileExists(); }
|
||||
static inline void open(const bool read) { card.openJobRecoveryFile(read); }
|
||||
static inline void close() { file.close(); }
|
||||
|
||||
static void purge();
|
||||
static void load();
|
||||
static void save(const bool force=
|
||||
#if ENABLED(SAVE_EACH_CMD_MODE)
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
|
||||
static inline bool valid() { return info.valid_head && info.valid_head == info.valid_foot; }
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
static void debug(PGM_P const prefix);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static void write();
|
||||
};
|
||||
extern JobRecoveryPhase job_recovery_phase;
|
||||
|
||||
#if HAS_LEVELING
|
||||
#define APPEND_CMD_COUNT 9
|
||||
#else
|
||||
#define APPEND_CMD_COUNT 7
|
||||
#endif
|
||||
|
||||
extern char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
|
||||
extern uint8_t job_recovery_commands_count;
|
||||
|
||||
void check_print_job_recovery();
|
||||
void save_job_recovery_info();
|
||||
extern PrintJobRecovery recovery;
|
||||
|
|
65
Marlin/src/gcode/feature/powerloss/M1000.cpp
Normal file
65
Marlin/src/gcode/feature/powerloss/M1000.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
|
||||
#include "../../gcode.h"
|
||||
#include "../../../feature/power_loss_recovery.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../lcd/ultralcd.h"
|
||||
|
||||
void menu_job_recovery();
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
|
||||
inline void plr_error(PGM_P const prefix) {
|
||||
SERIAL_ECHO_START();
|
||||
serialprintPGM(prefix);
|
||||
SERIAL_ECHOLNPGM(" Power-Loss Recovery Data");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* M1000: Resume from power-loss (undocumented)
|
||||
* - With 'S' go to the Resume/Cancel menu
|
||||
* - With no parameters, run recovery commands
|
||||
*/
|
||||
void GcodeSuite::M1000() {
|
||||
|
||||
if (recovery.valid()) {
|
||||
if (parser.seen('S'))
|
||||
ui.goto_screen(menu_job_recovery);
|
||||
else
|
||||
recovery.resume();
|
||||
}
|
||||
else {
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
plr_error(recovery.info.valid_head ? PSTR("No") : PSTR("Invalid"));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // POWER_LOSS_RECOVERY
|
58
Marlin/src/gcode/feature/powerloss/M413.cpp
Normal file
58
Marlin/src/gcode/feature/powerloss/M413.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
|
||||
#include "../../gcode.h"
|
||||
#include "../../../feature/power_loss_recovery.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../lcd/ultralcd.h"
|
||||
|
||||
/**
|
||||
* M413: Enable / Disable power-loss recovery
|
||||
*
|
||||
* Parameters
|
||||
* S[bool] - Flag to enable / disable.
|
||||
* If omitted, report current state.
|
||||
*/
|
||||
void GcodeSuite::M413() {
|
||||
|
||||
if (parser.seen('S'))
|
||||
recovery.enable(parser.value_bool());
|
||||
else {
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM("Power-loss recovery ");
|
||||
serialprintln_onoff(recovery.enabled);
|
||||
}
|
||||
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
if (parser.seen('R') || parser.seen('L')) recovery.load();
|
||||
if (parser.seen('W')) recovery.save(true);
|
||||
if (parser.seen('P')) recovery.purge();
|
||||
if (parser.seen('E')) serialprintPGM(recovery.exists() ? PSTR("BIN Exists\n") : PSTR("No BIN\n"));
|
||||
if (parser.seen('V')) serialprintPGM(recovery.valid() ? PSTR("Valid\n") : PSTR("Invalid\n"));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // POWER_LOSS_RECOVERY
|
|
@ -695,6 +695,11 @@ void GcodeSuite::process_parsed_command(
|
|||
|
||||
case 999: M999(); break; // M999: Restart after being Stopped
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
case 413: M413(); break; // M413: Enable/disable/query Power-Loss Recovery
|
||||
case 1000: M1000(); break; // M1000: Resume from power-loss
|
||||
#endif
|
||||
|
||||
default: parser.unknown_command_error(); break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -196,7 +196,8 @@
|
|||
* M406 - Disable Filament Sensor flow control. (Requires FILAMENT_WIDTH_SENSOR)
|
||||
* M407 - Display measured filament diameter in millimeters. (Requires FILAMENT_WIDTH_SENSOR)
|
||||
* M410 - Quickstop. Abort all planned moves.
|
||||
* M412 - Enable / Disable filament runout detection. (Requires FILAMENT_RUNOUT_SENSOR)
|
||||
* M412 - Enable / Disable Filament Runout Detection. (Requires FILAMENT_RUNOUT_SENSOR)
|
||||
* M413 - Enable / Disable Power-Loss Recovery. (Requires POWER_LOSS_RECOVERY)
|
||||
* M420 - Enable/Disable Leveling (with current values) S1=enable S0=disable (Requires MESH_BED_LEVELING or ABL)
|
||||
* M421 - Set a single Z coordinate in the Mesh Leveling grid. X<units> Y<units> Z<units> (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, or AUTO_BED_LEVELING_UBL)
|
||||
* M422 - Set Z Stepper automatic alignment position using probe. X<units> Y<units> A<axis> (Requires Z_STEPPER_AUTO_ALIGN)
|
||||
|
@ -822,6 +823,11 @@ private:
|
|||
|
||||
static void M999();
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
static void M413();
|
||||
static void M1000();
|
||||
#endif
|
||||
|
||||
static void T(const uint8_t tool_index);
|
||||
|
||||
};
|
||||
|
|
|
@ -809,22 +809,6 @@ inline void get_serial_commands() {
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
|
||||
inline bool drain_job_recovery_commands() {
|
||||
static uint8_t job_recovery_commands_index = 0; // Resets on reboot
|
||||
if (job_recovery_commands_count) {
|
||||
if (_enqueuecommand(job_recovery_commands[job_recovery_commands_index])) {
|
||||
++job_recovery_commands_index;
|
||||
if (!--job_recovery_commands_count) job_recovery_phase = JOB_RECOVERY_DONE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDSUPPORT
|
||||
|
||||
/**
|
||||
|
@ -840,11 +824,6 @@ void get_available_commands() {
|
|||
|
||||
get_serial_commands();
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
// Commands for power-loss recovery take precedence
|
||||
if (job_recovery_phase == JOB_RECOVERY_YES && drain_job_recovery_commands()) return;
|
||||
#endif
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
get_sdcard_commands();
|
||||
#endif
|
||||
|
@ -890,7 +869,7 @@ void advance_command_queue() {
|
|||
else {
|
||||
gcode.process_next_command();
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
if (card.cardOK && IS_SD_PRINTING()) save_job_recovery_info();
|
||||
if (IS_SD_PRINTING()) recovery.save();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1629,7 +1629,7 @@
|
|||
// If platform requires early initialization of watchdog to properly boot
|
||||
#define EARLY_WATCHDOG (ENABLED(USE_WATCHDOG) && defined(ARDUINO_ARCH_SAM))
|
||||
|
||||
#define USE_EXECUTE_COMMANDS_IMMEDIATE (ENABLED(G29_RETRY_AND_RECOVER) || ENABLED(GCODE_MACROS))
|
||||
#define USE_EXECUTE_COMMANDS_IMMEDIATE (ENABLED(G29_RETRY_AND_RECOVER) || ENABLED(GCODE_MACROS) || ENABLED(POWER_LOSS_RECOVERY))
|
||||
|
||||
#if ENABLED(Z_TRIPLE_STEPPER_DRIVERS)
|
||||
#define Z_STEPPER_COUNT 3
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("Pozastavit tisk")
|
||||
#define MSG_RESUME_PRINT _UxGT("Obnovit tisk")
|
||||
#define MSG_STOP_PRINT _UxGT("Zastavit tisk")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Obnova vypadku")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Obnova vypadku")
|
||||
#define MSG_CARD_MENU _UxGT("Tisknout z SD")
|
||||
#define MSG_NO_CARD _UxGT("Žádná SD karta")
|
||||
#define MSG_DWELL _UxGT("Uspáno...")
|
||||
|
|
|
@ -268,7 +268,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("SD-Druck pausieren")
|
||||
#define MSG_RESUME_PRINT _UxGT("SD-Druck fortsetzen")
|
||||
#define MSG_STOP_PRINT _UxGT("SD-Druck abbrechen")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Wiederh. n. Stroma.")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Wiederh. n. Stroma.")
|
||||
#define MSG_CARD_MENU _UxGT("Druck v. SD-Karte")
|
||||
#define MSG_NO_CARD _UxGT("Keine SD-Karte")
|
||||
#define MSG_DWELL _UxGT("Warten...")
|
||||
|
|
|
@ -728,8 +728,8 @@
|
|||
#ifndef MSG_STOP_PRINT
|
||||
#define MSG_STOP_PRINT _UxGT("Stop print")
|
||||
#endif
|
||||
#ifndef MSG_POWER_LOSS_RECOVERY
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Power-Loss Recovery")
|
||||
#ifndef MSG_OUTAGE_RECOVERY
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Outage Recovery")
|
||||
#endif
|
||||
#ifndef MSG_CARD_MENU
|
||||
#define MSG_CARD_MENU _UxGT("Print from SD")
|
||||
|
|
|
@ -266,7 +266,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("Pausa stampa")
|
||||
#define MSG_RESUME_PRINT _UxGT("Riprendi stampa")
|
||||
#define MSG_STOP_PRINT _UxGT("Arresta stampa")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Ripresa da PowerLoss")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Ripresa da PowerLoss")
|
||||
#define MSG_CARD_MENU _UxGT("Stampa da SD")
|
||||
#define MSG_NO_CARD _UxGT("SD non presente")
|
||||
#define MSG_DWELL _UxGT("Sospensione...")
|
||||
|
|
|
@ -259,7 +259,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("일시정지")
|
||||
#define MSG_RESUME_PRINT _UxGT("재시작")
|
||||
#define MSG_STOP_PRINT _UxGT("출력중지")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Power-Loss Recovery")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Outage Recovery")
|
||||
#define MSG_CARD_MENU _UxGT("SD 카드출력")
|
||||
#define MSG_NO_CARD _UxGT("SD 카드없음")
|
||||
#define MSG_DWELL _UxGT("슬립모드...")
|
||||
|
|
|
@ -273,7 +273,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("Pausar impressão")
|
||||
#define MSG_RESUME_PRINT _UxGT("Resumir impressão")
|
||||
#define MSG_STOP_PRINT _UxGT("Parar impressão")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Recuperar Impressão")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Recuperar Impressão")
|
||||
#define MSG_CARD_MENU _UxGT("Imprimir do SD")
|
||||
#define MSG_NO_CARD _UxGT("Sem cartão SD")
|
||||
#define MSG_DWELL _UxGT("Dormindo...")
|
||||
|
|
|
@ -278,7 +278,7 @@
|
|||
#define MSG_PAUSE_PRINT _UxGT("Pozastaviť tlač")
|
||||
#define MSG_RESUME_PRINT _UxGT("Obnoviť tlač")
|
||||
#define MSG_STOP_PRINT _UxGT("Zastaviť tlač")
|
||||
#define MSG_POWER_LOSS_RECOVERY _UxGT("Obnova po výp. nap.")
|
||||
#define MSG_OUTAGE_RECOVERY _UxGT("Obnova po výp. nap.")
|
||||
#define MSG_CARD_MENU _UxGT("Tlačiť z SD")
|
||||
#define MSG_NO_CARD _UxGT("Žiadna SD karta")
|
||||
#define MSG_DWELL _UxGT("Spím...")
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#include "../../feature/runout.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
#include "../../feature/power_loss_recovery.h"
|
||||
#endif
|
||||
|
||||
#define HAS_DEBUG_MENU ENABLED(LCD_PROGRESS_BAR_TEST)
|
||||
|
||||
void menu_advanced_settings();
|
||||
|
@ -350,6 +354,10 @@ void menu_configuration() {
|
|||
MENU_ITEM_EDIT_CALLBACK(bool, MSG_RUNOUT_SENSOR_ENABLE, &runout.enabled, runout.reset);
|
||||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
MENU_ITEM_EDIT_CALLBACK(bool, MSG_OUTAGE_RECOVERY, &recovery.enabled, recovery.changed);
|
||||
#endif
|
||||
|
||||
#if DISABLED(SLIM_LCD_MENUS)
|
||||
// Preheat configurations
|
||||
MENU_ITEM(submenu, MSG_PREHEAT_1_SETTINGS, menu_preheat_material1_settings);
|
||||
|
|
|
@ -34,58 +34,8 @@
|
|||
#include "../../feature/power_loss_recovery.h"
|
||||
|
||||
static void lcd_power_loss_recovery_resume() {
|
||||
char cmd[20];
|
||||
|
||||
// Return to status now
|
||||
ui.return_to_status();
|
||||
|
||||
// Turn leveling off and home
|
||||
enqueue_and_echo_commands_P(PSTR("M420 S0\nG28 R0"
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
" S"
|
||||
#elif !IS_KINEMATIC
|
||||
" X Y"
|
||||
#endif
|
||||
));
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
const int16_t bt = job_recovery_info.target_temperature_bed;
|
||||
if (bt) {
|
||||
// Restore the bed temperature
|
||||
sprintf_P(cmd, PSTR("M190 S%i"), bt);
|
||||
enqueue_and_echo_command(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Restore all hotend temperatures
|
||||
HOTEND_LOOP() {
|
||||
const int16_t et = job_recovery_info.target_temperature[e];
|
||||
if (et) {
|
||||
#if HOTENDS > 1
|
||||
sprintf_P(cmd, PSTR("T%i"), e);
|
||||
enqueue_and_echo_command(cmd);
|
||||
#endif
|
||||
sprintf_P(cmd, PSTR("M109 S%i"), et);
|
||||
enqueue_and_echo_command(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
#if HOTENDS > 1
|
||||
sprintf_P(cmd, PSTR("T%i"), job_recovery_info.active_hotend);
|
||||
enqueue_and_echo_command(cmd);
|
||||
#endif
|
||||
|
||||
// Restore print cooling fan speeds
|
||||
for (uint8_t i = 0; i < FAN_COUNT; i++) {
|
||||
uint8_t f = job_recovery_info.fan_speed[i];
|
||||
if (f) {
|
||||
sprintf_P(cmd, PSTR("M106 P%i S%i"), i, f);
|
||||
enqueue_and_echo_command(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Start draining the job recovery command queue
|
||||
job_recovery_phase = JOB_RECOVERY_YES;
|
||||
enqueue_and_echo_commands_P(PSTR("M1000"));
|
||||
}
|
||||
|
||||
static void lcd_power_loss_recovery_cancel() {
|
||||
|
@ -97,7 +47,7 @@ static void lcd_power_loss_recovery_cancel() {
|
|||
void menu_job_recovery() {
|
||||
ui.defer_status_screen(true);
|
||||
START_MENU();
|
||||
STATIC_ITEM(MSG_POWER_LOSS_RECOVERY);
|
||||
STATIC_ITEM(MSG_OUTAGE_RECOVERY);
|
||||
MENU_ITEM(function, MSG_RESUME_PRINT, lcd_power_loss_recovery_resume);
|
||||
MENU_ITEM(function, MSG_STOP_PRINT, lcd_power_loss_recovery_cancel);
|
||||
END_MENU();
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
#if ENABLED(MENU_ADDAUTOSTART)
|
||||
|
||||
void lcd_autostart_sd() { card.beginautostart(); }
|
||||
inline void lcd_autostart_sd() { card.beginautostart(); }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -659,13 +659,6 @@ void MarlinUI::update() {
|
|||
|
||||
#endif // SDSUPPORT && SD_DETECT_PIN
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
if (job_recovery_commands_count && job_recovery_phase == JOB_RECOVERY_IDLE) {
|
||||
goto_screen(menu_job_recovery);
|
||||
job_recovery_phase = JOB_RECOVERY_MAYBE; // Waiting for a response
|
||||
}
|
||||
#endif
|
||||
|
||||
const millis_t ms = millis();
|
||||
if (ELAPSED(ms, next_lcd_update_ms)
|
||||
#if HAS_GRAPHICAL_LCD
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
|
||||
// Change EEPROM version if the structure changes
|
||||
#define EEPROM_VERSION "V62"
|
||||
#define EEPROM_VERSION "V63"
|
||||
#define EEPROM_OFFSET 100
|
||||
|
||||
// Check the integrity of data offsets.
|
||||
|
@ -82,6 +82,11 @@
|
|||
#endif
|
||||
|
||||
#include "../feature/fwretract.h"
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
#include "../feature/power_loss_recovery.h"
|
||||
#endif
|
||||
|
||||
#include "../feature/pause.h"
|
||||
|
||||
#if EXTRUDERS > 1
|
||||
|
@ -221,6 +226,11 @@ typedef struct SettingsDataStruct {
|
|||
//
|
||||
int16_t lcd_contrast; // M250 C
|
||||
|
||||
//
|
||||
// POWER_LOSS_RECOVERY
|
||||
//
|
||||
bool recovery_enabled; // M413 S
|
||||
|
||||
//
|
||||
// FWRETRACT
|
||||
//
|
||||
|
@ -269,7 +279,7 @@ typedef struct SettingsDataStruct {
|
|||
// Tool-change settings
|
||||
//
|
||||
#if EXTRUDERS > 1
|
||||
toolchange_settings_t toolchange_settings; // M217 S P R
|
||||
toolchange_settings_t toolchange_settings; // M217 S P R
|
||||
#endif
|
||||
|
||||
} SettingsData;
|
||||
|
@ -746,6 +756,22 @@ void MarlinSettings::postprocess() {
|
|||
EEPROM_WRITE(lcd_contrast);
|
||||
}
|
||||
|
||||
//
|
||||
// Power-Loss Recovery
|
||||
//
|
||||
{
|
||||
_FIELD_TEST(recovery_enabled);
|
||||
|
||||
const bool recovery_enabled =
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
recovery.enabled
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
;
|
||||
EEPROM_WRITE(recovery_enabled);
|
||||
}
|
||||
|
||||
//
|
||||
// Firmware Retraction
|
||||
//
|
||||
|
@ -1387,6 +1413,20 @@ void MarlinSettings::postprocess() {
|
|||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Power-Loss Recovery
|
||||
//
|
||||
{
|
||||
_FIELD_TEST(recovery_enabled);
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
EEPROM_READ(recovery.enabled);
|
||||
#else
|
||||
bool recovery_enabled;
|
||||
EEPROM_READ(recovery_enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Firmware Retraction
|
||||
//
|
||||
|
@ -2075,6 +2115,10 @@ void MarlinSettings::reset(PORTARG_SOLO) {
|
|||
ui.set_contrast(DEFAULT_LCD_CONTRAST);
|
||||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
recovery.enable(true);
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
fwretract.reset();
|
||||
#endif
|
||||
|
@ -2643,6 +2687,15 @@ void MarlinSettings::reset(PORTARG_SOLO) {
|
|||
SERIAL_ECHOLNPAIR_P(port, " M250 C", ui.contrast);
|
||||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
if (!forReplay) {
|
||||
CONFIG_ECHO_START;
|
||||
SERIAL_ECHOLNPGM_P(port, "Power-Loss Recovery:");
|
||||
}
|
||||
CONFIG_ECHO_START;
|
||||
SERIAL_ECHOLNPAIR_P(port, " M413 S", int(recovery.enabled));
|
||||
#endif
|
||||
|
||||
#if ENABLED(FWRETRACT)
|
||||
|
||||
if (!forReplay) {
|
||||
|
@ -2683,7 +2736,7 @@ void MarlinSettings::reset(PORTARG_SOLO) {
|
|||
#if HAS_BED_PROBE
|
||||
if (!forReplay) {
|
||||
CONFIG_ECHO_START;
|
||||
SERIAL_ECHOPGM_P(port, "Z-Probe Offset (mm):");
|
||||
SERIAL_ECHOPGM_P(port, "Z-Probe Offset");
|
||||
SAY_UNITS_P(port, true);
|
||||
}
|
||||
CONFIG_ECHO_START;
|
||||
|
|
|
@ -478,7 +478,7 @@ void CardReader::openFile(char * const path, const bool read, const bool subcall
|
|||
void CardReader::removeFile(const char * const name) {
|
||||
if (!cardOK) return;
|
||||
|
||||
stopSDPrint();
|
||||
//stopSDPrint();
|
||||
|
||||
SdFile *curDir;
|
||||
const char * const fname = diveToFile(curDir, name, false);
|
||||
|
@ -549,7 +549,7 @@ void CardReader::checkautostart() {
|
|||
|
||||
if (cardOK
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
&& !jobRecoverFileExists() // Don't run auto#.g when a resume file exists
|
||||
&& !recovery.valid() // Don't run auto#.g when a resume file exists
|
||||
#endif
|
||||
) {
|
||||
char autoname[8];
|
||||
|
@ -577,6 +577,7 @@ void CardReader::closefile(const bool store_location) {
|
|||
file.sync();
|
||||
file.close();
|
||||
saving = logging = false;
|
||||
sdpos = 0;
|
||||
#if ENABLED(EMERGENCY_PARSER)
|
||||
emergency_parser.enable();
|
||||
#endif
|
||||
|
@ -622,8 +623,12 @@ uint16_t CardReader::getnrfilenames() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Dive to the given file path, with optional echo.
|
||||
* On exit set curDir and return the name part of the path.
|
||||
* Dive to the given DOS 8.3 file path, with optional echo of the dive paths.
|
||||
*
|
||||
* On exit, curDir contains an SdFile reference to the file's directory.
|
||||
*
|
||||
* Returns a pointer to the last segment (filename) of the given DOS 8.3 path.
|
||||
*
|
||||
* A NULL result indicates an unrecoverable error.
|
||||
*/
|
||||
const char* CardReader::diveToFile(SdFile*& curDir, const char * const path, const bool echo) {
|
||||
|
@ -993,12 +998,18 @@ void CardReader::printingHasFinished() {
|
|||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
|
||||
char job_recovery_file_name[4] = "bin";
|
||||
constexpr char job_recovery_file_name[4] = "BIN";
|
||||
|
||||
bool CardReader::jobRecoverFileExists() {
|
||||
const bool exists = recovery.file.open(&root, job_recovery_file_name, O_READ);
|
||||
if (exists) recovery.file.close();
|
||||
return exists;
|
||||
}
|
||||
|
||||
void CardReader::openJobRecoveryFile(const bool read) {
|
||||
if (!cardOK) return;
|
||||
if (jobRecoveryFile.isOpen()) return;
|
||||
if (!jobRecoveryFile.open(&root, job_recovery_file_name, read ? O_READ : O_CREAT | O_WRITE | O_TRUNC | O_SYNC)) {
|
||||
if (recovery.file.isOpen()) return;
|
||||
if (!recovery.file.open(&root, job_recovery_file_name, read ? O_READ : O_CREAT | O_WRITE | O_TRUNC | O_SYNC)) {
|
||||
SERIAL_PROTOCOLPAIR(MSG_SD_OPEN_FILE_FAIL, job_recovery_file_name);
|
||||
SERIAL_PROTOCOLCHAR('.');
|
||||
SERIAL_EOL();
|
||||
|
@ -1007,31 +1018,12 @@ void CardReader::printingHasFinished() {
|
|||
SERIAL_PROTOCOLLNPAIR(MSG_SD_WRITE_TO_FILE, job_recovery_file_name);
|
||||
}
|
||||
|
||||
void CardReader::closeJobRecoveryFile() { jobRecoveryFile.close(); }
|
||||
|
||||
bool CardReader::jobRecoverFileExists() {
|
||||
const bool exists = jobRecoveryFile.open(&root, job_recovery_file_name, O_READ);
|
||||
if (exists) jobRecoveryFile.close();
|
||||
return exists;
|
||||
}
|
||||
|
||||
int16_t CardReader::saveJobRecoveryInfo() {
|
||||
jobRecoveryFile.seekSet(0);
|
||||
const int16_t ret = jobRecoveryFile.write(&job_recovery_info, sizeof(job_recovery_info));
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
if (ret == -1) SERIAL_PROTOCOLLNPGM("Power-loss file write failed.");
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int16_t CardReader::loadJobRecoveryInfo() {
|
||||
return jobRecoveryFile.read(&job_recovery_info, sizeof(job_recovery_info));
|
||||
}
|
||||
|
||||
// Removing the job recovery file currently requires closing
|
||||
// the file being printed, so during SD printing the file should
|
||||
// be zeroed and written instead of deleted.
|
||||
void CardReader::removeJobRecoveryFile() {
|
||||
job_recovery_info.valid_head = job_recovery_info.valid_foot = job_recovery_commands_count = 0;
|
||||
if (jobRecoverFileExists()) {
|
||||
closefile();
|
||||
//closefile();
|
||||
removeFile(job_recovery_file_name);
|
||||
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
|
||||
SERIAL_PROTOCOLPGM("Power-loss file delete");
|
||||
|
|
|
@ -106,11 +106,8 @@ public:
|
|||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
void openJobRecoveryFile(const bool read);
|
||||
void closeJobRecoveryFile();
|
||||
bool jobRecoverFileExists();
|
||||
int16_t saveJobRecoveryInfo();
|
||||
int16_t loadJobRecoveryInfo();
|
||||
void openJobRecoveryFile(const bool read);
|
||||
void removeJobRecoveryFile();
|
||||
#endif
|
||||
|
||||
|
@ -217,10 +214,6 @@ private:
|
|||
SdVolume volume;
|
||||
SdFile file;
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
SdFile jobRecoveryFile;
|
||||
#endif
|
||||
|
||||
#define SD_PROCEDURE_DEPTH 1
|
||||
#define MAXPATHNAMELENGTH (FILENAME_LENGTH*MAX_DIR_DEPTH + MAX_DIR_DEPTH + 1)
|
||||
uint8_t file_subcall_ctr;
|
||||
|
|
Loading…
Reference in a new issue