Parcourir la source

Fix and improve POWER_LOSS_RECOVERY (#11187)

Scott Lahteine il y a 7 ans
Parent
révision
1a0f4dedad
Aucun compte lié à l'adresse e-mail de l'auteur

+ 4
- 1
Marlin/src/Marlin.cpp Voir le fichier

@@ -897,7 +897,7 @@ void setup() {
897 897
   #endif
898 898
 
899 899
   #if ENABLED(POWER_LOSS_RECOVERY)
900
-    do_print_job_recovery();
900
+    check_print_job_recovery();
901 901
   #endif
902 902
 
903 903
   #if ENABLED(USE_WATCHDOG) // Reinit watchdog after HAL_get_reset_source call
@@ -937,6 +937,9 @@ void loop() {
937 937
           for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;
938 938
         #endif
939 939
         wait_for_heatup = false;
940
+        #if ENABLED(POWER_LOSS_RECOVERY)
941
+          card.removeJobRecoveryFile();
942
+        #endif
940 943
       }
941 944
     #endif // SDSUPPORT && ULTIPANEL
942 945
 

+ 41
- 27
Marlin/src/feature/power_loss_recovery.cpp Voir le fichier

@@ -43,14 +43,14 @@ job_recovery_info_t job_recovery_info;
43 43
 JobRecoveryPhase job_recovery_phase = JOB_RECOVERY_IDLE;
44 44
 uint8_t job_recovery_commands_count; //=0
45 45
 char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
46
-
47
-// Private
48
-static char sd_filename[MAXPATHNAMELENGTH];
46
+// Extern
47
+extern uint8_t active_extruder, commands_in_queue, cmd_queue_index_r;
49 48
 
50 49
 #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
51 50
   void debug_print_job_recovery(const bool recovery) {
52
-    SERIAL_PROTOCOLPAIR("valid_head:", (int)job_recovery_info.valid_head);
53
-    SERIAL_PROTOCOLLNPAIR(" valid_foot:", (int)job_recovery_info.valid_foot);
51
+    SERIAL_PROTOCOLLNPGM("---- Job Recovery Info ----");
52
+    SERIAL_PROTOCOLPAIR("valid_head:", int(job_recovery_info.valid_head));
53
+    SERIAL_PROTOCOLLNPAIR(" valid_foot:", int(job_recovery_info.valid_foot));
54 54
     if (job_recovery_info.valid_head) {
55 55
       if (job_recovery_info.valid_head == job_recovery_info.valid_foot) {
56 56
         SERIAL_PROTOCOLPGM("current_position: ");
@@ -60,6 +60,11 @@ static char sd_filename[MAXPATHNAMELENGTH];
60 60
         }
61 61
         SERIAL_EOL();
62 62
         SERIAL_PROTOCOLLNPAIR("feedrate: ", job_recovery_info.feedrate);
63
+
64
+        #if HOTENDS > 1
65
+          SERIAL_PROTOCOLLNPAIR("active_hotend: ", int(job_recovery_info.active_hotend));
66
+        #endif
67
+
63 68
         SERIAL_PROTOCOLPGM("target_temperature: ");
64 69
         HOTEND_LOOP() {
65 70
           SERIAL_PROTOCOL(job_recovery_info.target_temperature[e]);
@@ -84,8 +89,8 @@ static char sd_filename[MAXPATHNAMELENGTH];
84 89
           SERIAL_PROTOCOLPAIR("leveling: ", int(job_recovery_info.leveling));
85 90
           SERIAL_PROTOCOLLNPAIR(" fade: ", int(job_recovery_info.fade));
86 91
         #endif
87
-        SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", job_recovery_info.cmd_queue_index_r);
88
-        SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", job_recovery_info.commands_in_queue);
92
+        SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", int(job_recovery_info.cmd_queue_index_r));
93
+        SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", int(job_recovery_info.commands_in_queue));
89 94
         if (recovery)
90 95
           for (uint8_t i = 0; i < job_recovery_commands_count; i++) SERIAL_PROTOCOLLNPAIR("> ", job_recovery_commands[i]);
91 96
         else
@@ -97,15 +102,17 @@ static char sd_filename[MAXPATHNAMELENGTH];
97 102
       else
98 103
         SERIAL_PROTOCOLLNPGM("INVALID DATA");
99 104
     }
105
+    SERIAL_PROTOCOLLNPGM("---------------------------");
100 106
   }
101 107
 #endif // DEBUG_POWER_LOSS_RECOVERY
102 108
 
103 109
 /**
104
- * Check for Print Job Recovery
105
- * If the file has a saved state, populate the job_recovery_commands queue
110
+ * Check for Print Job Recovery during setup()
111
+ *
112
+ * If a saved state exists, populate job_recovery_commands with
113
+ * commands to restore the machine state and continue the file.
106 114
  */
107
-void do_print_job_recovery() {
108
-  //if (job_recovery_commands_count > 0) return;
115
+void check_print_job_recovery() {
109 116
   memset(&job_recovery_info, 0, sizeof(job_recovery_info));
110 117
   ZERO(job_recovery_commands);
111 118
 
@@ -114,7 +121,7 @@ void do_print_job_recovery() {
114 121
   if (card.cardOK) {
115 122
 
116 123
     #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
117
-      SERIAL_PROTOCOLLNPAIR("Init job recovery info. Size: ", (int)sizeof(job_recovery_info));
124
+      SERIAL_PROTOCOLLNPAIR("Init job recovery info. Size: ", int(sizeof(job_recovery_info)));
118 125
     #endif
119 126
 
120 127
     if (card.jobRecoverFileExists()) {
@@ -134,7 +141,9 @@ void do_print_job_recovery() {
134 141
         strcpy_P(job_recovery_commands[ind++], PSTR("G92.0 Z0"));                   // Ensure Z is equal to 0
135 142
         strcpy_P(job_recovery_commands[ind++], PSTR("G1 Z2"));                      // Raise Z by 2mm (we hope!)
136 143
         strcpy_P(job_recovery_commands[ind++], PSTR("G28 R0"
137
-          #if !IS_KINEMATIC
144
+          #if ENABLED(MARLIN_DEV_MODE)
145
+            " S"
146
+          #elif !IS_KINEMATIC
138 147
             " X Y"                                                                  // Home X and Y for Cartesian
139 148
           #endif
140 149
         ));
@@ -142,10 +151,12 @@ void do_print_job_recovery() {
142 151
         char str_1[16], str_2[16];
143 152
 
144 153
         #if HAS_LEVELING
145
-          // Restore leveling state before G92 sets Z
146
-          // This ensures the steppers correspond to the native Z
147
-          dtostrf(job_recovery_info.fade, 1, 1, str_1);
148
-          sprintf_P(job_recovery_commands[ind++], PSTR("M420 S%i Z%s"), int(job_recovery_info.leveling), str_1);
154
+          if (job_recovery_info.fade || job_recovery_info.leveling) {
155
+            // Restore leveling state before G92 sets Z
156
+            // This ensures the steppers correspond to the native Z
157
+            dtostrf(job_recovery_info.fade, 1, 1, str_1);
158
+            sprintf_P(job_recovery_commands[ind++], PSTR("M420 S%i Z%s"), int(job_recovery_info.leveling), str_1);
159
+          }
149 160
         #endif
150 161
 
151 162
         dtostrf(job_recovery_info.current_position[Z_AXIS] + 2, 1, 3, str_1);
@@ -157,23 +168,21 @@ void do_print_job_recovery() {
157 168
         );
158 169
         sprintf_P(job_recovery_commands[ind++], PSTR("G92.0 Z%s E%s"), str_1, str_2); // Current Z + 2 and E
159 170
 
160
-        strcpy_P(job_recovery_commands[ind++], PSTR("M117 Continuing..."));
161
-
162
-        uint8_t r = job_recovery_info.cmd_queue_index_r;
163
-        while (job_recovery_info.commands_in_queue) {
171
+        uint8_t r = job_recovery_info.cmd_queue_index_r, c = job_recovery_info.commands_in_queue;
172
+        while (c--) {
164 173
           strcpy(job_recovery_commands[ind++], job_recovery_info.command_queue[r]);
165
-          job_recovery_info.commands_in_queue--;
166 174
           r = (r + 1) % BUFSIZE;
167 175
         }
168 176
 
177
+        if (job_recovery_info.sd_filename[0] == '/') job_recovery_info.sd_filename[0] = ' ';
178
+        sprintf_P(job_recovery_commands[ind++], PSTR("M23 %s"), job_recovery_info.sd_filename);
179
+        sprintf_P(job_recovery_commands[ind++], PSTR("M24 S%ld T%ld"), job_recovery_info.sdpos, job_recovery_info.print_job_elapsed);
180
+
169 181
         job_recovery_commands_count = ind;
170 182
 
171 183
         #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
172 184
           debug_print_job_recovery(true);
173 185
         #endif
174
-
175
-        card.openFile(job_recovery_info.sd_filename, true);
176
-        card.setIndex(job_recovery_info.sdpos);
177 186
       }
178 187
       else {
179 188
         if (job_recovery_info.valid_head != job_recovery_info.valid_foot)
@@ -213,6 +222,11 @@ void save_job_recovery_info() {
213 222
     // Machine state
214 223
     COPY(job_recovery_info.current_position, current_position);
215 224
     job_recovery_info.feedrate = feedrate_mm_s;
225
+
226
+    #if HOTENDS > 1
227
+      job_recovery_info.active_hotend = active_extruder;
228
+    #endif
229
+
216 230
     COPY(job_recovery_info.target_temperature, thermalManager.target_temperature);
217 231
 
218 232
     #if HAS_HEATED_BED
@@ -240,14 +254,14 @@ void save_job_recovery_info() {
240 254
     COPY(job_recovery_info.command_queue, command_queue);
241 255
 
242 256
     // Elapsed print job time
243
-    job_recovery_info.print_job_elapsed = print_job_timer.duration() * 1000UL;
257
+    job_recovery_info.print_job_elapsed = print_job_timer.duration();
244 258
 
245 259
     // SD file position
246 260
     card.getAbsFilename(job_recovery_info.sd_filename);
247 261
     job_recovery_info.sdpos = card.getIndex();
248 262
 
249 263
     #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
250
-      SERIAL_PROTOCOLLNPGM("Saving job_recovery_info");
264
+      SERIAL_PROTOCOLLNPGM("Saving...");
251 265
       debug_print_job_recovery(false);
252 266
     #endif
253 267
 

+ 10
- 4
Marlin/src/feature/power_loss_recovery.h Voir le fichier

@@ -40,6 +40,11 @@ typedef struct {
40 40
 
41 41
   // Machine state
42 42
   float current_position[NUM_AXIS], feedrate;
43
+
44
+  #if HOTENDS > 1
45
+    uint8_t active_hotend;
46
+  #endif
47
+
43 48
   int16_t target_temperature[HOTENDS];
44 49
 
45 50
   #if HAS_HEATED_BED
@@ -74,20 +79,21 @@ extern job_recovery_info_t job_recovery_info;
74 79
 enum JobRecoveryPhase : unsigned char {
75 80
   JOB_RECOVERY_IDLE,
76 81
   JOB_RECOVERY_MAYBE,
77
-  JOB_RECOVERY_YES
82
+  JOB_RECOVERY_YES,
83
+  JOB_RECOVERY_DONE
78 84
 };
79 85
 extern JobRecoveryPhase job_recovery_phase;
80 86
 
81 87
 #if HAS_LEVELING
82
-  #define APPEND_CMD_COUNT 7
88
+  #define APPEND_CMD_COUNT 9
83 89
 #else
84
-  #define APPEND_CMD_COUNT 5
90
+  #define APPEND_CMD_COUNT 7
85 91
 #endif
86 92
 
87 93
 extern char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
88 94
 extern uint8_t job_recovery_commands_count;
89 95
 
90
-void do_print_job_recovery();
96
+void check_print_job_recovery();
91 97
 void save_job_recovery_info();
92 98
 
93 99
 #endif // _POWER_LOSS_RECOVERY_H_

+ 1
- 1
Marlin/src/gcode/queue.cpp Voir le fichier

@@ -496,7 +496,7 @@ inline void get_serial_commands() {
496 496
       if (job_recovery_commands_count) {
497 497
         if (_enqueuecommand(job_recovery_commands[job_recovery_commands_index])) {
498 498
           ++job_recovery_commands_index;
499
-          if (!--job_recovery_commands_count) job_recovery_phase = JOB_RECOVERY_IDLE;
499
+          if (!--job_recovery_commands_count) job_recovery_phase = JOB_RECOVERY_DONE;
500 500
         }
501 501
         return true;
502 502
       }

+ 14
- 5
Marlin/src/gcode/sdcard/M20-M30_M32-M34_M928.cpp Voir le fichier

@@ -72,6 +72,9 @@ void GcodeSuite::M22() { card.release(); }
72 72
  * M23: Open a file
73 73
  */
74 74
 void GcodeSuite::M23() {
75
+  #if ENABLED(POWER_LOSS_RECOVERY)
76
+    card.removeJobRecoveryFile();
77
+  #endif
75 78
   // Simplify3D includes the size, so zero out all spaces (#7227)
76 79
   for (char *fn = parser.string_arg; *fn; ++fn) if (*fn == ' ') *fn = '\0';
77 80
   card.openFile(parser.string_arg, true);
@@ -81,16 +84,22 @@ void GcodeSuite::M23() {
81 84
  * M24: Start or Resume SD Print
82 85
  */
83 86
 void GcodeSuite::M24() {
84
-  #if ENABLED(POWER_LOSS_RECOVERY)
85
-    card.removeJobRecoveryFile();
86
-  #endif
87
-
88 87
   #if ENABLED(PARK_HEAD_ON_PAUSE)
89 88
     resume_print();
90 89
   #endif
91 90
 
91
+  #if ENABLED(POWER_LOSS_RECOVERY)
92
+    if (parser.seenval('S')) card.setIndex(parser.value_long());
93
+  #endif
94
+
92 95
   card.startFileprint();
93
-  print_job_timer.start();
96
+
97
+  #if ENABLED(POWER_LOSS_RECOVERY)
98
+    if (parser.seenval('T'))
99
+      print_job_timer.resume(parser.value_long());
100
+    else
101
+  #endif
102
+      print_job_timer.start();
94 103
 }
95 104
 
96 105
 /**

+ 3
- 0
Marlin/src/lcd/language/language_en.h Voir le fichier

@@ -666,6 +666,9 @@
666 666
 #ifndef MSG_STOP_PRINT
667 667
   #define MSG_STOP_PRINT                      _UxGT("Stop print")
668 668
 #endif
669
+#ifndef MSG_POWER_LOSS_RECOVERY
670
+  #define MSG_POWER_LOSS_RECOVERY             _UxGT("Power-Loss Recovery")
671
+#endif
669 672
 #ifndef MSG_CARD_MENU
670 673
   #define MSG_CARD_MENU                       _UxGT("Print from SD")
671 674
 #endif

+ 37
- 21
Marlin/src/lcd/ultralcd.cpp Voir le fichier

@@ -873,17 +873,13 @@ void lcd_quick_feedback(const bool clear_buttons) {
873 873
       abort_sd_printing = true;
874 874
       lcd_setstatusPGM(PSTR(MSG_PRINT_ABORTED), -1);
875 875
       lcd_return_to_status();
876
-
877
-      #if ENABLED(POWER_LOSS_RECOVERY)
878
-        card.removeJobRecoveryFile();
879
-      #endif
880 876
     }
881 877
 
882 878
   #endif // SDSUPPORT
883 879
 
884 880
   #if ENABLED(POWER_LOSS_RECOVERY)
885 881
 
886
-    static void lcd_sdcard_recover_job() {
882
+    static void lcd_power_loss_recovery_resume() {
887 883
       char cmd[20];
888 884
 
889 885
       // Return to status now
@@ -891,45 +887,65 @@ void lcd_quick_feedback(const bool clear_buttons) {
891 887
 
892 888
       // Turn leveling off and home
893 889
       enqueue_and_echo_commands_P(PSTR("M420 S0\nG28"
894
-        #if !IS_KINEMATIC
890
+        #if ENABLED(MARLIN_DEV_MODE)
891
+          " S"
892
+        #elif !IS_KINEMATIC
895 893
           " X Y"
896 894
         #endif
897 895
       ));
898 896
 
899 897
       #if HAS_HEATED_BED
900
-        // Restore the bed temperature
901
-        sprintf_P(cmd, PSTR("M190 S%i"), job_recovery_info.target_temperature_bed);
902
-        enqueue_and_echo_command(cmd);
898
+        const int16_t bt = job_recovery_info.target_temperature_bed;
899
+        if (bt) {
900
+          // Restore the bed temperature
901
+          sprintf_P(cmd, PSTR("M190 S%i"), bt);
902
+          enqueue_and_echo_command(cmd);
903
+        }
903 904
       #endif
904 905
 
905 906
       // Restore all hotend temperatures
906 907
       HOTEND_LOOP() {
907
-        sprintf_P(cmd, PSTR("M109 S%i"), job_recovery_info.target_temperature[e]);
908
-        enqueue_and_echo_command(cmd);
908
+        const int16_t et = job_recovery_info.target_temperature[e];
909
+        if (et) {
910
+          #if HOTENDS > 1
911
+            sprintf_P(cmd, PSTR("T%i"), e);
912
+            enqueue_and_echo_command(cmd);
913
+          #endif
914
+          sprintf_P(cmd, PSTR("M109 S%i"), et);
915
+          enqueue_and_echo_command(cmd);
916
+        }
909 917
       }
910 918
 
919
+      #if HOTENDS > 1
920
+        sprintf_P(cmd, PSTR("T%i"), job_recovery_info.active_hotend);
921
+        enqueue_and_echo_command(cmd);
922
+      #endif
923
+
911 924
       // Restore print cooling fan speeds
912 925
       for (uint8_t i = 0; i < FAN_COUNT; i++) {
913
-        sprintf_P(cmd, PSTR("M106 P%i S%i"), i, job_recovery_info.fanSpeeds[i]);
914
-        enqueue_and_echo_command(cmd);
926
+        int16_t f = job_recovery_info.fanSpeeds[i];
927
+        if (f) {
928
+          sprintf_P(cmd, PSTR("M106 P%i S%i"), i, f);
929
+          enqueue_and_echo_command(cmd);
930
+        }
915 931
       }
916 932
 
917 933
       // Start draining the job recovery command queue
918 934
       job_recovery_phase = JOB_RECOVERY_YES;
935
+    }
919 936
 
920
-      // Resume the print job timer
921
-      if (job_recovery_info.print_job_elapsed)
922
-        print_job_timer.resume(job_recovery_info.print_job_elapsed);
923
-
924
-      // Start getting commands from SD
925
-      card.startFileprint();
937
+    static void lcd_power_loss_recovery_cancel() {
938
+      card.removeJobRecoveryFile();
939
+      card.autostart_index = 0;
940
+      lcd_return_to_status();
926 941
     }
927 942
 
928 943
     static void lcd_job_recovery_menu() {
929 944
       defer_return_to_status = true;
930 945
       START_MENU();
931
-      MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_recover_job);
932
-      MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
946
+      STATIC_ITEM(MSG_POWER_LOSS_RECOVERY);
947
+      MENU_ITEM(function, MSG_RESUME_PRINT, lcd_power_loss_recovery_resume);
948
+      MENU_ITEM(function, MSG_STOP_PRINT, lcd_power_loss_recovery_cancel);
933 949
       END_MENU();
934 950
     }
935 951
 

+ 23
- 12
Marlin/src/sd/cardreader.cpp Voir le fichier

@@ -541,9 +541,13 @@ void CardReader::checkautostart() {
541 541
 
542 542
   if (!cardOK) initsd();
543 543
 
544
-  if (cardOK) {
544
+  if (cardOK
545
+    #if ENABLED(POWER_LOSS_RECOVERY)
546
+      && !jobRecoverFileExists() // Don't run auto#.g when a resume file exists
547
+    #endif
548
+  ) {
545 549
     char autoname[10];
546
-    sprintf_P(autoname, PSTR("auto%i.g"), autostart_index);
550
+    sprintf_P(autoname, PSTR("auto%i.g"), int(autostart_index));
547 551
     dir_t p;
548 552
     root.rewind();
549 553
     while (root.readDir(&p, NULL) > 0) {
@@ -990,20 +994,24 @@ void CardReader::printingHasFinished() {
990 994
       SERIAL_PROTOCOLCHAR('.');
991 995
       SERIAL_EOL();
992 996
     }
993
-    else
997
+    else if (!read)
994 998
       SERIAL_PROTOCOLLNPAIR(MSG_SD_WRITE_TO_FILE, job_recovery_file_name);
995 999
   }
996 1000
 
997 1001
   void CardReader::closeJobRecoveryFile() { jobRecoveryFile.close(); }
998 1002
 
999 1003
   bool CardReader::jobRecoverFileExists() {
1000
-    return jobRecoveryFile.open(&root, job_recovery_file_name, O_READ);
1004
+    const bool exists = jobRecoveryFile.open(&root, job_recovery_file_name, O_READ);
1005
+    if (exists) jobRecoveryFile.close();
1006
+    return exists;
1001 1007
   }
1002 1008
 
1003 1009
   int16_t CardReader::saveJobRecoveryInfo() {
1004 1010
     jobRecoveryFile.seekSet(0);
1005 1011
     const int16_t ret = jobRecoveryFile.write(&job_recovery_info, sizeof(job_recovery_info));
1006
-    if (ret == -1) SERIAL_PROTOCOLLNPGM("Power-loss file write failed.");
1012
+    #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
1013
+      if (ret == -1) SERIAL_PROTOCOLLNPGM("Power-loss file write failed.");
1014
+    #endif
1007 1015
     return ret;
1008 1016
   }
1009 1017
 
@@ -1013,13 +1021,16 @@ void CardReader::printingHasFinished() {
1013 1021
 
1014 1022
   void CardReader::removeJobRecoveryFile() {
1015 1023
     job_recovery_info.valid_head = job_recovery_info.valid_foot = job_recovery_commands_count = 0;
1016
-    const bool success = jobRecoveryFile.remove(&root, job_recovery_file_name);
1017
-    #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
1018
-      SERIAL_PROTOCOLPGM("Power-loss file delete");
1019
-      serialprintPGM(success ? PSTR("d.\n") : PSTR(" failed.\n"));
1020
-    #else
1021
-      UNUSED(success);
1022
-    #endif
1024
+    if (jobRecoverFileExists()) {
1025
+      closefile();
1026
+      removeFile(job_recovery_file_name);
1027
+      #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
1028
+        SERIAL_PROTOCOLPGM("Power-loss file delete");
1029
+        serialprintPGM(jobRecoverFileExists() ? PSTR(" failed.\n") : PSTR("d.\n"));
1030
+      #else
1031
+        UNUSED(success);
1032
+      #endif
1033
+    }
1023 1034
   }
1024 1035
 
1025 1036
 #endif // POWER_LOSS_RECOVERY

+ 1
- 1
Marlin/src/sd/cardreader.h Voir le fichier

@@ -142,7 +142,7 @@ public:
142 142
 public:
143 143
   bool saving, logging, sdprinting, cardOK, filenameIsDir;
144 144
   char filename[FILENAME_LENGTH], longFilename[LONG_FILENAME_LENGTH];
145
-  int autostart_index;
145
+  int8_t autostart_index;
146 146
 private:
147 147
   SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
148 148
   uint8_t workDirDepth;

Chargement…
Annuler
Enregistrer