rusEFI
The most advanced open source ECU
flash_main.cpp
Go to the documentation of this file.
1 /**
2  * @file flash_main.cpp
3  * @brief Higher-level logic of saving data into internal flash memory
4  *
5  *
6  * @date Sep 19, 2013
7  * @author Andrey Belomutskiy, (c) 2012-2020
8  */
9 
10 #include "pch.h"
11 
12 /* If any setting storage is exist */
13 #if EFI_CONFIGURATION_STORAGE
14 
15 #include "mpu_util.h"
16 #include "flash_main.h"
17 #include "eficonsole.h"
18 
19 #include "flash_int.h"
20 
21 #if EFI_TUNER_STUDIO
22 #include "tunerstudio.h"
23 #endif
24 
25 #if EFI_STORAGE_MFS == TRUE
26 #include "hal_mfs.h"
27 #endif
28 
29 #include "runtime_state.h"
30 
31 #ifndef EFI_STORAGE_MFS_EXTERNAL
32 #define EFI_STORAGE_MFS_EXTERNAL FALSE
33 #endif
34 
35 #ifndef EFI_FLASH_WRITE_THREAD
36 #define EFI_FLASH_WRITE_THREAD FALSE
37 #endif
38 
39 // Sanity check
40 #if (EFI_STORAGE_MFS_EXTERNAL == TRUE) && (EFI_FLASH_WRITE_THREAD == FALSE)
41  #error EFI_FLASH_WRITE_THREAD should be enabled if MFS is used for external flash
42 #endif
43 
44 static bool needToWriteConfiguration = false;
45 
46 /* if we use ChibiOS MFS for settings */
47 #if EFI_STORAGE_MFS == TRUE
48 
49 /* Managed Flash Storage driver */
50 MFSDriver mfsd;
51 
52 #define EFI_MFS_SETTINGS_RECORD_ID 1
53 
54 extern void boardInitMfs(void);
55 extern const MFSConfig *boardGetMfsConfig(void);
56 
57 #endif
58 
59 /**
60  * https://sourceforge.net/p/rusefi/tickets/335/
61  *
62  * In order to preserve at least one copy of the tune in case of electrical issues address of second configuration copy
63  * should be in a different sector of flash since complete flash sectors are erased on write.
64  */
65 
67  return crc32(&state.persistentConfiguration, sizeof(persistent_config_s));
68 }
69 
70 #if (EFI_FLASH_WRITE_THREAD == TRUE)
71 chibios_rt::BinarySemaphore flashWriteSemaphore(/*taken =*/ true);
72 
73 #if EFI_STORAGE_MFS == TRUE
74 /* in case of MFS we need more stack */
75 static THD_WORKING_AREA(flashWriteStack, 3 * UTILITY_THREAD_STACK_SIZE);
76 #else
77 static THD_WORKING_AREA(flashWriteStack, UTILITY_THREAD_STACK_SIZE);
78 #endif
79 
80 static void flashWriteThread(void*) {
81  chRegSetThreadName("flash writer");
82 
83  while (true) {
84  // Wait for a request to come in
85  flashWriteSemaphore.wait();
86 
87  // Do the actual flash write operation
89  }
90 }
91 #endif // EFI_FLASH_WRITE_THREAD
92 
93 // Allow saving setting to flash while engine is runnig.
95  // either MCU supports flashing while executing
96  // either we store settings in external storage
97  return (mcuCanFlashWhileRunning() || (EFI_STORAGE_MFS_EXTERNAL == TRUE));
98 }
99 
101  efiPrintf("Scheduling configuration write");
103 
104 #if (EFI_FLASH_WRITE_THREAD == TRUE)
105  if (allowFlashWhileRunning()) {
106  // Signal the flash writer thread to wake up and write at its leisure
107  flashWriteSemaphore.signal();
108  }
109 #endif // EFI_FLASH_WRITE_THREAD
110 }
111 
114 }
115 
117 #if (EFI_FLASH_WRITE_THREAD == TRUE)
118  // with a flash write thread, the schedule happens directly from
119  // setNeedToWriteConfiguration and writing happens from flash thread,
120  // so there's nothing to do here
121  if (allowFlashWhileRunning()) {
122  return;
123  }
124 #endif
126  // Allow sensor timeouts again now that we're done (and a little time has passed)
128  return;
129  }
130 
131  // Prevent sensor timeouts while flashing
133  writeToFlashNow();
134  // we do not want to allow sensor timeouts right away, we re-enable next time method is invoked
135 }
136 
137 // Erase and write a copy of the configuration at the specified address
138 template <typename TStorage>
139 int eraseAndFlashCopy(flashaddr_t storageAddress, const TStorage& data) {
140  // error already reported, return
141  if (!storageAddress) {
142  return FLASH_RETURN_SUCCESS;
143  }
144 
145  auto err = intFlashErase(storageAddress, sizeof(TStorage));
146  if (FLASH_RETURN_SUCCESS != err) {
147  criticalError("Failed to erase flash at 0x%08x: %d", storageAddress, err);
148  return err;
149  }
150 
151  err = intFlashWrite(storageAddress, reinterpret_cast<const char*>(&data), sizeof(TStorage));
152  if (FLASH_RETURN_SUCCESS != err) {
153  criticalError("Failed to write flash at 0x%08x: %d", storageAddress, err);
154  return err;
155  }
156 
157  return err;
158 }
159 
160 bool burnWithoutFlash = false;
161 
163  engine->configBurnTimer.reset();
164  bool isSuccess = false;
165 
166  if (burnWithoutFlash) {
167  needToWriteConfiguration = false;
168  return;
169  }
170  efiPrintf("Writing pending configuration... %d bytes", sizeof(persistentState));
171  efitick_t startNt = getTimeNowNt();
172 
173  // Set up the container
175  persistentState.version = FLASH_DATA_VERSION;
177 
178  // there's no wdgStop() for STM32, so we cannot disable it.
179  // we just set a long timeout of 5 secs to wait until flash is done.
180  startWatchdog(WATCHDOG_FLASH_TIMEOUT_MS);
181 
182 #if EFI_STORAGE_MFS == TRUE
183  mfs_error_t err;
184  /* In case of MFS:
185  * do we need to have two copies?
186  * do we need to protect it with CRC? */
187 
188  err = mfsWriteRecord(&mfsd, EFI_MFS_SETTINGS_RECORD_ID,
189  sizeof(persistentState), (uint8_t *)&persistentState);
190 
191  if (err >= MFS_NO_ERROR)
192  isSuccess = true;
193 #endif
194 
195 #if EFI_STORAGE_INT_FLASH == TRUE
196  // Flash two copies
198  int result2 = FLASH_RETURN_SUCCESS;
199  /* Only if second copy is supported */
200  if (getFlashAddrSecondCopy()) {
202  }
203 
204  // handle success/failure
205  isSuccess = (result1 == FLASH_RETURN_SUCCESS) && (result2 == FLASH_RETURN_SUCCESS);
206 #endif
207 
208  // restart the watchdog with the default timeout
209  startWatchdog();
210 
211  if (isSuccess) {
212  efitick_t endNt = getTimeNowNt();
213  int elapsed_Ms = US2MS(NT2US(endNt - startNt));
214 
215 #if EFI_STORAGE_MFS == TRUE
216  efiPrintf("FLASH_SUCCESS after %d mS MFS status %d", elapsed_Ms, err);
217 #else
218  efiPrintf("FLASH_SUCCESS after %d mS", elapsed_Ms);
219 #endif
220  } else {
221  efiPrintf("Flashing failed");
222  }
223 
224  resetMaxValues();
225 
226  // Write complete, clear the flag
227  needToWriteConfiguration = false;
228 }
229 
230 static void doResetConfiguration() {
232 }
233 
234 enum class FlashState {
235  Ok,
236  CrcFailed,
238  // all is well, but we're on a fresh chip with blank memory
239  BlankChip,
240 };
241 
243  auto flashCrc = flashStateCrc(persistentState);
244 
245  if (flashCrc != persistentState.crc) {
246  // If the stored crc is all 1s, that probably means the flash is actually blank, not that the crc failed.
247  if (persistentState.crc == ((decltype(persistentState.crc))-1)) {
248  return FlashState::BlankChip;
249  } else {
250  return FlashState::CrcFailed;
251  }
252  } else if (persistentState.version != FLASH_DATA_VERSION || persistentState.size != sizeof(persistentState)) {
254  } else {
255  return FlashState::Ok;
256  }
257 }
258 
259 #if EFI_STORAGE_INT_FLASH == TRUE
260 /**
261  * Read single copy of rusEFI configuration from interan flash using custom driver
262  */
264  efiPrintf("readFromFlash %x", address);
265 
266  // error already reported, return
267  if (!address) {
268  return FlashState::BlankChip;
269  }
270 
271  intFlashRead(address, (char *) &persistentState, sizeof(persistentState));
272 
273  return validatePersistentState();
274 }
275 #endif
276 
277 /**
278  * this method could and should be executed before we have any
279  * connectivity so no console output here
280  *
281  * in this method we read first copy of configuration in flash. if that first copy has CRC or other issues we read second copy.
282  */
284 #if EFI_STORAGE_MFS == TRUE
285  size_t settings_size = sizeof(persistentState);
286  mfs_error_t err = mfsReadRecord(&mfsd, EFI_MFS_SETTINGS_RECORD_ID,
287  &settings_size, (uint8_t *)&persistentState);
288 
289  if (err >= MFS_NO_ERROR) {
290  // readed size is not exactly the same
291  if (settings_size != sizeof(persistentState))
293  return validatePersistentState();
294  } else {
295  return FlashState::BlankChip;
296  }
297 #endif
298 
299 #if EFI_STORAGE_INT_FLASH == TRUE
300  auto firstCopyAddr = getFlashAddrFirstCopy();
301  auto secondyCopyAddr = getFlashAddrSecondCopy();
302 
303  FlashState firstCopy = readOneConfigurationCopy(firstCopyAddr);
304 
305  if (firstCopy == FlashState::Ok) {
306  // First copy looks OK, don't even need to check second copy.
307  return firstCopy;
308  }
309 
310  /* no second copy? */
311  if (getFlashAddrSecondCopy() == 0x0) {
312  return firstCopy;
313  }
314 
315  efiPrintf("Reading second configuration copy");
316  return readOneConfigurationCopy(secondyCopyAddr);
317 #endif
318 
319  // In case of neither of those cases, return that things went OK?
320  return FlashState::Ok;
321 }
322 
324 #if HW_CHECK_MODE
325  /*
326  * getFlashAddr does device validation, we want validation to be invoked even while we are
327  * HW_CHECK_MODE mode where we would not need actual address
328  * todo: rename method to emphasis the fact of validation check?
329  */
332 
333  resetConfigurationExt(DEFAULT_ENGINE_TYPE);
334 
335  FlashState result = FlashState::Ok;
336 #else
337  FlashState result = readConfiguration();
338 #endif
339 
340  switch (result) {
342  warning(ObdCode::CUSTOM_ERR_FLASH_CRC_FAILED, "flash CRC failed");
343  efiPrintf("Need to reset flash to default due to CRC mismatch");
344  [[fallthrough]];
346  resetConfigurationExt(DEFAULT_ENGINE_TYPE);
347  break;
349  // Preserve engine type from old config
350  efiPrintf("Resetting due to version mismatch but preserving engine type [%d]", (int)engineConfiguration->engineType);
352  break;
353  case FlashState::Ok:
354  // At this point we know that CRC and version number is what we expect. Safe to assume it's a valid configuration.
356  efiPrintf("Read valid configuration from flash!");
357  break;
358  }
359 
360  // we can only change the state after the CRC check
363  engine->preCalculate();
364 }
365 
366 static void rewriteConfig() {
368  writeToFlashNow();
369 }
370 
371 #if EFI_STORAGE_MFS == TRUE
372 static void eraseConfig() {
373  efitick_t startNt = getTimeNowNt();
374 
375  mfs_error_t err;
376  err = mfsErase(&mfsd);
377 
378  efitick_t endNt = getTimeNowNt();
379  int elapsed_Ms = US2MS(NT2US(endNt - startNt));
380  efiPrintf("erase done %d mS err %d", elapsed_Ms, err);
381 }
382 #endif
383 
384 void initFlash() {
385 #if EFI_STORAGE_MFS == TRUE
386  boardInitMfs();
387  const MFSConfig *mfsConfig = boardGetMfsConfig();
388 
389  /* MFS */
390  mfsObjectInit(&mfsd);
391  mfs_error_t err = mfsStart(&mfsd, mfsConfig);
392  if (err < MFS_NO_ERROR) {
393  /* hm...? */
394  }
395 
396  addConsoleAction("eraseconfig", eraseConfig);
397 #endif
398 
399  addConsoleAction("readconfig", readFromFlash);
400  /**
401  * This would write NOW (you should not be doing this while connected to real engine)
402  */
403  addConsoleAction(CMD_WRITECONFIG, writeToFlashNow);
404 #if EFI_TUNER_STUDIO
405  /**
406  * This would schedule write to flash once the engine is stopped
407  */
408  addConsoleAction(CMD_BURNCONFIG, requestBurn);
409 #endif
410  addConsoleAction("resetconfig", doResetConfiguration);
411  addConsoleAction("rewriteconfig", rewriteConfig);
412 
413 #if (EFI_FLASH_WRITE_THREAD == TRUE)
414  if (allowFlashWhileRunning()) {
415  chThdCreateStatic(flashWriteStack, sizeof(flashWriteStack), PRIO_FLASH_WRITE, flashWriteThread, nullptr);
416  } else {
417  efiPrintf("EFI_FLASH_WRITE_THREAD is enabled, but not used");
418  }
419 #endif
420 }
421 
422 #endif /* EFI_CONFIGURATION_STORAGE */
bool mcuCanFlashWhileRunning()
Definition: mpu_util.cpp:10
void startWatchdog(int)
void preCalculate()
Definition: engine.cpp:352
Timer configBurnTimer
Definition: engine.h:282
static void inhibitTimeouts(bool inhibit)
Definition: sensor.cpp:232
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
return FLASH_RETURN_SUCCESS
Definition: flash_int.cpp:80
Console package entry point header.
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
void applyNonPersistentConfiguration()
void resetConfigurationExt(configuration_callback_t boardCallback, engine_type_e engineType)
persistent_config_container_s persistentState
Engine * engine
bool warning(ObdCode code, const char *fmt,...)
int getRusEfiVersion()
int intFlashErase(flashaddr_t address, size_t size)
Erase the sectors containing the span of size bytes starting at address.
Definition: flash_int.cpp:115
uintptr_t flashaddr_t
Address in the flash memory.
Definition: flash_int.h:86
int intFlashWrite(flashaddr_t address, const char *buffer, size_t size)
Copy data from a buffer to the flash memory.
Definition: flash_int.cpp:365
uintptr_t getFlashAddrFirstCopy(void)
Definition: mpu_util.cpp:236
int intFlashRead(flashaddr_t source, char *destination, size_t size)
Copy data from the flash memory to a destination.
Definition: flash_int.cpp:130
uintptr_t getFlashAddrSecondCopy(void)
Definition: mpu_util.cpp:240
void initFlash()
Definition: flash_main.cpp:384
static void flashWriteThread(void *)
Definition: flash_main.cpp:80
int eraseAndFlashCopy(flashaddr_t storageAddress, const TStorage &data)
Definition: flash_main.cpp:139
MFSDriver mfsd
Definition: flash_main.cpp:50
static FlashState readOneConfigurationCopy(flashaddr_t address)
Definition: flash_main.cpp:263
void boardInitMfs(void)
void setNeedToWriteConfiguration()
Definition: flash_main.cpp:100
bool allowFlashWhileRunning()
Definition: flash_main.cpp:94
chibios_rt::BinarySemaphore flashWriteSemaphore(true)
static bool needToWriteConfiguration
Definition: flash_main.cpp:44
const MFSConfig * boardGetMfsConfig(void)
static void doResetConfiguration()
Definition: flash_main.cpp:230
void readFromFlash()
Definition: flash_main.cpp:323
static uint32_t flashStateCrc(const persistent_config_container_s &state)
Definition: flash_main.cpp:66
FlashState
Definition: flash_main.cpp:234
@ IncompatibleVersion
void writeToFlashNow()
Definition: flash_main.cpp:162
static THD_WORKING_AREA(flashWriteStack, 3 *UTILITY_THREAD_STACK_SIZE)
static FlashState validatePersistentState()
Definition: flash_main.cpp:242
static void rewriteConfig()
Definition: flash_main.cpp:366
void writeToFlashIfPending()
Definition: flash_main.cpp:116
bool getNeedToWriteConfiguration()
Definition: flash_main.cpp:112
static FlashState readConfiguration()
Definition: flash_main.cpp:283
static void eraseConfig()
Definition: flash_main.cpp:372
bool burnWithoutFlash
Definition: flash_main.cpp:160
@ CUSTOM_ERR_FLASH_CRC_FAILED
engine_configuration_s * engineConfiguration
void resetMaxValues()
static ScState state
void requestBurn()