GCC Code Coverage Report


Directory: ./
File: firmware/controllers/actuators/idle_thread.h
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 60.0% 6 0 10
Functions: 60.0% 3 0 5
Branches: 31.2% 5 0 16
Decisions: -% 0 - 0

Line Branch Decision Exec Source
1 /**
2 * @file idle_thread.h
3 * @brief Idle Valve Control thread
4 *
5 * @date May 23, 2013
6 * @author Andrey Belomutskiy, (c) 2012-2020
7 */
8
9 #pragma once
10
11 #include "engine_module.h"
12 #include "rusefi_types.h"
13 #include "efi_pid.h"
14 #include "sensor.h"
15 #include "idle_state_generated.h"
16 #include "closed_loop_idle.h"
17 #include "biquad.h"
18
19 struct IIdleController {
20 enum class Phase : uint8_t {
21 Cranking, // Below cranking threshold
22 Idling, // Below idle RPM, off throttle
23 Coasting, // Off throttle but above idle RPM
24 CrankToIdleTaper, // Taper between cranking and idling
25 Running, // On throttle
26 };
27
28 struct TargetInfo {
29 // Target speed for closed loop control
30 float ClosedLoopTarget;
31
32 // If below this speed, enter idle
33 float IdleEntryRpm;
34
35 // If above this speed, exit idle
36 float IdleExitRpm;
37
38 7 bool operator==(const TargetInfo& other) const {
39
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 return ClosedLoopTarget == other.ClosedLoopTarget && IdleEntryRpm == other.IdleEntryRpm && IdleExitRpm == other.IdleExitRpm;
40 }
41 };
42
43 virtual Phase determinePhase(float rpm, TargetInfo targetRpm, SensorResult tps, float vss, float crankingTaperFraction) = 0;
44 virtual TargetInfo getTargetRpm(float clt) = 0;
45 virtual float getCrankingOpenLoop(float clt) const = 0;
46 virtual float getRunningOpenLoop(IIdleController::Phase phase, float rpm, float clt, SensorResult tps) = 0;
47 virtual float getOpenLoop(Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction) = 0;
48 virtual float getClosedLoop(Phase phase, float tps, float rpm, float target) = 0;
49 virtual float getCrankingTaperFraction(float clt) const = 0;
50 virtual bool isIdlingOrTaper() const = 0;
51 virtual bool isCoastingAdvance() const = 0;
52 virtual float getIdleTimingAdjustment(float rpm) = 0;
53 virtual Phase getCurrentPhase() const = 0;
54 };
55
56 class IdleController : public IIdleController, public EngineModule, public idle_state_s {
57 public:
58 // Mockable<> interface
59 using interface_t = IdleController;
60
61 void init();
62
63 float getIdlePosition(float rpm);
64
65 // TARGET DETERMINATION
66 TargetInfo getTargetRpm(float clt) override;
67
68 // PHASE DETERMINATION: what is the driver trying to do right now?
69 Phase determinePhase(float rpm, TargetInfo targetRpm, SensorResult tps, float vss, float crankingTaperFraction) override;
70 float getCrankingTaperFraction(float clt) const override;
71
72 // OPEN LOOP CORRECTIONS
73 percent_t getCrankingOpenLoop(float clt) const override;
74 percent_t getRunningOpenLoop(IIdleController::Phase phase, float rpm, float clt, SensorResult tps) override;
75 percent_t getOpenLoop(Phase phase, float rpm, float clt, SensorResult tps, float crankingTaperFraction) override;
76
77 float getIdleTimingAdjustment(float rpm) override;
78 float getIdleTimingAdjustment(float rpm, float targetRpm, Phase phase);
79
80 // CLOSED LOOP CORRECTION
81 float getClosedLoop(IIdleController::Phase phase, float tpsPos, float rpm, float targetRpm) override;
82
83 void onConfigurationChange(engine_configuration_s const * previousConfig) override final;
84 void onFastCallback() override final;
85 void onEngineStop() override final;
86
87 // Allow querying state from outside
88 1093 bool isIdlingOrTaper() const override {
89
2/6
✓ Branch 0 taken 1093 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1093 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1093 return m_lastPhase == Phase::Idling || (engineConfiguration->useSeparateIdleTablesForCrankingTaper && m_lastPhase == Phase::CrankToIdleTaper);
90 }
91
92 bool isCoastingAdvance() const override {
93 return m_lastPhase == Phase::Coasting && engineConfiguration->useIdleAdvanceWhileCoasting;
94 }
95
96 Phase getCurrentPhase() const override {
97 return m_lastPhase;
98 }
99
100 PidIndustrial industrialWithOverrideIdlePid;
101
102 #if EFI_IDLE_PID_CIC
103 // Use PID with CIC integrator
104 PidCic idleCicPid;
105 #endif //EFI_IDLE_PID_CIC
106
107 4104 Pid * getIdlePid() {
108 #if EFI_IDLE_PID_CIC
109 if (engineConfiguration->useCicPidForIdle) {
110 return &idleCicPid;
111 }
112 #endif /* EFI_IDLE_PID_CIC */
113 4104 return &industrialWithOverrideIdlePid;
114 }
115
116 void updateLtit(float rpm, float clt, bool acActive, bool fan1Active, bool fan2Active, float idleIntegral);
117 void onIgnitionStateChanged(bool ignitionOn) override;
118
119 private:
120
121 // These are stored by getIdlePosition() and used by getIdleTimingAdjustment()
122 Phase m_lastPhase = Phase::Cranking;
123 efitimeus_t restoreAfterPidResetTimeUs = 0;
124 // used by 'dashpot' (hold+decay) logic for iacByTpsTaper
125 efitimeus_t lastTimeRunningUs = 0;
126 // used by "soft" idle entry
127 float m_crankTaperEndTime = 0.0f;
128 float m_idleTimingSoftEntryEndTime = 0.0f;
129
130 Timer m_timeInIdlePhase;
131
132 // This is stored by getClosedLoop and used in case we want to "do nothing"
133 float m_lastAutomaticPosition = 0;
134
135 Pid m_timingPid;
136 float m_modeledFlowIdleTiming = 0;
137 Biquad m_timingHpf;
138 };
139
140 percent_t getIdlePosition();
141
142 void applyIACposition(percent_t position);
143 void setManualIdleValvePosition(int positionPercent);
144
145 void startIdleThread();
146 void setDefaultIdleParameters();
147 void startIdleBench(void);
148 void setTargetIdleRpm(int value);
149 void startSwitchPins();
150 void stopSwitchPins();
151