Implement CRC16, develop mesh allocation table

- Add crc16 utility function
 - Implement CRC16 for config store, remove old checksum, increment layout version
 - Move UBL mesh store/load to MarlinSettings; increment UBL_VERSION
 - Begin to lay out MAT structure, prototype functions, etc.
 - Rename ubl.state.eeprom_storage_slot to .storage_slot
 - Misc. optimization
 - Cleanup/standardize/improve some messages

This is a work in progress!
2.0.x
Brian 8 years ago committed by Scott Lahteine
parent 00d358d92d
commit 7852369987

@ -8341,15 +8341,22 @@ void quickstop_stepper() {
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
// L to load a mesh from the EEPROM // L to load a mesh from the EEPROM
if (code_seen('L')) { if (code_seen('L')) {
const int8_t storage_slot = code_has_value() ? code_value_int() : ubl.state.eeprom_storage_slot; const int8_t 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); const 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;
}
if (!WITHIN(storage_slot, 0, a - 1)) {
SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return; return;
} }
ubl.load_mesh(storage_slot); settings.load_mesh(storage_slot);
ubl.state.eeprom_storage_slot = storage_slot; ubl.state.storage_slot = storage_slot;
} }
#endif // AUTO_BED_LEVELING_UBL #endif // AUTO_BED_LEVELING_UBL
@ -8377,7 +8384,7 @@ void quickstop_stepper() {
if (code_seen('L') || code_seen('V')) { if (code_seen('L') || code_seen('V')) {
ubl.display_map(0); // Currently only supports one map type ubl.display_map(0); // Currently only supports one map type
SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID); 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 #endif

@ -36,16 +36,16 @@
* *
*/ */
#define EEPROM_VERSION "V37" #define EEPROM_VERSION "V38"
// Change EEPROM version if these are changed: // Change EEPROM version if these are changed:
#define EEPROM_OFFSET 100 #define EEPROM_OFFSET 100
/** /**
* V37 EEPROM Layout: * V38 EEPROM Layout:
* *
* 100 Version (char x4) * 100 Version (char x4)
* 104 EEPROM Checksum (uint16_t) * 104 EEPROM CRC16 (uint16_t)
* *
* 106 E_STEPPERS (uint8_t) * 106 E_STEPPERS (uint8_t)
* 107 M92 XYZE planner.axis_steps_per_mm (float x4 ... x8) * 107 M92 XYZE planner.axis_steps_per_mm (float x4 ... x8)
@ -90,7 +90,7 @@
* AUTO_BED_LEVELING_UBL: 6 bytes * AUTO_BED_LEVELING_UBL: 6 bytes
* 324 G29 A ubl.state.active (bool) * 324 G29 A ubl.state.active (bool)
* 325 G29 Z ubl.state.z_offset (float) * 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 * DELTA: 48 bytes
* 348 M666 XYZ endstop_adj (float x3) * 348 M666 XYZ endstop_adj (float x3)
@ -158,6 +158,14 @@
* *
* 588 Minimum end-point * 588 Minimum end-point
* 1909 (588 + 36 + 9 + 288 + 988) Maximum 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" #include "configuration_store.h"
@ -230,18 +238,26 @@ void MarlinSettings::postprocess() {
#if ENABLED(EEPROM_SETTINGS) #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; const char version[4] = EEPROM_VERSION;
uint16_t MarlinSettings::eeprom_checksum; bool MarlinSettings::eeprom_error;
bool MarlinSettings::eeprom_write_error, #if ENABLED(AUTO_BED_LEVELING_UBL)
MarlinSettings::eeprom_read_error; int MarlinSettings::meshes_begin;
#endif
void MarlinSettings::write_data(int &pos, const uint8_t* value, uint16_t size) { void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
if (eeprom_write_error) return; if (eeprom_error) return;
while (size--) { while (size--) {
uint8_t * const p = (uint8_t * const)pos; uint8_t * const p = (uint8_t * const)pos;
const uint8_t v = *value; uint8_t v = *value;
// EEPROM has only ~100,000 write cycles, // EEPROM has only ~100,000 write cycles,
// so only write bytes that have changed! // so only write bytes that have changed!
if (v != eeprom_read_byte(p)) { if (v != eeprom_read_byte(p)) {
@ -249,32 +265,27 @@ void MarlinSettings::postprocess() {
if (eeprom_read_byte(p) != v) { if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_START; SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE); SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
eeprom_write_error = true; eeprom_error = true;
return; return;
} }
} }
eeprom_checksum += v; crc16(crc, &v, 1);
pos++; pos++;
value++; 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 { do {
uint8_t c = eeprom_read_byte((unsigned char*)pos); uint8_t c = eeprom_read_byte((unsigned char*)pos);
if (!eeprom_read_error) *value = c; *value = c;
eeprom_checksum += c; crc16(crc, &c, 1);
pos++; pos++;
value++; value++;
} while (--size); } 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 * M500 - Store Configuration
*/ */
@ -282,14 +293,16 @@ void MarlinSettings::postprocess() {
float dummy = 0.0f; float dummy = 0.0f;
char ver[4] = "000"; char ver[4] = "000";
uint16_t working_crc = 0;
EEPROM_START(); EEPROM_START();
eeprom_write_error = false; eeprom_error = false;
EEPROM_WRITE(ver); // invalidate data first 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; const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ;
EEPROM_WRITE(esteppers); EEPROM_WRITE(esteppers);
@ -410,14 +423,14 @@ void MarlinSettings::postprocess() {
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
EEPROM_WRITE(ubl.state.active); EEPROM_WRITE(ubl.state.active);
EEPROM_WRITE(ubl.state.z_offset); EEPROM_WRITE(ubl.state.z_offset);
EEPROM_WRITE(ubl.state.eeprom_storage_slot); EEPROM_WRITE(ubl.state.storage_slot);
#else #else
const bool ubl_active = 0; const bool ubl_active = 0;
dummy = 0.0f; dummy = 0.0f;
const int8_t eeprom_slot = -1; const int8_t storage_slot = -1;
EEPROM_WRITE(ubl_active); EEPROM_WRITE(ubl_active);
EEPROM_WRITE(dummy); EEPROM_WRITE(dummy);
EEPROM_WRITE(eeprom_slot); EEPROM_WRITE(storage_slot);
#endif // AUTO_BED_LEVELING_UBL #endif // AUTO_BED_LEVELING_UBL
// 9 floats for DELTA / Z_DUAL_ENDSTOPS // 9 floats for DELTA / Z_DUAL_ENDSTOPS
@ -609,43 +622,42 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(dummy); EEPROM_WRITE(dummy);
#endif #endif
if (!eeprom_write_error) { if (!eeprom_error) {
const int eeprom_size = eeprom_index;
const uint16_t final_checksum = eeprom_checksum,
eeprom_size = eeprom_index;
// Write the EEPROM header // Write the EEPROM header
eeprom_index = EEPROM_OFFSET; eeprom_index = EEPROM_OFFSET;
EEPROM_WRITE(version); EEPROM_WRITE(version);
EEPROM_WRITE(final_checksum); EEPROM_WRITE(working_crc);
// Report storage size // Report storage size
SERIAL_ECHO_START; SERIAL_ECHO_START;
SERIAL_ECHOPAIR("Settings Stored (", eeprom_size - (EEPROM_OFFSET)); 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 ENABLED(UBL_SAVE_ACTIVE_ON_M500)
if (ubl.state.eeprom_storage_slot >= 0) if (ubl.state.storage_slot >= 0)
ubl.store_mesh(ubl.state.eeprom_storage_slot); store_mesh(ubl.state.storage_slot);
#endif #endif
return !eeprom_write_error; return !eeprom_error;
} }
/** /**
* M501 - Retrieve Configuration * M501 - Retrieve Configuration
*/ */
bool MarlinSettings::load() { bool MarlinSettings::load() {
uint16_t working_crc = 0;
EEPROM_START(); EEPROM_START();
eeprom_read_error = false; // If set EEPROM_READ won't write into RAM
char stored_ver[4]; char stored_ver[4];
EEPROM_READ(stored_ver); EEPROM_READ(stored_ver);
uint16_t stored_checksum; uint16_t stored_crc;
EEPROM_READ(stored_checksum); EEPROM_READ(stored_crc);
// Version has to match or defaults are used // Version has to match or defaults are used
if (strncmp(version, stored_ver, 3) != 0) { if (strncmp(version, stored_ver, 3) != 0) {
@ -662,7 +674,7 @@ void MarlinSettings::postprocess() {
else { else {
float dummy = 0; 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 // Number of esteppers may change
uint8_t esteppers; uint8_t esteppers;
@ -788,7 +800,7 @@ void MarlinSettings::postprocess() {
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
EEPROM_READ(ubl.state.active); EEPROM_READ(ubl.state.active);
EEPROM_READ(ubl.state.z_offset); EEPROM_READ(ubl.state.z_offset);
EEPROM_READ(ubl.state.eeprom_storage_slot); EEPROM_READ(ubl.state.storage_slot);
#else #else
bool dummyb; bool dummyb;
uint8_t dummyui8; uint8_t dummyui8;
@ -960,27 +972,28 @@ void MarlinSettings::postprocess() {
EEPROM_READ(dummy); EEPROM_READ(dummy);
#endif #endif
if (eeprom_checksum == stored_checksum) { if (working_crc == stored_crc) {
if (eeprom_read_error)
reset();
else {
postprocess(); postprocess();
SERIAL_ECHO_START; SERIAL_ECHO_START;
SERIAL_ECHO(version); SERIAL_ECHO(version);
SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET)); SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
SERIAL_ECHOLNPGM(" bytes)"); SERIAL_ECHOPAIR(" bytes; crc ", working_crc);
} SERIAL_ECHOLNPGM(")");
} }
else { else {
SERIAL_ERROR_START; 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(); reset();
} }
#if ENABLED(AUTO_BED_LEVELING_UBL) #if ENABLED(AUTO_BED_LEVELING_UBL)
ubl.eeprom_start = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it meshes_begin = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it
// can float up or down a little bit without // can float up or down a little bit without
// disrupting the Unified Bed Leveling data // disrupting the mesh data
SERIAL_ECHOPGM(" UBL "); SERIAL_ECHOPGM(" UBL ");
if (!ubl.state.active) SERIAL_ECHO("not "); if (!ubl.state.active) SERIAL_ECHO("not ");
SERIAL_ECHOLNPGM("active!"); SERIAL_ECHOLNPGM("active!");
@ -993,9 +1006,9 @@ void MarlinSettings::postprocess() {
ubl.reset(); ubl.reset();
} }
if (ubl.state.eeprom_storage_slot >= 0) { if (ubl.state.storage_slot >= 0) {
ubl.load_mesh(ubl.state.eeprom_storage_slot); load_mesh(ubl.state.storage_slot);
SERIAL_ECHOPAIR("Mesh ", ubl.state.eeprom_storage_slot); SERIAL_ECHOPAIR("Mesh ", ubl.state.storage_slot);
SERIAL_ECHOLNPGM(" loaded from storage."); SERIAL_ECHOLNPGM(" loaded from storage.");
} }
else { else {
@ -1009,9 +1022,85 @@ void MarlinSettings::postprocess() {
report(); report();
#endif #endif
return !eeprom_read_error; return !eeprom_error;
} }
#if ENABLED(AUTO_BED_LEVELING_UBL)
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)) {
SERIAL_PROTOCOLLNPGM("?Invalid slot.");
SERIAL_PROTOCOL(a);
SERIAL_PROTOCOLLNPGM(" mesh slots available.");
SERIAL_PROTOCOLLNPAIR("E2END : ", E2END);
SERIAL_PROTOCOLLNPAIR("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)) {
SERIAL_PROTOCOLLNPGM("?Invalid Slot.");
SERIAL_PROTOCOL(a);
SERIAL_PROTOCOLLNPGM(" mesh slots available.");
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 #else // !EEPROM_SETTINGS
bool MarlinSettings::save() { bool MarlinSettings::save() {
@ -1458,7 +1547,18 @@ void MarlinSettings::reset() {
#endif #endif
SERIAL_EOL; SERIAL_EOL;
if (!forReplay) ubl.g29_what_command(); if (!forReplay) {
SERIAL_ECHOPGM("\nUBL is ");
ubl.state.active ? SERIAL_CHAR('A') : SERIAL_ECHOPGM("Ina");
SERIAL_ECHOLNPAIR("ctive\n\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 #elif HAS_ABL

@ -34,6 +34,18 @@ class MarlinSettings {
#if ENABLED(EEPROM_SETTINGS) #if ENABLED(EEPROM_SETTINGS)
static bool load(); 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 #else
FORCE_INLINE FORCE_INLINE
static bool load() { reset(); report(); return true; } static bool load() { reset(); report(); return true; }
@ -50,10 +62,18 @@ class MarlinSettings {
static void postprocess(); static void postprocess();
#if ENABLED(EEPROM_SETTINGS) #if ENABLED(EEPROM_SETTINGS)
static uint16_t eeprom_checksum; static bool eeprom_error;
static bool eeprom_read_error, eeprom_write_error;
static void write_data(int &pos, const uint8_t* value, uint16_t size); #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
static void read_data(int &pos, uint8_t* value, uint16_t size); // 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 #endif
}; };

@ -63,9 +63,6 @@
bool unified_bed_leveling::g26_debug_flag = false, bool unified_bed_leveling::g26_debug_flag = false,
unified_bed_leveling::has_control_of_lcd_panel = 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; volatile int unified_bed_leveling::encoder_diff;
unified_bed_leveling::unified_bed_leveling() { unified_bed_leveling::unified_bed_leveling() {
@ -73,53 +70,10 @@
reset(); 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() { void unified_bed_leveling::reset() {
state.active = false; state.active = false;
state.z_offset = 0; state.z_offset = 0;
state.eeprom_storage_slot = -1; state.storage_slot = -1;
ZERO(z_values); ZERO(z_values);
@ -203,9 +157,9 @@
bool unified_bed_leveling::sanity_check() { bool unified_bed_leveling::sanity_check() {
uint8_t error_flag = 0; uint8_t error_flag = 0;
const int j = (UBL_LAST_EEPROM_INDEX - eeprom_start) / sizeof(z_values); const int a = settings.calc_num_meshes();
if (j < 1) { if (a < 1) {
SERIAL_PROTOCOLLNPGM("?No EEPROM storage available for a mesh of this size.\n"); SERIAL_PROTOCOLLNPGM("?Insufficient EEPROM storage for a mesh of this size.");
error_flag++; error_flag++;
} }

@ -30,8 +30,9 @@
#include "planner.h" #include "planner.h"
#include "math.h" #include "math.h"
#include "vector_3.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_OK false
#define UBL_ERR true #define UBL_ERR true
@ -92,7 +93,7 @@
typedef struct { typedef struct {
bool active = false; bool active = false;
float z_offset = 0.0; float z_offset = 0.0;
int8_t eeprom_storage_slot = -1; int8_t storage_slot = -1;
} ubl_state; } ubl_state;
class unified_bed_leveling { class unified_bed_leveling {
@ -117,10 +118,6 @@
void display_map(const int); void display_map(const int);
void reset(); void reset();
void invalidate(); void invalidate();
void store_state();
void load_state();
void store_mesh(const int16_t);
void load_mesh(const int16_t);
bool sanity_check(); bool sanity_check();
static ubl_state state; static ubl_state state;
@ -153,9 +150,6 @@
static bool g26_debug_flag, has_control_of_lcd_panel; 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. static volatile int encoder_diff; // Volatile because it's changed at interrupt time.
unified_bed_leveling(); unified_bed_leveling();
@ -351,7 +345,5 @@
extern unified_bed_leveling ubl; extern unified_bed_leveling ubl;
#define UBL_LAST_EEPROM_INDEX E2END
#endif // AUTO_BED_LEVELING_UBL #endif // AUTO_BED_LEVELING_UBL
#endif // UNIFIED_BED_LEVELING_H #endif // UNIFIED_BED_LEVELING_H

@ -314,7 +314,7 @@
void __attribute__((optimize("O0"))) gcode_G29() { 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("?You need to enable your EEPROM and initialize it");
SERIAL_PROTOCOLLNPGM("with M502, M500, M501 in that order.\n"); SERIAL_PROTOCOLLNPGM("with M502, M500, M501 in that order.\n");
return; return;
@ -419,9 +419,9 @@
} }
if (code_seen('P')) { if (code_seen('P')) {
if (WITHIN(phase_value, 0, 1) && ubl.state.eeprom_storage_slot == -1) { if (WITHIN(phase_value, 0, 1) && ubl.state.storage_slot == -1) {
ubl.state.eeprom_storage_slot = 0; ubl.state.storage_slot = 0;
SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.\n"); SERIAL_PROTOCOLLNPGM("Default storage slot 0 selected.");
} }
switch (phase_value) { switch (phase_value) {
@ -430,7 +430,7 @@
// Zero Mesh Data // Zero Mesh Data
// //
ubl.reset(); ubl.reset();
SERIAL_PROTOCOLLNPGM("Mesh zeroed.\n"); SERIAL_PROTOCOLLNPGM("Mesh zeroed.");
break; break;
case 1: case 1:
@ -439,7 +439,7 @@
// //
if (!code_seen('C')) { if (!code_seen('C')) {
ubl.invalidate(); ubl.invalidate();
SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh.\n"); SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh.");
} }
if (g29_verbose_level > 1) { if (g29_verbose_level > 1) {
SERIAL_PROTOCOLPAIR("Probing Mesh Points Closest to (", x_pos); 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 // 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); do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
if (!x_flag && !y_flag) { if (!x_flag && !y_flag) {
/** /**
@ -485,7 +485,7 @@
card_thickness = code_has_value() ? code_value_float() : measure_business_card_thickness(height); card_thickness = code_has_value() ? code_value_float() : measure_business_card_thickness(height);
if (fabs(card_thickness) > 1.5) { if (fabs(card_thickness) > 1.5) {
SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement.\n"); SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement.");
return; return;
} }
} }
@ -561,17 +561,25 @@
// //
if (code_seen('L')) { // Load Current Mesh Data 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) { if (!a) {
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
return; return;
} }
ubl.load_mesh(storage_slot);
ubl.state.eeprom_storage_slot = storage_slot; if (!WITHIN(storage_slot, 0, a - 1)) {
SERIAL_PROTOCOLLNPGM("Done.\n"); 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 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 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 SERIAL_ECHOLNPGM("G29 I 999"); // host in a form it can be reconstructed on a different machine
@ -597,17 +605,23 @@
return; 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) { if (!a) {
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", j - 1);
goto LEAVE; 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')) if (code_seen('T'))
@ -1157,8 +1171,6 @@
* good to have the extra information. Soon... we prune this to just a few items * good to have the extra information. Soon... we prune this to just a few items
*/ */
void unified_bed_leveling::g29_what_command() { void unified_bed_leveling::g29_what_command() {
const uint16_t k = E2END - ubl.eeprom_start;
say_ubl_name(); say_ubl_name();
SERIAL_PROTOCOLPGM("System Version " UBL_VERSION " "); SERIAL_PROTOCOLPGM("System Version " UBL_VERSION " ");
if (state.active) if (state.active)
@ -1168,10 +1180,10 @@
SERIAL_PROTOCOLLNPGM("ctive.\n"); SERIAL_PROTOCOLLNPGM("ctive.\n");
safe_delay(50); safe_delay(50);
if (state.eeprom_storage_slot == -1) if (state.storage_slot == -1)
SERIAL_PROTOCOLPGM("No Mesh Loaded."); SERIAL_PROTOCOLPGM("No Mesh Loaded.");
else { else {
SERIAL_PROTOCOLPAIR("Mesh ", state.eeprom_storage_slot); SERIAL_PROTOCOLPAIR("Mesh ", state.storage_slot);
SERIAL_PROTOCOLPGM(" Loaded."); SERIAL_PROTOCOLPGM(" Loaded.");
} }
SERIAL_EOL; SERIAL_EOL;
@ -1188,12 +1200,15 @@
SERIAL_PROTOCOL_F(zprobe_zoffset, 7); SERIAL_PROTOCOL_F(zprobe_zoffset, 7);
SERIAL_EOL; 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_X ", GRID_MAX_POINTS_X);
SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y);
safe_delay(25); safe_delay(25);
SERIAL_ECHOLNPAIR("MESH_X_DIST ", MESH_X_DIST); SERIAL_ECHOLNPAIR("MESH_X_DIST ", MESH_X_DIST);
SERIAL_ECHOLNPAIR("MESH_Y_DIST ", MESH_Y_DIST); SERIAL_ECHOLNPAIR("MESH_Y_DIST ", MESH_Y_DIST);
safe_delay(25); safe_delay(25);
@ -1214,38 +1229,34 @@
} }
SERIAL_EOL; SERIAL_EOL;
SERIAL_PROTOCOLLNPAIR("Free EEPROM space starts at: ", hex_address((void*)eeprom_start)); #if HAS_KILL
SERIAL_PROTOCOLLNPAIR("end of EEPROM: ", hex_address((void*)E2END)); SERIAL_PROTOCOLPAIR("Kill pin on :", KILL_PIN);
safe_delay(25); 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_EOL;
SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values)); SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk);
SERIAL_EOL; SERIAL_EOL;
safe_delay(25); safe_delay(50);
SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)k));
safe_delay(25);
SERIAL_PROTOCOLPAIR("EEPROM can hold ", k / sizeof(z_values)); SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes()));
SERIAL_PROTOCOLLNPGM(" meshes.\n"); SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes()));
safe_delay(25); safe_delay(50);
SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); SERIAL_PROTOCOLLNPAIR("sizeof(ubl) : ", (int)sizeof(ubl));
SERIAL_PROTOCOLPAIR("\nGRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); SERIAL_EOL;
safe_delay(25); SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values));
SERIAL_EOL; 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); safe_delay(25);
SERIAL_ECHOPGM("UBL_MESH_MAX_X " STRINGIFY(UBL_MESH_MAX_X)); SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes())));
SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_X); safe_delay(50);
SERIAL_ECHOPGM("UBL_MESH_MAX_Y " STRINGIFY(UBL_MESH_MAX_Y));
SERIAL_ECHOLNPAIR("=", UBL_MESH_MAX_Y); SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
SERIAL_PROTOCOLLNPGM(" meshes.\n");
safe_delay(25); safe_delay(25);
if (!sanity_check()) { if (!sanity_check()) {
@ -1284,27 +1295,31 @@
* use cases for the users. So we can wait and see what to do with it. * use cases for the users. So we can wait and see what to do with it.
*/ */
void g29_compare_current_mesh_to_stored_mesh() { 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()) { if (!code_has_value()) {
SERIAL_PROTOCOLLNPGM("?Mesh # required.\n"); SERIAL_PROTOCOLLNPGM("?Storage slot # required.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return; return;
} }
storage_slot = code_value_int();
int16_t j = (UBL_LAST_EEPROM_INDEX - ubl.eeprom_start) / sizeof(tmp_z_values); storage_slot = code_value_int();
if (!WITHIN(storage_slot, 0, j - 1) || ubl.eeprom_start <= 0) { if (!WITHIN(storage_slot, 0, a - 1)) {
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available for use.\n"); SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return; return;
} }
j = UBL_LAST_EEPROM_INDEX - (storage_slot + 1) * sizeof(tmp_z_values); float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
eeprom_read_block((void *)&tmp_z_values, (void *)j, sizeof(tmp_z_values)); settings.load_mesh(storage_slot, &tmp_z_values);
SERIAL_ECHOPAIR("Subtracting Mesh ", storage_slot); SERIAL_ECHOPAIR("Subtracting current mesh from mesh loaded from slot ", 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.
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++) for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)

@ -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 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) #if ENABLED(ULTRA_LCD)
char conv[8] = { 0 }; char conv[8] = { 0 };

@ -25,6 +25,10 @@
void safe_delay(millis_t ms); 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) #if ENABLED(ULTRA_LCD)
// Convert unsigned int to string with 12 format // Convert unsigned int to string with 12 format

Loading…
Cancel
Save