From 8a83839ca9167621835b09141f9576f2c5c59973 Mon Sep 17 00:00:00 2001 From: rusEfi Date: Mon, 10 Oct 2016 15:02:10 -0400 Subject: [PATCH] auto-sync --- firmware/controllers/algo/engine.cpp | 2 +- .../controllers/algo/engine_configuration.cpp | 6 +- firmware/controllers/algo/error_handling.h | 5 +- firmware/controllers/algo/fuel_math.cpp | 2 +- firmware/controllers/algo/obd_error_codes.h | 55 +++++++++++++++++++ firmware/controllers/core/EfiWave.cpp | 4 +- firmware/controllers/core/interpolation.cpp | 2 +- firmware/controllers/error_handling.cpp | 20 ++++--- firmware/controllers/lcd_controller.cpp | 4 +- firmware/controllers/sensors/map.cpp | 4 +- firmware/controllers/sensors/thermistors.cpp | 4 +- firmware/controllers/system/event_queue.h | 2 +- .../system/pwm_generator_logic.cpp | 4 +- .../trigger/main_trigger_callback.cpp | 2 +- .../controllers/trigger/trigger_decoder.cpp | 2 +- .../controllers/trigger/trigger_simulator.cpp | 2 +- firmware/hw_layer/io_pins.cpp | 4 +- firmware/hw_layer/pin_repository.cpp | 8 +-- firmware/hw_layer/trigger_input.cpp | 2 +- firmware/rusefi.cpp | 1 + unit_tests/main.cpp | 2 +- 21 files changed, 100 insertions(+), 37 deletions(-) diff --git a/firmware/controllers/algo/engine.cpp b/firmware/controllers/algo/engine.cpp index 5b31220cdd..46a74cc222 100644 --- a/firmware/controllers/algo/engine.cpp +++ b/firmware/controllers/algo/engine.cpp @@ -288,7 +288,7 @@ void Engine::watchdog() { return; if (!isSpinning) { if (!isRunningBenchTest() && stopPins()) { - firmwareError(OBD_PCM_Processor_Fault, "Some pins were turned off by 2nd pass watchdog"); + firmwareError(CUSTOM_ERR_6103, "Some pins were turned off by 2nd pass watchdog"); } return; } diff --git a/firmware/controllers/algo/engine_configuration.cpp b/firmware/controllers/algo/engine_configuration.cpp index c5e80c22b2..9d92f6950b 100644 --- a/firmware/controllers/algo/engine_configuration.cpp +++ b/firmware/controllers/algo/engine_configuration.cpp @@ -990,7 +990,7 @@ void resetConfigurationExt(Logging * logger, engine_type_e engineType DECLARE_EN applyNonPersistentConfiguration(logger PASS_ENGINE_PARAMETER); // todo: eliminate triggerShape.operationMode? if (engineConfiguration->operationMode != engine->triggerShape.getOperationMode()) - firmwareError(OBD_PCM_Processor_Fault, "operationMode/trigger mismatch"); + firmwareError(CUSTOM_ERR_6100, "operationMode/trigger mismatch"); #if EFI_TUNER_STUDIO syncTunerStudioCopy(); @@ -1015,11 +1015,11 @@ void applyNonPersistentConfiguration(Logging * logger DECLARE_ENGINE_PARAMETER_S engine->triggerShape.initializeTriggerShape(logger PASS_ENGINE_PARAMETER); #endif if (engine->triggerShape.getSize() == 0) { - firmwareError(OBD_PCM_Processor_Fault, "triggerShape size is zero"); + firmwareError(CUSTOM_ERR_6101, "triggerShape size is zero"); return; } if (engine->triggerShape.getSize() == 0) { - firmwareError(OBD_PCM_Processor_Fault, "shaftPositionEventCount is zero"); + firmwareError(CUSTOM_ERR_6102, "shaftPositionEventCount is zero"); return; } engine->engineCycleEventCount = engine->triggerShape.getLength(); diff --git a/firmware/controllers/algo/error_handling.h b/firmware/controllers/algo/error_handling.h index 3a6db1bce4..f82c01d318 100644 --- a/firmware/controllers/algo/error_handling.h +++ b/firmware/controllers/algo/error_handling.h @@ -22,12 +22,13 @@ int getVtSizeEstimate(void); void assertVtList(void); +void setWarningCode(obd_code_e code, efitimesec_t now); /** * Something is wrong, but we can live with it: some minor sensor is disconnected * or something like that * */ -int warning(obd_code_e code, const char *fmt, ...); +bool warning(obd_code_e code, const char *fmt, ...); bool isWarningNow(efitimesec_t now, bool forIndicator); /** * Something really bad had happened - firmware cannot function @@ -53,7 +54,7 @@ char *getFirmwareError(void); void chDbgPanic3(const char *msg, const char * file, int line); void initErrorHandling(void); -char *getWarninig(void); +char *getWarning(void); // todo: better place for this shared declaration? int getRusEfiVersion(void); diff --git a/firmware/controllers/algo/fuel_math.cpp b/firmware/controllers/algo/fuel_math.cpp index 0e9494335b..3949519d82 100644 --- a/firmware/controllers/algo/fuel_math.cpp +++ b/firmware/controllers/algo/fuel_math.cpp @@ -105,7 +105,7 @@ int getNumberOfInjections(injection_mode_e mode DECLARE_ENGINE_PARAMETER_S) { case IM_BATCH: return 2; default: - firmwareError(OBD_PCM_Processor_Fault, "Unexpected getFuelMultiplier %d", mode); + firmwareError(CUSTOM_ERR_6104, "Unexpected getFuelMultiplier %d", mode); return 1; } } diff --git a/firmware/controllers/algo/obd_error_codes.h b/firmware/controllers/algo/obd_error_codes.h index 7c7f08bddc..50104b6748 100644 --- a/firmware/controllers/algo/obd_error_codes.h +++ b/firmware/controllers/algo/obd_error_codes.h @@ -1774,6 +1774,61 @@ typedef enum { CUSTOM_DWELL = 6098, CUSTOM_TS_OVERFLOW = 6099, + CUSTOM_ERR_6100 = 6100, + CUSTOM_ERR_6101 = 6101, + CUSTOM_ERR_6102 = 6102, + CUSTOM_ERR_6103 = 6103, + CUSTOM_ERR_6104 = 6104, + CUSTOM_ERR_6105 = 6105, + CUSTOM_ERR_6106 = 6106, + CUSTOM_ERR_6107 = 6107, + CUSTOM_ERR_6108 = 6108, + CUSTOM_ERR_6109 = 6109, + + CUSTOM_ERR_6110 = 6110, + CUSTOM_ERR_6111 = 6111, + CUSTOM_ERR_6112 = 6112, + CUSTOM_ERR_6113 = 6113, + CUSTOM_ERR_6114 = 6114, + CUSTOM_ERR_6115 = 6115, + CUSTOM_ERR_6116 = 6116, + CUSTOM_ERR_6117 = 6117, + CUSTOM_ERR_6118 = 6118, + CUSTOM_ERR_6119 = 6119, + + CUSTOM_ERR_6120 = 6120, + CUSTOM_ERR_6121 = 6121, + CUSTOM_ERR_6122 = 6122, + CUSTOM_ERR_6123 = 6123, + CUSTOM_ERR_6124 = 6124, + CUSTOM_ERR_6125 = 6125, + CUSTOM_ERR_6126 = 6126, + CUSTOM_ERR_6127 = 6127, + CUSTOM_ERR_6128 = 6128, + CUSTOM_ERR_6129 = 6129, + + CUSTOM_ERR_6130 = 6130, + CUSTOM_ERR_6131 = 6131, + CUSTOM_ERR_6132 = 6132, + CUSTOM_ERR_6133 = 6133, + CUSTOM_ERR_6134 = 6134, + CUSTOM_ERR_6135 = 6135, + CUSTOM_ERR_6136 = 6136, + CUSTOM_ERR_6137 = 6137, + CUSTOM_ERR_6138 = 6138, + CUSTOM_ERR_6139 = 6139, + + CUSTOM_ERR_6140 = 6140, + CUSTOM_ERR_6141 = 6141, + CUSTOM_ERR_6142 = 6142, + CUSTOM_ERR_6143 = 6143, + CUSTOM_ERR_6144 = 6144, + CUSTOM_ERR_6145 = 6145, + CUSTOM_ERR_6146 = 6146, + CUSTOM_ERR_6147 = 6147, + CUSTOM_ERR_6148 = 6148, + CUSTOM_ERR_6149 = 6149, + // this is needed for proper enum size, this matters for malfunction_central Internal_ForceMyEnumIntSize_cranking_obd_code = ENUM_32_BITS, diff --git a/firmware/controllers/core/EfiWave.cpp b/firmware/controllers/core/EfiWave.cpp index 7ae584988b..93022ac6af 100644 --- a/firmware/controllers/core/EfiWave.cpp +++ b/firmware/controllers/core/EfiWave.cpp @@ -51,12 +51,12 @@ float multi_wave_s::getSwitchTime(int index) const { void checkSwitchTimes2(int size, float *switchTimes) { if (switchTimes[size - 1] != 1) { - firmwareError(OBD_PCM_Processor_Fault, "last switch time has to be 1 not %f", switchTimes[size - 1]); + firmwareError(CUSTOM_ERR_6105, "last switch time has to be 1 not %f", switchTimes[size - 1]); return; } for (int i = 0; i < size - 1; i++) { if (switchTimes[i] >= switchTimes[i + 1]) { - firmwareError(OBD_PCM_Processor_Fault, "invalid switchTimes @%d: %f/%f", i, switchTimes[i], switchTimes[i + 1]); + firmwareError(CUSTOM_ERR_6106, "invalid switchTimes @%d: %f/%f", i, switchTimes[i], switchTimes[i + 1]); } } } diff --git a/firmware/controllers/core/interpolation.cpp b/firmware/controllers/core/interpolation.cpp index 8ab9cc5e0a..2741517ac7 100644 --- a/firmware/controllers/core/interpolation.cpp +++ b/firmware/controllers/core/interpolation.cpp @@ -81,7 +81,7 @@ FastInterpolation::FastInterpolation(float x1, float y1, float x2, float y2) { void FastInterpolation::init(float x1, float y1, float x2, float y2) { if (x1 == x2) { - firmwareError(OBD_PCM_Processor_Fault, "init: Same x1 and x2 in interpolate: %f/%f", x1, x2); + firmwareError(CUSTOM_ERR_6110, "init: Same x1 and x2 in interpolate: %f/%f", x1, x2); return; } a = INTERPOLATION_A(x1, y1, x2, y2); diff --git a/firmware/controllers/error_handling.cpp b/firmware/controllers/error_handling.cpp index 796bd9e87f..d4af4dcf5e 100644 --- a/firmware/controllers/error_handling.cpp +++ b/firmware/controllers/error_handling.cpp @@ -26,6 +26,7 @@ EXTERN_ENGINE; extern int warningEnabled; extern bool main_loop_started; +extern bool hasFirmwareErrorFlag; const char *dbg_panic_file; int dbg_panic_line; @@ -70,14 +71,22 @@ bool isWarningNow(efitimesec_t now, bool forIndicator) { return absI(now - engine->engineState.timeOfPreviousWarning) < period; } +void setWarningCode(obd_code_e code, efitimesec_t now) { + engine->engineState.timeOfPreviousWarning = now; + + engine->engineState.warningCounter++; + engine->engineState.lastErrorCode = code; +} + /** * OBD_PCM_Processor_Fault is the general error code for now * * @returns TRUE in case there are too many warnings */ -int warning(obd_code_e code, const char *fmt, ...) { +bool warning(obd_code_e code, const char *fmt, ...) { + if (hasFirmwareErrorFlag) + return true; efiAssert(isWarningStreamInitialized, "warn stream not initialized", false); - UNUSED(code); #if EFI_UNIT_TEST || EFI_SIMULATOR || defined(__DOXYGEN__) printf("warning %s\r\n", fmt); @@ -86,10 +95,7 @@ int warning(obd_code_e code, const char *fmt, ...) { efitimesec_t now = getTimeNowSeconds(); if (isWarningNow(now, false) || !warningEnabled) return true; // we just had another warning, let's not spam - engine->engineState.timeOfPreviousWarning = now; - - engine->engineState.warningCounter++; - engine->engineState.lastErrorCode = code; + setWarningCode(code, now); resetLogging(&logger); // todo: is 'reset' really needed here? appendMsgPrefix(&logger); @@ -109,7 +115,7 @@ int warning(obd_code_e code, const char *fmt, ...) { return FALSE; } -char *getWarninig(void) { +char *getWarning(void) { return warningBuffer; } diff --git a/firmware/controllers/lcd_controller.cpp b/firmware/controllers/lcd_controller.cpp index c0a2d8d0d3..2c1b5fd5ec 100644 --- a/firmware/controllers/lcd_controller.cpp +++ b/firmware/controllers/lcd_controller.cpp @@ -339,7 +339,7 @@ void updateHD44780lcd(Engine *engine) { fillWithSpaces(); } - memcpy(buffer, getWarninig(), engineConfiguration->HD44780width); + memcpy(buffer, getWarning(), engineConfiguration->HD44780width); buffer[engineConfiguration->HD44780width] = 0; lcd_HD44780_set_position(engineConfiguration->HD44780height - 1, 0); lcd_HD44780_print_string(buffer); @@ -375,7 +375,7 @@ void updateHD44780lcd(Engine *engine) { // // lcd_HD44780_set_position(1, 0); // memset(buffer, ' ', LCD_WIDTH); -// memcpy(buffer, getWarninig(), LCD_WIDTH); +// memcpy(buffer, getWarning(), LCD_WIDTH); // buffer[LCD_WIDTH] = 0; // lcd_HD44780_print_string(buffer); // diff --git a/firmware/controllers/sensors/map.cpp b/firmware/controllers/sensors/map.cpp index 3ae2239877..d021e3a07c 100644 --- a/firmware/controllers/sensors/map.cpp +++ b/firmware/controllers/sensors/map.cpp @@ -88,7 +88,7 @@ float decodePressure(float voltage, air_pressure_sensor_config_s * mapConfig DEC case MT_MPX4100: return mpx4100.getValue(voltage); default: - firmwareError(OBD_PCM_Processor_Fault, "Unknown MAP type: %d", mapConfig->type); + firmwareError(CUSTOM_ERR_6111, "Unknown MAP type: %d", mapConfig->type); return NAN; } } @@ -159,7 +159,7 @@ static FastInterpolation *getDecoder(air_pressure_sensor_type_e type) { case MT_GM_3_BAR: return &gm3bar; default: - firmwareError(OBD_PCM_Processor_Fault, "Unknown MAP type: %d", type); + firmwareError(CUSTOM_ERR_6112, "Unknown MAP type: %d", type); return &customMap; } } diff --git a/firmware/controllers/sensors/thermistors.cpp b/firmware/controllers/sensors/thermistors.cpp index 4f2d4a9d0a..0a6993829d 100644 --- a/firmware/controllers/sensors/thermistors.cpp +++ b/firmware/controllers/sensors/thermistors.cpp @@ -82,7 +82,7 @@ float getResistance(ThermistorConf *config) { float getTemperatureC(ThermistorConf *config, ThermistorMath *tm) { if (!initialized) { - firmwareError(OBD_PCM_Processor_Fault, "thermstr not initialized"); + firmwareError(CUSTOM_ERR_6113, "thermstr not initialized"); return NAN; } float resistance = getResistance(config); @@ -137,7 +137,7 @@ static void prepareThermistorCurve(thermistor_conf_s *tc, thermistor_curve_s * c float L1 = logf(tc->resistance_1); if (L1 == tc->resistance_1) { - firmwareError(OBD_PCM_Processor_Fault, "log is broken?"); + firmwareError(CUSTOM_ERR_6114, "log is broken?"); } float L2 = logf(tc->resistance_2); float L3 = logf(tc->resistance_3); diff --git a/firmware/controllers/system/event_queue.h b/firmware/controllers/system/event_queue.h index b945c6dc34..57eb6b6099 100644 --- a/firmware/controllers/system/event_queue.h +++ b/firmware/controllers/system/event_queue.h @@ -26,7 +26,7 @@ bool assertNotInList(T *head, T*element) { LL_FOREACH(head, current) { if (++counter > QUEUE_LENGTH_LIMIT) { - firmwareError(OBD_PCM_Processor_Fault, "Looped queue?"); + firmwareError(CUSTOM_ERR_6115, "Looped queue?"); return false; } if (current == element) { diff --git a/firmware/controllers/system/pwm_generator_logic.cpp b/firmware/controllers/system/pwm_generator_logic.cpp index 0c4461433e..e50d6b99c4 100644 --- a/firmware/controllers/system/pwm_generator_logic.cpp +++ b/firmware/controllers/system/pwm_generator_logic.cpp @@ -182,11 +182,11 @@ void PwmConfig::weComplexInit(const char *msg, int phaseCount, float *switchTime efiAssertVoid(periodNt != 0, "period is not initialized"); if (phaseCount == 0) { - firmwareError(OBD_PCM_Processor_Fault, "signal length cannot be zero"); + firmwareError(CUSTOM_ERR_6116, "signal length cannot be zero"); return; } if (phaseCount > PWM_PHASE_MAX_COUNT) { - firmwareError(OBD_PCM_Processor_Fault, "too many phases in PWM"); + firmwareError(CUSTOM_ERR_6117, "too many phases in PWM"); return; } efiAssertVoid(waveCount > 0, "waveCount should be positive"); diff --git a/firmware/controllers/trigger/main_trigger_callback.cpp b/firmware/controllers/trigger/main_trigger_callback.cpp index 5f362babcb..d5d65b7aaf 100644 --- a/firmware/controllers/trigger/main_trigger_callback.cpp +++ b/firmware/controllers/trigger/main_trigger_callback.cpp @@ -440,7 +440,7 @@ static ALWAYS_INLINE void ignitionMathCalc(int rpm DECLARE_ENGINE_PARAMETER_S) { float dwellMs = ENGINE(engineState.sparkDwell); if (cisnan(dwellMs) || dwellMs < 0) { - firmwareError(OBD_PCM_Processor_Fault, "invalid dwell: %f at %d", dwellMs, rpm); + firmwareError(CUSTOM_ERR_6118, "invalid dwell: %f at %d", dwellMs, rpm); return; } } diff --git a/firmware/controllers/trigger/trigger_decoder.cpp b/firmware/controllers/trigger/trigger_decoder.cpp index 0fddfd43d3..954e9c756c 100644 --- a/firmware/controllers/trigger/trigger_decoder.cpp +++ b/firmware/controllers/trigger/trigger_decoder.cpp @@ -599,7 +599,7 @@ void TriggerShape::initializeTriggerShape(Logging *logger DECLARE_ENGINE_PARAMET break; default: - firmwareError(OBD_PCM_Processor_Fault, "initializeTriggerShape() not implemented: %d", triggerConfig->type); + firmwareError(CUSTOM_ERR_6119, "initializeTriggerShape() not implemented: %d", triggerConfig->type); return; } wave.checkSwitchTimes(getSize()); diff --git a/firmware/controllers/trigger/trigger_simulator.cpp b/firmware/controllers/trigger/trigger_simulator.cpp index 4e341663dc..497e9b9622 100644 --- a/firmware/controllers/trigger/trigger_simulator.cpp +++ b/firmware/controllers/trigger/trigger_simulator.cpp @@ -79,6 +79,6 @@ uint32_t TriggerStimulatorHelper::doFindTrigger(TriggerShape * shape, if (state->shaft_is_synchronized) return i; } - firmwareError(OBD_PCM_Processor_Fault, "findTriggerZeroEventIndex() failed"); + firmwareError(CUSTOM_ERR_6120, "findTriggerZeroEventIndex() failed"); return EFI_ERROR_CODE; } diff --git a/firmware/hw_layer/io_pins.cpp b/firmware/hw_layer/io_pins.cpp index efd4e8362d..8f40df6d1c 100644 --- a/firmware/hw_layer/io_pins.cpp +++ b/firmware/hw_layer/io_pins.cpp @@ -64,7 +64,7 @@ ioportid_t getHwPort(brain_pin_e brainPin) { if (brainPin == GPIO_UNASSIGNED) return GPIO_NULL; if (brainPin > GPIO_UNASSIGNED || brainPin < 0) { - firmwareError(OBD_PCM_Processor_Fault, "Invalid brain_pin_e: %d", brainPin); + firmwareError(CUSTOM_ERR_6130, "Invalid brain_pin_e: %d", brainPin); return GPIO_NULL; } return PORTS[brainPin / PORT_SIZE]; @@ -74,7 +74,7 @@ ioportmask_t getHwPin(brain_pin_e brainPin) { if (brainPin == GPIO_UNASSIGNED) return EFI_ERROR_CODE; if (brainPin > GPIO_UNASSIGNED || brainPin < 0) { - firmwareError(OBD_PCM_Processor_Fault, "Invalid brain_pin_e: %d", brainPin); + firmwareError(CUSTOM_ERR_6131, "Invalid brain_pin_e: %d", brainPin); return EFI_ERROR_CODE; } return brainPin % PORT_SIZE; diff --git a/firmware/hw_layer/pin_repository.cpp b/firmware/hw_layer/pin_repository.cpp index efd5a5a29f..1ee995de49 100644 --- a/firmware/hw_layer/pin_repository.cpp +++ b/firmware/hw_layer/pin_repository.cpp @@ -80,7 +80,7 @@ static int getPortIndex(ioportid_t port) { if (port == GPIOH) return 6; #endif /* defined(STM32F4XX) */ - firmwareError(OBD_PCM_Processor_Fault, "unknown port"); + firmwareError(CUSTOM_ERR_6132, "unknown port"); return -1; } @@ -197,7 +197,7 @@ const char * getPinFunction(brain_input_pin_e brainPin) { */ void mySetPadMode(const char *msg, ioportid_t port, ioportmask_t pin, iomode_t mode) { if (!initialized) { - firmwareError(OBD_PCM_Processor_Fault, "repository not initialized"); + firmwareError(CUSTOM_ERR_6132, "repository not initialized"); return; } if (port == GPIO_NULL) @@ -216,7 +216,7 @@ void mySetPadMode(const char *msg, ioportid_t port, ioportmask_t pin, iomode_t m * connected, so the warning is never displayed on the console and that's quite a problem! */ // warning(OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, PIN_USED[index]); - firmwareError(OBD_PCM_Processor_Fault, "%s%d req by %s used by %s", portname(port), pin, msg, PIN_USED[index]); + firmwareError(CUSTOM_ERR_6133, "%s%d req by %s used by %s", portname(port), pin, msg, PIN_USED[index]); return; } markUsed(index, msg); @@ -250,7 +250,7 @@ void registedFundamentralIoPin(char *msg, ioportid_t port, ioportmask_t pin, iom if (PIN_USED[index] != NULL) { print("!!!!!!!!!!!!! Already used [%s] %d\r\n", msg, pin); print("!!!!!!!!!!!!! Already used by [%s]\r\n", PIN_USED[index]); - firmwareError(OBD_PCM_Processor_Fault, "pin already used"); + firmwareError(CUSTOM_ERR_6134, "pin already used"); return; } markUsed(index, msg); diff --git a/firmware/hw_layer/trigger_input.cpp b/firmware/hw_layer/trigger_input.cpp index 3d3d280bb5..c1a39ea642 100644 --- a/firmware/hw_layer/trigger_input.cpp +++ b/firmware/hw_layer/trigger_input.cpp @@ -114,7 +114,7 @@ static ICUDriver *turnOnTriggerInputPin(brain_pin_e hwPin, ICUConfig *icucfg) { icuEnable(driver); } else { // we would be here for example if same pin is used for multiple input capture purposes - firmwareError(OBD_PCM_Processor_Fault, "ICU unexpected state [%s]", hwPortname(hwPin)); + firmwareError(CUSTOM_ERR_6135, "ICU unexpected state [%s]", hwPortname(hwPin)); } } return driver; diff --git a/firmware/rusefi.cpp b/firmware/rusefi.cpp index 21e548d01f..beb0a6cd9a 100644 --- a/firmware/rusefi.cpp +++ b/firmware/rusefi.cpp @@ -263,6 +263,7 @@ void chDbgStackOverflowPanic(Thread *otp) { void firmwareError(obd_code_e code, const char *errorMsg, ...) { if (hasFirmwareErrorFlag) return; + setWarningCode(code, getTimeNowSeconds()); ON_FATAL_ERROR() ; hasFirmwareErrorFlag = true; diff --git a/unit_tests/main.cpp b/unit_tests/main.cpp index b0fb9349fe..27c59d6a76 100644 --- a/unit_tests/main.cpp +++ b/unit_tests/main.cpp @@ -177,7 +177,7 @@ int main(void) { return EXIT_SUCCESS; } -int warning(obd_code_e code, const char *fmt, ...) { +bool warning(obd_code_e code, const char *fmt, ...) { printf("Warning: %s\r\n", fmt); }