Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | #include "pch.h" | |||
2 | ||||
3 | #include "adc_subscription.h" | |||
4 | #include "functional_sensor.h" | |||
5 | #include "redundant_sensor.h" | |||
6 | #include "redundant_ford_tps.h" | |||
7 | #include "proxy_sensor.h" | |||
8 | #include "linear_func.h" | |||
9 | #include "tps.h" | |||
10 | #include "auto_generated_sensor.h" | |||
11 | #include "defaults.h" | |||
12 | ||||
13 | struct TpsConfig { | |||
14 | adc_channel_e channel; | |||
15 | float closed; | |||
16 | float open; | |||
17 | float min; | |||
18 | float max; | |||
19 | }; | |||
20 | ||||
21 | 35 | PUBLIC_API_WEAK float getFuncPairAllowedSplit() { | ||
22 | 35 | return 0.5f; | ||
23 | } | |||
24 | ||||
25 | class FuncSensPair { | |||
26 | public: | |||
27 | AdcSubscriptionEntry *adc = nullptr; | |||
28 | 8 | FuncSensPair(float divideInput, SensorType type) | ||
29 | 8 | : m_func(divideInput) | ||
30 | 8 | , m_sens(type, MS2NT(10)) | ||
31 | { | |||
32 | 8 | m_sens.setFunction(m_func); | ||
33 | 8 | } | ||
34 | ||||
35 | 113 | bool init(const TpsConfig& cfg) { | ||
36 | // If the configuration was invalid, don't continue to configure the sensor | |||
37 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 33 times.
|
2/2✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 33 times.
|
113 | if (!configure(cfg)) { |
38 | 78 | return false; | ||
39 | } | |||
40 | ||||
41 | 33 | adc = AdcSubscription::SubscribeSensor(m_sens, cfg.channel, /*lowpassCutoffHz*/ 200); | ||
42 | ||||
43 | 33 | return m_sens.Register(); | ||
44 | } | |||
45 | ||||
46 | 16 | void deinit() { | ||
47 | 16 | AdcSubscription::UnsubscribeSensor(m_sens); | ||
48 | 16 | } | ||
49 | ||||
50 | 6 | SensorType type() const { | ||
51 | 6 | return m_sens.type(); | ||
52 | } | |||
53 | ||||
54 | 113 | const char* name() const { | ||
55 | 113 | return m_sens.getSensorName(); | ||
56 | } | |||
57 | ||||
58 | private: | |||
59 | 113 | bool configure(const TpsConfig& cfg) { | ||
60 | // Only configure if we have a channel | |||
61 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 35 times.
|
2/2✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 35 times.
|
113 | if (!isAdcChannelValid(cfg.channel)) { |
62 | #if EFI_UNIT_TEST | |||
63 | 78 | printf("Configured NO hardware %s\n", name()); | ||
64 | #endif | |||
65 | 78 | return false; | ||
66 | } | |||
67 | ||||
68 | 35 | float scaledClosed = cfg.closed / m_func.getDivideInput(); | ||
69 | 35 | float scaledOpen = cfg.open / m_func.getDivideInput(); | ||
70 | ||||
71 | 35 | float split = std::abs(scaledOpen - scaledClosed); | ||
72 | ||||
73 | // If the voltage for closed vs. open is very near, something is wrong with your calibration | |||
74 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 33 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 33 times.
|
35 | if (split < getFuncPairAllowedSplit()) { |
75 | 2 | firmwareError(ObdCode::OBD_TPS_Configuration, "\"%s\" problem: open %.2f/closed %.2f cal values are too close together. Check your calibration and wiring!", name(), | ||
76 | 2 | cfg.open, | ||
77 | 2 | cfg.closed); | ||
78 | ✗ | return false; | ||
79 | } | |||
80 | ||||
81 | 33 | m_func.configure( | ||
82 | 33 | cfg.closed, 0, | ||
83 | 33 | cfg.open, POSITION_FULLY_OPEN, | ||
84 | 33 | cfg.min, cfg.max | ||
85 | ); | |||
86 | ||||
87 | #if EFI_UNIT_TEST | |||
88 | 33 | printf("Configured YES %s\n", name()); | ||
89 | #endif | |||
90 | 33 | return true; | ||
91 | } | |||
92 | ||||
93 | LinearFunc m_func; | |||
94 | FunctionalSensor m_sens; | |||
95 | }; | |||
96 | ||||
97 | struct RedundantPair { | |||
98 | public: | |||
99 | 3 | RedundantPair(FuncSensPair& pri, FuncSensPair& sec, SensorType outputType) | ||
100 | 3 | : m_pri(pri) | ||
101 | 3 | , m_sec(sec) | ||
102 | 3 | , m_redund(outputType, m_pri.type(), m_sec.type()) | ||
103 | { | |||
104 | 3 | } | ||
105 | ||||
106 | 55 | void init(bool isFordTps, RedundantFordTps* fordTps, float secondaryMaximum, const TpsConfig& primary, const TpsConfig& secondary, bool allowIdenticalSensors = false) { | ||
107 | 55 | bool hasFirst = m_pri.init(primary); | ||
108 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 22 times.
|
2/2✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 22 times.
|
53 | if (!hasFirst) { |
109 | // no input if we have no first channel | |||
110 | 31 | return; | ||
111 | } | |||
112 | ||||
113 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 22 times.
✗ Decision 'false' not taken.
|
22 | if (!allowIdenticalSensors) { |
114 | // Check that the primary and secondary aren't too close together - if so, the user may have done | |||
115 | // an unsafe thing where they wired a single sensor to both inputs. Don't do that! | |||
116 |
3/4✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 11 times.
|
22 | bool hasBothSensors = isAdcChannelValid(primary.channel) && isAdcChannelValid(secondary.channel); | |
117 | 22 | bool tooCloseClosed = std::abs(primary.closed - secondary.closed) < 0.2f; | ||
118 | 22 | bool tooCloseOpen = std::abs(primary.open - secondary.open) < 0.2f; | ||
119 | ||||
120 |
3/6✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 22 times.
|
22 | if (hasBothSensors && tooCloseClosed && tooCloseOpen) { |
121 | ✗ | firmwareError(ObdCode::OBD_TPS_Configuration, "Configuration for redundant pair %s/%s are too similar - did you wire one sensor to both inputs...?", m_pri.name(), m_sec.name()); | ||
122 | ✗ | return; | ||
123 | } | |||
124 | } | |||
125 | ||||
126 | 22 | bool hasSecond = m_sec.init(secondary); | ||
127 | ||||
128 |
3/6✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 22 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 22 times.
|
22 | if (engineConfiguration->etbSplit <= 0 || engineConfiguration->etbSplit > MAX_TPS_PPS_DISCREPANCY) { |
129 | ✗ | engineConfiguration->etbSplit = MAX_TPS_PPS_DISCREPANCY; | ||
130 | } | |||
131 | ||||
132 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 18 times.
|
22 | if (isFordTps && fordTps) { |
133 | // we have a secondary | |||
134 | 4 | fordTps->configure(engineConfiguration->etbSplit, secondaryMaximum); | ||
135 | 4 | fordTps->Register(); | ||
136 | } else { | |||
137 | // not ford TPS | |||
138 | 18 | m_redund.configure(engineConfiguration->etbSplit, !hasSecond); | ||
139 | #if EFI_UNIT_TEST | |||
140 | 18 | printf("init m_redund.Register() %s\n", getSensorType(m_redund.type())); | ||
141 | #endif | |||
142 | 18 | m_redund.Register(); | ||
143 | } | |||
144 | } | |||
145 | ||||
146 | 6 | void deinit(bool isFordTps, RedundantFordTps* fordTps) { | ||
147 | 6 | m_pri.deinit(); | ||
148 | 6 | m_sec.deinit(); | ||
149 | ||||
150 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 6 times.
|
6 | if (isFordTps && fordTps) { |
151 | ✗ | fordTps->unregister(); | ||
152 | } else { | |||
153 | 6 | m_redund.unregister(); | ||
154 | } | |||
155 | ||||
156 | 6 | } | ||
157 | ||||
158 | // technical debt: oop violation: this method is specific to PPS usage | |||
159 | 522954 | void updateUnfilteredRawValues() { | ||
160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 522954 times.
|
522954 | engine->outputChannels.rawRawPpsPrimary = m_pri.adc == nullptr ? 0 : m_pri.adc->sensorVolts; | |
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 522954 times.
|
522954 | engine->outputChannels.rawRawPpsSecondary = m_sec.adc == nullptr ? 0 : m_sec.adc->sensorVolts; | |
162 | 522954 | } | ||
163 | ||||
164 | private: | |||
165 | FuncSensPair& m_pri; | |||
166 | FuncSensPair& m_sec; | |||
167 | ||||
168 | RedundantSensor m_redund; | |||
169 | }; | |||
170 | ||||
171 | static FuncSensPair tps1p(TPS_TS_CONVERSION, SensorType::Tps1Primary); | |||
172 | static FuncSensPair tps1s(TPS_TS_CONVERSION, SensorType::Tps1Secondary); | |||
173 | static FuncSensPair tps2p(TPS_TS_CONVERSION, SensorType::Tps2Primary); | |||
174 | static FuncSensPair tps2s(TPS_TS_CONVERSION, SensorType::Tps2Secondary); | |||
175 | ||||
176 | // Used in case of "normal", non-Ford ETB TPS | |||
177 | static RedundantPair analogTps1(tps1p, tps1s, SensorType::Tps1); | |||
178 | static RedundantPair tps2(tps2p, tps2s, SensorType::Tps2); | |||
179 | ||||
180 | #if EFI_SENT_SUPPORT | |||
181 | SentTps sentTps; | |||
182 | #endif | |||
183 | ||||
184 | // Used only in case of weird Ford-style ETB TPS | |||
185 | static RedundantFordTps fordTps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary); | |||
186 | static RedundantFordTps fordTps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary); | |||
187 | static RedundantFordTps fordPps(SensorType::AcceleratorPedalUnfiltered, SensorType::AcceleratorPedalPrimary, SensorType::AcceleratorPedalSecondary); | |||
188 | ||||
189 | // Pedal sensors and redundancy | |||
190 | static FuncSensPair pedalPrimary(1, SensorType::AcceleratorPedalPrimary); | |||
191 | static FuncSensPair pedalSecondary(1, SensorType::AcceleratorPedalSecondary); | |||
192 | static RedundantPair pedal(pedalPrimary, pedalSecondary, SensorType::AcceleratorPedalUnfiltered); | |||
193 | ||||
194 | 522954 | void updateUnfilteredRawPedal() { | ||
195 | 522954 | pedal.updateUnfilteredRawValues(); | ||
196 | 522954 | } | ||
197 | ||||
198 | // This sensor indicates the driver's throttle intent - Pedal if we have one, TPS if not. | |||
199 | static ProxySensor driverIntent(SensorType::DriverThrottleIntent); | |||
200 | static ProxySensor ppsFilterSensor(SensorType::AcceleratorPedal); | |||
201 | ||||
202 | // These sensors are TPS-like, so handle them in here too | |||
203 | static FuncSensPair wastegate(1, SensorType::WastegatePosition); | |||
204 | static FuncSensPair idlePos(PACK_MULT_VOLTAGE, SensorType::IdlePosition); | |||
205 | ||||
206 | 20 | void initTps() { | ||
207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | criticalAssertVoid(engineConfiguration != nullptr, "null engineConfiguration"); | |
208 | 20 | percent_t minTpsPps = engineConfiguration->tpsErrorDetectionTooLow; | ||
209 | 20 | percent_t maxTpsPps = engineConfiguration->tpsErrorDetectionTooHigh; | ||
210 | ||||
211 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 20 times.
✗ Decision 'false' not taken.
|
20 | if (!engineConfiguration->consumeObdSensors) { |
212 | 20 | bool isFordTps = engineConfiguration->useFordRedundantTps; | ||
213 | 20 | bool isFordPps = engineConfiguration->useFordRedundantPps; | ||
214 | ||||
215 | 20 | float tpsSecondaryMaximum = engineConfiguration->tpsSecondaryMaximum; | ||
216 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 20 times.
✗ Decision 'false' not taken.
|
20 | if (tpsSecondaryMaximum < 20) { |
217 | // don't allow <20% split point | |||
218 | 20 | tpsSecondaryMaximum = 20; | ||
219 | } | |||
220 | ||||
221 | ||||
222 | #if EFI_SENT_SUPPORT | |||
223 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 19 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 19 times.
|
20 | if (isDigitalTps1()) { |
224 | 1 | sentTps.Register(); | ||
225 | } else | |||
226 | #endif | |||
227 | { | |||
228 | 40 | analogTps1.init(isFordTps, &fordTps1, tpsSecondaryMaximum, | ||
229 |
1/1✓ Branch 1 taken 17 times.
|
19 | { engineConfiguration->tps1_1AdcChannel, (float)engineConfiguration->tpsMin, (float)engineConfiguration->tpsMax, minTpsPps, maxTpsPps }, | |
230 | 19 | { engineConfiguration->tps1_2AdcChannel, (float)engineConfiguration->tps1SecondaryMin, (float)engineConfiguration->tps1SecondaryMax, minTpsPps, maxTpsPps } | ||
231 | ); | |||
232 | } | |||
233 | ||||
234 | 36 | tps2.init(isFordTps, &fordTps2, tpsSecondaryMaximum, | ||
235 |
1/1✓ Branch 1 taken 18 times.
|
18 | { engineConfiguration->tps2_1AdcChannel, (float)engineConfiguration->tps2Min, (float)engineConfiguration->tps2Max, minTpsPps, maxTpsPps }, | |
236 | 18 | { engineConfiguration->tps2_2AdcChannel, (float)engineConfiguration->tps2SecondaryMin, (float)engineConfiguration->tps2SecondaryMax, minTpsPps, maxTpsPps } | ||
237 | ); | |||
238 | ||||
239 | 18 | float ppsSecondaryMaximum = engineConfiguration->ppsSecondaryMaximum; | ||
240 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 18 times.
✗ Decision 'false' not taken.
|
18 | if (ppsSecondaryMaximum < 20) { |
241 | // don't allow <20% split point | |||
242 | 18 | ppsSecondaryMaximum = 20; | ||
243 | } | |||
244 | ||||
245 | // Pedal sensors | |||
246 | 18 | pedal.init(isFordPps, &fordPps, ppsSecondaryMaximum, | ||
247 |
1/1✓ Branch 1 taken 18 times.
|
18 | { engineConfiguration->throttlePedalPositionAdcChannel, engineConfiguration->throttlePedalUpVoltage, engineConfiguration->throttlePedalWOTVoltage, minTpsPps, maxTpsPps }, | |
248 | 18 | { engineConfiguration->throttlePedalPositionSecondAdcChannel, engineConfiguration->throttlePedalSecondaryUpVoltage, engineConfiguration->throttlePedalSecondaryWOTVoltage, minTpsPps, maxTpsPps }, | ||
249 | 18 | engineConfiguration->allowIdenticalPps | ||
250 | ); | |||
251 | 18 | ppsFilterSensor.setProxiedSensor(SensorType::AcceleratorPedalUnfiltered); | ||
252 | 18 | ppsFilterSensor.setConverter([](SensorResult arg) { | ||
253 |
2/2✓ Branch 1 taken 205 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 205 times.
✓ Decision 'false' taken 2 times.
|
207 | if (!arg) { |
254 | 205 | return arg; | ||
255 | } | |||
256 | static ExpAverage ppsExpAverage; | |||
257 | 2 | ppsExpAverage.setSmoothingFactor(engineConfiguration->ppsExpAverageAlpha); | ||
258 |
1/1✓ Branch 2 taken 2 times.
|
2 | SensorResult result = ppsExpAverage.initOrAverage(arg.Value); | |
259 | 2 | return result; | ||
260 | }); | |||
261 | 18 | ppsFilterSensor.Register(); | ||
262 | ||||
263 | // TPS-like stuff that isn't actually a TPS | |||
264 |
1/1✓ Branch 2 taken 18 times.
|
18 | wastegate.init({ engineConfiguration->wastegatePositionSensor, engineConfiguration->wastegatePositionClosedVoltage, engineConfiguration->wastegatePositionOpenedVoltage, minTpsPps, maxTpsPps }); | |
265 |
1/1✓ Branch 2 taken 18 times.
|
18 | idlePos.init({ engineConfiguration->idlePositionChannel, (float)engineConfiguration->idlePositionMin, (float)engineConfiguration->idlePositionMax, minTpsPps, maxTpsPps }); | |
266 | } | |||
267 | ||||
268 | // Route the pedal or TPS to driverIntent as appropriate | |||
269 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 10 times.
|
18 | if (isAdcChannelValid(engineConfiguration->throttlePedalPositionAdcChannel)) { |
270 | 8 | driverIntent.setProxiedSensor(SensorType::AcceleratorPedal); | ||
271 | } else { | |||
272 | 10 | driverIntent.setProxiedSensor(SensorType::Tps1); | ||
273 | } | |||
274 | ||||
275 | 18 | driverIntent.Register(); | ||
276 | } | |||
277 | ||||
278 | 2 | void deinitTps() { | ||
279 | 2 | bool isFordTps = activeConfiguration.useFordRedundantTps; | ||
280 | 2 | bool isFordPps = activeConfiguration.useFordRedundantPps; | ||
281 | ||||
282 | 2 | analogTps1.deinit(isFordTps, &fordTps1); | ||
283 | 2 | tps2.deinit(isFordTps, &fordTps2); | ||
284 | 2 | pedal.deinit(isFordPps, &fordPps); | ||
285 | ||||
286 | #if EFI_SENT_SUPPORT | |||
287 | 2 | sentTps.unregister(); | ||
288 | #endif | |||
289 | ||||
290 | 2 | wastegate.deinit(); | ||
291 | 2 | idlePos.deinit(); | ||
292 | 2 | } | ||
293 |