diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index b5541c7231..f3f193b765 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -261,7 +261,8 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 0, 0 int16_t autoscale m_requested_pump;"DI: Pump Angle";"deg",{1/@@PACK_MULT_ANGLE@@}, 0, 0, 0, 0 int16_t autoscale boostControlTarget;"Pump Angle";"deg",{1/@@PACK_MULT_PRESSURE@@}, 0, 0, 0, 0 - int16_t autoscale unusedHere1111;"Pump Angle";"deg",{1/@@PACK_MULT_PRESSURE@@}, 0, 0, 0, 0 + int8_t sparkCutReason;"Spark Cut Code";"code",1, 0, 0, 0, 0 + int8_t fuelCutReason;"Fuel Cut Code";"code",1, 0, 0, 0, 0 float fuel_requested_percent;"DI: fuel_requested_percent";"v", 1, 0, 0, 100, 0 float fuel_requested_percent_pi;"DI: fuel_requested_percent_pi";"v", 1, 0, 0, 100, 0 float m_I_sum_percent;"DI: m_I_sum_percent";"v", 1, 0, 0, 100, 0 diff --git a/firmware/console/binary/ts_outputs_generated.h b/firmware/console/binary/ts_outputs_generated.h index 64b7eaa293..09a0b22835 100644 --- a/firmware/console/binary/ts_outputs_generated.h +++ b/firmware/console/binary/ts_outputs_generated.h @@ -1,4 +1,4 @@ -// this section was generated automatically by rusEFI tool ConfigDefinition.jar based on (unknown script) console/binary/output_channels.txt Wed Jan 05 06:47:26 UTC 2022 +// this section was generated automatically by rusEFI tool ConfigDefinition.jar based on (unknown script) console/binary/output_channels.txt Sat Jan 08 21:38:58 EST 2022 // by class com.rusefi.output.CHeaderConsumer // begin #pragma once @@ -864,11 +864,17 @@ struct ts_outputs_s { */ scaled_channel boostControlTarget = (int16_t)0; /** - * "Pump Angle" - deg + * "Spark Cut Code" + code * offset 338 */ - scaled_channel unusedHere1111 = (int16_t)0; + int8_t sparkCutReason = (int8_t)0; + /** + * "Fuel Cut Code" + code + * offset 339 + */ + int8_t fuelCutReason = (int8_t)0; /** * "DI: fuel_requested_percent" v @@ -920,79 +926,79 @@ struct ts_outputs_s { bool launchActivatePinState : 1 {}; /** offset 468 bit 7 */ - bool unusedBit_178_7 : 1 {}; + bool unusedBit_179_7 : 1 {}; /** offset 468 bit 8 */ - bool unusedBit_178_8 : 1 {}; + bool unusedBit_179_8 : 1 {}; /** offset 468 bit 9 */ - bool unusedBit_178_9 : 1 {}; + bool unusedBit_179_9 : 1 {}; /** offset 468 bit 10 */ - bool unusedBit_178_10 : 1 {}; + bool unusedBit_179_10 : 1 {}; /** offset 468 bit 11 */ - bool unusedBit_178_11 : 1 {}; + bool unusedBit_179_11 : 1 {}; /** offset 468 bit 12 */ - bool unusedBit_178_12 : 1 {}; + bool unusedBit_179_12 : 1 {}; /** offset 468 bit 13 */ - bool unusedBit_178_13 : 1 {}; + bool unusedBit_179_13 : 1 {}; /** offset 468 bit 14 */ - bool unusedBit_178_14 : 1 {}; + bool unusedBit_179_14 : 1 {}; /** offset 468 bit 15 */ - bool unusedBit_178_15 : 1 {}; + bool unusedBit_179_15 : 1 {}; /** offset 468 bit 16 */ - bool unusedBit_178_16 : 1 {}; + bool unusedBit_179_16 : 1 {}; /** offset 468 bit 17 */ - bool unusedBit_178_17 : 1 {}; + bool unusedBit_179_17 : 1 {}; /** offset 468 bit 18 */ - bool unusedBit_178_18 : 1 {}; + bool unusedBit_179_18 : 1 {}; /** offset 468 bit 19 */ - bool unusedBit_178_19 : 1 {}; + bool unusedBit_179_19 : 1 {}; /** offset 468 bit 20 */ - bool unusedBit_178_20 : 1 {}; + bool unusedBit_179_20 : 1 {}; /** offset 468 bit 21 */ - bool unusedBit_178_21 : 1 {}; + bool unusedBit_179_21 : 1 {}; /** offset 468 bit 22 */ - bool unusedBit_178_22 : 1 {}; + bool unusedBit_179_22 : 1 {}; /** offset 468 bit 23 */ - bool unusedBit_178_23 : 1 {}; + bool unusedBit_179_23 : 1 {}; /** offset 468 bit 24 */ - bool unusedBit_178_24 : 1 {}; + bool unusedBit_179_24 : 1 {}; /** offset 468 bit 25 */ - bool unusedBit_178_25 : 1 {}; + bool unusedBit_179_25 : 1 {}; /** offset 468 bit 26 */ - bool unusedBit_178_26 : 1 {}; + bool unusedBit_179_26 : 1 {}; /** offset 468 bit 27 */ - bool unusedBit_178_27 : 1 {}; + bool unusedBit_179_27 : 1 {}; /** offset 468 bit 28 */ - bool unusedBit_178_28 : 1 {}; + bool unusedBit_179_28 : 1 {}; /** offset 468 bit 29 */ - bool unusedBit_178_29 : 1 {}; + bool unusedBit_179_29 : 1 {}; /** offset 468 bit 30 */ - bool unusedBit_178_30 : 1 {}; + bool unusedBit_179_30 : 1 {}; /** offset 468 bit 31 */ - bool unusedBit_178_31 : 1 {}; + bool unusedBit_179_31 : 1 {}; /** * offset 472 */ @@ -1190,4 +1196,4 @@ struct ts_outputs_s { }; // end -// this section was generated automatically by rusEFI tool ConfigDefinition.jar based on (unknown script) console/binary/output_channels.txt Wed Jan 05 06:47:26 UTC 2022 +// this section was generated automatically by rusEFI tool ConfigDefinition.jar based on (unknown script) console/binary/output_channels.txt Sat Jan 08 21:38:58 EST 2022 diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index 9c42e38899..ed4edda47f 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -656,8 +656,8 @@ static void updateFlags() { engine->outputChannels.isFanOn = enginePins.fanRelay.getLogicValue(); engine->outputChannels.isFan2On = enginePins.fanRelay2.getLogicValue(); engine->outputChannels.isO2HeaterOn = enginePins.o2heater.getLogicValue(); - engine->outputChannels.isIgnitionEnabledIndicator = engine->limpManager.allowIgnition(); - engine->outputChannels.isInjectionEnabledIndicator = engine->limpManager.allowInjection(); + engine->outputChannels.isIgnitionEnabledIndicator = engine->limpManager.allowIgnition().value; + engine->outputChannels.isInjectionEnabledIndicator = engine->limpManager.allowInjection().value; engine->outputChannels.isCylinderCleanupActivated = engine->isCylinderCleanupMode; #if EFI_LAUNCH_CONTROL diff --git a/firmware/controllers/engine_cycle/main_trigger_callback.cpp b/firmware/controllers/engine_cycle/main_trigger_callback.cpp index 8e648614c2..048ab9fdf9 100644 --- a/firmware/controllers/engine_cycle/main_trigger_callback.cpp +++ b/firmware/controllers/engine_cycle/main_trigger_callback.cpp @@ -398,8 +398,13 @@ void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp) { return; } - bool limitedSpark = !engine->limpManager.allowIgnition(); - bool limitedFuel = !engine->limpManager.allowInjection(); + LimpState limitedSparkState = engine->limpManager.allowIgnition(); + engine->outputChannels.sparkCutReason = (int8_t)limitedSparkState.reason; + bool limitedSpark = !limitedSparkState.value; + + LimpState limitedFuelState = engine->limpManager.allowInjection(); + engine->outputChannels.fuelCutReason = (int8_t)limitedFuelState.reason; + bool limitedFuel = !limitedFuelState.value; #if EFI_LAUNCH_CONTROL if (engine->launchController.isLaunchCondition && !limitedSpark && !limitedFuel) { diff --git a/firmware/controllers/limp_manager.cpp b/firmware/controllers/limp_manager.cpp index 3e341f2446..648ac129ab 100644 --- a/firmware/controllers/limp_manager.cpp +++ b/firmware/controllers/limp_manager.cpp @@ -9,23 +9,23 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) { // User-configured hard RPM limit if (rpm > engineConfiguration->rpmHardLimit) { if (engineConfiguration->cutFuelOnHardLimit) { - allowFuel.clear(); + allowFuel.clear(ClearReason::HardLimit); } if (engineConfiguration->cutSparkOnHardLimit) { - allowSpark.clear(); + allowSpark.clear(ClearReason::HardLimit); } } // Force fuel limiting on the fault rev limit if (rpm > m_faultRevLimit) { - allowFuel.clear(); + allowFuel.clear(ClearReason::FaultRevLimit); } // Limit fuel only on boost pressure (limiting spark bends valves) if (engineConfiguration->boostCutPressure != 0) { if (Sensor::getOrZero(SensorType::Map) > engineConfiguration->boostCutPressure) { - allowFuel.clear(); + allowFuel.clear(ClearReason::BoostCut); } } @@ -51,7 +51,7 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) { // If time is up, the sensor works, and no pressure, kill the engine. if (isTimedOut && !m_hadOilPressureAfterStart) { - allowFuel.clear(); + allowFuel.clear(ClearReason::OilPressure); } } } else { @@ -63,7 +63,7 @@ void LimpManager::updateState(int rpm, efitick_t nowNt) { /** * todo: we need explicit clarification on why do we cut fuel but do not cut spark here! */ - allowFuel.clear(); + allowFuel.clear(ClearReason::StopRequested); } if (!engine->isMainRelayEnabled()) { @@ -79,15 +79,15 @@ todo AndreiKA this change breaks 22 unit tests? } void LimpManager::etbProblem() { - m_allowEtb.clear(); + m_allowEtb.clear(ClearReason::EtbProblem); setFaultRevLimit(1500); } void LimpManager::fatalError() { - m_allowEtb.clear(); - m_allowIgnition.clear(); - m_allowInjection.clear(); - m_allowTriggerInput.clear(); + m_allowEtb.clear(ClearReason::Fatal); + m_allowIgnition.clear(ClearReason::Fatal); + m_allowInjection.clear(ClearReason::Fatal); + m_allowTriggerInput.clear(ClearReason::Fatal); setFaultRevLimit(0); } @@ -106,10 +106,22 @@ bool LimpManager::allowTriggerInput() const { return m_allowTriggerInput; } -bool LimpManager::allowInjection() const { - return m_transientAllowInjection && m_allowInjection; +LimpState LimpManager::allowInjection() const { + if (!m_allowInjection) { + return {false, m_allowInjection.clearReason}; + } + if (!m_transientAllowInjection) { + return {false, ClearReason::Fatal}; + } + return {true, ClearReason::None}; } -bool LimpManager::allowIgnition() const { - return m_transientAllowIgnition && m_allowIgnition; +LimpState LimpManager::allowIgnition() const { + if (!m_allowIgnition) { + return {false, m_allowIgnition.clearReason}; + } + if (!m_transientAllowIgnition) { + return {false, ClearReason::Fatal}; + } + return {true, ClearReason::None}; } diff --git a/firmware/controllers/limp_manager.h b/firmware/controllers/limp_manager.h index a145e8f892..d0994067dd 100644 --- a/firmware/controllers/limp_manager.h +++ b/firmware/controllers/limp_manager.h @@ -4,24 +4,52 @@ #include +enum class ClearReason : uint8_t { + None, // 0 + Fatal, + Settings, + HardLimit, + FaultRevLimit, + BoostCut, // 5 + OilPressure, + StopRequested, + EtbProblem, +}; + // Only allows clearing the value, but never resetting it. class Clearable { public: Clearable() : m_value(true) {} - Clearable(bool value) : m_value(value) {} + Clearable(bool value) : m_value(value) { + if (!m_value) { + clearReason = ClearReason::Settings; + } + } - void clear() { + void clear(ClearReason clearReason) { m_value = false; + this->clearReason = clearReason; } operator bool() const { return m_value; } + ClearReason clearReason = ClearReason::None; private: bool m_value = true; }; +struct LimpState { + const bool value; + const ClearReason reason; + + // Implicit conversion operator to bool, so you can do things like if (myResult) { ... } + constexpr explicit operator bool() const { + return value; + } +}; + class LimpManager { public: // This is called from periodicFastCallback to update internal state @@ -30,8 +58,8 @@ public: // Other subsystems call these APIs to determine their behavior bool allowElectronicThrottle() const; - bool allowInjection() const; - bool allowIgnition() const; + LimpState allowInjection() const; + LimpState allowIgnition() const; bool allowTriggerInput() const; diff --git a/firmware/controllers/lua/generated/output_lookup_generated.cpp b/firmware/controllers/lua/generated/output_lookup_generated.cpp index 1be0eeb589..b13d38ffb1 100644 --- a/firmware/controllers/lua/generated/output_lookup_generated.cpp +++ b/firmware/controllers/lua/generated/output_lookup_generated.cpp @@ -316,6 +316,10 @@ float getOutputValueByName(const char *name) { return engine->outputChannels.m_requested_pump; if (strEqualCaseInsensitive(name, "boostControlTarget")) return engine->outputChannels.boostControlTarget; + if (strEqualCaseInsensitive(name, "sparkCutReason")) + return engine->outputChannels.sparkCutReason; + if (strEqualCaseInsensitive(name, "fuelCutReason")) + return engine->outputChannels.fuelCutReason; if (strEqualCaseInsensitive(name, "fuel_requested_percent")) return engine->outputChannels.fuel_requested_percent; if (strEqualCaseInsensitive(name, "fuel_requested_percent_pi")) diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index bcaeb3c677..03bd2f99a9 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -1064,6 +1064,7 @@ gaugeCategory = VVT vvtTargets4Gauge = vvtTargets4, @@GAUGE_NAME_VVT_TARGET_B2E@@, "deg", -60, 60, -60, -60, 60, 60, 0, 0 gaugeCategory = Ignition +sparkCutReasonGauge = sparkCutReason,"Spark Cut Code", "code", 0.0,0.0, 0.0,0.0, 0.0,0.0, 0,0 ignadvGauge = ignitionAdvance, "Ignition timing", "degrees", -100, 100, -999, -999, 999, 999, 1, 1 dwellGauge = sparkDwellValue, "Dwell", "mSec", 0, 10, 0.5, 1.0, 6.0, 8.0, 1, 1 coilDutyCycleGauge = coilDutyCycle, @@GAUGE_NAME_DWELL_DUTY@@, "%", 0, 110, 0, 0, 90, 100, 1, 1 @@ -1077,6 +1078,7 @@ gaugeCategory = Acceleration Enrichment gaugeCategory = Fueling ;Name Var Title Units Lo Hi LoD LoW HiW HiD vd ld +fuelCutReasonGauge = fuelCutReason,"Fuel Cut Code", "code", 0.0,0.0, 0.0,0.0, 0.0,0.0, 0,0 tChargeGauge = tCharge, @@GAUGE_NAME_FUEL_CHARGE_TEMP@@, "C", -40, 140, -15, 1, 95, 110, 1, 1 baroCorrectionGauge = baroCorrection,@@GAUGE_NAME_FUEL_BARO_CORR@@, "ratio", 0.5, 1.5, 0.6, 0.7, 1.3, 1.4, 1, 1 crankingFuelGauge = crankingFuelMs, @@GAUGE_NAME_FUEL_CRANKING@@, "mg", 0, 100, 0, 0, 100, 100, 3, 1