2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file flash_main.cpp
|
|
|
|
* @brief Higher-level logic of saving data into internal flash memory
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @date Sep 19, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2018-09-16 19:39:46 -07:00
|
|
|
#include "global.h"
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_INTERNAL_FLASH
|
2019-07-05 17:03:32 -07:00
|
|
|
#include "os_access.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "flash_main.h"
|
|
|
|
#include "eficonsole.h"
|
2019-07-04 00:57:21 -07:00
|
|
|
|
2020-04-25 13:32:32 -07:00
|
|
|
#include "flash_int.h"
|
2018-02-03 07:55:15 -08:00
|
|
|
#include "engine_math.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "tunerstudio.h"
|
|
|
|
#endif
|
|
|
|
|
2021-01-31 19:41:17 -08:00
|
|
|
#include "runtime_state.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#include "engine_controller.h"
|
|
|
|
|
|
|
|
static bool needToWriteConfiguration = false;
|
|
|
|
|
|
|
|
EXTERN_ENGINE;
|
|
|
|
|
|
|
|
extern persistent_config_container_s persistentState;
|
|
|
|
|
|
|
|
extern engine_configuration_s *engineConfiguration;
|
|
|
|
|
2017-02-13 22:03:01 -08:00
|
|
|
/**
|
|
|
|
* https://sourceforge.net/p/rusefi/tickets/335/
|
|
|
|
*
|
2019-04-24 21:10:39 -07:00
|
|
|
* In order to preserve at least one copy of the tune in case of electrical issues address of second configuration copy
|
|
|
|
* should be in a different sector of flash since complete flash sectors are erased on write.
|
2017-02-13 22:03:01 -08:00
|
|
|
*/
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
crc_t flashStateCrc(persistent_config_container_s *state) {
|
|
|
|
return calc_crc((const crc_t*) &state->persistentConfiguration, sizeof(persistent_config_s));
|
|
|
|
}
|
|
|
|
|
2021-03-25 15:44:41 -07:00
|
|
|
#if EFI_FLASH_WRITE_THREAD
|
|
|
|
chibios_rt::BinarySemaphore flashWriteSemaphore(/*taken =*/ true);
|
|
|
|
|
|
|
|
static THD_WORKING_AREA(flashWriteStack, UTILITY_THREAD_STACK_SIZE);
|
|
|
|
static void flashWriteThread(void*) {
|
|
|
|
while (true) {
|
|
|
|
// Wait for a request to come in
|
|
|
|
flashWriteSemaphore.wait();
|
|
|
|
|
|
|
|
// Do the actual flash write operation
|
|
|
|
writeToFlashNow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // EFI_FLASH_WRITE_THREAD
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void setNeedToWriteConfiguration(void) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Scheduling configuration write");
|
2015-07-10 06:01:56 -07:00
|
|
|
needToWriteConfiguration = true;
|
2021-03-25 15:44:41 -07:00
|
|
|
|
|
|
|
#if EFI_FLASH_WRITE_THREAD
|
2021-05-28 22:05:29 -07:00
|
|
|
if (allowFlashWhileRunning()) {
|
|
|
|
// Signal the flash writer thread to wake up and write at its leisure
|
|
|
|
flashWriteSemaphore.signal();
|
|
|
|
}
|
2021-03-25 15:44:41 -07:00
|
|
|
#endif // EFI_FLASH_WRITE_THREAD
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool getNeedToWriteConfiguration(void) {
|
|
|
|
return needToWriteConfiguration;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeToFlashIfPending() {
|
2021-05-28 22:05:29 -07:00
|
|
|
// with a flash write thread, the schedule happens directly from
|
|
|
|
// setNeedToWriteConfiguration, so there's nothing to do here
|
|
|
|
if (allowFlashWhileRunning() || !getNeedToWriteConfiguration()) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2021-03-25 15:44:41 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
writeToFlashNow();
|
|
|
|
}
|
|
|
|
|
2020-03-07 07:23:30 -08:00
|
|
|
// Erase and write a copy of the configuration at the specified address
|
|
|
|
template <typename TStorage>
|
2021-05-09 06:19:20 -07:00
|
|
|
int eraseAndFlashCopy(flashaddr_t storageAddress, const TStorage& data) {
|
|
|
|
// error already reported, return
|
|
|
|
if (!storageAddress) {
|
|
|
|
return FLASH_RETURN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-04-12 05:18:11 -07:00
|
|
|
auto err = intFlashErase(storageAddress, sizeof(TStorage));
|
|
|
|
if (FLASH_RETURN_SUCCESS != err) {
|
2021-05-28 10:35:54 -07:00
|
|
|
firmwareError(OBD_PCM_Processor_Fault, "Failed to erase flash at 0x%08x", storageAddress);
|
2021-04-12 05:18:11 -07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-04-25 13:32:32 -07:00
|
|
|
return intFlashWrite(storageAddress, reinterpret_cast<const char*>(&data), sizeof(TStorage));
|
2020-03-07 07:23:30 -08:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void writeToFlashNow(void) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Writing pending configuration...");
|
2020-03-07 07:23:30 -08:00
|
|
|
|
|
|
|
// Set up the container
|
|
|
|
persistentState.size = sizeof(persistentState);
|
2015-07-10 06:01:56 -07:00
|
|
|
persistentState.version = FLASH_DATA_VERSION;
|
2020-03-07 07:23:30 -08:00
|
|
|
persistentState.value = flashStateCrc(&persistentState);
|
|
|
|
|
|
|
|
// Flash two copies
|
|
|
|
int result1 = eraseAndFlashCopy(getFlashAddrFirstCopy(), persistentState);
|
|
|
|
int result2 = eraseAndFlashCopy(getFlashAddrSecondCopy(), persistentState);
|
|
|
|
|
|
|
|
// handle success/failure
|
|
|
|
bool isSuccess = (result1 == FLASH_RETURN_SUCCESS) && (result2 == FLASH_RETURN_SUCCESS);
|
|
|
|
|
2015-07-13 17:02:18 -07:00
|
|
|
if (isSuccess) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("FLASH_SUCCESS");
|
2015-07-13 17:02:18 -07:00
|
|
|
} else {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Flashing failed");
|
2015-07-13 17:02:18 -07:00
|
|
|
}
|
2018-02-03 07:55:15 -08:00
|
|
|
assertEngineReference();
|
2020-02-26 15:16:35 -08:00
|
|
|
|
2017-05-19 18:52:10 -07:00
|
|
|
resetMaxValues();
|
2021-03-25 15:44:41 -07:00
|
|
|
|
|
|
|
// Write complete, clear the flag
|
|
|
|
needToWriteConfiguration = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool isValidCrc(persistent_config_container_s *state) {
|
|
|
|
crc_t result = flashStateCrc(state);
|
|
|
|
int isValidCrc_b = result == state->value;
|
|
|
|
return isValidCrc_b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void doResetConfiguration(void) {
|
2021-04-21 11:28:48 -07:00
|
|
|
resetConfigurationExt(engineConfiguration->engineType PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-03-25 15:16:26 -07:00
|
|
|
typedef enum {
|
|
|
|
PC_OK = 0,
|
|
|
|
CRC_FAILED = 1,
|
|
|
|
INCOMPATIBLE_VERSION = 2,
|
|
|
|
RESET_REQUESTED = 3,
|
|
|
|
PC_ERROR = 4
|
|
|
|
} persisted_configuration_state_e;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-04-21 11:28:48 -07:00
|
|
|
static persisted_configuration_state_e doReadConfiguration(flashaddr_t address) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("readFromFlash %x", address);
|
2021-05-09 06:19:20 -07:00
|
|
|
|
|
|
|
// error already reported, return
|
|
|
|
if (!address) {
|
|
|
|
return CRC_FAILED;
|
|
|
|
}
|
|
|
|
|
2020-04-25 13:32:32 -07:00
|
|
|
intFlashRead(address, (char *) &persistentState, sizeof(persistentState));
|
2017-02-13 22:03:01 -08:00
|
|
|
|
|
|
|
if (!isValidCrc(&persistentState)) {
|
|
|
|
return CRC_FAILED;
|
2020-03-07 07:23:30 -08:00
|
|
|
} else if (persistentState.version != FLASH_DATA_VERSION || persistentState.size != sizeof(persistentState)) {
|
2017-02-13 22:03:01 -08:00
|
|
|
return INCOMPATIBLE_VERSION;
|
|
|
|
} else {
|
|
|
|
return PC_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-03 11:02:00 -07:00
|
|
|
/**
|
|
|
|
* this method could and should be executed before we have any
|
|
|
|
* connectivity so no console output here
|
|
|
|
*/
|
2021-04-21 11:28:48 -07:00
|
|
|
static persisted_configuration_state_e readConfiguration() {
|
2019-12-13 15:02:24 -08:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, getCurrentRemainingStack() > EXPECTED_REMAINING_STACK, "read f", PC_ERROR);
|
2021-05-10 06:02:27 -07:00
|
|
|
/*
|
|
|
|
* getFlashAddr does device validation, we want validation to be invoked even while we are
|
|
|
|
* HW_CHECK_MODE mode where we would not need actual address
|
|
|
|
* todo: rename method to emphasis the fact of validation check?
|
|
|
|
*/
|
2021-05-10 05:53:19 -07:00
|
|
|
auto firstCopyAddr = getFlashAddrFirstCopy();
|
|
|
|
auto secondyCopyAddr = getFlashAddrSecondCopy();
|
|
|
|
|
2021-04-22 19:04:39 -07:00
|
|
|
#if HW_CHECK_MODE
|
|
|
|
persisted_configuration_state_e result = PC_OK;
|
|
|
|
resetConfigurationExt(DEFAULT_ENGINE_TYPE PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
#else // HW_CHECK_MODE
|
2021-05-10 05:53:19 -07:00
|
|
|
persisted_configuration_state_e result = doReadConfiguration(firstCopyAddr);
|
2021-04-22 19:04:39 -07:00
|
|
|
|
2017-02-13 22:03:01 -08:00
|
|
|
if (result != PC_OK) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Reading second configuration copy");
|
2021-05-10 05:53:19 -07:00
|
|
|
result = doReadConfiguration(secondyCopyAddr);
|
2017-02-13 22:03:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result == CRC_FAILED) {
|
2020-05-23 13:24:26 -07:00
|
|
|
// we are here on first boot on brand new chip
|
|
|
|
warning(CUSTOM_ERR_FLASH_CRC_FAILED, "flash CRC failed");
|
2021-04-21 11:28:48 -07:00
|
|
|
resetConfigurationExt(DEFAULT_ENGINE_TYPE PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-02-13 22:03:01 -08:00
|
|
|
} else if (result == INCOMPATIBLE_VERSION) {
|
2021-04-21 11:28:48 -07:00
|
|
|
resetConfigurationExt(engineConfiguration->engineType PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
2015-12-21 20:01:27 -08:00
|
|
|
/**
|
|
|
|
* At this point we know that CRC and version number is what we expect. Safe to assume it's a valid configuration.
|
|
|
|
*/
|
2021-04-21 11:28:48 -07:00
|
|
|
applyNonPersistentConfiguration(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2021-04-22 19:04:39 -07:00
|
|
|
#endif // HW_CHECK_MODE
|
2015-07-10 06:01:56 -07:00
|
|
|
// we can only change the state after the CRC check
|
2016-12-25 08:02:42 -08:00
|
|
|
engineConfiguration->byFirmwareVersion = getRusEfiVersion();
|
2020-04-19 18:42:00 -07:00
|
|
|
memset(persistentState.persistentConfiguration.warning_message , 0, ERROR_BUFFER_SIZE);
|
2017-08-31 04:53:41 -07:00
|
|
|
validateConfiguration(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2016-04-03 11:02:00 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-25 15:16:26 -07:00
|
|
|
void readFromFlash() {
|
2021-04-21 11:28:48 -07:00
|
|
|
persisted_configuration_state_e result = readConfiguration();
|
2015-12-21 20:01:27 -08:00
|
|
|
|
|
|
|
if (result == CRC_FAILED) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Need to reset flash to default due to CRC");
|
2015-12-21 20:01:27 -08:00
|
|
|
} else if (result == INCOMPATIBLE_VERSION) {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Resetting due to version mismatch but preserving engine type [%d]", engineConfiguration->engineType);
|
2015-12-21 20:01:27 -08:00
|
|
|
} else {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("Read valid configuration from flash!");
|
2015-12-21 20:01:27 -08:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rewriteConfig(void) {
|
|
|
|
doResetConfiguration();
|
|
|
|
writeToFlashNow();
|
|
|
|
}
|
|
|
|
|
2019-04-08 08:57:16 -07:00
|
|
|
static void writeConfigCommand() {
|
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
// on start-up rusEfi would read from working copy of TS while
|
|
|
|
// we have a lot of console commands which write into real copy of configuration directly
|
|
|
|
// we have a bit of a mess here
|
|
|
|
syncTunerStudioCopy();
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
|
|
|
writeToFlashNow();
|
|
|
|
}
|
|
|
|
|
2021-04-21 11:28:48 -07:00
|
|
|
void initFlash() {
|
2015-07-10 06:01:56 -07:00
|
|
|
addConsoleAction("readconfig", readFromFlash);
|
|
|
|
/**
|
|
|
|
* This would write NOW (you should not be doing this while connected to real engine)
|
|
|
|
*/
|
2019-07-14 12:21:38 -07:00
|
|
|
addConsoleAction(CMD_WRITECONFIG, writeConfigCommand);
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* This would schedule write to flash once the engine is stopped
|
|
|
|
*/
|
2021-06-20 21:51:25 -07:00
|
|
|
addConsoleAction(CMD_BURNCONFIG, requestBurn);
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif
|
|
|
|
addConsoleAction("resetconfig", doResetConfiguration);
|
|
|
|
addConsoleAction("rewriteconfig", rewriteConfig);
|
2021-03-25 15:44:41 -07:00
|
|
|
|
|
|
|
#if EFI_FLASH_WRITE_THREAD
|
2021-05-28 22:05:29 -07:00
|
|
|
if (allowFlashWhileRunning()) {
|
|
|
|
chThdCreateStatic(flashWriteStack, sizeof(flashWriteStack), PRIO_FLASH_WRITE, flashWriteThread, nullptr);
|
|
|
|
}
|
2021-03-25 15:44:41 -07:00
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* EFI_INTERNAL_FLASH */
|