M808 Repeat Markers (#20084)
This commit is contained in:
parent
3231741cd2
commit
deb8df8eff
|
@ -1186,6 +1186,8 @@
|
|||
//#define SD_IGNORE_AT_STARTUP // Don't mount the SD card when starting up
|
||||
//#define SDCARD_READONLY // Read-only SD card (to save over 2K of flash)
|
||||
|
||||
//#define GCODE_REPEAT_MARKERS // Enable G-code M808 to set repeat markers and do looping
|
||||
|
||||
#define SD_PROCEDURE_DEPTH 1 // Increase if you need more nested M32 calls
|
||||
|
||||
#define SD_FINISHED_STEPPERRELEASE true // Disable steppers when SD Print is finished
|
||||
|
|
|
@ -173,6 +173,10 @@
|
|||
#include "feature/pause.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
#include "feature/repeat.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
#include "feature/powerloss.h"
|
||||
#endif
|
||||
|
@ -435,6 +439,7 @@ bool printingIsPaused() {
|
|||
|
||||
void startOrResumeJob() {
|
||||
if (!printingIsPaused()) {
|
||||
TERN_(GCODE_REPEAT_MARKERS, repeat.reset());
|
||||
TERN_(CANCEL_OBJECTS, cancelable.reset());
|
||||
TERN_(LCD_SHOW_E_TOTAL, e_move_accumulator = 0);
|
||||
#if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME)
|
||||
|
|
|
@ -182,6 +182,8 @@ void PrintJobRecovery::save(const bool force/*=false*/, const float zraise/*=0*/
|
|||
info.current_position = current_position;
|
||||
info.feedrate = uint16_t(feedrate_mm_s * 60.0f);
|
||||
info.zraise = zraise;
|
||||
|
||||
TERN_(GCODE_REPEAT_MARKERS, info.stored_repeat = repeat);
|
||||
TERN_(HAS_HOME_OFFSET, info.home_offset = home_offset);
|
||||
TERN_(HAS_POSITION_SHIFT, info.position_shift = position_shift);
|
||||
|
||||
|
@ -507,6 +509,7 @@ void PrintJobRecovery::resume() {
|
|||
sprintf_P(cmd, PSTR("G92.9 E%s"), dtostrf(info.current_position.e, 1, 3, str_1));
|
||||
gcode.process_subcommands_now(cmd);
|
||||
|
||||
TERN_(GCODE_REPEAT_MARKERS, repeat = info.stored_repeat);
|
||||
TERN_(HAS_HOME_OFFSET, home_offset = info.home_offset);
|
||||
TERN_(HAS_POSITION_SHIFT, position_shift = info.position_shift);
|
||||
#if HAS_HOME_OFFSET || HAS_POSITION_SHIFT
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
#include "../feature/repeat.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
#include "../feature/mixing.h"
|
||||
#endif
|
||||
|
@ -50,6 +54,8 @@ typedef struct {
|
|||
uint16_t feedrate;
|
||||
float zraise;
|
||||
|
||||
// Repeat information
|
||||
TERN_(GCODE_REPEAT_MARKERS, Repeat stored_repeat);
|
||||
|
||||
TERN_(HAS_HOME_OFFSET, xyz_pos_t home_offset);
|
||||
TERN_(HAS_POSITION_SHIFT, xyz_pos_t position_shift);
|
||||
|
|
81
Marlin/src/feature/repeat.cpp
Normal file
81
Marlin/src/feature/repeat.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
|
||||
//#define DEBUG_GCODE_REPEAT_MARKERS
|
||||
|
||||
#include "repeat.h"
|
||||
|
||||
#include "../gcode/gcode.h"
|
||||
#include "../sd/cardreader.h"
|
||||
|
||||
#define DEBUG_OUT ENABLED(DEBUG_GCODE_REPEAT_MARKERS)
|
||||
#include "../core/debug_out.h"
|
||||
|
||||
repeat_marker_t Repeat::marker[MAX_REPEAT_NESTING];
|
||||
uint8_t Repeat::index;
|
||||
|
||||
void Repeat::add_marker(const uint32_t sdpos, const uint16_t count) {
|
||||
if (index >= MAX_REPEAT_NESTING)
|
||||
SERIAL_ECHO_MSG("!Too many markers.");
|
||||
else {
|
||||
marker[index].sdpos = sdpos;
|
||||
marker[index].counter = count ?: -1;
|
||||
index++;
|
||||
DEBUG_ECHOLNPAIR("Add Marker ", int(index), " at ", sdpos, " (", count, ")");
|
||||
}
|
||||
}
|
||||
|
||||
void Repeat::loop() {
|
||||
if (!index) // No marker?
|
||||
SERIAL_ECHO_MSG("!No marker set."); // Inform the user.
|
||||
else {
|
||||
const uint8_t ind = index - 1; // Active marker's index
|
||||
if (!marker[ind].counter) { // Did its counter run out?
|
||||
DEBUG_ECHOLNPAIR("Pass Marker ", int(index));
|
||||
index--; // Carry on. Previous marker on the next 'M808'.
|
||||
}
|
||||
else {
|
||||
card.setIndex(marker[ind].sdpos); // Loop back to the marker.
|
||||
if (marker[ind].counter > 0) // Ignore a negative (or zero) counter.
|
||||
--marker[ind].counter; // Decrement the counter. If zero this 'M808' will be skipped next time.
|
||||
DEBUG_ECHOLNPAIR("Goto Marker ", int(index), " at ", marker[ind].sdpos, " (", marker[ind].counter, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Repeat::cancel() { LOOP_L_N(i, index) marker[i].counter = 0; }
|
||||
|
||||
void Repeat::early_parse_M808(char * const cmd) {
|
||||
if (is_command_M808(cmd)) {
|
||||
DEBUG_ECHOLNPAIR("Parsing \"", cmd, "\"");
|
||||
parser.parse(cmd);
|
||||
if (parser.seen('L'))
|
||||
add_marker(card.getIndex(), parser.value_ushort());
|
||||
else
|
||||
Repeat::loop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GCODE_REPEAT_MARKERS
|
49
Marlin/src/feature/repeat.h
Normal file
49
Marlin/src/feature/repeat.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../inc/MarlinConfigPre.h"
|
||||
#include "../gcode/parser.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_REPEAT_NESTING 10
|
||||
|
||||
typedef struct {
|
||||
uint32_t sdpos; // The repeat file position
|
||||
int16_t counter; // The counter for looping
|
||||
} repeat_marker_t;
|
||||
|
||||
class Repeat {
|
||||
private:
|
||||
static repeat_marker_t marker[MAX_REPEAT_NESTING];
|
||||
static uint8_t index;
|
||||
public:
|
||||
static inline void reset() { index = 0; }
|
||||
static bool is_command_M808(char * const cmd) { return cmd[0] == 'M' && cmd[1] == '8' && cmd[2] == '0' && cmd[3] == '8' && !NUMERIC(cmd[4]); }
|
||||
static void early_parse_M808(char * const cmd);
|
||||
static void add_marker(const uint32_t sdpos, const uint16_t count);
|
||||
static void loop();
|
||||
static void cancel();
|
||||
};
|
||||
|
||||
extern Repeat repeat;
|
|
@ -882,6 +882,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
|
|||
case 800: parser.debug(); break; // M800: GCode Parser Test for M
|
||||
#endif
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
case 808: M808(); break; // M808: Set / Goto repeat markers
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_POSITION_ENCODERS)
|
||||
case 860: M860(); break; // M860: Report encoder module position
|
||||
case 861: M861(); break; // M861: Report encoder module status
|
||||
|
|
|
@ -242,6 +242,7 @@
|
|||
* M672 - Set/Reset Duet Smart Effector's sensitivity. (Requires DUET_SMART_EFFECTOR and SMART_EFFECTOR_MOD_PIN)
|
||||
* M701 - Load filament (Requires FILAMENT_LOAD_UNLOAD_GCODES)
|
||||
* M702 - Unload filament (Requires FILAMENT_LOAD_UNLOAD_GCODES)
|
||||
* M808 - Set or Goto a Repeat Marker (Requires GCODE_REPEAT_MARKERS)
|
||||
* M810-M819 - Define/execute a G-code macro (Requires GCODE_MACROS)
|
||||
* M851 - Set Z probe's XYZ offsets in current units. (Negative values: X=left, Y=front, Z=below)
|
||||
* M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ)
|
||||
|
@ -807,6 +808,8 @@ private:
|
|||
static void M702();
|
||||
#endif
|
||||
|
||||
TERN_(GCODE_REPEAT_MARKERS, static void M808());
|
||||
|
||||
TERN_(GCODE_MACROS, static void M810_819());
|
||||
|
||||
TERN_(HAS_BED_PROBE, static void M851());
|
||||
|
|
|
@ -117,6 +117,9 @@ void GcodeSuite::M115() {
|
|||
// SDCARD (M20, M23, M24, etc.)
|
||||
cap_line(PSTR("SDCARD"), ENABLED(SDSUPPORT));
|
||||
|
||||
// REPEAT (M808)
|
||||
cap_line(PSTR("REPEAT"), ENABLED(GCODE_REPEAT_MARKERS));
|
||||
|
||||
// AUTOREPORT_SD_STATUS (M27 extension)
|
||||
cap_line(PSTR("AUTOREPORT_SD_STATUS"), ENABLED(AUTO_REPORT_SD_STATUS));
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ GCodeQueue queue;
|
|||
#include "../feature/powerloss.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
#include "../feature/repeat.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GCode line number handling. Hosts may opt to include line numbers when
|
||||
* sending commands to Marlin, and lines will be checked for sequentiality.
|
||||
|
@ -577,10 +581,9 @@ void GCodeQueue::get_serial_commands() {
|
|||
if (!IS_SD_PRINTING()) return;
|
||||
|
||||
int sd_count = 0;
|
||||
bool card_eof = card.eof();
|
||||
while (length < BUFSIZE && !card_eof) {
|
||||
while (length < BUFSIZE && !card.eof()) {
|
||||
const int16_t n = card.get();
|
||||
card_eof = card.eof();
|
||||
const bool card_eof = card.eof();
|
||||
if (n < 0 && !card_eof) { SERIAL_ERROR_MSG(STR_SD_ERR_READ); continue; }
|
||||
|
||||
const char sd_char = (char)n;
|
||||
|
@ -590,17 +593,21 @@ void GCodeQueue::get_serial_commands() {
|
|||
// Reset stream state, terminate the buffer, and commit a non-empty command
|
||||
if (!is_eol && sd_count) ++sd_count; // End of file with no newline
|
||||
if (!process_line_done(sd_input_state, command_buffer[index_w], sd_count)) {
|
||||
|
||||
// M808 S saves the sdpos of the next line. M808 loops to a new sdpos.
|
||||
TERN_(GCODE_REPEAT_MARKERS, repeat.early_parse_M808(command_buffer[index_w]));
|
||||
|
||||
// Put the new command into the buffer (no "ok" sent)
|
||||
_commit_command(false);
|
||||
#if ENABLED(POWER_LOSS_RECOVERY)
|
||||
recovery.cmd_sdpos = card.getIndex(); // Prime for the NEXT _commit_command
|
||||
#endif
|
||||
|
||||
// Prime Power-Loss Recovery for the NEXT _commit_command
|
||||
TERN_(POWER_LOSS_RECOVERY, recovery.cmd_sdpos = card.getIndex());
|
||||
}
|
||||
|
||||
if (card_eof) card.fileHasFinished(); // Handle end of file reached
|
||||
if (card.eof()) card.fileHasFinished(); // Handle end of file reached
|
||||
}
|
||||
else
|
||||
process_stream_char(sd_char, sd_input_state, command_buffer[index_w], sd_count);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
51
Marlin/src/gcode/sd/M808.cpp
Normal file
51
Marlin/src/gcode/sd/M808.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(GCODE_REPEAT_MARKERS)
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../feature/repeat.h"
|
||||
|
||||
/**
|
||||
* M808: Set / Goto a repeat marker
|
||||
*
|
||||
* L<count> - Set a repeat marker with 'count' repetitions. If omitted, infinity.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* M808 L ; Set a loop marker with a count of infinity
|
||||
* M808 L2 ; Set a loop marker with a count of 2
|
||||
* M808 ; Decrement and loop if not zero.
|
||||
*/
|
||||
void GcodeSuite::M808() {
|
||||
|
||||
// Handled early and ignored here in the queue.
|
||||
// Allowed to go into the queue for logging purposes.
|
||||
|
||||
// M808 K sent from the host to cancel all loops
|
||||
if (parser.seen('K')) repeat.cancel();
|
||||
|
||||
}
|
||||
|
||||
#endif // GCODE_REPEAT_MARKERS
|
|
@ -699,8 +699,7 @@ void CardReader::removeFile(const char * const name) {
|
|||
|
||||
void CardReader::report_status() {
|
||||
if (isPrinting()) {
|
||||
SERIAL_ECHOPGM(STR_SD_PRINTING_BYTE);
|
||||
SERIAL_ECHO(sdpos);
|
||||
SERIAL_ECHOPAIR(STR_SD_PRINTING_BYTE, sdpos);
|
||||
SERIAL_CHAR('/');
|
||||
SERIAL_ECHOLN(filesize);
|
||||
}
|
||||
|
|
|
@ -159,9 +159,9 @@ public:
|
|||
static inline uint32_t getIndex() { return sdpos; }
|
||||
static inline uint32_t getFileSize() { return filesize; }
|
||||
static inline bool eof() { return sdpos >= filesize; }
|
||||
static inline void setIndex(const uint32_t index) { sdpos = index; file.seekSet(index); }
|
||||
static inline void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); }
|
||||
static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
|
||||
static inline int16_t get() { sdpos = file.curPosition(); return (int16_t)file.read(); }
|
||||
static inline int16_t get() { int16_t out = (int16_t)file.read(); sdpos = file.curPosition(); return out; }
|
||||
static inline int16_t read(void* buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
|
||||
static inline int16_t write(void* buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }
|
||||
|
||||
|
@ -244,7 +244,8 @@ private:
|
|||
static SdVolume volume;
|
||||
static SdFile file;
|
||||
|
||||
static uint32_t filesize, sdpos;
|
||||
static uint32_t filesize, // Total size of the current file, in bytes
|
||||
sdpos; // Index most recently read (one behind file.getPos)
|
||||
|
||||
//
|
||||
// Procedure calls to other files
|
||||
|
|
16
buildroot/test-gcode/M808-loops.gcode
Normal file
16
buildroot/test-gcode/M808-loops.gcode
Normal file
|
@ -0,0 +1,16 @@
|
|||
;
|
||||
; M808 Repeat Marker Test
|
||||
;
|
||||
|
||||
M808 L3 ; Marker at 54
|
||||
|
||||
M118 Outer Loop
|
||||
M300 S220 P100
|
||||
|
||||
M808 L5 ; Marker at 111
|
||||
|
||||
M118 Inner Loop
|
||||
M300 S110 P100
|
||||
|
||||
M808
|
||||
M808
|
|
@ -107,7 +107,7 @@ restore_configs
|
|||
opt_set MOTHERBOARD BOARD_MEGACONTROLLER
|
||||
opt_set LCD_LANGUAGE de
|
||||
opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT \
|
||||
MINIPANEL SDSUPPORT PCA9632 LCD_INFO_MENU SOUND_MENU_ITEM \
|
||||
MINIPANEL SDSUPPORT PCA9632 LCD_INFO_MENU SOUND_MENU_ITEM GCODE_REPEAT_MARKERS \
|
||||
AUTO_BED_LEVELING_BILINEAR PROBE_MANUALLY LCD_BED_LEVELING G26_MESH_VALIDATION MESH_EDIT_MENU \
|
||||
LIN_ADVANCE EXTRA_LIN_ADVANCE_K \
|
||||
INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT EXPERIMENTAL_I2CBUS M100_FREE_MEMORY_WATCHER \
|
||||
|
|
|
@ -101,6 +101,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
|
|||
-<src/feature/power_monitor.cpp> -<src/gcode/feature/power_monitor>
|
||||
-<src/feature/powerloss.cpp> -<src/gcode/feature/powerloss>
|
||||
-<src/feature/probe_temp_comp.cpp>
|
||||
-<src/feature/repeat.cpp>
|
||||
-<src/feature/runout.cpp> -<src/gcode/feature/runout>
|
||||
-<src/feature/solenoid.cpp> -<src/gcode/control/M380_M381.cpp>
|
||||
-<src/feature/spindle_laser.cpp> -<src/gcode/control/M3-M5.cpp>
|
||||
|
@ -182,6 +183,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
|
|||
-<src/gcode/scara>
|
||||
-<src/gcode/sd>
|
||||
-<src/gcode/sd/M32.cpp>
|
||||
-<src/gcode/sd/M808.cpp>
|
||||
-<src/gcode/temp/M104_M109.cpp>
|
||||
-<src/gcode/temp/M155.cpp>
|
||||
-<src/gcode/units/G20_G21.cpp>
|
||||
|
@ -374,6 +376,7 @@ G38_PROBE_TARGET = src_filter=+<src/gcode/probe/G38.cpp>
|
|||
MAGNETIC_PARKING_EXTRUDER = src_filter=+<src/gcode/probe/M951.cpp>
|
||||
SDSUPPORT = src_filter=+<src/gcode/sd>
|
||||
HAS_MEDIA_SUBCALLS = src_filter=+<src/gcode/sd/M32.cpp>
|
||||
GCODE_REPEAT_MARKERS = src_filter=+<src/feature/repeat.cpp> +<src/gcode/sd/M808.cpp>
|
||||
HAS_EXTRUDERS = src_filter=+<src/gcode/temp/M104_M109.cpp> +<src/gcode/config/M221.cpp>
|
||||
AUTO_REPORT_TEMPERATURES = src_filter=+<src/gcode/temp/M155.cpp>
|
||||
INCH_MODE_SUPPORT = src_filter=+<src/gcode/units/G20_G21.cpp>
|
||||
|
@ -402,7 +405,7 @@ framework = arduino
|
|||
extra_scripts = ${common.extra_scripts}
|
||||
build_flags = ${common.build_flags}
|
||||
lib_deps = ${common.lib_deps}
|
||||
monitor_speed = 250000
|
||||
monitor_speed = 115200
|
||||
monitor_flags =
|
||||
--quiet
|
||||
--echo
|
||||
|
|
Loading…
Reference in a new issue