@ -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 storag e_slot = - 1 ;
EEPROM_WRITE ( ubl_active ) ;
EEPROM_WRITE ( dummy ) ;
EEPROM_WRITE ( eeprom _slot ) ;
EEPROM_WRITE ( storag e_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
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 Unified Bed Leveling data
// 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 ( " \n UBL is " ) ;
ubl . state . active ? SERIAL_CHAR ( ' A ' ) : SERIAL_ECHOPGM ( " Ina " ) ;
SERIAL_ECHOLNPAIR ( " ctive \n \n Active 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