diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 545f9df641..58d9eb5848 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -192,6 +192,7 @@ #define STR_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" #define STR_ERR_HOTEND_TOO_COLD "Hotend too cold" #define STR_ERR_EEPROM_WRITE "Error writing to EEPROM!" +#define STR_ERR_EEPROM_CORRUPT "EEPROM Corrupt" #define STR_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle" #define STR_FILAMENT_CHANGE_INSERT_LCD "Insert filament and press button" diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index fe3415dc8a..09b979b5f7 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -414,7 +414,7 @@ namespace Language_de { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Standardwerte laden"); LSTR MSG_INIT_EEPROM = _UxGT("Werkseinstellungen"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC Fehler"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index Fehler"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("EEPROM Größe Fehler"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version Fehler"); LSTR MSG_SETTINGS_STORED = _UxGT("Einstell. gespei."); LSTR MSG_MEDIA_UPDATE = _UxGT("FW Update vom Medium"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 0d5b36516c..8dab8fcdae 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -445,9 +445,10 @@ namespace Language_en { LSTR MSG_LOAD_EEPROM = _UxGT("Load Settings"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Restore Defaults"); LSTR MSG_INIT_EEPROM = _UxGT("Initialize EEPROM"); - LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC Error"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index Error"); - LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version Error"); + 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"); + LSTR MSG_ERR_EEPROM_CORRUPT = _UxGT("Err: EEPROM Corrupt"); LSTR MSG_SETTINGS_STORED = _UxGT("Settings Stored"); LSTR MSG_MEDIA_UPDATE = MEDIA_TYPE_EN _UxGT(" Update"); LSTR MSG_RESET_PRINTER = _UxGT("Reset Printer"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index d95275c317..eb39a8a089 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -315,7 +315,7 @@ namespace Language_es { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Rest. fábrica"); LSTR MSG_INIT_EEPROM = _UxGT("Inicializar EEPROM"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Err: EEPROM CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Err: Índice EEPROM"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Err: EEPROM Tamaño"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: Versión EEPROM"); LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar SD/FD"); LSTR MSG_RESET_PRINTER = _UxGT("Resetear Impresora"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index e591661062..54ae62bac9 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -317,7 +317,7 @@ namespace Language_gl { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Rest. Defecto"); LSTR MSG_INIT_EEPROM = _UxGT("Inicializar EEPROM"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Erro: CRC EEPROM"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Erro: Índice EEPROM"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Erro: Tamaño EEPROM"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Erro: Versión EEPROM"); LSTR MSG_SETTINGS_STORED = _UxGT("Config Gardada"); LSTR MSG_MEDIA_UPDATE = _UxGT("Actualizar SD/FD"); diff --git a/Marlin/src/lcd/language/language_hu.h b/Marlin/src/lcd/language/language_hu.h index abc4b4c67e..148a0fb64e 100644 --- a/Marlin/src/lcd/language/language_hu.h +++ b/Marlin/src/lcd/language/language_hu.h @@ -363,7 +363,7 @@ namespace Language_hu { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Alapértelmezett"); LSTR MSG_INIT_EEPROM = _UxGT("EEPROM inicializálás"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Hiba: EEPROM CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Hiba: EEPROM index"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Hiba: EEPROM mérete"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Hiba: EEPROM verzió"); LSTR MSG_SETTINGS_STORED = _UxGT("Beállítások mentve"); LSTR MSG_MEDIA_UPDATE = _UxGT("Tároló frissítés"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index 9eb641a64e..41786f4d7b 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -451,7 +451,7 @@ namespace Language_it { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Ripristina imp."); LSTR MSG_INIT_EEPROM = _UxGT("Inizializza EEPROM"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Err: CRC EEPROM"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Err: Indice EEPROM"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Err: Taglia EEPROM"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: Versione EEPROM"); LSTR MSG_SETTINGS_STORED = _UxGT("Impostazioni mem."); LSTR MSG_MEDIA_UPDATE = _UxGT("Aggiorna media"); diff --git a/Marlin/src/lcd/language/language_ro.h b/Marlin/src/lcd/language/language_ro.h index c739b6bf41..4eefc11cb9 100644 --- a/Marlin/src/lcd/language/language_ro.h +++ b/Marlin/src/lcd/language/language_ro.h @@ -317,9 +317,9 @@ namespace Language_ro { LSTR MSG_LOAD_EEPROM = _UxGT("Load Settings"); LSTR MSG_RESTORE_DEFAULTS = _UxGT("Restore Defaults"); LSTR MSG_INIT_EEPROM = _UxGT("Initialize EEPROM"); - LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC Error"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index Error"); - LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version Error"); + LSTR MSG_ERR_EEPROM_CRC = _UxGT("Err: EEPROM CRC"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Err: Mărimea EEPROM"); + LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Err: Versiunea EEPROM"); LSTR MSG_SETTINGS_STORED = _UxGT("Settings Stored"); LSTR MSG_MEDIA_UPDATE = _UxGT("Media Update"); LSTR MSG_RESET_PRINTER = _UxGT("Reset Imprimanta"); diff --git a/Marlin/src/lcd/language/language_ru.h b/Marlin/src/lcd/language/language_ru.h index a5396b49ef..03380af15e 100644 --- a/Marlin/src/lcd/language/language_ru.h +++ b/Marlin/src/lcd/language/language_ru.h @@ -454,7 +454,7 @@ namespace Language_ru { LSTR MSG_INIT_EEPROM = _UxGT("Инициализ. EEPROM"); #endif LSTR MSG_ERR_EEPROM_CRC = _UxGT("Сбой EEPROM: CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Сбой EEPROM: индекс"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Сбой EEPROM: размер"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Сбой EEPROM: версия"); LSTR MSG_SETTINGS_STORED = _UxGT("Параметры сохранены"); LSTR MSG_MEDIA_UPDATE = _UxGT("Обновление прошивки"); diff --git a/Marlin/src/lcd/language/language_sk.h b/Marlin/src/lcd/language/language_sk.h index c4319c8ef4..024d02b713 100644 --- a/Marlin/src/lcd/language/language_sk.h +++ b/Marlin/src/lcd/language/language_sk.h @@ -452,7 +452,7 @@ namespace Language_sk { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Obnoviť nastavenie"); LSTR MSG_INIT_EEPROM = _UxGT("Inicializ. EEPROM"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Chyba: EEPROM CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Chyba: EEPROM Index"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Chyba: Veľkosť EEPROM"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Chyba: Verzia EEPROM"); LSTR MSG_SETTINGS_STORED = _UxGT("Nastavenie uložené"); LSTR MSG_MEDIA_UPDATE = _UxGT("Aktualiz. z karty"); diff --git a/Marlin/src/lcd/language/language_sv.h b/Marlin/src/lcd/language/language_sv.h index e2202e32c8..e66de33c22 100644 --- a/Marlin/src/lcd/language/language_sv.h +++ b/Marlin/src/lcd/language/language_sv.h @@ -348,7 +348,7 @@ namespace Language_sv { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Återställ Standard"); LSTR MSG_INIT_EEPROM = _UxGT("Initiera EEPROM"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC Fel"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index Fel"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("EEPROM Storlek Fel"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version Fel"); LSTR MSG_SETTINGS_STORED = _UxGT("Inställningar Lagrad"); LSTR MSG_MEDIA_UPDATE = _UxGT("Media Uppdatera"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index 569b32b93d..ca6a38142c 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -431,7 +431,7 @@ namespace Language_tr { LSTR MSG_RESTORE_DEFAULTS = _UxGT("Fabrika Ayarları"); LSTR MSG_INIT_EEPROM = _UxGT("EEPROM'u başlat"); LSTR MSG_ERR_EEPROM_CRC = _UxGT("Hata: EEPROM CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Hata: EEPROM Indeks"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Hata: EEPROM Boyutu"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Hata: EEPROM Sürümü"); LSTR MSG_SETTINGS_STORED = _UxGT("Ayarlar Kaydedildi"); LSTR MSG_MEDIA_UPDATE = _UxGT("SD Güncellemesi"); diff --git a/Marlin/src/lcd/language/language_uk.h b/Marlin/src/lcd/language/language_uk.h index 3c4dbe5d9c..e678cd872e 100644 --- a/Marlin/src/lcd/language/language_uk.h +++ b/Marlin/src/lcd/language/language_uk.h @@ -465,7 +465,7 @@ namespace Language_uk { LSTR MSG_INIT_EEPROM = _UxGT("Ініціаліз. EEPROM"); #endif LSTR MSG_ERR_EEPROM_CRC = _UxGT("Збій EEPROM: CRC"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("Збій EEPROM: індекс"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("Збій EEPROM: розмір"); LSTR MSG_ERR_EEPROM_VERSION = _UxGT("Збій EEPROM: версія"); LSTR MSG_SETTINGS_STORED = _UxGT("Параметри збережені"); LSTR MSG_MEDIA_UPDATE = _UxGT("Оновити SD-картку"); diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index 2f16a45724..9dbb61e70b 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -317,9 +317,9 @@ namespace Language_zh_CN { LSTR MSG_LOAD_EEPROM = _UxGT("装载设置"); // "Load memory" LSTR MSG_RESTORE_DEFAULTS = _UxGT("恢复安全值"); // "Restore Defaults" LSTR MSG_INIT_EEPROM = _UxGT("初始化设置"); // "Initialize EEPROM" - LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM CRC 错误"); - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("EEPROM Index 错误"); - LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM Version 错误"); + LSTR MSG_ERR_EEPROM_CRC = _UxGT("EEPROM 校验和 错误"); + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("EEPROM 尺寸 错误"); + LSTR MSG_ERR_EEPROM_VERSION = _UxGT("EEPROM 版本 错误"); LSTR MSG_SETTINGS_STORED = _UxGT("设置已保存"); LSTR MSG_MEDIA_UPDATE = _UxGT("存储器更新"); LSTR MSG_RESET_PRINTER = _UxGT("复位打印机"); diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index dcaf1bb95d..49e57d6220 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -299,8 +299,8 @@ namespace Language_zh_TW { LSTR MSG_RESTORE_DEFAULTS = _UxGT("恢復安全值"); // "Restore failsafe" LSTR MSG_INIT_EEPROM = _UxGT("初始化設置"); // "Initialize EEPROM" LSTR MSG_ERR_EEPROM_CRC = _UxGT("錯誤: EEPROM CRC"); // "Err: EEPROM CRC" - LSTR MSG_ERR_EEPROM_INDEX = _UxGT("錯誤: EEPROM Index"); // "Err: EEPROM Index" - LSTR MSG_ERR_EEPROM_VERSION = _UxGT("錯誤: EEPROM Version"); // "EEPROM Version" + LSTR MSG_ERR_EEPROM_SIZE = _UxGT("錯誤: EEPROM 尺寸"); // "Err: EEPROM Index" + LSTR MSG_ERR_EEPROM_VERSION = _UxGT("錯誤: EEPROM 版本"); // "EEPROM Version" LSTR MSG_MEDIA_UPDATE = _UxGT("媒體更新"); // "Media Update" LSTR MSG_RESET_PRINTER = _UxGT("重置打印機"); // "Reset Printer LSTR MSG_REFRESH = _UxGT("刷新"); // "Refresh" diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index 6f25cf1942..604e9bb0ca 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -1899,18 +1899,22 @@ void MarlinUI::init() { #if DISABLED(EEPROM_AUTO_INIT) - static inline FSTR_P eeprom_err(const uint8_t msgid) { - switch (msgid) { - default: - case 0: return GET_TEXT_F(MSG_ERR_EEPROM_CRC); - case 1: return GET_TEXT_F(MSG_ERR_EEPROM_INDEX); - case 2: return GET_TEXT_F(MSG_ERR_EEPROM_VERSION); + static inline FSTR_P eeprom_err(const EEPROM_Error err) { + switch (err) { + case ERR_EEPROM_VERSION: return GET_TEXT_F(MSG_ERR_EEPROM_VERSION); + case ERR_EEPROM_SIZE: return GET_TEXT_F(MSG_ERR_EEPROM_SIZE); + case ERR_EEPROM_CRC: return GET_TEXT_F(MSG_ERR_EEPROM_CRC); + case ERR_EEPROM_CORRUPT: return GET_TEXT_F(MSG_ERR_EEPROM_CORRUPT); + default: return nullptr; } } - void MarlinUI::eeprom_alert(const uint8_t msgid) { + void MarlinUI::eeprom_alert(const EEPROM_Error err) { + FSTR_P const err_msg = eeprom_err(err); + set_status(err_msg); + TERN_(HOST_PROMPT_SUPPORT, hostui.notify(err_msg)); #if HAS_MARLINUI_MENU - editable.uint8 = msgid; + editable.uint8 = err; goto_screen([]{ FSTR_P const restore_msg = GET_TEXT_F(MSG_INIT_EEPROM); char msg[utf8_strlen(restore_msg) + 1]; @@ -1918,11 +1922,9 @@ void MarlinUI::init() { MenuItem_confirm::select_screen( GET_TEXT_F(MSG_BUTTON_RESET), GET_TEXT_F(MSG_BUTTON_IGNORE), init_eeprom, return_to_status, - eeprom_err(editable.uint8), msg, F("?") + eeprom_err((EEPROM_Error)editable.uint8), msg, F("?") ); }); - #else - set_status(eeprom_err(msgid)); #endif } diff --git a/Marlin/src/lcd/marlinui.h b/Marlin/src/lcd/marlinui.h index 16fcf194eb..e33eda0591 100644 --- a/Marlin/src/lcd/marlinui.h +++ b/Marlin/src/lcd/marlinui.h @@ -27,6 +27,10 @@ #include "../libs/buzzer.h" #include "buttons.h" +#if ENABLED(EEPROM_SETTINGS) + #include "../module/settings.h" +#endif + #if ENABLED(TOUCH_SCREEN_CALIBRATION) #include "tft_io/touch_calibration.h" #endif @@ -672,12 +676,7 @@ public: static void load_settings(); static void store_settings(); #endif - #if DISABLED(EEPROM_AUTO_INIT) - static void eeprom_alert(const uint8_t msgid); - static void eeprom_alert_crc() { eeprom_alert(0); } - static void eeprom_alert_index() { eeprom_alert(1); } - static void eeprom_alert_version() { eeprom_alert(2); } - #endif + static void eeprom_alert(const EEPROM_Error) TERN_(EEPROM_AUTO_INIT, {}); #endif // diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index f7e49cc219..e01bd9ae60 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -36,12 +36,13 @@ */ // Change EEPROM version if the structure changes -#define EEPROM_VERSION "V87" +#define EEPROM_VERSION "V88" #define EEPROM_OFFSET 100 // Check the integrity of data offsets. // Can be disabled for production build. //#define DEBUG_EEPROM_READWRITE +//#define DEBUG_EEPROM_OBSERVE #include "settings.h" @@ -207,7 +208,8 @@ typedef struct SettingsDataStruct { #if ENABLED(EEPROM_INIT_NOW) uint32_t build_hash; // Unique build hash #endif - uint16_t crc; // Data Checksum + uint16_t crc; // Data Checksum for validation + uint16_t data_size; // Data Size for validation // // DISTINCT_E_FACTORS @@ -250,6 +252,7 @@ typedef struct SettingsDataStruct { // float mbl_z_offset; // bedlevel.z_offset uint8_t mesh_num_x, mesh_num_y; // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y + uint16_t mesh_check; // Hash to check against X/Y float mbl_z_values[TERN(MESH_BED_LEVELING, GRID_MAX_POINTS_X, 3)] // bedlevel.z_values [TERN(MESH_BED_LEVELING, GRID_MAX_POINTS_Y, 3)]; @@ -268,6 +271,7 @@ typedef struct SettingsDataStruct { // AUTO_BED_LEVELING_BILINEAR // uint8_t grid_max_x, grid_max_y; // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y + uint16_t grid_check; // Hash to check against X/Y xy_pos_t bilinear_grid_spacing, bilinear_start; // G29 L F #if ENABLED(AUTO_BED_LEVELING_BILINEAR) bed_mesh_t z_values; // G29 @@ -716,10 +720,13 @@ void MarlinSettings::postprocess() { #if ENABLED(EEPROM_SETTINGS) - #define EEPROM_ASSERT(TST,ERR) do{ if (!(TST)) { SERIAL_ERROR_MSG(ERR); eeprom_error = true; } }while(0) + #define EEPROM_ASSERT(TST,ERR) do{ if (!(TST)) { SERIAL_ERROR_MSG(ERR); eeprom_error = ERR_EEPROM_SIZE; } }while(0) + + #define TWO_BYTE_HASH(A,B) uint16_t((uint16_t(A ^ 0xC3) << 4) ^ (uint16_t(B ^ 0xC3) << 12)) #if ENABLED(DEBUG_EEPROM_READWRITE) #define _FIELD_TEST(FIELD) \ + SERIAL_ECHOLNPGM("Field: " STRINGIFY(FIELD)); \ EEPROM_ASSERT( \ eeprom_error || eeprom_index == offsetof(SettingsData, FIELD) + EEPROM_OFFSET, \ "Field " STRINGIFY(FIELD) " mismatch." \ @@ -728,6 +735,14 @@ void MarlinSettings::postprocess() { #define _FIELD_TEST(FIELD) NOOP #endif + #if ENABLED(DEBUG_EEPROM_OBSERVE) + #define EEPROM_READ(V...) do{ SERIAL_ECHOLNPGM("READ: ", F(STRINGIFY(FIRST(V)))); EEPROM_READ_(V); }while(0) + #define EEPROM_READ_ALWAYS(V...) do{ SERIAL_ECHOLNPGM("READ: ", F(STRINGIFY(FIRST(V)))); EEPROM_READ_ALWAYS_(V); }while(0) + #else + #define EEPROM_READ(V...) EEPROM_READ_(V) + #define EEPROM_READ_ALWAYS(V...) EEPROM_READ_ALWAYS_(V) + #endif + const char version[4] = EEPROM_VERSION; #if ENABLED(EEPROM_INIT_NOW) @@ -737,20 +752,20 @@ void MarlinSettings::postprocess() { constexpr uint32_t build_hash = strhash32(__DATE__ __TIME__); #endif - bool MarlinSettings::eeprom_error, MarlinSettings::validating; + bool MarlinSettings::validating; int MarlinSettings::eeprom_index; uint16_t MarlinSettings::working_crc; - bool MarlinSettings::size_error(const uint16_t size) { + EEPROM_Error MarlinSettings::size_error(const uint16_t size) { if (size != datasize()) { DEBUG_ERROR_MSG("EEPROM datasize error." #if ENABLED(MARLIN_DEV_MODE) " (Actual:", size, " Expected:", datasize(), ")" #endif ); - return true; + return ERR_EEPROM_SIZE; } - return false; + return ERR_EEPROM_NOERR; } /** @@ -762,18 +777,25 @@ void MarlinSettings::postprocess() { if (!EEPROM_START(EEPROM_OFFSET)) return false; - eeprom_error = false; + EEPROM_Error eeprom_error = ERR_EEPROM_NOERR; // Write or Skip version. (Flash doesn't allow rewrite without erase.) TERN(FLASH_EEPROM_EMULATION, EEPROM_SKIP, EEPROM_WRITE)(ver); #if ENABLED(EEPROM_INIT_NOW) - EEPROM_SKIP(build_hash); // Skip the hash slot + EEPROM_SKIP(build_hash); // Skip the hash slot which will be written later #endif EEPROM_SKIP(working_crc); // Skip the checksum slot - working_crc = 0; // clear before first "real data" + // + // Clear after skipping CRC and before writing the CRC'ed data + // + working_crc = 0; + + // Write the size of the data structure for use in validation + const uint16_t data_size = datasize(); + EEPROM_WRITE(data_size); const uint8_t e_factors = DISTINCT_AXES - (NUM_AXES); _FIELD_TEST(e_factors); @@ -875,6 +897,10 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(mesh_num_x); EEPROM_WRITE(mesh_num_y); + // Check value for the X/Y values + const uint16_t mesh_check = TWO_BYTE_HASH(mesh_num_x, mesh_num_y); + EEPROM_WRITE(mesh_check); + #if ENABLED(MESH_BED_LEVELING) EEPROM_WRITE(bedlevel.z_values); #else @@ -922,6 +948,11 @@ void MarlinSettings::postprocess() { grid_max_y = TERN(AUTO_BED_LEVELING_BILINEAR, GRID_MAX_POINTS_Y, 3); EEPROM_WRITE(grid_max_x); EEPROM_WRITE(grid_max_y); + + // Check value for the X/Y values + const uint16_t grid_check = TWO_BYTE_HASH(grid_max_x, grid_max_y); + EEPROM_WRITE(grid_check); + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) EEPROM_WRITE(bedlevel.grid_spacing); EEPROM_WRITE(bedlevel.grid_start); @@ -1631,7 +1662,7 @@ void MarlinSettings::postprocess() { // // Report final CRC and Data Size // - if (!eeprom_error) { + if (eeprom_error == ERR_EEPROM_NOERR) { const uint16_t eeprom_size = eeprom_index - (EEPROM_OFFSET), final_crc = working_crc; @@ -1647,7 +1678,7 @@ void MarlinSettings::postprocess() { // Report storage size DEBUG_ECHO_MSG("Settings Stored (", eeprom_size, " bytes; crc ", (uint32_t)final_crc, ")"); - eeprom_error |= size_error(eeprom_size); + eeprom_error = size_error(eeprom_size); } EEPROM_FINISH(); @@ -1659,56 +1690,82 @@ void MarlinSettings::postprocess() { store_mesh(bedlevel.storage_slot); #endif - if (!eeprom_error) { + const bool success = (eeprom_error == ERR_EEPROM_NOERR); + if (success) { LCD_MESSAGE(MSG_SETTINGS_STORED); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_SETTINGS_STORED))); } - TERN_(EXTENSIBLE_UI, ExtUI::onSettingsStored(!eeprom_error)); + TERN_(EXTENSIBLE_UI, ExtUI::onSettingsStored(success)); - return !eeprom_error; + return success; } /** * M501 - Retrieve Configuration */ - bool MarlinSettings::_load() { - if (!EEPROM_START(EEPROM_OFFSET)) return false; + EEPROM_Error MarlinSettings::_load() { + EEPROM_Error eeprom_error = ERR_EEPROM_NOERR; + + if (!EEPROM_START(EEPROM_OFFSET)) return eeprom_error; char stored_ver[4]; EEPROM_READ_ALWAYS(stored_ver); - // Version has to match or defaults are used - if (strncmp(version, stored_ver, 3) != 0) { - if (stored_ver[3] != '\0') { - stored_ver[0] = '?'; - stored_ver[1] = '\0'; + uint16_t stored_crc; + + do { // A block to break out of on error + + // Version has to match or defaults are used + if (strncmp(version, stored_ver, 3) != 0) { + if (stored_ver[3] != '\0') { + stored_ver[0] = '?'; + stored_ver[1] = '\0'; + } + DEBUG_ECHO_MSG("EEPROM version mismatch (EEPROM=", stored_ver, " Marlin=" EEPROM_VERSION ")"); + eeprom_error = ERR_EEPROM_VERSION; + break; } - DEBUG_ECHO_MSG("EEPROM version mismatch (EEPROM=", stored_ver, " Marlin=" EEPROM_VERSION ")"); - LCD_MESSAGE(MSG_ERR_EEPROM_VERSION); - TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_ERR_EEPROM_VERSION))); - IF_DISABLED(EEPROM_AUTO_INIT, ui.eeprom_alert_version()); - eeprom_error = true; - } - else { - - // Optionally reset on the first boot after flashing + // + // Optionally reset on first boot after flashing + // #if ENABLED(EEPROM_INIT_NOW) uint32_t stored_hash; EEPROM_READ_ALWAYS(stored_hash); - if (stored_hash != build_hash) { EEPROM_FINISH(); return false; } + if (stored_hash != build_hash) { + eeprom_error = ERR_EEPROM_CORRUPT; + break; + } #endif - uint16_t stored_crc; + // + // Get the stored CRC to compare at the end + // EEPROM_READ_ALWAYS(stored_crc); + // + // A temporary float for safe storage + // float dummyf = 0; - working_crc = 0; // Init to 0. Accumulated by EEPROM_READ - _FIELD_TEST(e_factors); + // + // Init to 0. Accumulated by EEPROM_READ + // + working_crc = 0; + // + // Validate the stored size against the current data structure size + // + uint16_t stored_size; + EEPROM_READ_ALWAYS(stored_size); + if ((eeprom_error = size_error(stored_size))) break; + + // + // Extruder Parameter Count // Number of e_factors may change + // + _FIELD_TEST(e_factors); uint8_t e_factors; EEPROM_READ_ALWAYS(e_factors); @@ -1808,16 +1865,28 @@ void MarlinSettings::postprocess() { // { uint8_t mesh_num_x, mesh_num_y; + uint16_t mesh_check; EEPROM_READ(dummyf); EEPROM_READ_ALWAYS(mesh_num_x); EEPROM_READ_ALWAYS(mesh_num_y); + // Check value must correspond to the X/Y values + EEPROM_READ_ALWAYS(mesh_check); + if (mesh_check != TWO_BYTE_HASH(mesh_num_x, mesh_num_y)) { + eeprom_error = ERR_EEPROM_CORRUPT; + break; + } + #if ENABLED(MESH_BED_LEVELING) if (!validating) bedlevel.z_offset = dummyf; if (mesh_num_x == (GRID_MAX_POINTS_X) && mesh_num_y == (GRID_MAX_POINTS_Y)) { // EEPROM data fits the current mesh EEPROM_READ(bedlevel.z_values); } + else if (mesh_num_x > (GRID_MAX_POINTS_X) || mesh_num_y > (GRID_MAX_POINTS_Y)) { + eeprom_error = ERR_EEPROM_CORRUPT; + break; + } else { // EEPROM data is stale if (!validating) bedlevel.reset(); @@ -1860,6 +1929,15 @@ void MarlinSettings::postprocess() { uint8_t grid_max_x, grid_max_y; EEPROM_READ_ALWAYS(grid_max_x); // 1 byte EEPROM_READ_ALWAYS(grid_max_y); // 1 byte + + // Check value must correspond to the X/Y values + uint16_t grid_check; + EEPROM_READ_ALWAYS(grid_check); + if (grid_check != TWO_BYTE_HASH(grid_max_x, grid_max_y)) { + eeprom_error = ERR_EEPROM_CORRUPT; + break; + } + xy_pos_t spacing, start; EEPROM_READ(spacing); // 2 ints EEPROM_READ(start); // 2 ints @@ -1869,6 +1947,10 @@ void MarlinSettings::postprocess() { bedlevel.set_grid(spacing, start); EEPROM_READ(bedlevel.z_values); // 9 to 256 floats } + else if (grid_max_x > (GRID_MAX_POINTS_X) || grid_max_y > (GRID_MAX_POINTS_Y)) { + eeprom_error = ERR_EEPROM_CORRUPT; + break; + } else // EEPROM data is stale #endif // AUTO_BED_LEVELING_BILINEAR { @@ -2623,27 +2705,22 @@ void MarlinSettings::postprocess() { // // Validate Final Size and CRC // - eeprom_error = size_error(eeprom_index - (EEPROM_OFFSET)); - if (eeprom_error) { - DEBUG_ECHO_MSG("Index: ", eeprom_index - (EEPROM_OFFSET), " Size: ", datasize()); - IF_DISABLED(EEPROM_AUTO_INIT, ui.eeprom_alert_index()); + const uint16_t eeprom_total = eeprom_index - (EEPROM_OFFSET); + if ((eeprom_error = size_error(eeprom_total))) { + // Handle below and on return + break; } else if (working_crc != stored_crc) { - eeprom_error = true; - DEBUG_ERROR_MSG("EEPROM CRC mismatch - (stored) ", stored_crc, " != ", working_crc, " (calculated)!"); - LCD_MESSAGE(MSG_ERR_EEPROM_CRC); - TERN_(HOST_EEPROM_CHITCHAT, hostui.notify(GET_TEXT_F(MSG_ERR_EEPROM_CRC))); - IF_DISABLED(EEPROM_AUTO_INIT, ui.eeprom_alert_crc()); + eeprom_error = ERR_EEPROM_CRC; + break; } else if (!validating) { DEBUG_ECHO_START(); DEBUG_ECHO(version); - DEBUG_ECHOLNPGM(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET), " bytes; crc ", (uint32_t)working_crc, ")"); + DEBUG_ECHOLNPGM(" stored settings retrieved (", eeprom_total, " bytes; crc ", working_crc, ")"); TERN_(HOST_EEPROM_CHITCHAT, hostui.notify(F("Stored settings retrieved"))); } - if (!validating && !eeprom_error) postprocess(); - #if ENABLED(AUTO_BED_LEVELING_UBL) if (!validating) { bedlevel.report_state(); @@ -2655,7 +2732,7 @@ void MarlinSettings::postprocess() { #endif } else { - eeprom_error = true; + eeprom_error = ERR_EEPROM_CORRUPT; #if BOTH(EEPROM_CHITCHAT, DEBUG_LEVELING_FEATURE) DEBUG_ECHOPGM("?Can't enable "); bedlevel.echo_name(); @@ -2674,6 +2751,26 @@ void MarlinSettings::postprocess() { } } #endif + + } while(0); + + EEPROM_FINISH(); + + switch (eeprom_error) { + case ERR_EEPROM_NOERR: + if (!validating) postprocess(); + break; + case ERR_EEPROM_SIZE: + DEBUG_ECHO_MSG("Index: ", eeprom_index - (EEPROM_OFFSET), " Size: ", datasize()); + break; + case ERR_EEPROM_CORRUPT: + DEBUG_ERROR_MSG(STR_ERR_EEPROM_CORRUPT); + break; + case ERR_EEPROM_CRC: + DEBUG_ERROR_MSG("EEPROM CRC mismatch - (stored) ", stored_crc, " != ", working_crc, " (calculated)!"); + TERN_(HOST_EEPROM_CHITCHAT, hostui.notify(GET_TEXT_F(MSG_ERR_EEPROM_CRC))); + break; + default: break; } #if ENABLED(EEPROM_CHITCHAT) && DISABLED(DISABLE_M503) @@ -2681,9 +2778,7 @@ void MarlinSettings::postprocess() { if (!validating && TERN1(EEPROM_BOOT_SILENT, IsRunning())) report(); #endif - EEPROM_FINISH(); - - return !eeprom_error; + return eeprom_error; } #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE @@ -2693,21 +2788,25 @@ void MarlinSettings::postprocess() { bool MarlinSettings::validate() { validating = true; #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE - bool success = _load(); - if (!success && restoreEEPROM()) { + EEPROM_Error err = _load(); + if (err != ERR_EEPROM_NOERR && restoreEEPROM()) { SERIAL_ECHOLNPGM("Recovered backup EEPROM settings from SPI Flash"); - success = _load(); + err = _load(); } #else - const bool success = _load(); + const EEPROM_Error err = _load(); #endif validating = false; - return success; + + if (err) ui.eeprom_alert(err); + + return (err == ERR_EEPROM_NOERR); } bool MarlinSettings::load() { if (validate()) { - const bool success = _load(); + const EEPROM_Error err = _load(); + const bool success = (err == ERR_EEPROM_NOERR); TERN_(EXTENSIBLE_UI, ExtUI::onSettingsLoaded(success)); return success; } diff --git a/Marlin/src/module/settings.h b/Marlin/src/module/settings.h index a8fca60baa..b7c5210db5 100644 --- a/Marlin/src/module/settings.h +++ b/Marlin/src/module/settings.h @@ -29,6 +29,13 @@ #if ENABLED(EEPROM_SETTINGS) #include "../HAL/shared/eeprom_api.h" + enum EEPROM_Error : uint8_t { + ERR_EEPROM_NOERR, + ERR_EEPROM_VERSION, + ERR_EEPROM_SIZE, + ERR_EEPROM_CRC, + ERR_EEPROM_CORRUPT + }; #endif class MarlinSettings { @@ -98,7 +105,7 @@ class MarlinSettings { #if ENABLED(EEPROM_SETTINGS) - static bool eeprom_error, validating; + static bool validating; #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system // That can store is enabled @@ -106,8 +113,8 @@ class MarlinSettings { // live at the very end of the eeprom #endif - static bool _load(); - static bool size_error(const uint16_t size); + static EEPROM_Error _load(); + static EEPROM_Error size_error(const uint16_t size); static int eeprom_index; static uint16_t working_crc; @@ -130,16 +137,16 @@ class MarlinSettings { } template - static void EEPROM_READ(T &VAR) { + static void EEPROM_READ_(T &VAR) { persistentStore.read_data(eeprom_index, (uint8_t *) &VAR, sizeof(VAR), &working_crc, !validating); } - static void EEPROM_READ(uint8_t *VAR, size_t sizeof_VAR) { + static void EEPROM_READ_(uint8_t *VAR, size_t sizeof_VAR) { persistentStore.read_data(eeprom_index, VAR, sizeof_VAR, &working_crc, !validating); } template - static void EEPROM_READ_ALWAYS(T &VAR) { + static void EEPROM_READ_ALWAYS_(T &VAR) { persistentStore.read_data(eeprom_index, (uint8_t *) &VAR, sizeof(VAR), &working_crc); }