#include #include #include "config.h" #include "config_pins.h" #include "data.h" // TODO make defines platform specific #define EEPROM_SIZE 4096 #define RAM_SIZE (8192 / 8) struct data_config { uint8_t data_schema_version; uint8_t preset_count; uint32_t checksum; struct data_config_options options; struct data_config_preset *presets; }; static struct data_config d; static const char *last_error = ""; static unsigned int max_presets_eeprom(void) { unsigned int s = EEPROM_SIZE - sizeof(struct data_config) + sizeof(struct data_config_preset *); return s / sizeof(struct data_config_preset); } static unsigned int max_presets_ram(void) { unsigned int s = RAM_SIZE - sizeof(struct data_config) + sizeof(struct data_config_preset *); return s / sizeof(struct data_config_preset); } static unsigned int max_presets(void) { unsigned int eeprom = max_presets_eeprom(); unsigned int ram = max_presets_ram(); return (eeprom < ram) ? eeprom : ram; } static uint32_t data_checksum(struct data_config *data) { uint32_t temp_checksum = data->checksum; data->checksum = 0; struct data_config_preset *temp_presets = data->presets; data->presets = NULL; uint32_t c = 0; uint8_t *t = (uint8_t *)data; for (unsigned int i = 0; i < sizeof(struct data_config); i++) { c ^= t[i]; } for (unsigned int i = 0; i < data->preset_count; i++) { t = (uint8_t *)(temp_presets + i); for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) { c ^= t[j]; } } data->checksum = temp_checksum; data->presets = temp_presets; return c; } const char *data_eeprom_error(void) { return last_error; } bool data_eeprom_read(void) { struct data_config config; uint8_t *data = (uint8_t *)&config; // read meta-data and settings unsigned int s = sizeof(struct data_config); for (unsigned int i = 0; i < s; i++) { data[i] = EEPROM.read(i); } if (config.preset_count > 0) { if (config.preset_count > max_presets()) { last_error = "Preset"; return false; } config.presets = (struct data_config_preset *)malloc(config.preset_count * sizeof(struct data_config_preset)); if (config.presets == NULL) { last_error = "Alloc"; return false; } // read presets for (unsigned int i = 0; i < config.preset_count; i++) { data = (uint8_t *)(&config.presets[i]); for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) { data[j] = EEPROM.read(s + j); s += sizeof(struct data_config_preset); } } } else { config.presets = NULL; } // verify checksum uint32_t read_checksum = config.checksum; uint32_t checksum = data_checksum(&config); if (read_checksum == checksum) { // verify version if (config.data_schema_version == DATA_SCHEMA_VERSION) { if (d.presets != NULL) { free(d.presets); } d = config; last_error = ""; return true; } else { last_error = "Version"; return false; } } else { Serial.print(F("checksum read=")); Serial.print(read_checksum); Serial.print(F(" calc=")); Serial.println(checksum); last_error = "Checksum"; return false; } } void data_eeprom_write(void) { d.checksum = data_checksum(&d); // write meta-data and settings uint8_t *data = (uint8_t *)&d; unsigned int s = sizeof(struct data_config); for (unsigned int i = 0; i < s; i++) { EEPROM.update(i, data[i]); } // write presets for (unsigned int i = 0; i < d.preset_count; i++) { data = (uint8_t *)(&d.presets[i]); for (unsigned int j = 0; j < sizeof(struct data_config_preset); j++) { EEPROM.update(s + j, data[j]); s += sizeof(struct data_config_preset); } } } void data_init(void) { d.presets = NULL; data_clear(); Serial.print(F("EEPROM max presets: ")); Serial.println(max_presets()); Serial.print(F("EEPROM read... ")); if (!data_eeprom_read()) { Serial.print(last_error); Serial.println(F(" Error")); } else { Serial.println(F("Ok")); } } void data_clear(void) { if (d.presets != NULL) { free(d.presets); d.presets = NULL; } d.data_schema_version = DATA_SCHEMA_VERSION; d.preset_count = 0; d.checksum = 0; d.options.speed_x = XY_MAX_SPEED; d.options.speed_y = XY_MAX_SPEED; d.options.speed_z = Z_MAX_SPEED; d.options.speed_e = E_MAX_SPEED; d.options.accel_x = XY_MAX_ACCEL; d.options.accel_y = XY_MAX_ACCEL; d.options.accel_z = Z_MAX_ACCEL; d.options.accel_e = E_MAX_ACCEL; } struct data_config_options *data_options(void) { return &d.options; } unsigned int data_preset_count(void) { return d.preset_count; } struct data_config_preset *data_preset(unsigned int i) { if (i < d.preset_count) { return &d.presets[i]; } return NULL; } bool data_preset_add(struct data_config_preset preset) { if ((d.preset_count == 0) || (d.presets == NULL)) { d.preset_count = 1; d.presets = (struct data_config_preset *)malloc(d.preset_count * sizeof(struct data_config_preset)); if (d.presets == NULL) { d.preset_count = 0; last_error = "Alloc"; return false; } else { d.presets[d.preset_count - 1] = preset; return true; } } else if (d.preset_count < max_presets()) { d.preset_count += 1; struct data_config_preset *new_mem = (struct data_config_preset *)realloc(d.presets, d.preset_count * sizeof(struct data_config_preset)); if (new_mem == NULL) { d.preset_count -= 1; last_error = "Realloc"; return false; } else { d.presets = new_mem; d.presets[d.preset_count - 1] = preset; return true; } } else { return false; } } bool data_preset_remove(unsigned int i) { if (d.preset_count == 1) { d.preset_count = 0; free(d.presets); d.presets = NULL; return true; } else if (d.preset_count > 1) { for (int j = i; j < (d.preset_count - 1); j++) { d.presets[j] = d.presets[j + 1]; } d.preset_count -= 1; struct data_config_preset *new_mem = (struct data_config_preset *)realloc(d.presets, d.preset_count * sizeof(struct data_config_preset)); if (new_mem == NULL) { d.preset_count += 1; last_error = "Realloc"; return false; } else { d.presets = new_mem; return true; } } else { return true; // nothing to delete } }