Merge pull request #6738 from thinkyhead/bf_config_crc_rebase
Implement CRC16, develop mesh allocation table
This commit is contained in:
		@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								Marlin/ubl.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
@@ -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");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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...
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -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 };
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user