diff --git a/.travis.yml b/.travis.yml index e29f7f6d7..20a507510 100644 --- a/.travis.yml +++ b/.travis.yml @@ -375,17 +375,17 @@ script: - use_example_configs Hephestos_2 - build_marlin # - # Delta Config (generic) + # Delta Config (generic) + ABL bilinear + PROBE_MANUALLY - restore_configs - use_example_configs delta/generic - - opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER DELTA_CALIBRATION_MENU + - opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER DELTA_CALIBRATION_MENU AUTO_BED_LEVELING_BILINEAR PROBE_MANUALLY - build_marlin # - # Delta Config (generic) + ABL + ALLEN_KEY + # Delta Config (generic) + UBL + ALLEN_KEY + OLED_PANEL_TINYBOY2 + EEPROM_SETTINGS # - use_example_configs delta/generic - opt_disable DISABLE_MIN_ENDSTOPS - - opt_enable AUTO_BED_LEVELING_BILINEAR Z_PROBE_ALLEN_KEY + - opt_enable AUTO_BED_LEVELING_UBL Z_PROBE_ALLEN_KEY EEPROM_SETTINGS EEPROM_CHITCHAT OLED_PANEL_TINYBOY2 - build_marlin # # Delta Config (FLSUN AC because it's complex) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index cb7ec8696..f68ec7b09 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3943,7 +3943,7 @@ void home_all_axes() { gcode_G28(true); } #if ENABLED(MESH_BED_LEVELING) // Save 130 bytes with non-duplication of PSTR - void say_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); } + void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); } void mbl_mesh_report() { SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(GRID_MAX_POINTS_X) "," STRINGIFY(GRID_MAX_POINTS_Y)); @@ -4074,7 +4074,7 @@ void home_all_axes() { gcode_G28(true); } } } else { - SERIAL_CHAR('X'); say_not_entered(); + SERIAL_CHAR('X'); echo_not_entered(); return; } @@ -4086,7 +4086,7 @@ void home_all_axes() { gcode_G28(true); } } } else { - SERIAL_CHAR('Y'); say_not_entered(); + SERIAL_CHAR('Y'); echo_not_entered(); return; } @@ -4094,7 +4094,7 @@ void home_all_axes() { gcode_G28(true); } mbl.z_values[px][py] = code_value_linear_units(); } else { - SERIAL_CHAR('Z'); say_not_entered(); + SERIAL_CHAR('Z'); echo_not_entered(); return; } break; @@ -4104,7 +4104,7 @@ void home_all_axes() { gcode_G28(true); } mbl.z_offset = code_value_linear_units(); } else { - SERIAL_CHAR('Z'); say_not_entered(); + SERIAL_CHAR('Z'); echo_not_entered(); return; } break; @@ -5123,7 +5123,7 @@ void home_all_axes() { gcode_G28(true); } SERIAL_PROTOCOLPGM("Checking... AC"); if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)"); SERIAL_EOL; - LCD_MESSAGEPGM("Checking... AC"); + LCD_MESSAGEPGM("Checking... AC"); // TODO: Make translatable string SERIAL_PROTOCOLPAIR(".Height:", DELTA_HEIGHT + home_offset[Z_AXIS]); if (!do_height_only) { @@ -5343,7 +5343,7 @@ void home_all_axes() { gcode_G28(true); } SERIAL_PROTOCOL_SP(36); SERIAL_PROTOCOLPGM("rolling back."); SERIAL_EOL; - LCD_MESSAGEPGM("Calibration OK"); + LCD_MESSAGEPGM("Calibration OK"); // TODO: Make translatable string } else { // !end iterations char mess[15] = "No convergence"; @@ -5394,7 +5394,7 @@ void home_all_axes() { gcode_G28(true); } } else { SERIAL_PROTOCOLLNPGM("Calibration OK"); - LCD_MESSAGEPGM("Calibration OK"); + LCD_MESSAGEPGM("Calibration OK"); // TODO: Make translatable string SERIAL_PROTOCOLPAIR(".Height:", DELTA_HEIGHT + home_offset[Z_AXIS]); SERIAL_EOL; serialprintPGM(save_message); @@ -8460,15 +8460,22 @@ void quickstop_stepper() { #if ENABLED(AUTO_BED_LEVELING_UBL) // L to load a mesh from the EEPROM if (code_seen('L')) { - const int8_t storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot; - const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values); - if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); + const int8_t storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot; + const int16_t a = settings.calc_num_meshes(); + + if (!a) { + SERIAL_PROTOCOLLNPGM("?EEPROM storage not available."); return; } - ubl.load_mesh(storage_slot); - ubl.state.eeprom_storage_slot = storage_slot; + if (!WITHIN(storage_slot, 0, a - 1)) { + SERIAL_PROTOCOLLNPGM("?Invalid storage slot."); + SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1); + return; + } + + settings.load_mesh(storage_slot); + ubl.state.storage_slot = storage_slot; } #endif // AUTO_BED_LEVELING_UBL @@ -8496,7 +8503,7 @@ void quickstop_stepper() { if (code_seen('L') || code_seen('V')) { ubl.display_map(0); // Currently only supports one map type SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID); - SERIAL_ECHOLNPAIR("eeprom_storage_slot = ", ubl.state.eeprom_storage_slot); + SERIAL_ECHOLNPAIR("ubl.state.storage_slot = ", ubl.state.storage_slot); } #endif diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp index 5f063d8c0..4ea56ff6f 100644 --- a/Marlin/configuration_store.cpp +++ b/Marlin/configuration_store.cpp @@ -36,16 +36,16 @@ * */ -#define EEPROM_VERSION "V37" +#define EEPROM_VERSION "V38" // Change EEPROM version if these are changed: #define EEPROM_OFFSET 100 /** - * V37 EEPROM Layout: + * V38 EEPROM Layout: * * 100 Version (char x4) - * 104 EEPROM Checksum (uint16_t) + * 104 EEPROM CRC16 (uint16_t) * * 106 E_STEPPERS (uint8_t) * 107 M92 XYZE planner.axis_steps_per_mm (float x4 ... x8) @@ -90,7 +90,7 @@ * AUTO_BED_LEVELING_UBL: 6 bytes * 324 G29 A ubl.state.active (bool) * 325 G29 Z ubl.state.z_offset (float) - * 329 G29 S ubl.state.eeprom_storage_slot (int8_t) + * 329 G29 S ubl.state.storage_slot (int8_t) * * DELTA: 48 bytes * 348 M666 XYZ endstop_adj (float x3) @@ -158,6 +158,14 @@ * * 588 Minimum end-point * 1909 (588 + 36 + 9 + 288 + 988) Maximum end-point + * + * ======================================================================== + * meshes_begin (between max and min end-point, directly above) + * -- MESHES -- + * meshes_end + * -- MAT (Mesh Allocation Table) -- 128 bytes (placeholder size) + * mat_end = E2END (0xFFF) + * */ #include "configuration_store.h" @@ -230,18 +238,26 @@ void MarlinSettings::postprocess() { #if ENABLED(EEPROM_SETTINGS) + #define DUMMY_PID_VALUE 3000.0f + #define EEPROM_START() int eeprom_index = EEPROM_OFFSET + #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR) + #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc) + #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc) + #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0) + const char version[4] = EEPROM_VERSION; - uint16_t MarlinSettings::eeprom_checksum; + bool MarlinSettings::eeprom_error; - bool MarlinSettings::eeprom_write_error, - MarlinSettings::eeprom_read_error; + #if ENABLED(AUTO_BED_LEVELING_UBL) + int MarlinSettings::meshes_begin; + #endif - void MarlinSettings::write_data(int &pos, const uint8_t* value, uint16_t size) { - if (eeprom_write_error) return; + void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) { + if (eeprom_error) return; while (size--) { uint8_t * const p = (uint8_t * const)pos; - const uint8_t v = *value; + uint8_t v = *value; // EEPROM has only ~100,000 write cycles, // so only write bytes that have changed! if (v != eeprom_read_byte(p)) { @@ -249,32 +265,27 @@ void MarlinSettings::postprocess() { if (eeprom_read_byte(p) != v) { SERIAL_ECHO_START; SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE); - eeprom_write_error = true; + eeprom_error = true; return; } } - eeprom_checksum += v; + crc16(crc, &v, 1); pos++; value++; }; } - void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size) { + + void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc) { + if (eeprom_error) return; do { uint8_t c = eeprom_read_byte((unsigned char*)pos); - if (!eeprom_read_error) *value = c; - eeprom_checksum += c; + *value = c; + crc16(crc, &c, 1); pos++; value++; } while (--size); } - #define DUMMY_PID_VALUE 3000.0f - #define EEPROM_START() int eeprom_index = EEPROM_OFFSET - #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR) - #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR)) - #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR)) - #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0) - /** * M500 - Store Configuration */ @@ -282,14 +293,16 @@ void MarlinSettings::postprocess() { float dummy = 0.0f; char ver[4] = "000"; + uint16_t working_crc = 0; + EEPROM_START(); - eeprom_write_error = false; + eeprom_error = false; EEPROM_WRITE(ver); // invalidate data first - EEPROM_SKIP(eeprom_checksum); // Skip the checksum slot + EEPROM_SKIP(working_crc); // Skip the checksum slot - eeprom_checksum = 0; // clear before first "real data" + working_crc = 0; // clear before first "real data" const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ; EEPROM_WRITE(esteppers); @@ -410,14 +423,14 @@ void MarlinSettings::postprocess() { #if ENABLED(AUTO_BED_LEVELING_UBL) EEPROM_WRITE(ubl.state.active); EEPROM_WRITE(ubl.state.z_offset); - EEPROM_WRITE(ubl.state.eeprom_storage_slot); + EEPROM_WRITE(ubl.state.storage_slot); #else - const bool ubl_active = 0; + const bool ubl_active = false; dummy = 0.0f; - const int8_t eeprom_slot = -1; + const int8_t storage_slot = -1; EEPROM_WRITE(ubl_active); EEPROM_WRITE(dummy); - EEPROM_WRITE(eeprom_slot); + EEPROM_WRITE(storage_slot); #endif // AUTO_BED_LEVELING_UBL // 9 floats for DELTA / Z_DUAL_ENDSTOPS @@ -609,43 +622,42 @@ void MarlinSettings::postprocess() { EEPROM_WRITE(dummy); #endif - if (!eeprom_write_error) { - - const uint16_t final_checksum = eeprom_checksum, - eeprom_size = eeprom_index; + if (!eeprom_error) { + const int eeprom_size = eeprom_index; // Write the EEPROM header eeprom_index = EEPROM_OFFSET; EEPROM_WRITE(version); - EEPROM_WRITE(final_checksum); + EEPROM_WRITE(working_crc); // Report storage size SERIAL_ECHO_START; SERIAL_ECHOPAIR("Settings Stored (", eeprom_size - (EEPROM_OFFSET)); - SERIAL_ECHOLNPGM(" bytes)"); + SERIAL_ECHOPAIR(" bytes; crc ", working_crc); + SERIAL_ECHOLNPGM(")"); } #if ENABLED(UBL_SAVE_ACTIVE_ON_M500) - if (ubl.state.eeprom_storage_slot >= 0) - ubl.store_mesh(ubl.state.eeprom_storage_slot); + if (ubl.state.storage_slot >= 0) + store_mesh(ubl.state.storage_slot); #endif - return !eeprom_write_error; + return !eeprom_error; } /** * M501 - Retrieve Configuration */ bool MarlinSettings::load() { + uint16_t working_crc = 0; EEPROM_START(); - eeprom_read_error = false; // If set EEPROM_READ won't write into RAM char stored_ver[4]; EEPROM_READ(stored_ver); - uint16_t stored_checksum; - EEPROM_READ(stored_checksum); + uint16_t stored_crc; + EEPROM_READ(stored_crc); // Version has to match or defaults are used if (strncmp(version, stored_ver, 3) != 0) { @@ -662,7 +674,7 @@ void MarlinSettings::postprocess() { else { float dummy = 0; - eeprom_checksum = 0; // clear before reading first "real data" + working_crc = 0; //clear before reading first "real data" // Number of esteppers may change uint8_t esteppers; @@ -788,7 +800,7 @@ void MarlinSettings::postprocess() { #if ENABLED(AUTO_BED_LEVELING_UBL) EEPROM_READ(ubl.state.active); EEPROM_READ(ubl.state.z_offset); - EEPROM_READ(ubl.state.eeprom_storage_slot); + EEPROM_READ(ubl.state.storage_slot); #else bool dummyb; uint8_t dummyui8; @@ -960,42 +972,45 @@ void MarlinSettings::postprocess() { EEPROM_READ(dummy); #endif - if (eeprom_checksum == stored_checksum) { - if (eeprom_read_error) - reset(); - else { + if (working_crc == stored_crc) { postprocess(); SERIAL_ECHO_START; SERIAL_ECHO(version); SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET)); - SERIAL_ECHOLNPGM(" bytes)"); - } + SERIAL_ECHOPAIR(" bytes; crc ", working_crc); + SERIAL_ECHOLNPGM(")"); } else { SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("EEPROM checksum mismatch"); + SERIAL_ERRORPGM("EEPROM checksum mismatch - (stored CRC)"); + SERIAL_ERROR(stored_crc); + SERIAL_ERRORPGM(" != "); + SERIAL_ERROR(working_crc); + SERIAL_ERRORLNPGM(" (calculated CRC)!"); reset(); } #if ENABLED(AUTO_BED_LEVELING_UBL) - ubl.eeprom_start = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it - // can float up or down a little bit without - // disrupting the Unified Bed Leveling data - SERIAL_ECHOPGM(" UBL "); - if (!ubl.state.active) SERIAL_ECHO("not "); - SERIAL_ECHOLNPGM("active!"); + meshes_begin = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it + // can float up or down a little bit without + // disrupting the mesh data + ubl.report_state(); if (!ubl.sanity_check()) { - SERIAL_ECHOLNPGM("\nUnified Bed Leveling system initialized.\n"); + SERIAL_EOL; + ubl.echo_name(); + SERIAL_ECHOLNPGM(" initialized.\n"); } else { - SERIAL_PROTOCOLPGM("?Unable to enable Unified Bed Leveling system.\n"); + SERIAL_PROTOCOLPGM("?Can't enable "); + ubl.echo_name(); + SERIAL_PROTOCOLLNPGM("."); ubl.reset(); } - if (ubl.state.eeprom_storage_slot >= 0) { - ubl.load_mesh(ubl.state.eeprom_storage_slot); - SERIAL_ECHOPAIR("Mesh ", ubl.state.eeprom_storage_slot); + if (ubl.state.storage_slot >= 0) { + load_mesh(ubl.state.storage_slot); + SERIAL_ECHOPAIR("Mesh ", ubl.state.storage_slot); SERIAL_ECHOLNPGM(" loaded from storage."); } else { @@ -1009,9 +1024,87 @@ void MarlinSettings::postprocess() { report(); #endif - return !eeprom_read_error; + return !eeprom_error; } + + #if ENABLED(AUTO_BED_LEVELING_UBL) + + void ubl_invalid_slot(const int s) { + SERIAL_PROTOCOLLNPGM("?Invalid slot."); + SERIAL_PROTOCOL(s); + SERIAL_PROTOCOLLNPGM(" mesh slots available."); + } + + int MarlinSettings::calc_num_meshes() { + //obviously this will get more sophisticated once we've added an actual MAT + + if (meshes_begin <= 0) return 0; + + return (meshes_end - meshes_begin) / sizeof(ubl.z_values); + } + + void MarlinSettings::store_mesh(int8_t slot) { + + #if ENABLED(AUTO_BED_LEVELING_UBL) + const int a = calc_num_meshes(); + if (!WITHIN(slot, 0, a - 1)) { + ubl_invalid_slot(a); + SERIAL_PROTOCOLPAIR("E2END=", E2END); + SERIAL_PROTOCOLPAIR(" meshes_end=", (int)meshes_end); + SERIAL_PROTOCOLLNPAIR(" slot=", slot); + SERIAL_EOL; + return; + } + + uint16_t crc = 0; + int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values); + + write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc); + + // Write crc to MAT along with other data, or just tack on to the beginning or end + + SERIAL_PROTOCOLPAIR("Mesh saved in slot ", slot); + + #else + + // Other mesh types + + #endif + } + + void MarlinSettings::load_mesh(int8_t slot, void *into /* = 0 */) { + + #if ENABLED(AUTO_BED_LEVELING_UBL) + + const int16_t a = settings.calc_num_meshes(); + + if (!WITHIN(slot, 0, a - 1)) { + ubl_invalid_slot(a); + return; + } + + uint16_t crc = 0; + int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values); + uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values; + read_data(pos, dest, sizeof(ubl.z_values), &crc); + + // Compare crc with crc from MAT, or read from end + + SERIAL_PROTOCOLPAIR("Mesh loaded from slot ", slot); + + #else + + // Other mesh types + + #endif + } + + //void MarlinSettings::delete_mesh() { return; } + //void MarlinSettings::defrag_meshes() { return; } + + #endif // AUTO_BED_LEVELING_UBL + #else // !EEPROM_SETTINGS bool MarlinSettings::save() { @@ -1449,7 +1542,8 @@ void MarlinSettings::reset() { if (!forReplay) { CONFIG_ECHO_START; - SERIAL_ECHOLNPGM("Unified Bed Leveling:"); + ubl.echo_name(); + SERIAL_ECHOLNPGM(":"); } CONFIG_ECHO_START; SERIAL_ECHOPAIR(" M420 S", ubl.state.active ? 1 : 0); @@ -1458,7 +1552,19 @@ void MarlinSettings::reset() { #endif SERIAL_EOL; - if (!forReplay) ubl.g29_what_command(); + if (!forReplay) { + SERIAL_EOL; + ubl.report_state(); + + SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.state.storage_slot); + + SERIAL_ECHOPGM("z_offset: "); + SERIAL_ECHO_F(ubl.state.z_offset, 6); + SERIAL_EOL; + + SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes()); + SERIAL_ECHOLNPGM(" meshes.\n"); + } #elif HAS_ABL diff --git a/Marlin/configuration_store.h b/Marlin/configuration_store.h index e31d20b5c..1166ed29e 100644 --- a/Marlin/configuration_store.h +++ b/Marlin/configuration_store.h @@ -34,6 +34,18 @@ class MarlinSettings { #if ENABLED(EEPROM_SETTINGS) static bool load(); + + #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system + // That can store is enabled + FORCE_INLINE static int get_start_of_meshes() { return meshes_begin; } + FORCE_INLINE static int get_end_of_meshes() { return meshes_end; } + static int calc_num_meshes(); + static void store_mesh(int8_t slot); + static void load_mesh(int8_t slot, void *into = 0); + + //static void delete_mesh(); // necessary if we have a MAT + //static void defrag_meshes(); // " + #endif #else FORCE_INLINE static bool load() { reset(); report(); return true; } @@ -50,10 +62,18 @@ class MarlinSettings { static void postprocess(); #if ENABLED(EEPROM_SETTINGS) - static uint16_t eeprom_checksum; - static bool eeprom_read_error, eeprom_write_error; - static void write_data(int &pos, const uint8_t* value, uint16_t size); - static void read_data(int &pos, uint8_t* value, uint16_t size); + static bool eeprom_error; + + #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system + // That can store is enabled + static int meshes_begin; + const static int mat_end = E2END; // Mesh allocation table; this may not end up being necessary + const static int meshes_end = mat_end - 128; // 128 is a placeholder for the size of the MAT + + #endif + + static void write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc); + static void read_data(int &pos, uint8_t *value, uint16_t size, uint16_t *crc); #endif }; diff --git a/Marlin/ubl.cpp b/Marlin/ubl.cpp index bff73b172..8ca43c5be 100644 --- a/Marlin/ubl.cpp +++ b/Marlin/ubl.cpp @@ -41,6 +41,16 @@ uint8_t ubl_cnt = 0; + void unified_bed_leveling::echo_name() { SERIAL_PROTOCOLPGM("Unified Bed Leveling"); } + + void unified_bed_leveling::report_state() { + echo_name(); + SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " "); + if (!state.active) SERIAL_PROTOCOLPGM("in"); + SERIAL_PROTOCOLLNPGM("active."); + safe_delay(50); + } + static void serial_echo_xy(const int16_t x, const int16_t y) { SERIAL_CHAR('('); SERIAL_ECHO(x); @@ -63,9 +73,6 @@ bool unified_bed_leveling::g26_debug_flag = false, unified_bed_leveling::has_control_of_lcd_panel = false; - int16_t unified_bed_leveling::eeprom_start = -1; // Please stop changing this to 8 bits in size - // It needs to hold values bigger than this. - volatile int unified_bed_leveling::encoder_diff; unified_bed_leveling::unified_bed_leveling() { @@ -73,53 +80,10 @@ reset(); } - void unified_bed_leveling::load_mesh(const int16_t slot) { - int16_t j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values); - - if (slot == -1) { - SERIAL_PROTOCOLLNPGM("?No mesh saved in EEPROM. Zeroing mesh in memory.\n"); - reset(); - return; - } - - if (!WITHIN(slot, 0, j - 1) || eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available to load mesh.\n"); - return; - } - - j = UBL_LAST_EEPROM_INDEX - (slot + 1) * sizeof(z_values); - eeprom_read_block((void *)&z_values, (void *)j, sizeof(z_values)); - - SERIAL_PROTOCOLPAIR("Mesh loaded from slot ", slot); - SERIAL_PROTOCOLLNPAIR(" at offset ", hex_address((void*)j)); - } - - void unified_bed_leveling::store_mesh(const int16_t slot) { - int16_t j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values); - - if (!WITHIN(slot, 0, j - 1) || eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available to load mesh.\n"); - SERIAL_PROTOCOL(slot); - SERIAL_PROTOCOLLNPGM(" mesh slots available.\n"); - SERIAL_PROTOCOLLNPAIR("E2END : ", E2END); - SERIAL_PROTOCOLLNPAIR("k : ", (int)UBL_LAST_EEPROM_INDEX); - SERIAL_PROTOCOLLNPAIR("j : ", j); - SERIAL_PROTOCOLLNPAIR("m : ", slot); - SERIAL_EOL; - return; - } - - j = UBL_LAST_EEPROM_INDEX - (slot + 1) * sizeof(z_values); - eeprom_write_block((const void *)&z_values, (void *)j, sizeof(z_values)); - - SERIAL_PROTOCOLPAIR("Mesh saved in slot ", slot); - SERIAL_PROTOCOLLNPAIR(" at offset ", hex_address((void*)j)); - } - void unified_bed_leveling::reset() { state.active = false; state.z_offset = 0; - state.eeprom_storage_slot = -1; + state.storage_slot = -1; ZERO(z_values); @@ -203,9 +167,9 @@ bool unified_bed_leveling::sanity_check() { uint8_t error_flag = 0; - const int j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values); - if (j < 1) { - SERIAL_PROTOCOLLNPGM("?No EEPROM storage available for a mesh of this size.\n"); + const int a = settings.calc_num_meshes(); + if (a < 1) { + SERIAL_PROTOCOLLNPGM("?Insufficient EEPROM storage for a mesh of this size."); error_flag++; } diff --git a/Marlin/ubl.h b/Marlin/ubl.h index 93718d6c5..b1a6b9f7e 100644 --- a/Marlin/ubl.h +++ b/Marlin/ubl.h @@ -30,8 +30,9 @@ #include "planner.h" #include "math.h" #include "vector_3.h" + #include "configuration_store.h" - #define UBL_VERSION "1.00" + #define UBL_VERSION "1.01" #define UBL_OK false #define UBL_ERR true @@ -92,7 +93,7 @@ typedef struct { bool active = false; float z_offset = 0.0; - int8_t eeprom_storage_slot = -1; + int8_t storage_slot = -1; } ubl_state; class unified_bed_leveling { @@ -102,6 +103,8 @@ public: + void echo_name(); + void report_state(); void find_mean_mesh_height(); void shift_mesh_height(); void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool do_furthest); @@ -117,10 +120,6 @@ void display_map(const int); void reset(); void invalidate(); - void store_state(); - void load_state(); - void store_mesh(const int16_t); - void load_mesh(const int16_t); bool sanity_check(); static ubl_state state; @@ -153,9 +152,6 @@ static bool g26_debug_flag, has_control_of_lcd_panel; - static int16_t eeprom_start; // Please do no change this to 8 bits in size - // It needs to hold values bigger than this. - static volatile int encoder_diff; // Volatile because it's changed at interrupt time. unified_bed_leveling(); @@ -351,7 +347,5 @@ extern unified_bed_leveling ubl; - #define UBL_LAST_EEPROM_INDEX E2END - #endif // AUTO_BED_LEVELING_UBL #endif // UNIFIED_BED_LEVELING_H diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp index 065256c8d..6e97d702f 100644 --- a/Marlin/ubl_G29.cpp +++ b/Marlin/ubl_G29.cpp @@ -314,7 +314,7 @@ void __attribute__((optimize("O0"))) gcode_G29() { - if (ubl.eeprom_start < 0) { + if (!settings.calc_num_meshes()) { SERIAL_PROTOCOLLNPGM("?You need to enable your EEPROM and initialize it"); SERIAL_PROTOCOLLNPGM("with M502, M500, M501 in that order.\n"); return; @@ -419,9 +419,9 @@ } if (code_seen('P')) { - if (WITHIN(phase_value, 0, 1) && ubl.state.eeprom_storage_slot == -1) { - ubl.state.eeprom_storage_slot = 0; - SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.\n"); + if (WITHIN(phase_value, 0, 1) && ubl.state.storage_slot == -1) { + ubl.state.storage_slot = 0; + SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected."); } switch (phase_value) { @@ -430,7 +430,7 @@ // Zero Mesh Data // ubl.reset(); - SERIAL_PROTOCOLLNPGM("Mesh zeroed.\n"); + SERIAL_PROTOCOLLNPGM("Mesh zeroed."); break; case 1: @@ -439,7 +439,7 @@ // if (!code_seen('C')) { ubl.invalidate(); - SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh.\n"); + SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh."); } if (g29_verbose_level > 1) { SERIAL_PROTOCOLPAIR("Probing Mesh Points Closest to (", x_pos); @@ -455,7 +455,7 @@ // // Manually Probe Mesh in areas that can't be reached by the probe // - SERIAL_PROTOCOLLNPGM("Manually probing unreachable mesh locations.\n"); + SERIAL_PROTOCOLLNPGM("Manually probing unreachable mesh locations."); do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES); if (!x_flag && !y_flag) { /** @@ -485,7 +485,7 @@ card_thickness = code_has_value() ? code_value_float() : measure_business_card_thickness(height); if (fabs(card_thickness) > 1.5) { - SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement.\n"); + SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement."); return; } } @@ -561,17 +561,25 @@ // if (code_seen('L')) { // Load Current Mesh Data - storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot; + storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot; - const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values); + int16_t a = settings.calc_num_meshes(); - if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); + if (!a) { + SERIAL_PROTOCOLLNPGM("?EEPROM storage not available."); return; } - ubl.load_mesh(storage_slot); - ubl.state.eeprom_storage_slot = storage_slot; - SERIAL_PROTOCOLLNPGM("Done.\n"); + + if (!WITHIN(storage_slot, 0, a - 1)) { + SERIAL_PROTOCOLLNPGM("?Invalid storage slot."); + SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1); + return; + } + + settings.load_mesh(storage_slot); + ubl.state.storage_slot = storage_slot; + + SERIAL_PROTOCOLLNPGM("Done."); } // @@ -579,7 +587,7 @@ // if (code_seen('S')) { // Store (or Save) Current Mesh Data - storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot; + storage_slot = code_has_value() ? code_value_int() : ubl.state.storage_slot; if (storage_slot == -1) { // Special case, we are going to 'Export' the mesh to the SERIAL_ECHOLNPGM("G29 I 999"); // host in a form it can be reconstructed on a different machine @@ -597,17 +605,23 @@ return; } - const int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(ubl.z_values); + int16_t a = settings.calc_num_meshes(); - if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); - SERIAL_PROTOCOLLNPAIR("?Use 0 to ", j - 1); + if (!a) { + SERIAL_PROTOCOLLNPGM("?EEPROM storage not available."); goto LEAVE; } - ubl.store_mesh(storage_slot); - ubl.state.eeprom_storage_slot = storage_slot; - SERIAL_PROTOCOLLNPGM("Done.\n"); + if (!WITHIN(storage_slot, 0, a - 1)) { + SERIAL_PROTOCOLLNPGM("?Invalid storage slot."); + SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1); + goto LEAVE; + } + + settings.store_mesh(storage_slot); + ubl.state.storage_slot = storage_slot; + + SERIAL_PROTOCOLLNPGM("Done."); } if (code_seen('T')) @@ -654,7 +668,7 @@ if (ELAPSED(millis(), nxt)) { SERIAL_PROTOCOLLNPGM("\nZ-Offset Adjustment Stopped."); do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); - LCD_MESSAGEPGM("Z-Offset Stopped"); + LCD_MESSAGEPGM("Z-Offset Stopped"); // TODO: Make translatable string ubl.restore_ubl_active_state_and_leave(); goto LEAVE; } @@ -892,7 +906,7 @@ return current_position[Z_AXIS]; } - static void say_and_take_a_measurement() { + static void echo_and_take_a_measurement() { SERIAL_PROTOCOLLNPGM(" and take a measurement."); } @@ -906,17 +920,17 @@ stepper.synchronize(); SERIAL_PROTOCOLPGM("Place shim under nozzle"); - LCD_MESSAGEPGM("Place shim & measure"); + LCD_MESSAGEPGM("Place shim & measure"); // TODO: Make translatable string lcd_goto_screen(lcd_status_screen); - say_and_take_a_measurement(); + echo_and_take_a_measurement(); const float z1 = use_encoder_wheel_to_measure_point(); do_blocking_move_to_z(current_position[Z_AXIS] + SIZE_OF_LITTLE_RAISE); stepper.synchronize(); SERIAL_PROTOCOLPGM("Remove shim"); - LCD_MESSAGEPGM("Remove & measure bed"); - say_and_take_a_measurement(); + LCD_MESSAGEPGM("Remove & measure bed"); // TODO: Make translatable string + echo_and_take_a_measurement(); const float z2 = use_encoder_wheel_to_measure_point(); @@ -962,7 +976,7 @@ do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES); - LCD_MESSAGEPGM("Moving to next"); + LCD_MESSAGEPGM("Moving to next"); // TODO: Make translatable string do_blocking_move_to_xy(xProbe, yProbe); do_blocking_move_to_z(z_clearance); @@ -972,8 +986,10 @@ if (do_ubl_mesh_map) ubl.display_map(map_type); // show user where we're probing - if (code_seen('B')) {LCD_MESSAGEPGM("Place shim & measure");} - else {LCD_MESSAGEPGM("Measure");} + if (code_seen('B')) + LCD_MESSAGEPGM("Place shim & measure"); // TODO: Make translatable string + else + LCD_MESSAGEPGM("Measure"); // TODO: Make translatable string while (ubl_lcd_clicked()) delay(50); // wait for user to release encoder wheel delay(50); // debounce @@ -1017,21 +1033,10 @@ do_blocking_move_to_xy(lx, ly); } - static void say_ubl_name() { - SERIAL_PROTOCOLPGM("Unified Bed Leveling "); - } - - static void report_ubl_state() { - say_ubl_name(); - SERIAL_PROTOCOLPGM("System "); - if (!ubl.state.active) SERIAL_PROTOCOLPGM("de"); - SERIAL_PROTOCOLLNPGM("activated.\n"); - } - bool g29_parameter_parsing() { bool err_flag = false; - LCD_MESSAGEPGM("Doing G29 UBL!"); + LCD_MESSAGEPGM("Doing G29 UBL!"); // TODO: Make translatable string lcd_quick_feedback(); ubl_constant = 0.0; @@ -1096,12 +1101,12 @@ SERIAL_PROTOCOLLNPGM("?Can't activate and deactivate at the same time.\n"); return UBL_ERR; } - ubl.state.active = 1; - report_ubl_state(); + ubl.state.active = true; + ubl.report_state(); } else if (code_seen('D')) { - ubl.state.active = 0; - report_ubl_state(); + ubl.state.active = false; + ubl.report_state(); } // Set global 'C' flag and its value @@ -1134,7 +1139,7 @@ ubl_state_recursion_chk++; if (ubl_state_recursion_chk != 1) { SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row."); - LCD_MESSAGEPGM("save_UBL_active() error"); + LCD_MESSAGEPGM("save_UBL_active() error"); // TODO: Make translatable string lcd_quick_feedback(); return; } @@ -1145,7 +1150,7 @@ void unified_bed_leveling::restore_ubl_active_state_and_leave() { if (--ubl_state_recursion_chk) { SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times."); - LCD_MESSAGEPGM("restore_UBL_active() error"); + LCD_MESSAGEPGM("restore_UBL_active() error"); // TODO: Make translatable string lcd_quick_feedback(); return; } @@ -1157,21 +1162,12 @@ * good to have the extra information. Soon... we prune this to just a few items */ void unified_bed_leveling::g29_what_command() { - const uint16_t k = E2END - ubl.eeprom_start; + report_state(); - say_ubl_name(); - SERIAL_PROTOCOLPGM("System Version " UBL_VERSION " "); - if (state.active) - SERIAL_PROTOCOLCHAR('A'); - else - SERIAL_PROTOCOLPGM("Ina"); - SERIAL_PROTOCOLLNPGM("ctive.\n"); - safe_delay(50); - - if (state.eeprom_storage_slot == -1) + if (state.storage_slot == -1) SERIAL_PROTOCOLPGM("No Mesh Loaded."); else { - SERIAL_PROTOCOLPAIR("Mesh ", state.eeprom_storage_slot); + SERIAL_PROTOCOLPAIR("Mesh ", state.storage_slot); SERIAL_PROTOCOLPGM(" Loaded."); } SERIAL_EOL; @@ -1188,12 +1184,15 @@ SERIAL_PROTOCOL_F(zprobe_zoffset, 7); SERIAL_EOL; - SERIAL_PROTOCOLLNPAIR("ubl.eeprom_start=", hex_address((void*)eeprom_start)); - + SERIAL_ECHOLNPAIR("UBL_MESH_MIN_X " STRINGIFY(UBL_MESH_MIN_X) "=", UBL_MESH_MIN_X); + SERIAL_ECHOLNPAIR("UBL_MESH_MIN_Y " STRINGIFY(UBL_MESH_MIN_Y) "=", UBL_MESH_MIN_Y); + safe_delay(25); + SERIAL_ECHOLNPAIR("UBL_MESH_MAX_X " STRINGIFY(UBL_MESH_MAX_X) "=", UBL_MESH_MAX_X); + SERIAL_ECHOLNPAIR("UBL_MESH_MAX_Y " STRINGIFY(UBL_MESH_MAX_Y) "=", UBL_MESH_MAX_Y); + safe_delay(25); SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); safe_delay(25); - SERIAL_ECHOLNPAIR("MESH_X_DIST ", MESH_X_DIST); SERIAL_ECHOLNPAIR("MESH_Y_DIST ", MESH_Y_DIST); safe_delay(25); @@ -1214,43 +1213,39 @@ } SERIAL_EOL; - SERIAL_PROTOCOLLNPAIR("Free EEPROM space starts at: ", hex_address((void*)eeprom_start)); - SERIAL_PROTOCOLLNPAIR("end of EEPROM: ", hex_address((void*)E2END)); - safe_delay(25); + #if HAS_KILL + SERIAL_PROTOCOLPAIR("Kill pin on :", KILL_PIN); + SERIAL_PROTOCOLLNPAIR(" state:", READ(KILL_PIN)); + #endif + SERIAL_EOL; + safe_delay(50); - SERIAL_PROTOCOLPAIR("sizeof(ubl.state) : ", (int)sizeof(state)); + SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation); + SERIAL_EOL; + SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk); + SERIAL_EOL; + safe_delay(50); + + SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes())); + SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes())); + safe_delay(50); + + SERIAL_PROTOCOLLNPAIR("sizeof(ubl) : ", (int)sizeof(ubl)); SERIAL_EOL; SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values)); SERIAL_EOL; safe_delay(25); - SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)k)); - safe_delay(25); + SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes()))); + safe_delay(50); - SERIAL_PROTOCOLPAIR("EEPROM can hold ", k / sizeof(z_values)); + SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes()); SERIAL_PROTOCOLLNPGM(" meshes.\n"); safe_delay(25); - SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); - SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); - safe_delay(25); - SERIAL_EOL; - - SERIAL_ECHOPGM("UBL_MESH_MIN_X " STRINGIFY(UBL_MESH_MIN_X)); - SERIAL_ECHOLNPAIR("=", UBL_MESH_MIN_X ); - SERIAL_ECHOPGM("UBL_MESH_MIN_Y " STRINGIFY(UBL_MESH_MIN_Y)); - SERIAL_ECHOLNPAIR("=", UBL_MESH_MIN_Y ); - safe_delay(25); - - SERIAL_ECHOPGM("UBL_MESH_MAX_X " STRINGIFY(UBL_MESH_MAX_X)); - SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_X); - SERIAL_ECHOPGM("UBL_MESH_MAX_Y " STRINGIFY(UBL_MESH_MAX_Y)); - SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_Y); - safe_delay(25); - if (!sanity_check()) { - say_ubl_name(); - SERIAL_PROTOCOLLNPGM("sanity checks passed."); + echo_name(); + SERIAL_PROTOCOLLNPGM(" sanity checks passed."); } } @@ -1284,27 +1279,32 @@ * use cases for the users. So we can wait and see what to do with it. */ void g29_compare_current_mesh_to_stored_mesh() { - float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; + int16_t a = settings.calc_num_meshes(); + + if (!a) { + SERIAL_PROTOCOLLNPGM("?EEPROM storage not available."); + return; + } if (!code_has_value()) { - SERIAL_PROTOCOLLNPGM("?Mesh # required.\n"); + SERIAL_PROTOCOLLNPGM("?Storage slot # required."); + SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1); return; } + storage_slot = code_value_int(); - int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(tmp_z_values); - - if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) { - SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); + if (!WITHIN(storage_slot, 0, a - 1)) { + SERIAL_PROTOCOLLNPGM("?Invalid storage slot."); + SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1); return; } - j = UBL_LAST_EEPROM_INDEX - (storage_slot + 1) * sizeof(tmp_z_values); - eeprom_read_block((void *)&tmp_z_values, (void *)j, sizeof(tmp_z_values)); + float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; + settings.load_mesh(storage_slot, &tmp_z_values); - SERIAL_ECHOPAIR("Subtracting Mesh ", storage_slot); - SERIAL_PROTOCOLLNPAIR(" loaded from EEPROM address ", hex_address((void*)j)); // Soon, we can remove the extra clutter of printing - // the address in the EEPROM where the Mesh is stored. + SERIAL_PROTOCOLPAIR("Subtracting mesh in slot ", storage_slot); + SERIAL_PROTOCOLLNPGM(" from current mesh."); for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++) @@ -1396,7 +1396,7 @@ memset(not_done, 0xFF, sizeof(not_done)); - LCD_MESSAGEPGM("Fine Tuning Mesh"); + LCD_MESSAGEPGM("Fine Tuning Mesh"); // TODO: Make translatable string do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); do_blocking_move_to_xy(lx, ly); @@ -1454,7 +1454,7 @@ lcd_return_to_status(); //SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped."); do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); - LCD_MESSAGEPGM("Mesh Editing Stopped"); + LCD_MESSAGEPGM("Mesh Editing Stopped"); // TODO: Make translatable string while (ubl_lcd_clicked()) idle(); @@ -1481,7 +1481,7 @@ do_blocking_move_to_xy(lx, ly); - LCD_MESSAGEPGM("Done Editing Mesh"); + LCD_MESSAGEPGM("Done Editing Mesh"); // TODO: Make translatable string SERIAL_ECHOLNPGM("Done Editing Mesh"); } diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 0c2117912..6b3784bac 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -1425,10 +1425,6 @@ void kill_screen(const char* lcd_msg) { static uint8_t manual_probe_index; - #if ENABLED(PROBE_MANUALLY) - extern bool g29_in_progress; - #endif - // LCD probed points are from defaults constexpr uint8_t total_probe_points = ( #if ENABLED(AUTO_BED_LEVELING_3POINT) @@ -1645,6 +1641,10 @@ void kill_screen(const char* lcd_msg) { #if ENABLED(LCD_BED_LEVELING) || HAS_ABL + #if ENABLED(PROBE_MANUALLY) + extern bool g29_in_progress; + #endif + /** * Step 2: Continue Bed Leveling... */ diff --git a/Marlin/utility.cpp b/Marlin/utility.cpp index 03b336af4..43544106e 100644 --- a/Marlin/utility.cpp +++ b/Marlin/utility.cpp @@ -34,6 +34,19 @@ void safe_delay(millis_t ms) { thermalManager.manage_heater(); // This keeps us safe if too many small safe_delay() calls are made } +#if ENABLED(EEPROM_SETTINGS) + + void crc16(uint16_t *crc, const void * const data, uint16_t cnt) { + uint8_t *ptr = (uint8_t*)data; + while (cnt-- > 0) { + *crc = (uint16_t)(*crc ^ (uint16_t)(((uint16_t)*ptr++) << 8)); + for (uint8_t x = 0; x < 8; x++) + *crc = (uint16_t)((*crc & 0x8000) ? ((uint16_t)(*crc << 1) ^ 0x1021) : (*crc << 1)); + } + } + +#endif // EEPROM_SETTINGS + #if ENABLED(ULTRA_LCD) char conv[8] = { 0 }; diff --git a/Marlin/utility.h b/Marlin/utility.h index 7306b053c..f14b272fb 100644 --- a/Marlin/utility.h +++ b/Marlin/utility.h @@ -25,6 +25,10 @@ void safe_delay(millis_t ms); +#if ENABLED(EEPROM_SETTINGS) + void crc16(uint16_t *crc, const void * const data, uint16_t cnt); +#endif + #if ENABLED(ULTRA_LCD) // Convert unsigned int to string with 12 format