Skip to content

Commit

Permalink
Add M41 GCODE_REPEAT_MARKERS
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkyhead committed Nov 10, 2020
1 parent f17394d commit 2f0fe38
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 26 deletions.
2 changes: 2 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,8 @@

//#define SDCARD_READONLY // Read-only SD card (to save over 2K of flash)

//#define GCODE_REPEAT_MARKERS // Enable G-code M41 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
Expand Down
72 changes: 72 additions & 0 deletions Marlin/src/feature/repeat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* 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 "repeat.h"

#include "../gcode/gcode.h"
#include "../sd/cardreader.h"

repeat_marker_t Repeat::marker[MAX_REPEAT_NESTING];
int8_t Repeat::index;

bool Repeat::is_command_M41(char * const cmd) {
parser.parse(cmd);
return parser.is_command('M', 41);
}

bool Repeat::early_parse_M41(char * const cmd, const uint32_t &sdpos) {
if (is_command_M41(cmd)) {
if (sdpos) {
gcode.process_parsed_command();
marker[index].sdpos = sdpos;
}
return false;
}
return true;
}

void Repeat::add_marker(const uint16_t count) {
if (index < MAX_REPEAT_NESTING) {
marker[index].counter = count ? count : -1;
index++;
}
}

void Repeat::loop() {
if (!index) // No marker has been set?
card.setIndex(0); // Go back to the top
else {
const uint16_t ind = index - 1; // The relevant marker index
if (!marker[ind].counter) // Did the counter run out?
--index; // Carry on and loop elsewhere on the next 'M41'
else {
card.setIndex(marker[ind].sdpos); // Loop back to the marker.
if (marker[ind].counter > 0) // Don't decrement a negative (or zero) counter.
--marker[ind].counter; // Decrement the counter. If zero this 'M41' will be skipped next time.
}
}
}

#endif // GCODE_REPEAT_MARKERS
45 changes: 45 additions & 0 deletions Marlin/src/feature/repeat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* 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 <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 {
public:
static repeat_marker_t marker[MAX_REPEAT_NESTING];
static int8_t index;
static bool is_command_M41(char * const cmd);
static bool early_parse_M41(char * const cmd, const uint32_t &sdpos);
static void add_marker(const uint16_t count);
static void loop();
};

extern Repeat repeat;
6 changes: 5 additions & 1 deletion Marlin/src/gcode/gcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
* Will still block Gcodes if M511 is disabled, in which case the printer should be unlocked via LCD Menu
*/
#if ENABLED(PASSWORD_FEATURE)
if (password.is_locked && !(parser.command_letter == 'M' && parser.codenum == 511)) {
if (password.is_locked && !parser.is_command('M', 511)) {
SERIAL_ECHO_MSG(STR_PRINTER_LOCKED);
return;
}
Expand Down Expand Up @@ -449,6 +449,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {

case 31: M31(); break; // M31: Report time since the start of SD print or last M109

#if ENABLED(GCODE_REPEAT_MARKERS)
case 41: M41(); break; // M41: Set / Goto repeat markers
#endif

#if ENABLED(DIRECT_PIN_CONTROL)
case 42: M42(); break; // M42: Change pin state
#endif
Expand Down
2 changes: 2 additions & 0 deletions Marlin/src/gcode/gcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,8 @@ class GcodeSuite {
#endif
#endif

TERN_(GCODE_REPEAT_MARKERS, static void M41());

TERN_(DIRECT_PIN_CONTROL, static void M42());
TERN_(PINS_DEBUGGING, static void M43());

Expand Down
3 changes: 3 additions & 0 deletions Marlin/src/gcode/host/M115.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ void GcodeSuite::M115() {
// SDCARD (M20, M23, M24, etc.)
cap_line(PSTR("SDCARD"), ENABLED(SDSUPPORT));

// REPEAT (M41)
cap_line(PSTR("REPEAT"), ENABLED(GCODE_REPEAT_MARKERS));

// AUTOREPORT_SD_STATUS (M27 extension)
cap_line(PSTR("AUTOREPORT_SD_STATUS"), ENABLED(AUTO_REPORT_SD_STATUS));

Expand Down
4 changes: 2 additions & 2 deletions Marlin/src/gcode/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ char *GCodeParser::command_ptr,
*GCodeParser::string_arg,
*GCodeParser::value_ptr;
char GCodeParser::command_letter;
int GCodeParser::codenum;
uint16_t GCodeParser::codenum;

#if ENABLED(USE_GCODE_SUBCODES)
uint8_t GCodeParser::subcode;
Expand Down Expand Up @@ -270,7 +270,7 @@ void GCodeParser::parse(char *p) {

// Special handling for M32 [P] !/path/to/file.g#
// The path must be the last parameter
if (param == '!' && letter == 'M' && codenum == 32) {
if (param == '!' && is_command('M', 32)) {
string_arg = p; // Name starts after '!'
char * const lb = strchr(p, '#'); // Already seen '#' as SD char (to pause buffering)
if (lb) *lb = '\0'; // Safe to mark the end of the filename
Expand Down
5 changes: 4 additions & 1 deletion Marlin/src/gcode/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class GCodeParser {
static char *command_ptr, // The command, so it can be echoed
*string_arg, // string of command line
command_letter; // G, M, or T
static int codenum; // 123
static uint16_t codenum; // 123
#if ENABLED(USE_GCODE_SUBCODES)
static uint8_t subcode; // .1
#endif
Expand Down Expand Up @@ -244,6 +244,9 @@ class GCodeParser {
static bool chain();
#endif

// Test whether the parsed command matches the input
static inline bool is_command(const char ltr, const uint16_t num) { return command_letter == ltr && codenum == num; }

// The code value pointer was set
FORCE_INLINE static bool has_value() { return !!value_ptr; }

Expand Down
38 changes: 23 additions & 15 deletions Marlin/src/gcode/queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -416,11 +420,14 @@ inline void process_stream_char(const char c, uint8_t &sis, char (&buff)[MAX_CMD
* keep sensor readings going and watchdog alive.
*/
inline bool process_line_done(uint8_t &sis, char (&buff)[MAX_CMD_SIZE], int &ind) {
sis = PS_NORMAL;
buff[ind] = 0;
if (ind) { ind = 0; return false; }
thermalManager.manage_heater();
return true;
sis = PS_NORMAL; // "Normal" Serial Input State
buff[ind] = '\0'; // Of course, I'm a Terminator.
const bool is_empty = (ind == 0); // An empty line?
if (is_empty)
thermalManager.manage_heater(); // Keep sensors satisfied
else
ind = 0; // Start a new line
return is_empty; // Inform the caller
}

/**
Expand Down Expand Up @@ -547,12 +554,14 @@ void GCodeQueue::get_serial_commands() {
last_command_time = ms;
#endif

// Add the command to the queue
_enqueue(serial_line_buffer[i], true
#if HAS_MULTI_SERIAL
, i
#endif
);
if (TERN1(GCODE_REPEAT_MARKERS, !repeat.is_command_M41(serial_line_buffer[i]))) { // Ignore 'M41' from serial
// Add the command to the queue
_enqueue(serial_line_buffer[i], true
#if HAS_MULTI_SERIAL
, i
#endif
);
}
}
else
process_stream_char(serial_char, serial_input_state[i], serial_line_buffer[i], serial_count[i]);
Expand Down Expand Up @@ -588,10 +597,9 @@ 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)) {
_commit_command(false);
#if ENABLED(POWER_LOSS_RECOVERY)
recovery.cmd_sdpos = card.getIndex(); // Prime for the NEXT _commit_command
#endif
if (TERN1(GCODE_REPEAT_MARKERS, repeat.early_parse_M41(command_buffer[index_w], card.getIndex())))
_commit_command(false);
TERN_(POWER_LOSS_RECOVERY, recovery.cmd_sdpos = card.getIndex()); // Prime for the NEXT _commit_command
}

if (card_eof) card.fileHasFinished(); // Handle end of file reached
Expand Down
50 changes: 50 additions & 0 deletions Marlin/src/gcode/sd/M41.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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"

/**
* M41: Set / Goto a repeat marker
*
* S<count> - Set a repeat marker with 'count' repetitions. If omitted, infinity.
*
* Examples:
*
* M41 S ; Set a loop marker with a count of infinity
* M41 S2 ; Set a loop marker with a count of 2
* M41 ; Decrement and loop if not zero.
*/
void GcodeSuite::M41() {

if (parser.seen('S')) // If 'S' was seen...
repeat.add_marker(parser.value_ushort()); // Add a marker with a count. 'S' or 'S0' = forever.
else
repeat.loop();

}

#endif // GCODE_REPEAT_MARKERS
4 changes: 0 additions & 4 deletions Marlin/src/lcd/marlinui.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@
inline void wrap_string_P(uint8_t &col, uint8_t &row, PGM_P const pstr, const bool wordwrap=false) { _wrap_string(col, row, pstr, read_byte_rom, wordwrap); }
inline void wrap_string(uint8_t &col, uint8_t &row, const char * const string, const bool wordwrap=false) { _wrap_string(col, row, string, read_byte_ram, wordwrap); }

#if ENABLED(SDSUPPORT)
#include "../sd/cardreader.h"
#endif

typedef void (*screenFunc_t)();
typedef void (*menuAction_t)();

Expand Down
2 changes: 1 addition & 1 deletion buildroot/tests/mega2560-tests
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,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 \
Expand Down
4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ default_src_filter = +<src/*> -<src/config> -<src/HAL> +<src/HAL/shared>
-<src/gcode/probe/M851.cpp>
-<src/gcode/probe/M951.cpp>
-<src/gcode/scara>
-<src/gcode/sd>
-<src/gcode/sd/M32.cpp>
-<src/gcode/sd> -<src/gcode/sd/M32.cpp> -<src/gcode/sd/M41.cpp>
-<src/gcode/temp/M104_M109.cpp>
-<src/gcode/temp/M155.cpp>
-<src/gcode/units/G20_G21.cpp>
Expand Down Expand Up @@ -372,6 +371,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/gcode/sd/M41.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>
Expand Down

0 comments on commit 2f0fe38

Please sign in to comment.