|
@@ -61,6 +61,11 @@ bool GcodeSuite::axis_relative_modes[] = AXIS_RELATIVE_MODES;
|
61
|
61
|
float GcodeSuite::coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ];
|
62
|
62
|
#endif
|
63
|
63
|
|
|
64
|
+#if HAS_LEVELING && ENABLED(G29_RETRY_AND_RECOVER)
|
|
65
|
+ #include "../feature/bedlevel/bedlevel.h"
|
|
66
|
+ #include "../module/planner.h"
|
|
67
|
+#endif
|
|
68
|
+
|
64
|
69
|
/**
|
65
|
70
|
* Set target_extruder from the T parameter or the active_extruder
|
66
|
71
|
*
|
|
@@ -125,6 +130,44 @@ void GcodeSuite::dwell(millis_t time) {
|
125
|
130
|
while (PENDING(millis(), time)) idle();
|
126
|
131
|
}
|
127
|
132
|
|
|
133
|
+/**
|
|
134
|
+ * When G29_RETRY_AND_RECOVER is enabled, call G29() in
|
|
135
|
+ * a loop with recovery and retry handling.
|
|
136
|
+ */
|
|
137
|
+#if HAS_LEVELING && ENABLED(G29_RETRY_AND_RECOVER)
|
|
138
|
+
|
|
139
|
+ void GcodeSuite::G29_with_retry() {
|
|
140
|
+ set_bed_leveling_enabled(false);
|
|
141
|
+ for (uint8_t i = G29_MAX_RETRIES; i--;) {
|
|
142
|
+ G29();
|
|
143
|
+ if (planner.leveling_active) break;
|
|
144
|
+ #ifdef G29_ACTION_ON_RECOVER
|
|
145
|
+ SERIAL_ECHOLNPGM("//action:" G29_ACTION_ON_RECOVER);
|
|
146
|
+ #endif
|
|
147
|
+ #ifdef G29_RECOVERY_COMMANDS
|
|
148
|
+ process_subcommands_now_P(PSTR(G29_RECOVER_COMMANDS));
|
|
149
|
+ #endif
|
|
150
|
+ }
|
|
151
|
+ if (planner.leveling_active) {
|
|
152
|
+ #ifdef G29_SUCCESS_COMMANDS
|
|
153
|
+ process_subcommands_now_P(PSTR(G29_SUCCESS_COMMANDS));
|
|
154
|
+ #endif
|
|
155
|
+ }
|
|
156
|
+ else {
|
|
157
|
+ #ifdef G29_FAILURE_COMMANDS
|
|
158
|
+ process_subcommands_now_P(PSTR(G29_FAILURE_COMMANDS));
|
|
159
|
+ #endif
|
|
160
|
+ #ifdef G29_ACTION_ON_FAILURE
|
|
161
|
+ SERIAL_ECHOLNPGM("//action:" G29_ACTION_ON_FAILURE);
|
|
162
|
+ #endif
|
|
163
|
+ #if ENABLED(G29_HALT_ON_FAILURE)
|
|
164
|
+ kill(PSTR(MSG_ERR_PROBING_FAILED));
|
|
165
|
+ #endif
|
|
166
|
+ }
|
|
167
|
+ }
|
|
168
|
+
|
|
169
|
+#endif // HAS_LEVELING && G29_RETRY_AND_RECOVER
|
|
170
|
+
|
128
|
171
|
//
|
129
|
172
|
// Placeholders for non-migrated codes
|
130
|
173
|
//
|
|
@@ -135,7 +178,11 @@ void GcodeSuite::dwell(millis_t time) {
|
135
|
178
|
/**
|
136
|
179
|
* Process the parsed command and dispatch it to its handler
|
137
|
180
|
*/
|
138
|
|
-void GcodeSuite::process_parsed_command() {
|
|
181
|
+void GcodeSuite::process_parsed_command(
|
|
182
|
+ #if ENABLED(USE_EXECUTE_COMMANDS_IMMEDIATE)
|
|
183
|
+ const bool no_ok
|
|
184
|
+ #endif
|
|
185
|
+) {
|
139
|
186
|
KEEPALIVE_STATE(IN_HANDLER);
|
140
|
187
|
|
141
|
188
|
// Handle a known G, M, or T
|
|
@@ -190,8 +237,14 @@ void GcodeSuite::process_parsed_command() {
|
190
|
237
|
case 28: G28(false); break; // G28: Home all axes, one at a time
|
191
|
238
|
|
192
|
239
|
#if HAS_LEVELING
|
193
|
|
- case 29: G29(); break; // G29: Bed leveling calibration
|
194
|
|
- #endif
|
|
240
|
+ case 29: // G29: Bed leveling calibration
|
|
241
|
+ #if ENABLED(G29_RETRY_AND_RECOVER)
|
|
242
|
+ G29_with_retry();
|
|
243
|
+ #else
|
|
244
|
+ G29();
|
|
245
|
+ #endif
|
|
246
|
+ break;
|
|
247
|
+ #endif // HAS_LEVELING
|
195
|
248
|
|
196
|
249
|
#if HAS_BED_PROBE
|
197
|
250
|
case 30: G30(); break; // G30: Single Z probe
|
|
@@ -612,7 +665,10 @@ void GcodeSuite::process_parsed_command() {
|
612
|
665
|
|
613
|
666
|
KEEPALIVE_STATE(NOT_BUSY);
|
614
|
667
|
|
615
|
|
- ok_to_send();
|
|
668
|
+ #if ENABLED(USE_EXECUTE_COMMANDS_IMMEDIATE)
|
|
669
|
+ if (!no_ok)
|
|
670
|
+ #endif
|
|
671
|
+ ok_to_send();
|
616
|
672
|
}
|
617
|
673
|
|
618
|
674
|
/**
|
|
@@ -638,6 +694,37 @@ void GcodeSuite::process_next_command() {
|
638
|
694
|
process_parsed_command();
|
639
|
695
|
}
|
640
|
696
|
|
|
697
|
+#if ENABLED(USE_EXECUTE_COMMANDS_IMMEDIATE)
|
|
698
|
+ /**
|
|
699
|
+ * Run a series of commands, bypassing the command queue to allow
|
|
700
|
+ * G-code "macros" to be called from within other G-code handlers.
|
|
701
|
+ */
|
|
702
|
+ void GcodeSuite::process_subcommands_now_P(const char *pgcode) {
|
|
703
|
+ // Save the parser state
|
|
704
|
+ char saved_cmd[strlen(parser.command_ptr) + 1];
|
|
705
|
+ strcpy(saved_cmd, parser.command_ptr);
|
|
706
|
+
|
|
707
|
+ // Process individual commands in string
|
|
708
|
+ while (pgm_read_byte_near(pgcode)) {
|
|
709
|
+ // Break up string at '\n' delimiters
|
|
710
|
+ const char *delim = strchr_P(pgcode, '\n');
|
|
711
|
+ size_t len = delim ? delim - pgcode : strlen_P(pgcode);
|
|
712
|
+ char cmd[len + 1];
|
|
713
|
+ strncpy_P(cmd, pgcode, len);
|
|
714
|
+ cmd[len] = '\0';
|
|
715
|
+ pgcode += len;
|
|
716
|
+ if (delim) pgcode++;
|
|
717
|
+
|
|
718
|
+ // Parse the next command in the string
|
|
719
|
+ parser.parse(cmd);
|
|
720
|
+ process_parsed_command(true);
|
|
721
|
+ }
|
|
722
|
+
|
|
723
|
+ // Restore the parser state
|
|
724
|
+ parser.parse(saved_cmd);
|
|
725
|
+ }
|
|
726
|
+#endif
|
|
727
|
+
|
641
|
728
|
#if ENABLED(HOST_KEEPALIVE_FEATURE)
|
642
|
729
|
|
643
|
730
|
/**
|