| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | // Deceleration Fuel Cut-off | |||
| 2 | ||||
| 3 | #include "pch.h" | |||
| 4 | ||||
| 5 | #include "dfco.h" | |||
| 6 | #include "closed_loop_fuel.h" | |||
| 7 | ||||
| 8 | 1101 | bool DfcoController::getState() const { | ||
| 9 |
2/2✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 17 times.
|
2/2✓ Decision 'true' taken 1084 times.
✓ Decision 'false' taken 17 times.
|
1101 | if (!engineConfiguration->coastingFuelCutEnabled) { |
| 10 | 1084 | return false; | ||
| 11 | } | |||
| 12 | ||||
| 13 |
2/3✓ Branch 1 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 17 times.
|
17 | if (checkIfTuningVeNow()) { |
| 14 | ✗ | return false; | ||
| 15 | } | |||
| 16 | ||||
| 17 |
1/1✓ Branch 2 taken 17 times.
|
17 | const auto tps = Sensor::get(SensorType::DriverThrottleIntent); | |
| 18 |
1/1✓ Branch 2 taken 17 times.
|
17 | const auto clt = Sensor::get(SensorType::Clt); | |
| 19 |
1/1✓ Branch 2 taken 17 times.
|
17 | const auto map = Sensor::get(SensorType::Map); | |
| 20 | ||||
| 21 | // If some sensor is broken, inhibit DFCO | |||
| 22 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 17 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 17 times.
|
17 | if (!tps || !clt) { |
| 23 | ✗ | return false; | ||
| 24 | } | |||
| 25 | ||||
| 26 | // MAP sensor is optional, only inhibit if the sensor is present but broken | |||
| 27 |
1/1✓ Branch 1 taken 17 times.
|
17 | bool hasMap = Sensor::hasSensor(SensorType::Map); | |
| 28 |
3/6✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 17 times.
|
17 | if (hasMap && !map) { |
| 29 | ✗ | return false; | ||
| 30 | } | |||
| 31 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 17 times.
|
17 | if (engine->engineState.lua.disableDecelerationFuelCutOff) { |
| 32 | // Lua might have reasons to disable | |||
| 33 | ✗ | return false; | ||
| 34 | } | |||
| 35 | ||||
| 36 |
1/1✓ Branch 1 taken 17 times.
|
17 | float rpm = Sensor::getOrZero(SensorType::Rpm); | |
| 37 |
1/1✓ Branch 1 taken 17 times.
|
17 | float vss = Sensor::getOrZero(SensorType::VehicleSpeed); | |
| 38 | ||||
| 39 |
3/5✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
|
17 | bool mapActivate = !hasMap || !m_mapHysteresis.test(map.value_or(0), engineConfiguration->coastingFuelCutMap + 1, engineConfiguration->coastingFuelCutMap - 1); | |
| 40 | 17 | bool tpsActivate = tps.Value < engineConfiguration->coastingFuelCutTps; | ||
| 41 | 17 | bool cltActivate = clt.Value > engineConfiguration->coastingFuelCutClt; | ||
| 42 | // True if throttle, MAP, and CLT are all acceptable for DFCO to occur | |||
| 43 |
5/6✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 1 time.
|
17 | bool dfcoAllowed = mapActivate && tpsActivate && cltActivate; | |
| 44 | ||||
| 45 | 17 | bool rpmActivate = (rpm > engineConfiguration->coastingFuelCutRpmHigh); | ||
| 46 | 17 | bool rpmDeactivate = (rpm < engineConfiguration->coastingFuelCutRpmLow); | ||
| 47 | ||||
| 48 | // greater than or equal so that it works if both config params are set to 0 | |||
| 49 | 17 | bool vssActivate = (vss >= engineConfiguration->coastingFuelCutVssHigh); | ||
| 50 | 17 | bool vssDeactivate = (vss < engineConfiguration->coastingFuelCutVssLow); | ||
| 51 | ||||
| 52 | // RPM is high enough, VSS high enough, and DFCO allowed | |||
| 53 |
6/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 3 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 10 times.
|
17 | if (dfcoAllowed && rpmActivate && vssActivate) { |
| 54 | 7 | return true; | ||
| 55 | } | |||
| 56 | ||||
| 57 | // RPM too low, VSS too low, or DFCO not allowed | |||
| 58 |
6/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 4 times.
|
2/2✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 4 times.
|
10 | if (!dfcoAllowed || rpmDeactivate || vssDeactivate) { |
| 59 | 6 | return false; | ||
| 60 | } | |||
| 61 | ||||
| 62 | // No conditions hit, no change to state (provides hysteresis) | |||
| 63 | 4 | return m_isDfco; | ||
| 64 | } | |||
| 65 | ||||
| 66 | 1101 | void DfcoController::update() { | ||
| 67 | // Run state machine | |||
| 68 | 1101 | bool newState = getState(); | ||
| 69 | ||||
| 70 | // If fuel is cut, reset the timer | |||
| 71 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1093 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1093 times.
|
1101 | if (newState) { |
| 72 | 8 | m_timeSinceCut.reset(); | ||
| 73 | } else { | |||
| 74 | // If fuel is not cut, reset the not-cut timer | |||
| 75 | 1093 | m_timeSinceNoCut.reset(); | ||
| 76 | } | |||
| 77 | ||||
| 78 | 1101 | m_isDfco = newState; | ||
| 79 | 1101 | } | ||
| 80 | ||||
| 81 | 532184 | bool DfcoController::cutFuel() const { | ||
| 82 | 532184 | float cutDelay = engineConfiguration->dfcoDelay; | ||
| 83 | ||||
| 84 | // 0 delay means cut immediately, aka timer has always expired | |||
| 85 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 532179 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 4 times.
|
532184 | bool hasBeenDelay = (cutDelay == 0) || m_timeSinceNoCut.hasElapsedSec(cutDelay); | |
| 86 | ||||
| 87 |
4/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 532176 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
|
532184 | return m_isDfco && hasBeenDelay; | |
| 88 | } | |||
| 89 | ||||
| 90 | 1 | float DfcoController::getTimeSinceCut() const { | ||
| 91 | 1 | return m_timeSinceCut.getElapsedSeconds(); | ||
| 92 | } | |||
| 93 | ||||
| 94 | 941 | float DfcoController::getTimingRetard() const { | ||
| 95 | 941 | float cutTiming = clampF(0, engineConfiguration->dfcoRetardDeg, 30); | ||
| 96 | ||||
| 97 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 933 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 933 times.
|
941 | if (m_isDfco) { |
| 98 | // While cut, always retard timing | |||
| 99 | 8 | return cutTiming; | ||
| 100 | } else { | |||
| 101 | 933 | float timeSinceCut = m_timeSinceCut.getElapsedSeconds(); | ||
| 102 | 933 | float rampInTime = engineConfiguration->dfcoRetardRampInTime; | ||
| 103 | ||||
| 104 |
2/2✓ Branch 0 taken 926 times.
✓ Branch 1 taken 7 times.
|
2/2✓ Decision 'true' taken 926 times.
✓ Decision 'false' taken 7 times.
|
933 | if (timeSinceCut > rampInTime) { |
| 105 | // Normal operation, no retard | |||
| 106 | 926 | return 0; | ||
| 107 | } else { | |||
| 108 | 7 | return interpolateClamped(0, cutTiming, 0.5, 0, timeSinceCut); | ||
| 109 | } | |||
| 110 | } | |||
| 111 | } | |||
| 112 |