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!
This commit is contained in:
@ -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;
|
||||
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,27 +972,28 @@ 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
|
||||
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
|
||||
SERIAL_ECHOPGM(" UBL ");
|
||||
if (!ubl.state.active) SERIAL_ECHO("not ");
|
||||
SERIAL_ECHOLNPGM("active!");
|
||||
@ -993,9 +1006,9 @@ void MarlinSettings::postprocess() {
|
||||
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 +1022,85 @@ void MarlinSettings::postprocess() {
|
||||
report();
|
||||
#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
|
||||
|
||||
bool MarlinSettings::save() {
|
||||
@ -1458,7 +1547,18 @@ void MarlinSettings::reset() {
|
||||
#endif
|
||||
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
|
||||
|
||||
|
Reference in New Issue
Block a user