Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gcode: Add Marlin / Octoprint SD card compatible behavior #3976

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/Marlin/Marlin/src/gcode/gcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,13 @@

enum AxisRelative : uint8_t { REL_X, REL_Y, REL_Z, REL_E, E_MODE_ABS, E_MODE_REL };

#if ENABLED(SDSUPPORT) || ENABLED(SDCARD_GCODES)
namespace M27_handler {
extern uint32_t sd_auto_report_delay;
void print_sd_status();
} // namespace M27_handler
#endif

class GcodeSuite {
public:

Expand Down
13 changes: 13 additions & 0 deletions src/common/marlin_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,15 @@ void handle_nfc() {

#endif

void print_sd_report() {
static uint32_t last_sd_report = 0;
uint32_t current_time = ticks_s();
if (M27_handler::sd_auto_report_delay && (current_time - last_sd_report) >= M27_handler::sd_auto_report_delay) {
M27_handler::print_sd_status();
last_sd_report = current_time;
}
}

#if ENABLED(PRUSA_MMU2)
/// Helper function that enqueues gcodes to safely unload filament from nozzle back to mmu
///
Expand Down Expand Up @@ -641,6 +650,10 @@ static void cycle() {

print_fan_spd();

#if ENABLED(SDSUPPORT) || ENABLED(SDCARD_GCODES)
print_sd_report();
#endif

#ifdef MINDA_BROKEN_CABLE_DETECTION
print_Z_probe_cnt();
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/common/media.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ void media_print_start() {
media_print_size_estimate = media_print_file->get_gcode_stream_size_estimate();

// Do not remove, needed for 3rd party tools such as octoprint to get status about the gcode file being opened
SERIAL_ECHOLNPAIR(MSG_SD_FILE_OPENED, marlin_vars()->media_SFN_path.get_ptr(), " Size:", media_print_size_estimate);
SERIAL_ECHOLNPAIR(MSG_SD_FILE_OPENED, marlin_vars()->media_SFN_path.get_ptr(), MSG_SD_SIZE, media_print_size_estimate);

gcode_filter.reset();
osSignalSet(prefetch_thread_id, PREFETCH_SIGNAL_START);
Expand Down
3 changes: 3 additions & 0 deletions src/marlin_stubs/host/M115.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ void GcodeSuite::M115() {
#endif
);

// EXTENDED_M20
cap_line(PSTR("EXTENDED_M20"), true);

// THERMAL_PROTECTION
cap_line(PSTR("THERMAL_PROTECTION")
#if ((ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_DWARF()) && (ENABLED(THERMAL_PROTECTION_BED) || !HAS_HEATED_BED || HAS_MODULARBED()) && (ENABLED(THERMAL_PROTECTION_CHAMBER) || !HAS_HEATED_CHAMBER))
Expand Down
166 changes: 141 additions & 25 deletions src/marlin_stubs/sdcard/M20-M30_M32-M34.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,92 @@
#include "media.hpp"
#include "marlin_vars.hpp"

struct ListControl {
bool print_lfn : 1;
bool print_time : 1;
uint8_t recursion_count;
time_t tz_offset_seconds;
};

// Forward reference (for recursion)
static void list_files(const char *const dir_path, struct ListControl *lc);
// Depends on stack size/RAM, etc
// Set to 0 to disallow recursion, Marlin MAX is 6
#define MAX_RECURSION_DEPTH 4
// Device root name for FatFS
#define ROOT_PREFIX "/usb"

// Routine to output single dirent info in Marlin M20 format
// Note: Use of 'alloca' prohibits inline
static void __attribute__((noinline)) list_single_entry(const char *dir_path, struct dirent *entry, struct ListControl *lc) {
// Construct path to sub-dir.
int len = strlen(dir_path) + strlen(entry->d_name) + 2;
char *path = reinterpret_cast<char *>(alloca(len));
strcpy(path, dir_path);
strcat(path, "/");
strcat(path, entry->d_name);

if (entry->d_type != DT_DIR) {
struct stat fstats;

// Hide ROOT_PREFIX
SERIAL_ECHO(&path[sizeof(ROOT_PREFIX) - 1]);
int rc = stat(path, &fstats);
if (rc == 0) {
SERIAL_ECHOPAIR(PSTR(" "), fstats.st_size);
if (lc->print_time) {
struct tm lt;
time_t t = fstats.st_mtim.tv_sec + lc->tz_offset_seconds;
localtime_r(&t, &lt);
// M20 Date in high-word
t = ((lt.tm_year + 1900 - 1980) << 9 | (lt.tm_mon + 1) << 5 | lt.tm_mday) << 16;
// M20 Time in low-word
t |= lt.tm_hour << 11 | lt.tm_min << 5 | int((lt.tm_sec - (lt.tm_sec % 2)) / 2);
SERIAL_ECHOPGM(" 0x");
SERIAL_PRINT((unsigned int)t, HEX);
}
if (lc->print_lfn) {
SERIAL_ECHOPAIR(PSTR(" \""), entry->lfn, PSTR("\""));
}
}
SERIAL_EOL();
} else {
// Check recursion depth
if (lc->recursion_count == 0) {
return;
}

if (lc->print_lfn) {
SERIAL_ECHOPAIR(PSTR("DIR_ENTER: "), &path[sizeof(ROOT_PREFIX) - 1], PSTR("/ \""), entry->lfn, PSTR("\""));
SERIAL_EOL();
}
// List sub-directory calling 'list_files' recursively
lc->recursion_count--;
list_files(path, lc);
lc->recursion_count++;
if (lc->print_lfn) {
SERIAL_ECHOLNPGM("DIR_EXIT");
}
}
return;
}

// List all files in a single directory
// Note that this function is called recursively
static void list_files(const char *const dir_path, struct ListControl *lc) {
DIR *dir;
dir = opendir(dir_path);
if (dir != NULL) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL && entry->d_name[0]) {
// Output single directory entry or perform recursion into sub-dir
list_single_entry(dir_path, entry, lc);
}
closedir(dir);
}
return;
}

/** \addtogroup G-Codes
* @{
*/
Expand All @@ -13,16 +99,18 @@
* M20 - List SD card on serial port
*/
void GcodeSuite::M20() {
SERIAL_ECHOLNPGM(MSG_BEGIN_FILE_LIST);
DIR *dir;
dir = opendir("/usb/");
if (dir != NULL) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL && entry->d_name[0]) {
SERIAL_ECHOLN(entry->d_name);
}
closedir(dir);
ListControl lc;
if (parser.seen('L')) {
lc.print_lfn = 1;
}
if (parser.seen('T')) {
lc.print_time = 1;
}
// Get timezone offset to report local filetime
lc.tz_offset_seconds = time_tools::calculate_total_timezone_offset_minutes() * 60;
lc.recursion_count = MAX_RECURSION_DEPTH;
SERIAL_ECHOLNPGM(MSG_BEGIN_FILE_LIST);
list_files(ROOT_PREFIX, &lc);
SERIAL_ECHOLNPGM(MSG_END_FILE_LIST);
}

Expand All @@ -44,22 +132,42 @@ void GcodeSuite::M22() {
* M23 - Select SD file
*/
void GcodeSuite::M23() {
// Simplify3D includes the size, so zero out all spaces (#7227)
for (char *fn = parser.string_arg; *fn; ++fn) {
if (*fn == ' ') {
*fn = '\0';
}
char namebuf[marlin_vars()->media_SFN_path.max_length()];
// Simplify3D includes the size, terminate name at first space
char *idx = strchr(parser.string_arg, ' ');
if (idx) {
*idx = '\0';
}
marlin_vars()->media_SFN_path.set(parser.string_arg);
// Need to prepend root device name
strcpy(namebuf, PSTR(ROOT_PREFIX));
strncpy(&namebuf[sizeof(ROOT_PREFIX) - 1], parser.string_arg, sizeof(namebuf) - sizeof(ROOT_PREFIX));

// Do not remove. Used by third party tools to detect that a file has been selected
SERIAL_ECHOLNPGM(MSG_SD_FILE_SELECTED);
SERIAL_ECHO_START();
SERIAL_ECHOPAIR(PSTR("Now doing file: "), parser.string_arg);
SERIAL_EOL();

struct stat fstats;
int rc = stat(namebuf, &fstats);
if (rc == 0) {
marlin_vars()->media_SFN_path.set(namebuf);
// Do not remove, needed for 3rd party tools such as octoprint to get notification about the gcode file being opened
SERIAL_ECHOLNPAIR(MSG_SD_FILE_OPENED, parser.string_arg, MSG_SD_SIZE, fstats.st_size);
SERIAL_ECHOLNPGM(MSG_SD_FILE_SELECTED);
} else {
SERIAL_ECHOLNPAIR(MSG_SD_OPEN_FILE_FAIL, parser.string_arg);
}
}

/**
* M24 - Start/resume SD print
*/
void GcodeSuite::M24() {
marlin_server::print_resume();
if (media_print_get_state() == media_print_state_PAUSED) {
marlin_server::print_resume();
} else {
marlin_server::print_start(marlin_vars()->media_SFN_path.get_ptr(), marlin_server::PreviewSkipIfAble::all);
}
}

/**
Expand Down Expand Up @@ -89,19 +197,27 @@ void GcodeSuite::M26() {
*
* - `C` - Report current file's short file name instead
*/
uint32_t M27_handler::sd_auto_report_delay = 0;

void M27_handler::print_sd_status() {
if (media_print_get_state() != media_print_state_NONE) {
SERIAL_ECHOPGM(MSG_SD_PRINTING_BYTE);
SERIAL_ECHO(media_print_get_position());
SERIAL_CHAR('/');
SERIAL_ECHOLN(media_print_get_size());
} else {
SERIAL_ECHOLNPGM(MSG_SD_NOT_PRINTING);
}
}

void GcodeSuite::M27() {
if (parser.seen('C')) {
SERIAL_ECHOPGM("Current file: ");
SERIAL_ECHOLN(marlin_vars()->media_SFN_path.get_ptr());
} else if (parser.seen('S')) {
M27_handler::sd_auto_report_delay = parser.byteval('S');
} else {
if (media_print_get_state() != media_print_state_NONE) {
SERIAL_ECHOPGM(MSG_SD_PRINTING_BYTE);
SERIAL_ECHO(media_print_get_position());
SERIAL_CHAR('/');
SERIAL_ECHOLN(media_print_get_size());
} else {
SERIAL_ECHOLNPGM(MSG_SD_NOT_PRINTING);
}
M27_handler::print_sd_status();
}
}

Expand Down