|
@@ -36,16 +36,16 @@
|
36
|
36
|
*
|
37
|
37
|
*/
|
38
|
38
|
|
39
|
|
-#define EEPROM_VERSION "V37"
|
|
39
|
+#define EEPROM_VERSION "V38"
|
40
|
40
|
|
41
|
41
|
// Change EEPROM version if these are changed:
|
42
|
42
|
#define EEPROM_OFFSET 100
|
43
|
43
|
|
44
|
44
|
/**
|
45
|
|
- * V37 EEPROM Layout:
|
|
45
|
+ * V38 EEPROM Layout:
|
46
|
46
|
*
|
47
|
47
|
* 100 Version (char x4)
|
48
|
|
- * 104 EEPROM Checksum (uint16_t)
|
|
48
|
+ * 104 EEPROM CRC16 (uint16_t)
|
49
|
49
|
*
|
50
|
50
|
* 106 E_STEPPERS (uint8_t)
|
51
|
51
|
* 107 M92 XYZE planner.axis_steps_per_mm (float x4 ... x8)
|
|
@@ -90,7 +90,7 @@
|
90
|
90
|
* AUTO_BED_LEVELING_UBL: 6 bytes
|
91
|
91
|
* 324 G29 A ubl.state.active (bool)
|
92
|
92
|
* 325 G29 Z ubl.state.z_offset (float)
|
93
|
|
- * 329 G29 S ubl.state.eeprom_storage_slot (int8_t)
|
|
93
|
+ * 329 G29 S ubl.state.storage_slot (int8_t)
|
94
|
94
|
*
|
95
|
95
|
* DELTA: 48 bytes
|
96
|
96
|
* 348 M666 XYZ endstop_adj (float x3)
|
|
@@ -158,6 +158,14 @@
|
158
|
158
|
*
|
159
|
159
|
* 588 Minimum end-point
|
160
|
160
|
* 1909 (588 + 36 + 9 + 288 + 988) Maximum end-point
|
|
161
|
+ *
|
|
162
|
+ * ========================================================================
|
|
163
|
+ * meshes_begin (between max and min end-point, directly above)
|
|
164
|
+ * -- MESHES --
|
|
165
|
+ * meshes_end
|
|
166
|
+ * -- MAT (Mesh Allocation Table) -- 128 bytes (placeholder size)
|
|
167
|
+ * mat_end = E2END (0xFFF)
|
|
168
|
+ *
|
161
|
169
|
*/
|
162
|
170
|
#include "configuration_store.h"
|
163
|
171
|
|
|
@@ -230,18 +238,26 @@ void MarlinSettings::postprocess() {
|
230
|
238
|
|
231
|
239
|
#if ENABLED(EEPROM_SETTINGS)
|
232
|
240
|
|
|
241
|
+ #define DUMMY_PID_VALUE 3000.0f
|
|
242
|
+ #define EEPROM_START() int eeprom_index = EEPROM_OFFSET
|
|
243
|
+ #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
|
|
244
|
+ #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
|
|
245
|
+ #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
|
|
246
|
+ #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0)
|
|
247
|
+
|
233
|
248
|
const char version[4] = EEPROM_VERSION;
|
234
|
249
|
|
235
|
|
- uint16_t MarlinSettings::eeprom_checksum;
|
|
250
|
+ bool MarlinSettings::eeprom_error;
|
236
|
251
|
|
237
|
|
- bool MarlinSettings::eeprom_write_error,
|
238
|
|
- MarlinSettings::eeprom_read_error;
|
|
252
|
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
|
|
253
|
+ int MarlinSettings::meshes_begin;
|
|
254
|
+ #endif
|
239
|
255
|
|
240
|
|
- void MarlinSettings::write_data(int &pos, const uint8_t* value, uint16_t size) {
|
241
|
|
- if (eeprom_write_error) return;
|
|
256
|
+ void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
|
|
257
|
+ if (eeprom_error) return;
|
242
|
258
|
while (size--) {
|
243
|
259
|
uint8_t * const p = (uint8_t * const)pos;
|
244
|
|
- const uint8_t v = *value;
|
|
260
|
+ uint8_t v = *value;
|
245
|
261
|
// EEPROM has only ~100,000 write cycles,
|
246
|
262
|
// so only write bytes that have changed!
|
247
|
263
|
if (v != eeprom_read_byte(p)) {
|
|
@@ -249,32 +265,27 @@ void MarlinSettings::postprocess() {
|
249
|
265
|
if (eeprom_read_byte(p) != v) {
|
250
|
266
|
SERIAL_ECHO_START;
|
251
|
267
|
SERIAL_ECHOLNPGM(MSG_ERR_EEPROM_WRITE);
|
252
|
|
- eeprom_write_error = true;
|
|
268
|
+ eeprom_error = true;
|
253
|
269
|
return;
|
254
|
270
|
}
|
255
|
271
|
}
|
256
|
|
- eeprom_checksum += v;
|
|
272
|
+ crc16(crc, &v, 1);
|
257
|
273
|
pos++;
|
258
|
274
|
value++;
|
259
|
275
|
};
|
260
|
276
|
}
|
261
|
|
- void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size) {
|
|
277
|
+
|
|
278
|
+ void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc) {
|
|
279
|
+ if (eeprom_error) return;
|
262
|
280
|
do {
|
263
|
281
|
uint8_t c = eeprom_read_byte((unsigned char*)pos);
|
264
|
|
- if (!eeprom_read_error) *value = c;
|
265
|
|
- eeprom_checksum += c;
|
|
282
|
+ *value = c;
|
|
283
|
+ crc16(crc, &c, 1);
|
266
|
284
|
pos++;
|
267
|
285
|
value++;
|
268
|
286
|
} while (--size);
|
269
|
287
|
}
|
270
|
288
|
|
271
|
|
- #define DUMMY_PID_VALUE 3000.0f
|
272
|
|
- #define EEPROM_START() int eeprom_index = EEPROM_OFFSET
|
273
|
|
- #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
|
274
|
|
- #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR))
|
275
|
|
- #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR))
|
276
|
|
- #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START; SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0)
|
277
|
|
-
|
278
|
289
|
/**
|
279
|
290
|
* M500 - Store Configuration
|
280
|
291
|
*/
|
|
@@ -282,14 +293,16 @@ void MarlinSettings::postprocess() {
|
282
|
293
|
float dummy = 0.0f;
|
283
|
294
|
char ver[4] = "000";
|
284
|
295
|
|
|
296
|
+ uint16_t working_crc = 0;
|
|
297
|
+
|
285
|
298
|
EEPROM_START();
|
286
|
299
|
|
287
|
|
- eeprom_write_error = false;
|
|
300
|
+ eeprom_error = false;
|
288
|
301
|
|
289
|
302
|
EEPROM_WRITE(ver); // invalidate data first
|
290
|
|
- EEPROM_SKIP(eeprom_checksum); // Skip the checksum slot
|
|
303
|
+ EEPROM_SKIP(working_crc); // Skip the checksum slot
|
291
|
304
|
|
292
|
|
- eeprom_checksum = 0; // clear before first "real data"
|
|
305
|
+ working_crc = 0; // clear before first "real data"
|
293
|
306
|
|
294
|
307
|
const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ;
|
295
|
308
|
EEPROM_WRITE(esteppers);
|
|
@@ -410,14 +423,14 @@ void MarlinSettings::postprocess() {
|
410
|
423
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
411
|
424
|
EEPROM_WRITE(ubl.state.active);
|
412
|
425
|
EEPROM_WRITE(ubl.state.z_offset);
|
413
|
|
- EEPROM_WRITE(ubl.state.eeprom_storage_slot);
|
|
426
|
+ EEPROM_WRITE(ubl.state.storage_slot);
|
414
|
427
|
#else
|
415
|
428
|
const bool ubl_active = 0;
|
416
|
429
|
dummy = 0.0f;
|
417
|
|
- const int8_t eeprom_slot = -1;
|
|
430
|
+ const int8_t storage_slot = -1;
|
418
|
431
|
EEPROM_WRITE(ubl_active);
|
419
|
432
|
EEPROM_WRITE(dummy);
|
420
|
|
- EEPROM_WRITE(eeprom_slot);
|
|
433
|
+ EEPROM_WRITE(storage_slot);
|
421
|
434
|
#endif // AUTO_BED_LEVELING_UBL
|
422
|
435
|
|
423
|
436
|
// 9 floats for DELTA / Z_DUAL_ENDSTOPS
|
|
@@ -609,43 +622,42 @@ void MarlinSettings::postprocess() {
|
609
|
622
|
EEPROM_WRITE(dummy);
|
610
|
623
|
#endif
|
611
|
624
|
|
612
|
|
- if (!eeprom_write_error) {
|
613
|
|
-
|
614
|
|
- const uint16_t final_checksum = eeprom_checksum,
|
615
|
|
- eeprom_size = eeprom_index;
|
|
625
|
+ if (!eeprom_error) {
|
|
626
|
+ const int eeprom_size = eeprom_index;
|
616
|
627
|
|
617
|
628
|
// Write the EEPROM header
|
618
|
629
|
eeprom_index = EEPROM_OFFSET;
|
619
|
630
|
EEPROM_WRITE(version);
|
620
|
|
- EEPROM_WRITE(final_checksum);
|
|
631
|
+ EEPROM_WRITE(working_crc);
|
621
|
632
|
|
622
|
633
|
// Report storage size
|
623
|
634
|
SERIAL_ECHO_START;
|
624
|
635
|
SERIAL_ECHOPAIR("Settings Stored (", eeprom_size - (EEPROM_OFFSET));
|
625
|
|
- SERIAL_ECHOLNPGM(" bytes)");
|
|
636
|
+ SERIAL_ECHOPAIR(" bytes; crc ", working_crc);
|
|
637
|
+ SERIAL_ECHOLNPGM(")");
|
626
|
638
|
}
|
627
|
639
|
|
628
|
640
|
#if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
|
629
|
|
- if (ubl.state.eeprom_storage_slot >= 0)
|
630
|
|
- ubl.store_mesh(ubl.state.eeprom_storage_slot);
|
|
641
|
+ if (ubl.state.storage_slot >= 0)
|
|
642
|
+ store_mesh(ubl.state.storage_slot);
|
631
|
643
|
#endif
|
632
|
644
|
|
633
|
|
- return !eeprom_write_error;
|
|
645
|
+ return !eeprom_error;
|
634
|
646
|
}
|
635
|
647
|
|
636
|
648
|
/**
|
637
|
649
|
* M501 - Retrieve Configuration
|
638
|
650
|
*/
|
639
|
651
|
bool MarlinSettings::load() {
|
|
652
|
+ uint16_t working_crc = 0;
|
640
|
653
|
|
641
|
654
|
EEPROM_START();
|
642
|
|
- eeprom_read_error = false; // If set EEPROM_READ won't write into RAM
|
643
|
655
|
|
644
|
656
|
char stored_ver[4];
|
645
|
657
|
EEPROM_READ(stored_ver);
|
646
|
658
|
|
647
|
|
- uint16_t stored_checksum;
|
648
|
|
- EEPROM_READ(stored_checksum);
|
|
659
|
+ uint16_t stored_crc;
|
|
660
|
+ EEPROM_READ(stored_crc);
|
649
|
661
|
|
650
|
662
|
// Version has to match or defaults are used
|
651
|
663
|
if (strncmp(version, stored_ver, 3) != 0) {
|
|
@@ -662,7 +674,7 @@ void MarlinSettings::postprocess() {
|
662
|
674
|
else {
|
663
|
675
|
float dummy = 0;
|
664
|
676
|
|
665
|
|
- eeprom_checksum = 0; // clear before reading first "real data"
|
|
677
|
+ working_crc = 0; //clear before reading first "real data"
|
666
|
678
|
|
667
|
679
|
// Number of esteppers may change
|
668
|
680
|
uint8_t esteppers;
|
|
@@ -788,7 +800,7 @@ void MarlinSettings::postprocess() {
|
788
|
800
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
789
|
801
|
EEPROM_READ(ubl.state.active);
|
790
|
802
|
EEPROM_READ(ubl.state.z_offset);
|
791
|
|
- EEPROM_READ(ubl.state.eeprom_storage_slot);
|
|
803
|
+ EEPROM_READ(ubl.state.storage_slot);
|
792
|
804
|
#else
|
793
|
805
|
bool dummyb;
|
794
|
806
|
uint8_t dummyui8;
|
|
@@ -960,27 +972,28 @@ void MarlinSettings::postprocess() {
|
960
|
972
|
EEPROM_READ(dummy);
|
961
|
973
|
#endif
|
962
|
974
|
|
963
|
|
- if (eeprom_checksum == stored_checksum) {
|
964
|
|
- if (eeprom_read_error)
|
965
|
|
- reset();
|
966
|
|
- else {
|
|
975
|
+ if (working_crc == stored_crc) {
|
967
|
976
|
postprocess();
|
968
|
977
|
SERIAL_ECHO_START;
|
969
|
978
|
SERIAL_ECHO(version);
|
970
|
979
|
SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
|
971
|
|
- SERIAL_ECHOLNPGM(" bytes)");
|
972
|
|
- }
|
|
980
|
+ SERIAL_ECHOPAIR(" bytes; crc ", working_crc);
|
|
981
|
+ SERIAL_ECHOLNPGM(")");
|
973
|
982
|
}
|
974
|
983
|
else {
|
975
|
984
|
SERIAL_ERROR_START;
|
976
|
|
- SERIAL_ERRORLNPGM("EEPROM checksum mismatch");
|
|
985
|
+ SERIAL_ERRORPGM("EEPROM checksum mismatch - (stored CRC)");
|
|
986
|
+ SERIAL_ERROR(stored_crc);
|
|
987
|
+ SERIAL_ERRORPGM(" != ");
|
|
988
|
+ SERIAL_ERROR(working_crc);
|
|
989
|
+ SERIAL_ERRORLNPGM(" (calculated CRC)!");
|
977
|
990
|
reset();
|
978
|
991
|
}
|
979
|
992
|
|
980
|
993
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
981
|
|
- ubl.eeprom_start = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it
|
982
|
|
- // can float up or down a little bit without
|
983
|
|
- // disrupting the Unified Bed Leveling data
|
|
994
|
+ meshes_begin = (eeprom_index + 32) & 0xFFF8; // Pad the end of configuration data so it
|
|
995
|
+ // can float up or down a little bit without
|
|
996
|
+ // disrupting the mesh data
|
984
|
997
|
SERIAL_ECHOPGM(" UBL ");
|
985
|
998
|
if (!ubl.state.active) SERIAL_ECHO("not ");
|
986
|
999
|
SERIAL_ECHOLNPGM("active!");
|
|
@@ -993,9 +1006,9 @@ void MarlinSettings::postprocess() {
|
993
|
1006
|
ubl.reset();
|
994
|
1007
|
}
|
995
|
1008
|
|
996
|
|
- if (ubl.state.eeprom_storage_slot >= 0) {
|
997
|
|
- ubl.load_mesh(ubl.state.eeprom_storage_slot);
|
998
|
|
- SERIAL_ECHOPAIR("Mesh ", ubl.state.eeprom_storage_slot);
|
|
1009
|
+ if (ubl.state.storage_slot >= 0) {
|
|
1010
|
+ load_mesh(ubl.state.storage_slot);
|
|
1011
|
+ SERIAL_ECHOPAIR("Mesh ", ubl.state.storage_slot);
|
999
|
1012
|
SERIAL_ECHOLNPGM(" loaded from storage.");
|
1000
|
1013
|
}
|
1001
|
1014
|
else {
|
|
@@ -1009,9 +1022,85 @@ void MarlinSettings::postprocess() {
|
1009
|
1022
|
report();
|
1010
|
1023
|
#endif
|
1011
|
1024
|
|
1012
|
|
- return !eeprom_read_error;
|
|
1025
|
+ return !eeprom_error;
|
1013
|
1026
|
}
|
1014
|
1027
|
|
|
1028
|
+
|
|
1029
|
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
|
|
1030
|
+
|
|
1031
|
+ int MarlinSettings::calc_num_meshes() {
|
|
1032
|
+ //obviously this will get more sophisticated once we've added an actual MAT
|
|
1033
|
+
|
|
1034
|
+ if (meshes_begin <= 0) return 0;
|
|
1035
|
+
|
|
1036
|
+ return (meshes_end - meshes_begin) / sizeof(ubl.z_values);
|
|
1037
|
+ }
|
|
1038
|
+
|
|
1039
|
+ void MarlinSettings::store_mesh(int8_t slot) {
|
|
1040
|
+
|
|
1041
|
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
|
|
1042
|
+ const int a = calc_num_meshes();
|
|
1043
|
+ if (!WITHIN(slot, 0, a - 1)) {
|
|
1044
|
+ SERIAL_PROTOCOLLNPGM("?Invalid slot.");
|
|
1045
|
+ SERIAL_PROTOCOL(a);
|
|
1046
|
+ SERIAL_PROTOCOLLNPGM(" mesh slots available.");
|
|
1047
|
+ SERIAL_PROTOCOLLNPAIR("E2END : ", E2END);
|
|
1048
|
+ SERIAL_PROTOCOLLNPAIR("meshes_end : ", (int)meshes_end);
|
|
1049
|
+ SERIAL_PROTOCOLLNPAIR("slot : ", slot);
|
|
1050
|
+ SERIAL_EOL;
|
|
1051
|
+ return;
|
|
1052
|
+ }
|
|
1053
|
+
|
|
1054
|
+ uint16_t crc = 0;
|
|
1055
|
+ int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values);
|
|
1056
|
+
|
|
1057
|
+ write_data(pos, (uint8_t *)&ubl.z_values, sizeof(ubl.z_values), &crc);
|
|
1058
|
+
|
|
1059
|
+ // Write crc to MAT along with other data, or just tack on to the beginning or end
|
|
1060
|
+
|
|
1061
|
+ SERIAL_PROTOCOLPAIR("Mesh saved in slot ", slot);
|
|
1062
|
+
|
|
1063
|
+ #else
|
|
1064
|
+
|
|
1065
|
+ // Other mesh types
|
|
1066
|
+
|
|
1067
|
+ #endif
|
|
1068
|
+ }
|
|
1069
|
+
|
|
1070
|
+ void MarlinSettings::load_mesh(int8_t slot, void *into /* = 0 */) {
|
|
1071
|
+
|
|
1072
|
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
|
|
1073
|
+
|
|
1074
|
+ const int16_t a = settings.calc_num_meshes();
|
|
1075
|
+
|
|
1076
|
+ if (!WITHIN(slot, 0, a - 1)) {
|
|
1077
|
+ SERIAL_PROTOCOLLNPGM("?Invalid Slot.");
|
|
1078
|
+ SERIAL_PROTOCOL(a);
|
|
1079
|
+ SERIAL_PROTOCOLLNPGM(" mesh slots available.");
|
|
1080
|
+ return;
|
|
1081
|
+ }
|
|
1082
|
+
|
|
1083
|
+ uint16_t crc = 0;
|
|
1084
|
+ int pos = meshes_end - (slot + 1) * sizeof(ubl.z_values);
|
|
1085
|
+ uint8_t * const dest = into ? (uint8_t*)into : (uint8_t*)&ubl.z_values;
|
|
1086
|
+ read_data(pos, dest, sizeof(ubl.z_values), &crc);
|
|
1087
|
+
|
|
1088
|
+ // Compare crc with crc from MAT, or read from end
|
|
1089
|
+
|
|
1090
|
+ SERIAL_PROTOCOLPAIR("Mesh loaded from slot ", slot);
|
|
1091
|
+
|
|
1092
|
+ #else
|
|
1093
|
+
|
|
1094
|
+ // Other mesh types
|
|
1095
|
+
|
|
1096
|
+ #endif
|
|
1097
|
+ }
|
|
1098
|
+
|
|
1099
|
+ //void MarlinSettings::delete_mesh() { return; }
|
|
1100
|
+ //void MarlinSettings::defrag_meshes() { return; }
|
|
1101
|
+
|
|
1102
|
+ #endif // AUTO_BED_LEVELING_UBL
|
|
1103
|
+
|
1015
|
1104
|
#else // !EEPROM_SETTINGS
|
1016
|
1105
|
|
1017
|
1106
|
bool MarlinSettings::save() {
|
|
@@ -1458,7 +1547,18 @@ void MarlinSettings::reset() {
|
1458
|
1547
|
#endif
|
1459
|
1548
|
SERIAL_EOL;
|
1460
|
1549
|
|
1461
|
|
- if (!forReplay) ubl.g29_what_command();
|
|
1550
|
+ if (!forReplay) {
|
|
1551
|
+ SERIAL_ECHOPGM("\nUBL is ");
|
|
1552
|
+ ubl.state.active ? SERIAL_CHAR('A') : SERIAL_ECHOPGM("Ina");
|
|
1553
|
+ SERIAL_ECHOLNPAIR("ctive\n\nActive Mesh Slot: ", ubl.state.storage_slot);
|
|
1554
|
+
|
|
1555
|
+ SERIAL_ECHOPGM("z_offset: ");
|
|
1556
|
+ SERIAL_ECHO_F(ubl.state.z_offset, 6);
|
|
1557
|
+ SERIAL_EOL;
|
|
1558
|
+
|
|
1559
|
+ SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
|
|
1560
|
+ SERIAL_ECHOLNPGM(" meshes.\n");
|
|
1561
|
+ }
|
1462
|
1562
|
|
1463
|
1563
|
#elif HAS_ABL
|
1464
|
1564
|
|