diff --git a/Marlin/src/core/serial.cpp b/Marlin/src/core/serial.cpp index d6c4b55459ded..f04f57d2d2ee7 100644 --- a/Marlin/src/core/serial.cpp +++ b/Marlin/src/core/serial.cpp @@ -27,6 +27,9 @@ #include "../feature/ethernet.h" #endif +#include +#include + // Echo commands to the terminal by default in dev mode uint8_t marlin_debug_flags = TERN(MARLIN_DEV_MODE, MARLIN_DEBUG_ECHO, MARLIN_DEBUG_NONE); @@ -144,3 +147,26 @@ void print_xyze(LOGICAL_AXIS_ARGS_(const_float_t) FSTR_P const prefix/*=nullptr* #endif if (suffix) SERIAL_ECHO(suffix); else SERIAL_EOL(); } + +#if ENABLED(SERIAL_2_FILE) + MediaFile sr_dump_file; + size_t sr_write_res; + + bool sr_file_open(const char * filename) + { + sr_write_res = 0; + MediaFile root = card.getroot(); + return sr_dump_file.open(&root, filename, O_CREAT | O_WRITE | O_TRUNC); + } + + void serial2file(uint8_t c) + { + if (sr_dump_file.isOpen() && sr_write_res != -1) + sr_write_res = sr_dump_file.write(c); + } + + bool sr_file_close() + { + return sr_dump_file.close(); + } +#endif \ No newline at end of file diff --git a/Marlin/src/core/serial.h b/Marlin/src/core/serial.h index f9b73e6d26678..e3f1bb0a095e0 100644 --- a/Marlin/src/core/serial.h +++ b/Marlin/src/core/serial.h @@ -250,6 +250,10 @@ inline void print_xyze(const xyze_pos_t &xyze, FSTR_P const prefix=nullptr, FSTR print_xyze(LOGICAL_AXIS_ELEM_(xyze) prefix, suffix); } +bool sr_file_open(const char * filename); +bool sr_file_close(); +extern size_t sr_write_res; + #define SERIAL_POS(SUFFIX,VAR) do { print_xyz(VAR, F(" " STRINGIFY(VAR) "="), F(" : " SUFFIX "\n")); }while(0) #define SERIAL_XYZ(PREFIX,V...) do { print_xyz(V, F(PREFIX)); }while(0) diff --git a/Marlin/src/core/serial_hook.h b/Marlin/src/core/serial_hook.h index 06efce1dc5fe7..a653fbdbc5202 100644 --- a/Marlin/src/core/serial_hook.h +++ b/Marlin/src/core/serial_hook.h @@ -200,6 +200,8 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial >, public Seria #define _S_CLASS(N) class Serial##N##T, #define _S_NAME(N) Serial##N##T, +void serial2file(uint8_t c); + template < REPEAT(NUM_SERIAL, _S_CLASS) const uint8_t offset=0, const uint8_t step=1 > struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > { typedef SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > BaseClassT; @@ -227,6 +229,9 @@ struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) #define _S_WRITE(N) if (portMask.enabled(output[N])) serial##N.write(c); REPEAT(NUM_SERIAL, _S_WRITE); #undef _S_WRITE + #if ENABLED(SERIAL_2_FILE) + serial2file(c); + #endif } NO_INLINE void msgDone() { #define _S_DONE(N) if (portMask.enabled(output[N])) serial##N.msgDone(); diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index 92799b7cd48bd..ddf0072608913 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -1888,3 +1888,8 @@ #if ALL(SPI_FLASH, HAS_MEDIA, MARLIN_DEV_MODE) #define SPI_FLASH_BACKUP 1 #endif + +#if ALL(HAS_MEDIA, HAS_MARLINUI_MENU) + #define EXPORT_SETTINGS // Export memory settings to file M503.gc in SD card root for replay + #define SERIAL_2_FILE // Dump serial output to file, needed for export settings +#endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index fdc78aa3e4b0c..4d0ac5836b37d 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2612,6 +2612,8 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #error "Either disable SDCARD_READONLY or disable BINARY_FILE_TRANSFER." #elif ENABLED(SDCARD_EEPROM_EMULATION) #error "Either disable SDCARD_READONLY or disable SDCARD_EEPROM_EMULATION." + #elif ENABLED(EXPORT_SETTINGS) + #error "Either disable SDCARD_READONLY or disable EXPORT_SETTINGS." #endif #endif diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 1ecf65a57fe0d..a1b57c9904553 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -470,6 +470,7 @@ namespace LanguageNarrow_en { LSTR MSG_LOAD_EEPROM = _UxGT("Load Settings"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Restore Defaults"); LSTR MSG_INIT_EEPROM = _UxGT("Initialize EEPROM"); + LSTR MSG_EXPORT_SETTINGS = _UxGT("Export Settings"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Err: EEPROM CRC"); LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Err: EEPROM Size"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: EEPROM Version"); diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index aaa8fb65e837b..c69c470bbf619 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1883,6 +1883,16 @@ void MarlinUI::host_notify(const char * const cstr) { } #endif + #if ENABLED(EXPORT_SETTINGS) + void MarlinUI::export_settings() { + if (sr_file_open("M503.gc")) { + settings.report(true); + completion_feedback(sr_file_close() && sr_write_res != -1); + } else + completion_feedback(false); + } + #endif + #endif #if ENABLED(EEPROM_SETTINGS) diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index f21d2565bef66..bed1744f57e7b 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -780,6 +780,10 @@ class MarlinUI { static void eeprom_alert(const EEPROM_Error) TERN_(EEPROM_AUTO_INIT, {}); #endif + #if ENABLED(EXPORT_SETTINGS) + static void export_settings(); + #endif + // // Special handling if a move is underway // diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index 22c0823f26138..10c0e61897478 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -792,6 +792,10 @@ void menu_advanced_settings() { ); #endif + #if ENABLED(EXPORT_SETTINGS) + ACTION_ITEM(MSG_EXPORT_SETTINGS, ui.export_settings); + #endif + END_MENU(); }