2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file error_handling.cpp
|
|
|
|
*
|
|
|
|
* @date Apr 1, 2014
|
2020-01-07 21:02:40 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2019-07-05 17:03:32 -07:00
|
|
|
#include "engine.h"
|
2020-03-23 06:00:57 -07:00
|
|
|
#include "os_access.h"
|
2020-07-10 20:27:27 -07:00
|
|
|
#include "perf_trace.h"
|
2017-01-02 12:03:26 -08:00
|
|
|
|
2020-05-03 07:58:52 -07:00
|
|
|
static char warningBuffer[ERROR_BUFFER_SIZE];
|
|
|
|
static critical_msg_t criticalErrorMessageBuffer;
|
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
#if EFI_SIMULATOR || EFI_PROD_CODE
|
2016-07-23 10:03:57 -07:00
|
|
|
//todo: move into simulator global
|
2017-01-02 12:03:26 -08:00
|
|
|
#include "memstreams.h"
|
2020-05-03 07:58:52 -07:00
|
|
|
class ErrorState {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Class constructors are a great way to have simple initialization sequence
|
|
|
|
*/
|
|
|
|
ErrorState();
|
|
|
|
MemoryStream warningStream;
|
|
|
|
MemoryStream firmwareErrorMessageStream;
|
|
|
|
};
|
|
|
|
|
|
|
|
ErrorState::ErrorState() {
|
|
|
|
/**
|
|
|
|
* these methods only change RAM state of data structures without any HAL access thus safe in contructor
|
|
|
|
*/
|
|
|
|
msObjectInit(&warningStream, (uint8_t *) warningBuffer, ERROR_BUFFER_SIZE, 0);
|
|
|
|
msObjectInit(&firmwareErrorMessageStream, criticalErrorMessageBuffer, sizeof(criticalErrorMessageBuffer), 0);
|
|
|
|
}
|
2017-01-02 12:03:26 -08:00
|
|
|
|
2020-05-03 07:58:52 -07:00
|
|
|
static ErrorState errorState;
|
|
|
|
|
|
|
|
#endif /* EFI_SIMULATOR || EFI_PROD_CODE */
|
2017-01-02 12:03:26 -08:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_HD44780_LCD
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "lcd_HD44780.h"
|
|
|
|
#endif /* EFI_HD44780_LCD */
|
|
|
|
|
|
|
|
static LoggingWithStorage logger("error handling");
|
|
|
|
|
2016-07-13 16:03:06 -07:00
|
|
|
EXTERN_ENGINE;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
#define WARNING_PREFIX "WARNING: "
|
|
|
|
|
|
|
|
extern int warningEnabled;
|
2016-01-11 14:01:33 -08:00
|
|
|
extern bool main_loop_started;
|
2017-01-02 12:03:26 -08:00
|
|
|
|
|
|
|
bool hasFirmwareErrorFlag = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
const char *dbg_panic_file;
|
|
|
|
int dbg_panic_line;
|
|
|
|
|
2020-03-28 17:14:17 -07:00
|
|
|
#if EFI_TUNER_STUDIO && !defined(EFI_NO_CONFIG_WORKING_COPY)
|
|
|
|
extern persistent_config_s configWorkingCopy;
|
|
|
|
#endif
|
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
char *getFirmwareError(void) {
|
2020-03-28 17:14:17 -07:00
|
|
|
return (char*) criticalErrorMessageBuffer;
|
2017-01-02 12:03:26 -08:00
|
|
|
}
|
|
|
|
|
2019-09-09 18:44:48 -07:00
|
|
|
#if EFI_PROD_CODE
|
|
|
|
|
2020-05-11 15:22:51 -07:00
|
|
|
extern ioportid_t criticalErrorLedPort;
|
|
|
|
extern ioportmask_t criticalErrorLedPin;
|
2019-09-09 18:44:48 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* low-level function is used here to reduce stack usage
|
|
|
|
*/
|
2020-03-28 18:28:32 -07:00
|
|
|
#define ON_CRITICAL_ERROR() \
|
2020-05-11 15:22:51 -07:00
|
|
|
palWritePad(criticalErrorLedPort, criticalErrorLedPin, 1); \
|
2019-09-09 18:44:48 -07:00
|
|
|
turnAllPinsOff(); \
|
|
|
|
enginePins.communicationLedPin.setValue(1);
|
|
|
|
#endif /* EFI_PROD_CODE */
|
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
#if EFI_SIMULATOR || EFI_PROD_CODE
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void chDbgPanic3(const char *msg, const char * file, int line) {
|
2020-03-28 18:28:32 -07:00
|
|
|
if (hasOsPanicError())
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
dbg_panic_file = file;
|
|
|
|
dbg_panic_line = line;
|
2019-04-12 19:07:03 -07:00
|
|
|
#if CH_DBG_SYSTEM_STATE_CHECK
|
2017-03-21 11:58:14 -07:00
|
|
|
ch.dbg.panic_msg = msg;
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif /* CH_DBG_SYSTEM_STATE_CHECK */
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_PROD_CODE
|
2020-03-28 18:28:32 -07:00
|
|
|
ON_CRITICAL_ERROR();
|
2016-07-23 10:03:57 -07:00
|
|
|
#else
|
|
|
|
printf("chDbgPanic3 %s %s%d", msg, file, line);
|
|
|
|
exit(-1);
|
|
|
|
#endif
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_HD44780_LCD
|
2017-04-21 19:47:50 -07:00
|
|
|
lcdShowPanicMessage((char *) msg);
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif /* EFI_HD44780_LCD */
|
|
|
|
|
|
|
|
if (!main_loop_started) {
|
2020-03-28 18:28:32 -07:00
|
|
|
print("%s %s %s:%d\r\n", CRITICAL_PREFIX, msg, file, line);
|
2017-03-22 16:16:45 -07:00
|
|
|
// chThdSleepSeconds(1);
|
2017-03-21 11:58:14 -07:00
|
|
|
chSysHalt("Main loop did not start");
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-28 15:30:53 -07:00
|
|
|
// todo: look into chsnprintf
|
2016-12-30 11:02:37 -08:00
|
|
|
// todo: move to some util file & reuse for 'firmwareError' method
|
2019-11-23 18:25:29 -08:00
|
|
|
static void printToStream(MemoryStream *stream, const char *fmt, va_list ap) {
|
2016-12-30 11:02:37 -08:00
|
|
|
stream->eos = 0; // reset
|
|
|
|
chvprintf((BaseSequentialStream *) stream, fmt, ap);
|
2019-11-23 18:25:29 -08:00
|
|
|
|
|
|
|
// Terminate, but don't write past the end of the buffer
|
|
|
|
int terminatorLocation = minI(stream->eos, stream->size - 1);
|
|
|
|
stream->buffer[terminatorLocation] = '\0';
|
2016-12-30 11:02:37 -08:00
|
|
|
}
|
2017-01-02 12:03:26 -08:00
|
|
|
|
2019-11-23 18:25:29 -08:00
|
|
|
static void printWarning(const char *fmt, va_list ap) {
|
2018-01-22 14:45:43 -08:00
|
|
|
resetLogging(&logger); // todo: is 'reset' really needed here?
|
|
|
|
appendMsgPrefix(&logger);
|
|
|
|
|
2018-08-31 19:19:19 -07:00
|
|
|
logger.append(WARNING_PREFIX);
|
2018-01-22 14:45:43 -08:00
|
|
|
|
2020-05-03 07:58:52 -07:00
|
|
|
printToStream(&errorState.warningStream, fmt, ap);
|
2018-01-22 14:45:43 -08:00
|
|
|
|
2020-04-22 16:07:42 -07:00
|
|
|
if (CONFIG(showHumanReadableWarning)) {
|
2020-04-19 18:42:00 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
#if defined(EFI_NO_CONFIG_WORKING_COPY)
|
|
|
|
memcpy(persistentState.persistentConfiguration.warning_message, warningBuffer, sizeof(warningBuffer));
|
|
|
|
#else /* defined(EFI_NO_CONFIG_WORKING_COPY) */
|
|
|
|
memcpy(configWorkingCopy.warning_message, warningBuffer, sizeof(warningBuffer));
|
|
|
|
#endif /* defined(EFI_NO_CONFIG_WORKING_COPY) */
|
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
2020-04-22 16:07:42 -07:00
|
|
|
}
|
2020-04-19 18:42:00 -07:00
|
|
|
|
2018-08-31 19:19:19 -07:00
|
|
|
logger.append(warningBuffer);
|
2018-01-22 14:45:43 -08:00
|
|
|
append(&logger, DELIMETER);
|
|
|
|
scheduleLogging(&logger);
|
|
|
|
}
|
2016-12-30 11:02:37 -08:00
|
|
|
|
2018-01-22 16:53:13 -08:00
|
|
|
#else
|
2019-01-12 05:34:38 -08:00
|
|
|
WarningCodeState unitTestWarningCodeState;
|
2018-01-22 16:53:13 -08:00
|
|
|
|
|
|
|
#endif /* EFI_SIMULATOR || EFI_PROD_CODE */
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* OBD_PCM_Processor_Fault is the general error code for now
|
|
|
|
*
|
2019-01-11 06:58:48 -08:00
|
|
|
* @returns TRUE in case there were warnings recently
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2016-10-10 12:02:10 -07:00
|
|
|
bool warning(obd_code_e code, const char *fmt, ...) {
|
|
|
|
if (hasFirmwareErrorFlag)
|
|
|
|
return true;
|
2016-09-26 17:02:24 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SIMULATOR
|
2017-03-03 18:33:49 -08:00
|
|
|
printf("sim_warning %s\r\n", fmt);
|
2017-05-21 07:46:43 -07:00
|
|
|
#endif /* EFI_SIMULATOR */
|
2016-09-26 17:02:24 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SIMULATOR || EFI_PROD_CODE
|
2019-01-11 06:58:48 -08:00
|
|
|
engine->engineState.warnings.addWarningCode(code);
|
2016-11-23 14:01:59 -08:00
|
|
|
|
2019-01-11 06:58:48 -08:00
|
|
|
// todo: move this logic into WarningCodeState?
|
2016-07-14 20:02:55 -07:00
|
|
|
efitimesec_t now = getTimeNowSeconds();
|
2019-01-11 06:58:48 -08:00
|
|
|
if (engine->engineState.warnings.isWarningNow(now, false) || !warningEnabled)
|
2015-07-10 06:01:56 -07:00
|
|
|
return true; // we just had another warning, let's not spam
|
2019-01-11 06:58:48 -08:00
|
|
|
engine->engineState.warnings.timeOfPreviousWarning = now;
|
2016-01-30 19:03:36 -08:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2019-11-23 18:25:29 -08:00
|
|
|
printWarning(fmt, ap);
|
2015-07-10 06:01:56 -07:00
|
|
|
va_end(ap);
|
2017-01-02 12:03:26 -08:00
|
|
|
#else
|
2019-05-10 19:10:40 -07:00
|
|
|
// todo: we need access to 'engine' here so that we can migrate to real 'engine->engineState.warnings'
|
2019-01-12 05:34:38 -08:00
|
|
|
unitTestWarningCodeState.addWarningCode(code);
|
2017-03-03 18:33:49 -08:00
|
|
|
printf("unit_test_warning: ");
|
2017-01-02 12:03:26 -08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vprintf(fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
printf("\r\n");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-21 07:46:43 -07:00
|
|
|
#endif /* EFI_SIMULATOR || EFI_PROD_CODE */
|
2017-01-02 12:03:26 -08:00
|
|
|
return false;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2020-03-28 18:28:32 -07:00
|
|
|
char *getWarningMessage(void) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return warningBuffer;
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:46:43 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_CLOCK_LOCKS
|
2015-07-10 06:01:56 -07:00
|
|
|
uint32_t lastLockTime;
|
2017-05-21 07:25:35 -07:00
|
|
|
/**
|
|
|
|
* Maximum time before requesting lock and releasing lock at the end of critical section
|
|
|
|
*/
|
|
|
|
uint32_t maxLockedDuration = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-01-23 10:18:59 -08:00
|
|
|
/**
|
|
|
|
* this depends on chdebug.h patch
|
|
|
|
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
|
|
|
-#define _dbg_enter_lock() (ch.dbg.lock_cnt = (cnt_t)1)
|
|
|
|
-#define _dbg_leave_lock() (ch.dbg.lock_cnt = (cnt_t)0)
|
|
|
|
+#define _dbg_enter_lock() {(ch.dbg.lock_cnt = (cnt_t)1); ON_LOCK_HOOK;}
|
|
|
|
+#define _dbg_leave_lock() {ON_UNLOCK_HOOK;(ch.dbg.lock_cnt = (cnt_t)0);}
|
|
|
|
#endif
|
|
|
|
*/
|
2020-07-10 20:27:27 -07:00
|
|
|
#endif /* EFI_CLOCK_LOCKS */
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void onLockHook(void) {
|
2020-07-10 21:16:36 -07:00
|
|
|
#if ENABLE_PERF_TRACE
|
2020-07-10 20:27:27 -07:00
|
|
|
perfEventInstantGlobal(PE::GlobalLock);
|
2020-07-10 21:16:36 -07:00
|
|
|
#endif /* ENABLE_PERF_TRACE */
|
2020-07-10 20:27:27 -07:00
|
|
|
|
|
|
|
#if EFI_CLOCK_LOCKS
|
2019-05-07 16:32:08 -07:00
|
|
|
lastLockTime = getTimeNowLowerNt();
|
2020-07-10 20:27:27 -07:00
|
|
|
#endif /* EFI_CLOCK_LOCKS */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void onUnlockHook(void) {
|
2020-07-10 20:27:27 -07:00
|
|
|
#if EFI_CLOCK_LOCKS
|
2019-05-07 16:32:08 -07:00
|
|
|
uint32_t lockedDuration = getTimeNowLowerNt() - lastLockTime;
|
2017-05-21 07:25:35 -07:00
|
|
|
if (lockedDuration > maxLockedDuration) {
|
|
|
|
maxLockedDuration = lockedDuration;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-06-03 19:43:05 -07:00
|
|
|
// if (lockedDuration > 2800) {
|
2015-07-10 06:01:56 -07:00
|
|
|
// // un-comment this if you want a nice stop for a breakpoint
|
2017-06-03 19:43:05 -07:00
|
|
|
// maxLockedDuration = lockedDuration + 1;
|
2015-07-10 06:01:56 -07:00
|
|
|
// }
|
2017-05-21 07:46:43 -07:00
|
|
|
#endif /* EFI_CLOCK_LOCKS */
|
|
|
|
|
2020-07-10 21:16:36 -07:00
|
|
|
#if ENABLE_PERF_TRACE
|
2020-07-10 20:27:27 -07:00
|
|
|
perfEventInstantGlobal(PE::GlobalUnlock);
|
2020-07-10 21:16:36 -07:00
|
|
|
#endif /* ENABLE_PERF_TRACE */
|
2020-07-10 20:27:27 -07:00
|
|
|
}
|
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
void firmwareError(obd_code_e code, const char *fmt, ...) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_PROD_CODE
|
2017-01-02 12:03:26 -08:00
|
|
|
if (hasFirmwareErrorFlag)
|
|
|
|
return;
|
2019-01-11 06:58:48 -08:00
|
|
|
engine->engineState.warnings.addWarningCode(code);
|
2018-01-22 14:45:43 -08:00
|
|
|
#ifdef EFI_PRINT_ERRORS_AS_WARNINGS
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2019-11-23 18:25:29 -08:00
|
|
|
printWarning(fmt, ap);
|
2018-01-22 14:45:43 -08:00
|
|
|
va_end(ap);
|
|
|
|
#endif
|
2020-03-28 18:28:32 -07:00
|
|
|
ON_CRITICAL_ERROR()
|
2017-01-02 12:03:26 -08:00
|
|
|
;
|
|
|
|
hasFirmwareErrorFlag = true;
|
|
|
|
if (indexOf(fmt, '%') == -1) {
|
|
|
|
/**
|
|
|
|
* in case of simple error message let's reduce stack usage
|
|
|
|
* because chvprintf might be causing an error
|
|
|
|
*/
|
2020-03-28 17:14:17 -07:00
|
|
|
strncpy((char*) criticalErrorMessageBuffer, fmt, sizeof(criticalErrorMessageBuffer) - 1);
|
|
|
|
criticalErrorMessageBuffer[sizeof(criticalErrorMessageBuffer) - 1] = 0; // just to be sure
|
2017-01-02 12:03:26 -08:00
|
|
|
} else {
|
2017-03-28 15:30:53 -07:00
|
|
|
// todo: look into chsnprintf once on Chibios 3
|
2020-05-03 07:58:52 -07:00
|
|
|
errorState.firmwareErrorMessageStream.eos = 0; // reset
|
2017-01-02 12:03:26 -08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2020-05-03 07:58:52 -07:00
|
|
|
chvprintf((BaseSequentialStream *) &errorState.firmwareErrorMessageStream, fmt, ap);
|
2017-01-02 12:03:26 -08:00
|
|
|
va_end(ap);
|
|
|
|
// todo: reuse warning buffer helper method
|
2020-05-03 07:58:52 -07:00
|
|
|
errorState.firmwareErrorMessageStream.buffer[errorState.firmwareErrorMessageStream.eos] = 0; // need to terminate explicitly
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2020-05-22 13:45:13 -07:00
|
|
|
int size = strlen((char*)criticalErrorMessageBuffer);
|
|
|
|
static char versionBuffer[32];
|
|
|
|
chsnprintf(versionBuffer, sizeof(versionBuffer), " %d@%s", getRusEfiVersion(), FIRMWARE_ID);
|
|
|
|
|
|
|
|
if (size + strlen(versionBuffer) < sizeof(criticalErrorMessageBuffer)) {
|
|
|
|
strcpy((char*)(criticalErrorMessageBuffer) + size, versionBuffer);
|
|
|
|
}
|
2020-03-28 17:14:17 -07:00
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
#else
|
|
|
|
printf("firmwareError [%s]\r\n", fmt);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-01-02 12:03:26 -08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vprintf(fmt, ap);
|
|
|
|
va_end(ap);
|
2017-03-12 19:46:01 -07:00
|
|
|
printf("\r\n");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SIMULATOR || EFI_UNIT_TEST
|
2020-05-23 07:46:28 -07:00
|
|
|
throw "fatal error";
|
2017-01-02 12:03:26 -08:00
|
|
|
#endif /* EFI_SIMULATOR */
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-01-02 12:03:26 -08:00
|
|
|
|