// Initialize all PG records from EEPROM. // This functions processes all PGs sequentially, scanning EEPROM for each one. This is suboptimal, // but each PG is loaded/initialized exactly once and in defined order. bool loadEEPROM(void) { // read in the transitional masterConfig record const uint8_t *p = &__config_start; p += sizeof(configHeader_t); // skip header masterConfig = *(master_t*)p; PG_FOREACH(reg) { configRecordFlags_e cls_start, cls_end; if (pgIsSystem(reg)) { cls_start = CR_CLASSICATION_SYSTEM; cls_end = CR_CLASSICATION_SYSTEM; } else { cls_start = CR_CLASSICATION_PROFILE1; cls_end = CR_CLASSICATION_PROFILE_LAST; } for (configRecordFlags_e cls = cls_start; cls <= cls_end; cls++) { int profileIndex = cls - cls_start; const configRecord_t *rec = findEEPROM(reg, cls); if (rec) { // config from EEPROM is available, use it to initialize PG. pgLoad will handle version mismatch pgLoad(reg, profileIndex, rec->pg, rec->size - offsetof(configRecord_t, pg), rec->version); } else { pgReset(reg, profileIndex); } } } return true; }
// Load a PG into RAM, upgrading and downgrading as needed. static bool loadPG(const configRecord_t *record) { const pgRegistry_t *reg = pgMatcher(pgMatcherForConfigRecord, record); if (reg == NULL) { return false; } uint8_t profileIndex = 0; if (!pgIsSystem(reg)) { profileIndex = (record->flags & CR_CLASSIFICATION_MASK) - 1; } pgLoad(reg, record->pg, record->size, profileIndex); return true; }
static bool writeSettingsToEEPROM(void) { config_streamer_t streamer; config_streamer_init(&streamer); config_streamer_start(&streamer, (uintptr_t)&__config_start, &__config_end - &__config_start); uint8_t chk = 0; configHeader_t header = { .eepromConfigVersion = EEPROM_CONF_VERSION, .boardIdentifier = TARGET_BOARD_IDENTIFIER, }; config_streamer_write(&streamer, (uint8_t *)&header, sizeof(header)); chk = updateChecksum(chk, (uint8_t *)&header, sizeof(header)); // write the transitional masterConfig record config_streamer_write(&streamer, (uint8_t *)&masterConfig, sizeof(masterConfig)); chk = updateChecksum(chk, (uint8_t *)&masterConfig, sizeof(masterConfig)); PG_FOREACH(reg) { const uint16_t regSize = pgSize(reg); configRecord_t record = { .size = sizeof(configRecord_t) + regSize, .pgn = pgN(reg), .version = pgVersion(reg), .flags = 0 }; if (pgIsSystem(reg)) { // write the only instance record.flags |= CR_CLASSICATION_SYSTEM; config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record)); chk = updateChecksum(chk, (uint8_t *)&record, sizeof(record)); config_streamer_write(&streamer, reg->address, regSize); chk = updateChecksum(chk, reg->address, regSize); } else { // write one instance for each profile for (uint8_t profileIndex = 0; profileIndex < MAX_PROFILE_COUNT; profileIndex++) { record.flags = 0; record.flags |= ((profileIndex + 1) & CR_CLASSIFICATION_MASK); config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record)); chk = updateChecksum(chk, (uint8_t *)&record, sizeof(record)); const uint8_t *address = reg->address + (regSize * profileIndex); config_streamer_write(&streamer, address, regSize); chk = updateChecksum(chk, address, regSize); } } } configFooter_t footer = { .terminator = 0, }; config_streamer_write(&streamer, (uint8_t *)&footer, sizeof(footer)); chk = updateChecksum(chk, (uint8_t *)&footer, sizeof(footer)); // append checksum now chk = ~chk; config_streamer_write(&streamer, &chk, sizeof(chk)); config_streamer_flush(&streamer); bool success = config_streamer_finish(&streamer) == 0; return success; } void writeConfigToEEPROM(void) { bool success = false; // write it for (int attempt = 0; attempt < 3 && !success; attempt++) { if (writeSettingsToEEPROM()) { success = true; } } if (success && isEEPROMContentValid()) { return; } // Flash write failed - just die now failureMode(FAILURE_FLASH_WRITE_FAILED); }