storage and mfs_storage: introduce, move code

storage.cpp/h is common implentation for saving/loading settings to
 some storage
mfs_storage.cpp/h is MFS specific implementation

MFS related code is moved out of flash_main.cpp. Actually we should
get rid of this file when rework is finished.
This commit is contained in:
Andrey Gusakov 2024-12-20 15:09:33 +03:00 committed by rusefillc
parent efafb76043
commit 5b749d6250
7 changed files with 242 additions and 106 deletions

View File

@ -43,6 +43,8 @@ CONTROLLERS_SRC_CPP = \
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
$(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \
$(CONTROLLERS_DIR)/flash_main.cpp \
$(CONTROLLERS_DIR)/storage.cpp \
$(CONTROLLERS_DIR)/mfs_storage.cpp \
$(CONTROLLERS_DIR)/bench_test.cpp \
$(CONTROLLERS_DIR)/can/obd2.cpp \
$(CONTROLLERS_DIR)/can/can_verbose.cpp \

View File

@ -22,40 +22,12 @@
#include "tunerstudio.h"
#endif
#if EFI_STORAGE_MFS == TRUE
#include "hal_mfs.h"
#endif
#include "storage.h"
#include "runtime_state.h"
#ifndef EFI_STORAGE_MFS_EXTERNAL
#define EFI_STORAGE_MFS_EXTERNAL FALSE
#endif
#ifndef EFI_FLASH_WRITE_THREAD
#define EFI_FLASH_WRITE_THREAD FALSE
#endif
// Sanity check
#if (EFI_STORAGE_MFS_EXTERNAL == TRUE) && (EFI_FLASH_WRITE_THREAD == FALSE)
#error EFI_FLASH_WRITE_THREAD should be enabled if MFS is used for external flash
#endif
static bool needToWriteConfiguration = false;
/* if we use ChibiOS MFS for settings */
#if EFI_STORAGE_MFS == TRUE
/* Managed Flash Storage driver */
MFSDriver mfsd;
#define EFI_MFS_SETTINGS_RECORD_ID 1
extern void boardInitMfs(void);
extern const MFSConfig *boardGetMfsConfig(void);
#endif
/**
* https://sourceforge.net/p/rusefi/tickets/335/
*
@ -157,14 +129,11 @@ bool burnWithoutFlash = false;
void writeToFlashNow() {
engine->configBurnTimer.reset();
bool isSuccess = false;
if (burnWithoutFlash) {
needToWriteConfiguration = false;
return;
}
efiPrintf("Writing pending configuration... %d bytes", sizeof(persistentState));
efitick_t startNt = getTimeNowNt();
// Set up the container
persistentState.size = sizeof(persistentState);
@ -175,20 +144,22 @@ void writeToFlashNow() {
// we just set a long timeout of 5 secs to wait until flash is done.
startWatchdog(WATCHDOG_FLASH_TIMEOUT_MS);
// Do actual write
#if EFI_STORAGE_MFS == TRUE
mfs_error_t err;
/* In case of MFS:
* do we need to have two copies?
* do we need to protect it with CRC? */
err = mfsWriteRecord(&mfsd, EFI_MFS_SETTINGS_RECORD_ID,
sizeof(persistentState), (uint8_t *)&persistentState);
if (err >= MFS_NO_ERROR)
isSuccess = true;
if (storageWrite(EFI_SETTINGS_RECORD_ID, (uint8_t *)&persistentState, sizeof(persistentState)) == StorageStatus::Ok) {
// Never used:
//isSuccess = true;
}
#endif
#if EFI_STORAGE_INT_FLASH == TRUE
bool isSuccess = false;
efiPrintf("Writing pending configuration... %d bytes", sizeof(persistentState));
efitick_t startNt = getTimeNowNt();
// Flash two copies
int result1 = eraseAndFlashCopy(getFlashAddrFirstCopy(), persistentState);
int result2 = FLASH_RETURN_SUCCESS;
@ -199,23 +170,19 @@ void writeToFlashNow() {
// handle success/failure
isSuccess = (result1 == FLASH_RETURN_SUCCESS) && (result2 == FLASH_RETURN_SUCCESS);
#endif
// restart the watchdog with the default timeout
startWatchdog();
if (isSuccess) {
efitick_t endNt = getTimeNowNt();
int elapsed_Ms = US2MS(NT2US(endNt - startNt));
#if EFI_STORAGE_MFS == TRUE
efiPrintf("FLASH_SUCCESS after %d mS MFS status %d", elapsed_Ms, err);
#else
efiPrintf("FLASH_SUCCESS after %d mS", elapsed_Ms);
#endif
} else {
efiPrintf("Flashing failed");
}
#endif
// restart the watchdog with the default timeout
startWatchdog();
resetMaxValues();
@ -227,28 +194,20 @@ static void doResetConfiguration() {
resetConfigurationExt(engineConfiguration->engineType);
}
enum class FlashState {
Ok,
CrcFailed,
IncompatibleVersion,
// all is well, but we're on a fresh chip with blank memory
BlankChip,
};
static FlashState validatePersistentState() {
static StorageStatus validatePersistentState() {
auto flashCrc = persistentState.getCrc();
if (flashCrc != persistentState.crc) {
// If the stored crc is all 1s, that probably means the flash is actually blank, not that the crc failed.
if (persistentState.crc == ((decltype(persistentState.crc))-1)) {
return FlashState::BlankChip;
return StorageStatus::NotFound;
} else {
return FlashState::CrcFailed;
return StorageStatus::CrcFailed;
}
} else if (persistentState.version != FLASH_DATA_VERSION || persistentState.size != sizeof(persistentState)) {
return FlashState::IncompatibleVersion;
return StorageStatus::IncompatibleVersion;
} else {
return FlashState::Ok;
return StorageStatus::Ok;
}
}
@ -256,12 +215,12 @@ static FlashState validatePersistentState() {
/**
* Read single copy of rusEFI configuration from interan flash using custom driver
*/
static FlashState readOneConfigurationCopy(flashaddr_t address) {
static StorageStatus readOneConfigurationCopy(flashaddr_t address) {
efiPrintf("readFromFlash %x", address);
// error already reported, return
if (!address) {
return FlashState::BlankChip;
return StorageStatus::NotFound;
}
intFlashRead(address, (char *) &persistentState, sizeof(persistentState));
@ -276,28 +235,23 @@ static FlashState readOneConfigurationCopy(flashaddr_t address) {
*
* in this method we read first copy of configuration in flash. if that first copy has CRC or other issues we read second copy.
*/
static FlashState readConfiguration() {
static StorageStatus readConfiguration() {
#if EFI_STORAGE_MFS == TRUE
size_t settings_size = sizeof(persistentState);
mfs_error_t err = mfsReadRecord(&mfsd, EFI_MFS_SETTINGS_RECORD_ID,
&settings_size, (uint8_t *)&persistentState);
StorageStatus ret = storageRead(EFI_SETTINGS_RECORD_ID, (uint8_t *)&persistentState, sizeof(persistentState));
if (err >= MFS_NO_ERROR) {
// readed size is not exactly the same
if (settings_size != sizeof(persistentState))
return FlashState::IncompatibleVersion;
if (ret == StorageStatus::Ok) {
return validatePersistentState();
} else {
return FlashState::BlankChip;
}
return ret;
#endif
#if EFI_STORAGE_INT_FLASH == TRUE
auto firstCopyAddr = getFlashAddrFirstCopy();
FlashState firstCopy = readOneConfigurationCopy(firstCopyAddr);
StorageStatus firstCopy = readOneConfigurationCopy(firstCopyAddr);
if (firstCopy == FlashState::Ok) {
if (firstCopy == StorageStatus::Ok) {
// First copy looks OK, don't even need to check second copy.
return firstCopy;
}
@ -313,26 +267,27 @@ static FlashState readConfiguration() {
#endif
// In case of neither of those cases, return that things went OK?
return FlashState::Ok;
return StorageStatus::Ok;
}
void readFromFlash() {
FlashState result = readConfiguration();
StorageStatus result = readConfiguration();
switch (result) {
case FlashState::CrcFailed:
case StorageStatus::CrcFailed:
warning(ObdCode::CUSTOM_ERR_FLASH_CRC_FAILED, "flash CRC failed");
efiPrintf("Need to reset flash to default due to CRC mismatch");
[[fallthrough]];
case FlashState::BlankChip:
case StorageStatus::NotFound:
case StorageStatus::Failed:
resetConfigurationExt(DEFAULT_ENGINE_TYPE);
break;
case FlashState::IncompatibleVersion:
case StorageStatus::IncompatibleVersion:
// Preserve engine type from old config
efiPrintf("Resetting due to version mismatch but preserving engine type [%d]", (int)engineConfiguration->engineType);
resetConfigurationExt(engineConfiguration->engineType);
break;
case FlashState::Ok:
case StorageStatus::Ok:
// At this point we know that CRC and version number is what we expect. Safe to assume it's a valid configuration.
applyNonPersistentConfiguration();
efiPrintf("Read valid configuration from flash!");
@ -349,33 +304,9 @@ static void rewriteConfig() {
writeToFlashNow();
}
#if EFI_STORAGE_MFS == TRUE
static void eraseConfig() {
efitick_t startNt = getTimeNowNt();
mfs_error_t err;
err = mfsErase(&mfsd);
efitick_t endNt = getTimeNowNt();
int elapsed_Ms = US2MS(NT2US(endNt - startNt));
efiPrintf("erase done %d mS err %d", elapsed_Ms, err);
}
#endif
void initFlash() {
#if EFI_STORAGE_MFS == TRUE
boardInitMfs();
const MFSConfig *mfsConfig = boardGetMfsConfig();
/* MFS */
mfsObjectInit(&mfsd);
mfs_error_t err = mfsStart(&mfsd, mfsConfig);
if (err < MFS_NO_ERROR) {
/* hm...? */
}
addConsoleAction("eraseconfig", eraseConfig);
#endif
// Init storage(s) if any
initStorage();
addConsoleAction("readconfig", readFromFlash);
/**

View File

@ -24,3 +24,5 @@ void setNeedToWriteConfiguration();
*/
bool getNeedToWriteConfiguration();
void writeToFlashIfPending();
void settingsLtftRequestWriteToFlash();

View File

@ -0,0 +1,98 @@
/**
* @file mfs_storage.cpp
* @brief Storage interface to ChibiOS MFS driver
*
* @date Jan 4, 2025
* @author Andrey Gusakov
*/
#include "pch.h"
#include "storage.h"
/* if we use ChibiOS MFS for settings */
#if EFI_STORAGE_MFS == TRUE
#include "hal_mfs.h"
/* Managed Flash Storage driver */
MFSDriver mfsd;
extern void boardInitMfs(void);
extern const MFSConfig *boardGetMfsConfig(void);
StorageStatus mfsStorageWrite(int id, const uint8_t *ptr, size_t size) {
efiPrintf("Writing storage ID %d ... %d bytes", id, size);
efitick_t startNt = getTimeNowNt();
// TODO: add watchdog disable and enable in case MFS is on internal flash and one bank
mfs_error_t err = mfsWriteRecord(&mfsd, id, size, ptr);
efitick_t endNt = getTimeNowNt();
int elapsed_Ms = US2MS(NT2US(endNt - startNt));
if (err >= MFS_NO_ERROR) {
efiPrintf("Write done with no errors after %d mS MFS status %d", elapsed_Ms, err);
} else {
efiPrintf("Write FAILED after %d with MFS status %d", elapsed_Ms, err);
return StorageStatus::Failed;
}
return StorageStatus::Ok;
}
StorageStatus mfsStorageRead(int id, uint8_t *ptr, size_t size) {
efiPrintf("Reading storage ID %d ... %d bytes", id, size);
size_t readed_size = size;
mfs_error_t err = mfsReadRecord(&mfsd, id, &readed_size, ptr);
if (err >= MFS_NO_ERROR) {
if (readed_size != size) {
efiPrintf("Incorrect size expected %d readed %d", size, readed_size);
return StorageStatus::IncompatibleVersion;
}
efiPrintf("Reding done with no errors and MFS status %d", err);
} else {
efiPrintf("Read FAILED with MFS status %d", err);
// TODO: or corrupted?
return StorageStatus::NotFound;
}
return StorageStatus::Ok;
}
StorageStatus mfsStorageFormat()
{
efitick_t startNt = getTimeNowNt();
mfs_error_t err;
err = mfsErase(&mfsd);
efitick_t endNt = getTimeNowNt();
int elapsed_Ms = US2MS(NT2US(endNt - startNt));
efiPrintf("MFS erase done %d mS err %d", elapsed_Ms, err);
return (err >= MFS_NO_ERROR) ? StorageStatus::Ok : StorageStatus::Failed;
}
static void eraseStorage() {
mfsStorageFormat();
}
void initStorageMfs() {
boardInitMfs();
const MFSConfig *mfsConfig = boardGetMfsConfig();
/* MFS */
mfsObjectInit(&mfsd);
mfs_error_t err = mfsStart(&mfsd, mfsConfig);
if (err < MFS_NO_ERROR) {
/* hm...? */
}
addConsoleAction("erasestorage", eraseStorage);
}
#endif //EFI_STORAGE_MFS

View File

@ -0,0 +1,17 @@
/**
* @file mfs_storage.h
* @brief
*
* @date Jan 3, 2025
* @author Andrey Gusakov
*/
#pragma once
#include "flash_main.h"
StorageStatus mfsStorageWrite(int id, const uint8_t *ptr, size_t size);
StorageStatus mfsStorageRead(int id, uint8_t *ptr, size_t size);
StorageStatus mfsStorageFormat();
void initStorageMfs();

View File

@ -0,0 +1,45 @@
/**
* @file storage.cpp
* @brief adapter for unify access to MFS and legacy 'internal flash' storage drivers
*
* @date Jan 4, 2025
* @author Andrey Gusakov
*/
#include "pch.h"
#include "storage.h"
/* If any setting storage is exist */
#if EFI_CONFIGURATION_STORAGE
#if EFI_STORAGE_MFS == TRUE
#include "mfs_storage.h"
#endif
StorageStatus storageWrite(int id, const uint8_t *ptr, size_t size)
{
#if EFI_STORAGE_MFS == TRUE
return mfsStorageWrite(id, ptr, size);
#endif // EFI_STORAGE_MFS
return StorageStatus::Failed;
}
StorageStatus storageRead(int id, uint8_t *ptr, size_t size)
{
#if EFI_STORAGE_MFS == TRUE
return mfsStorageRead(id, ptr, size);
#endif // EFI_STORAGE_MFS
return StorageStatus::NotFound;
}
void initStorage()
{
#if EFI_STORAGE_MFS == TRUE
initStorageMfs();
#endif // EFI_STORAGE_MFS
}
#endif // EFI_CONFIGURATION_STORAGE

View File

@ -0,0 +1,41 @@
/**
* @file storage.h
* @brief
*
* @date Jan 4, 2025
* @author Andrey Gusakov
*/
#ifndef EFI_STORAGE_MFS_EXTERNAL
#define EFI_STORAGE_MFS_EXTERNAL FALSE
#endif
#ifndef EFI_FLASH_WRITE_THREAD
#define EFI_FLASH_WRITE_THREAD FALSE
#endif
// Sanity check
#if (EFI_STORAGE_MFS_EXTERNAL == TRUE) && (EFI_FLASH_WRITE_THREAD == FALSE)
#error EFI_FLASH_WRITE_THREAD should be enabled if MFS is used for external flash
#endif
// Storage status
enum class StorageStatus {
Ok,
CrcFailed,
IncompatibleVersion,
// all is well, but we're on a fresh chip with blank memory
NotFound,
// Write failed
Failed
};
StorageStatus storageWrite(int id, const uint8_t *ptr, size_t size);
StorageStatus storageRead(int id, uint8_t *ptr, size_t size);
void initStorage();
// IDs used as MFS record ids and internal RusEFI ids
// Convert to enum/class
#define EFI_SETTINGS_RECORD_ID 1
#define EFI_LTFT_RECORD_ID 2