| 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 | 531078 | void updateUnfilteredRawValues() { | ||
| 160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531078 times.
|
531078 | engine->outputChannels.rawRawPpsPrimary = m_pri.adc == nullptr ? 0 : m_pri.adc->sensorVolts; | |
| 161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531078 times.
|
531078 | engine->outputChannels.rawRawPpsSecondary = m_sec.adc == nullptr ? 0 : m_sec.adc->sensorVolts; | |
| 162 | 531078 | } | ||
| 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 | 531078 | void updateUnfilteredRawPedal() { | ||
| 195 | 531078 | pedal.updateUnfilteredRawValues(); | ||
| 196 | 531078 | } | ||
| 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 |