unexpected contains information about why it failed (#4393)
* unexpected can contain information * info printing * sensors return appropriate error codes * remove reliance on undefined behavior * s
This commit is contained in:
parent
baf68363e0
commit
923d2c2e44
|
@ -5,16 +5,16 @@
|
||||||
#include "bench_test.h"
|
#include "bench_test.h"
|
||||||
|
|
||||||
bool FanController::getState(bool acActive, bool lastState) {
|
bool FanController::getState(bool acActive, bool lastState) {
|
||||||
auto [cltValid, clt] = Sensor::get(SensorType::Clt);
|
auto clt = Sensor::get(SensorType::Clt);
|
||||||
|
|
||||||
cranking = engine->rpmCalculator.isCranking();
|
cranking = engine->rpmCalculator.isCranking();
|
||||||
notRunning = !engine->rpmCalculator.isRunning();
|
notRunning = !engine->rpmCalculator.isRunning();
|
||||||
|
|
||||||
disabledWhileEngineStopped = notRunning && disableWhenStopped();
|
disabledWhileEngineStopped = notRunning && disableWhenStopped();
|
||||||
brokenClt = !cltValid;
|
brokenClt = !clt;
|
||||||
enabledForAc = enableWithAc() && acActive;
|
enabledForAc = enableWithAc() && acActive;
|
||||||
hot = clt > getFanOnTemp();
|
hot = clt.Value > getFanOnTemp();
|
||||||
cold = clt < getFanOffTemp();
|
cold = clt.Value < getFanOffTemp();
|
||||||
|
|
||||||
if (cranking) {
|
if (cranking) {
|
||||||
// Inhibit while cranking
|
// Inhibit while cranking
|
||||||
|
|
|
@ -55,10 +55,10 @@ static angle_t getRunningAdvance(int rpm, float engineLoad) {
|
||||||
engine->module<IdleController>()->isIdlingOrTaper()) {
|
engine->module<IdleController>()->isIdlingOrTaper()) {
|
||||||
float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance);
|
float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance);
|
||||||
|
|
||||||
auto [valid, tps] = Sensor::get(SensorType::DriverThrottleIntent);
|
auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
||||||
if (valid) {
|
if (tps) {
|
||||||
// interpolate between idle table and normal (running) table using TPS threshold
|
// interpolate between idle table and normal (running) table using TPS threshold
|
||||||
advanceAngle = interpolateClamped(0.0f, idleAdvance, engineConfiguration->idlePidDeactivationTpsThreshold, advanceAngle, tps);
|
advanceAngle = interpolateClamped(0.0f, idleAdvance, engineConfiguration->idlePidDeactivationTpsThreshold, advanceAngle, tps.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,14 +80,14 @@ static angle_t getRunningAdvance(int rpm, float engineLoad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
angle_t getAdvanceCorrections(int rpm) {
|
angle_t getAdvanceCorrections(int rpm) {
|
||||||
const auto [iatValid, iat] = Sensor::get(SensorType::Iat);
|
auto iat = Sensor::get(SensorType::Iat);
|
||||||
|
|
||||||
if (!iatValid) {
|
if (!iat) {
|
||||||
engine->engineState.timingIatCorrection = 0;
|
engine->engineState.timingIatCorrection = 0;
|
||||||
} else {
|
} else {
|
||||||
engine->engineState.timingIatCorrection = interpolate3d(
|
engine->engineState.timingIatCorrection = interpolate3d(
|
||||||
config->ignitionIatCorrTable,
|
config->ignitionIatCorrTable,
|
||||||
config->ignitionIatCorrLoadBins, iat,
|
config->ignitionIatCorrLoadBins, iat.Value,
|
||||||
config->ignitionIatCorrRpmBins, rpm
|
config->ignitionIatCorrRpmBins, rpm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,21 +5,21 @@ bool DfcoController::getState() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto [tpsValid, tpsPos] = Sensor::get(SensorType::DriverThrottleIntent);
|
const auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
||||||
const auto [cltValid, clt] = Sensor::get(SensorType::Clt);
|
const auto clt = Sensor::get(SensorType::Clt);
|
||||||
const auto [mapValid, map] = Sensor::get(SensorType::Map);
|
const auto map = Sensor::get(SensorType::Map);
|
||||||
|
|
||||||
// If some sensor is broken, inhibit DFCO
|
// If some sensor is broken, inhibit DFCO
|
||||||
if (!tpsValid || !cltValid || !mapValid) {
|
if (!tps || !clt || !map) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rpm = Sensor::getOrZero(SensorType::Rpm);
|
float rpm = Sensor::getOrZero(SensorType::Rpm);
|
||||||
float vss = Sensor::getOrZero(SensorType::VehicleSpeed);
|
float vss = Sensor::getOrZero(SensorType::VehicleSpeed);
|
||||||
|
|
||||||
bool mapActivate = map < engineConfiguration->coastingFuelCutMap;
|
bool mapActivate = map.Value < engineConfiguration->coastingFuelCutMap;
|
||||||
bool tpsActivate = tpsPos < engineConfiguration->coastingFuelCutTps;
|
bool tpsActivate = tps.Value < engineConfiguration->coastingFuelCutTps;
|
||||||
bool cltActivate = clt > engineConfiguration->coastingFuelCutClt;
|
bool cltActivate = clt.Value > engineConfiguration->coastingFuelCutClt;
|
||||||
// True if throttle, MAP, and CLT are all acceptable for DFCO to occur
|
// True if throttle, MAP, and CLT are all acceptable for DFCO to occur
|
||||||
bool dfcoAllowed = mapActivate && tpsActivate && cltActivate;
|
bool dfcoAllowed = mapActivate && tpsActivate && cltActivate;
|
||||||
|
|
||||||
|
|
|
@ -344,30 +344,30 @@ void initFuelMap() {
|
||||||
* @brief Engine warm-up fuel correction.
|
* @brief Engine warm-up fuel correction.
|
||||||
*/
|
*/
|
||||||
float getCltFuelCorrection() {
|
float getCltFuelCorrection() {
|
||||||
const auto [valid, clt] = Sensor::get(SensorType::Clt);
|
const auto clt = Sensor::get(SensorType::Clt);
|
||||||
|
|
||||||
if (!valid)
|
if (!clt)
|
||||||
return 1; // this error should be already reported somewhere else, let's just handle it
|
return 1; // this error should be already reported somewhere else, let's just handle it
|
||||||
|
|
||||||
return interpolate2d(clt, config->cltFuelCorrBins, config->cltFuelCorr);
|
return interpolate2d(clt.Value, config->cltFuelCorrBins, config->cltFuelCorr);
|
||||||
}
|
}
|
||||||
|
|
||||||
angle_t getCltTimingCorrection() {
|
angle_t getCltTimingCorrection() {
|
||||||
const auto [valid, clt] = Sensor::get(SensorType::Clt);
|
const auto clt = Sensor::get(SensorType::Clt);
|
||||||
|
|
||||||
if (!valid)
|
if (!clt)
|
||||||
return 0; // this error should be already reported somewhere else, let's just handle it
|
return 0; // this error should be already reported somewhere else, let's just handle it
|
||||||
|
|
||||||
return interpolate2d(clt, config->cltTimingBins, config->cltTimingExtra);
|
return interpolate2d(clt.Value, config->cltTimingBins, config->cltTimingExtra);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getIatFuelCorrection() {
|
float getIatFuelCorrection() {
|
||||||
const auto [valid, iat] = Sensor::get(SensorType::Iat);
|
const auto iat = Sensor::get(SensorType::Iat);
|
||||||
|
|
||||||
if (!valid)
|
if (!iat)
|
||||||
return 1; // this error should be already reported somewhere else, let's just handle it
|
return 1; // this error should be already reported somewhere else, let's just handle it
|
||||||
|
|
||||||
return interpolate2d(iat, config->iatFuelCorrBins, config->iatFuelCorr);
|
return interpolate2d(iat.Value, config->iatFuelCorrBins, config->iatFuelCorr);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBaroCorrection() {
|
float getBaroCorrection() {
|
||||||
|
|
|
@ -81,17 +81,17 @@ void recalculateAuxValveTiming() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [valid, tps] = Sensor::get(SensorType::DriverThrottleIntent);
|
auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
||||||
if (!valid) {
|
if (!tps) {
|
||||||
// error should be already reported by now
|
// error should be already reported by now
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->engineState.auxValveStart = interpolate2d(tps,
|
engine->engineState.auxValveStart = interpolate2d(tps.Value,
|
||||||
config->scriptCurve1Bins,
|
config->scriptCurve1Bins,
|
||||||
config->scriptCurve1);
|
config->scriptCurve1);
|
||||||
|
|
||||||
engine->engineState.auxValveEnd = interpolate2d(tps,
|
engine->engineState.auxValveEnd = interpolate2d(tps.Value,
|
||||||
config->scriptCurve2Bins,
|
config->scriptCurve2Bins,
|
||||||
config->scriptCurve2);
|
config->scriptCurve2);
|
||||||
|
|
||||||
|
|
|
@ -81,11 +81,16 @@ float HpfpQuantity::calcPI(int rpm, float calc_fuel_percent) {
|
||||||
m_pressureTarget_kPa - (engineConfiguration->hpfpTargetDecay *
|
m_pressureTarget_kPa - (engineConfiguration->hpfpTargetDecay *
|
||||||
(FAST_CALLBACK_PERIOD_MS / 1000.)),
|
(FAST_CALLBACK_PERIOD_MS / 1000.)),
|
||||||
interpolate3d(engineConfiguration->hpfpTarget,
|
interpolate3d(engineConfiguration->hpfpTarget,
|
||||||
engineConfiguration->hpfpTargetLoadBins, Sensor::get(SensorType::Map).Value, // TODO: allow other load axis, like we claim to
|
engineConfiguration->hpfpTargetLoadBins, Sensor::get(SensorType::Map).value_or(0), // TODO: allow other load axis, like we claim to
|
||||||
engineConfiguration->hpfpTargetRpmBins, rpm));
|
engineConfiguration->hpfpTargetRpmBins, rpm));
|
||||||
|
|
||||||
|
auto fuelPressure = Sensor::get(SensorType::FuelPressureHigh);
|
||||||
|
if (!fuelPressure) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
float pressureError_kPa =
|
float pressureError_kPa =
|
||||||
m_pressureTarget_kPa - Sensor::get(SensorType::FuelPressureHigh).Value;
|
m_pressureTarget_kPa - fuelPressure.Value;
|
||||||
|
|
||||||
float p_control_percent = pressureError_kPa * engineConfiguration->hpfpPidP;
|
float p_control_percent = pressureError_kPa * engineConfiguration->hpfpPidP;
|
||||||
float i_factor_divisor =
|
float i_factor_divisor =
|
||||||
|
|
|
@ -12,13 +12,17 @@ public:
|
||||||
SensorResult convert(float frequency) const override {
|
SensorResult convert(float frequency) const override {
|
||||||
// Sensor should only report 50-150hz, significantly outside that range indicates a problem
|
// Sensor should only report 50-150hz, significantly outside that range indicates a problem
|
||||||
// it changes to 200hz+ to indicate methanol "contamination"
|
// it changes to 200hz+ to indicate methanol "contamination"
|
||||||
if (frequency > 45 && frequency < 155) {
|
if (frequency < 45) {
|
||||||
float flexPct = clampF(0, frequency - 50, 100);
|
return UnexpectedCode::Low;
|
||||||
|
|
||||||
return m_filter.filter(flexPct);
|
|
||||||
} else {
|
|
||||||
return unexpected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frequency > 155) {
|
||||||
|
return UnexpectedCode::High;
|
||||||
|
}
|
||||||
|
|
||||||
|
float flexPct = clampF(0, frequency - 50, 100);
|
||||||
|
|
||||||
|
return m_filter.filter(flexPct);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -16,11 +16,15 @@ void LinearFunc::configure(float in1, float out1, float in2, float out2, float m
|
||||||
SensorResult LinearFunc::convert(float inputValue) const {
|
SensorResult LinearFunc::convert(float inputValue) const {
|
||||||
float result = m_a * inputValue + m_b;
|
float result = m_a * inputValue + m_b;
|
||||||
|
|
||||||
// Bounds check
|
// Bounds checks
|
||||||
bool isValid = result <= m_maxOutput && result >= m_minOutput;
|
// Flipped error codes in case of m_a < 0 so that they indicate whether the input
|
||||||
|
// voltage is high/low, instead of the output high/low
|
||||||
|
if (result > m_maxOutput) {
|
||||||
|
return m_a > 0 ? UnexpectedCode::High : UnexpectedCode::Low;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isValid) {
|
if (result < m_minOutput) {
|
||||||
return unexpected;
|
return m_a > 0 ? UnexpectedCode::Low : UnexpectedCode::High;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -12,12 +12,12 @@ void ResistanceFunc::configure(float supplyVoltage, float pullupResistor) {
|
||||||
SensorResult ResistanceFunc::convert(float raw) const {
|
SensorResult ResistanceFunc::convert(float raw) const {
|
||||||
// If the voltage is very low, the sensor is a dead short.
|
// If the voltage is very low, the sensor is a dead short.
|
||||||
if (raw < 0.05f) {
|
if (raw < 0.05f) {
|
||||||
return unexpected;
|
return UnexpectedCode::Low;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the voltage is very high (98% VCC), the sensor is open circuit.
|
// If the voltage is very high (98% VCC), the sensor is open circuit.
|
||||||
if (raw > (m_supplyVoltage * 0.98f)) {
|
if (raw > (m_supplyVoltage * 0.98f)) {
|
||||||
return unexpected;
|
return UnexpectedCode::High;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Voltage is in a sensible range - convert
|
// Voltage is in a sensible range - convert
|
||||||
|
|
|
@ -12,7 +12,7 @@ SensorResult ThermistorFunc::convert(float ohms) const {
|
||||||
// This resistance should have already been validated - only
|
// This resistance should have already been validated - only
|
||||||
// thing we can check is that it's non-negative
|
// thing we can check is that it's non-negative
|
||||||
if (ohms <= 0) {
|
if (ohms <= 0) {
|
||||||
return unexpected;
|
return UnexpectedCode::Low;
|
||||||
}
|
}
|
||||||
|
|
||||||
float lnR = logf(ohms);
|
float lnR = logf(ohms);
|
||||||
|
@ -26,9 +26,14 @@ SensorResult ThermistorFunc::convert(float ohms) const {
|
||||||
float celsius = convertKelvinToCelcius(kelvin);
|
float celsius = convertKelvinToCelcius(kelvin);
|
||||||
|
|
||||||
// bounds check result - please don't try to run rusEfi when colder than -50C
|
// bounds check result - please don't try to run rusEfi when colder than -50C
|
||||||
// high end limit is required as this could be an oil temp sensor
|
// high end limit is required as this could be an oil temp sensor on an
|
||||||
if (celsius < -50 || celsius > 250) {
|
// air cooled engine
|
||||||
return unexpected;
|
if (celsius < -50) {
|
||||||
|
return UnexpectedCode::Low;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (celsius > 250) {
|
||||||
|
return UnexpectedCode::High;
|
||||||
}
|
}
|
||||||
|
|
||||||
return celsius;
|
return celsius;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
void FunctionalSensor::postRawValue(float inputValue, efitick_t timestamp) {
|
void FunctionalSensor::postRawValue(float inputValue, efitick_t timestamp) {
|
||||||
// If no function is set, this sensor isn't valid.
|
// If no function is set, this sensor isn't valid.
|
||||||
if (!m_function) {
|
if (!m_function) {
|
||||||
invalidate();
|
invalidate(UnexpectedCode::Configuration);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@ void FunctionalSensor::postRawValue(float inputValue, efitick_t timestamp) {
|
||||||
if (r.Valid) {
|
if (r.Valid) {
|
||||||
setValidValue(r.Value, timestamp);
|
setValidValue(r.Value, timestamp);
|
||||||
} else {
|
} else {
|
||||||
invalidate();
|
invalidate(r.Code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ SensorResult RedundantFordTps::get() const {
|
||||||
|
|
||||||
// If either result is invalid, return invalid.
|
// If either result is invalid, return invalid.
|
||||||
if (!tps1 || !tps2) {
|
if (!tps1 || !tps2) {
|
||||||
return unexpected;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "actual" position resolved by the second throttle - this tops out at m_secondaryMaximum instead of 100%
|
// The "actual" position resolved by the second throttle - this tops out at m_secondaryMaximum instead of 100%
|
||||||
|
@ -37,7 +37,7 @@ SensorResult RedundantFordTps::get() const {
|
||||||
// Check that the resolved positions are close
|
// Check that the resolved positions are close
|
||||||
float delta = absF(tps1.Value - tps2Actual);
|
float delta = absF(tps1.Value - tps2Actual);
|
||||||
if (delta > m_maxDifference) {
|
if (delta > m_maxDifference) {
|
||||||
return unexpected;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (tps1.Value + tps2Actual) / 2;
|
return (tps1.Value + tps2Actual) / 2;
|
||||||
|
@ -49,5 +49,5 @@ SensorResult RedundantFordTps::get() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any other condition indicates an mismatch, and therefore an error
|
// Any other condition indicates an mismatch, and therefore an error
|
||||||
return unexpected;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ SensorResult RedundantSensor::get() const {
|
||||||
|
|
||||||
// If either result is invalid, return invalid.
|
// If either result is invalid, return invalid.
|
||||||
if (!result1.Valid || !result2.Valid) {
|
if (!result1.Valid || !result2.Valid) {
|
||||||
return unexpected;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If both are valid, check that they're near one another
|
// If both are valid, check that they're near one another
|
||||||
float delta = absF(result1.Value - result2.Value);
|
float delta = absF(result1.Value - result2.Value);
|
||||||
if (delta > m_maxDifference) {
|
if (delta > m_maxDifference) {
|
||||||
return unexpected;
|
return UnexpectedCode::Inconsistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both sensors are valid, and their readings are close. All is well.
|
// Both sensors are valid, and their readings are close. All is well.
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
if (s) {
|
if (s) {
|
||||||
// If this sensor says it doesn't exist, return unexpected
|
// If this sensor says it doesn't exist, return unexpected
|
||||||
if (!s->hasSensor()) {
|
if (!s->hasSensor()) {
|
||||||
return unexpected;
|
return UnexpectedCode::Configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found the sensor, ask it for a result.
|
// If we found the sensor, ask it for a result.
|
||||||
|
@ -63,7 +63,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've exhausted all valid ways to return something - sensor not found.
|
// We've exhausted all valid ways to return something - sensor not found.
|
||||||
return unexpected;
|
return UnexpectedCode::Configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showInfo(const char* sensorName) const {
|
void showInfo(const char* sensorName) const {
|
||||||
|
@ -155,7 +155,7 @@ void Sensor::unregister() {
|
||||||
|
|
||||||
// Check if this is a valid sensor entry
|
// Check if this is a valid sensor entry
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return unexpected;
|
return UnexpectedCode::Configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry->get();
|
return entry->get();
|
||||||
|
|
|
@ -15,8 +15,8 @@ void ProxySensor::showInfo(const char* sensorName) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionalSensor::showInfo(const char* sensorName) const {
|
void FunctionalSensor::showInfo(const char* sensorName) const {
|
||||||
const auto [valid, value] = get();
|
const auto value = get();
|
||||||
efiPrintf("Sensor \"%s\": Raw value: %.2f Valid: %s Converted value %.2f", sensorName, m_rawValue, boolToString(valid), value);
|
efiPrintf("Sensor \"%s\": Raw value: %.2f Valid: %s Converted value %.2f", sensorName, m_rawValue, boolToString(value.Valid), value.Value);
|
||||||
|
|
||||||
// now print out the underlying function's info
|
// now print out the underlying function's info
|
||||||
if (auto func = m_function) {
|
if (auto func = m_function) {
|
||||||
|
@ -28,8 +28,8 @@ void FunctionalSensor::showInfo(const char* sensorName) const {
|
||||||
#include "can_sensor.h"
|
#include "can_sensor.h"
|
||||||
|
|
||||||
void CanSensorBase::showInfo(const char* sensorName) const {
|
void CanSensorBase::showInfo(const char* sensorName) const {
|
||||||
const auto [valid, value] = get();
|
const auto value = get();
|
||||||
efiPrintf("CAN Sensor \"%s\": valid: %s value: %.2f", sensorName, boolToString(valid), value);
|
efiPrintf("CAN Sensor \"%s\": valid: %s value: %.2f", sensorName, boolToString(value.Valid), value.Value);
|
||||||
}
|
}
|
||||||
#endif // EFI_CAN_SUPPORT
|
#endif // EFI_CAN_SUPPORT
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ void Lps25Sensor::showInfo(const char* sensorName) const {
|
||||||
|
|
||||||
void LinearFunc::showInfo(float testRawValue) const {
|
void LinearFunc::showInfo(float testRawValue) const {
|
||||||
efiPrintf(" Linear function slope: %.2f offset: %.2f min: %.1f max: %.1f", m_a, m_b, m_minOutput, m_maxOutput);
|
efiPrintf(" Linear function slope: %.2f offset: %.2f min: %.1f max: %.1f", m_a, m_b, m_minOutput, m_maxOutput);
|
||||||
const auto [valid, value] = convert(testRawValue);
|
const auto value = convert(testRawValue);
|
||||||
efiPrintf(" raw value %.2f converts to %.2f valid: %s", testRawValue, value, boolToString(valid));
|
efiPrintf(" raw value %.2f converts to %.2f valid: %s", testRawValue, value.Value, boolToString(value.Valid));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResistanceFunc::showInfo(float testInputValue) const {
|
void ResistanceFunc::showInfo(float testInputValue) const {
|
||||||
|
@ -73,8 +73,8 @@ void ResistanceFunc::showInfo(float testInputValue) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThermistorFunc::showInfo(float testInputValue) const {
|
void ThermistorFunc::showInfo(float testInputValue) const {
|
||||||
const auto [valid, value] = convert(testInputValue);
|
const auto value = convert(testInputValue);
|
||||||
efiPrintf(" %.1f ohms -> valid: %s. %.1f deg C", testInputValue, boolToString(valid), value);
|
efiPrintf(" %.1f ohms -> valid: %s. %.1f deg C", testInputValue, boolToString(value.Valid), value.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdentityFunction::showInfo(float /*testInputValue*/) const {
|
void IdentityFunction::showInfo(float /*testInputValue*/) const {
|
||||||
|
|
|
@ -30,51 +30,50 @@
|
||||||
class StoredValueSensor : public Sensor {
|
class StoredValueSensor : public Sensor {
|
||||||
public:
|
public:
|
||||||
SensorResult get() const final override {
|
SensorResult get() const final override {
|
||||||
bool valid = m_isValid;
|
auto result = m_result;
|
||||||
float value = m_value;
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
return unexpected;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timeouts are disabled, return last value
|
// Timeouts are disabled, return last value
|
||||||
if (Sensor::s_inhibitSensorTimeouts) {
|
if (Sensor::s_inhibitSensorTimeouts) {
|
||||||
return value;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_timeoutPeriod != 0) { // zero m_timeoutPeriod means value lasts forever
|
if (m_timeoutPeriod != 0) { // zero m_timeoutPeriod means value lasts forever
|
||||||
if (getTimeNowNt() - m_timeoutPeriod > m_lastUpdate) {
|
if (getTimeNowNt() - m_timeoutPeriod > m_lastUpdate) {
|
||||||
return unexpected;
|
return UnexpectedCode::Timeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
StoredValueSensor(SensorType type, efitick_t timeoutNt)
|
StoredValueSensor(SensorType type, efitick_t timeoutNt)
|
||||||
: Sensor(type)
|
: Sensor(type)
|
||||||
|
, m_result(unexpected)
|
||||||
, m_timeoutPeriod(timeoutNt)
|
, m_timeoutPeriod(timeoutNt)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate the stored value.
|
// Invalidate the stored value.
|
||||||
void invalidate() {
|
void invalidate() {
|
||||||
m_isValid = false;
|
m_result = unexpected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate the stored value with an error code
|
||||||
|
void invalidate(UnexpectedCode why) {
|
||||||
|
m_result = why;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A new reading is available: set and validate a new value for the sensor.
|
// A new reading is available: set and validate a new value for the sensor.
|
||||||
void setValidValue(float value, efitick_t timestamp) {
|
void setValidValue(float value, efitick_t timestamp) {
|
||||||
// Set value before valid - so we don't briefly have the valid bit set on an invalid value
|
// Set value before valid - so we don't briefly have the valid bit set on an invalid value
|
||||||
m_value = value;
|
m_result = value;
|
||||||
m_isValid = true;
|
|
||||||
m_lastUpdate = timestamp;
|
m_lastUpdate = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showInfo(const char*) const override { }
|
void showInfo(const char*) const override { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_isValid = false;
|
SensorResult m_result;
|
||||||
float m_value = 0.0f;
|
|
||||||
|
|
||||||
const efitick_t m_timeoutPeriod;
|
const efitick_t m_timeoutPeriod;
|
||||||
efitick_t m_lastUpdate = 0;
|
efitick_t m_lastUpdate = 0;
|
||||||
|
|
|
@ -17,13 +17,35 @@
|
||||||
|
|
||||||
struct unexpected_t {};
|
struct unexpected_t {};
|
||||||
|
|
||||||
|
enum class UnexpectedCode : char {
|
||||||
|
Unknown = 0,
|
||||||
|
|
||||||
|
// Too much time has passed
|
||||||
|
Timeout,
|
||||||
|
|
||||||
|
// The decoded value was impossibly high/low
|
||||||
|
High,
|
||||||
|
Low,
|
||||||
|
|
||||||
|
// An inconsistency was detected using multiple sources of information
|
||||||
|
Inconsistent,
|
||||||
|
|
||||||
|
// A value is unavailable due to configuration
|
||||||
|
Configuration,
|
||||||
|
};
|
||||||
template <class TValue>
|
template <class TValue>
|
||||||
struct expected {
|
struct expected {
|
||||||
const bool Valid;
|
bool Valid;
|
||||||
const TValue Value;
|
|
||||||
|
union {
|
||||||
|
TValue Value;
|
||||||
|
UnexpectedCode Code;
|
||||||
|
};
|
||||||
|
|
||||||
// Implicit constructor to construct in the invalid state
|
// Implicit constructor to construct in the invalid state
|
||||||
constexpr expected(const unexpected_t&) : Valid(false), Value{} {}
|
constexpr expected(const unexpected_t&) : Valid(false), Code{UnexpectedCode::Unknown} {}
|
||||||
|
|
||||||
|
constexpr expected(UnexpectedCode code) : Valid(false), Code{code} {}
|
||||||
|
|
||||||
// Implicit constructor to convert from TValue (for valid values, so an expected<T> behaves like a T)
|
// Implicit constructor to convert from TValue (for valid values, so an expected<T> behaves like a T)
|
||||||
constexpr expected(TValue validValue)
|
constexpr expected(TValue validValue)
|
||||||
|
|
|
@ -64,6 +64,5 @@ TEST_F(SensorConverted, TestInvalid) {
|
||||||
{
|
{
|
||||||
auto s = Sensor::get(SensorType::Clt);
|
auto s = Sensor::get(SensorType::Clt);
|
||||||
EXPECT_FALSE(s.Valid);
|
EXPECT_FALSE(s.Valid);
|
||||||
EXPECT_FLOAT_EQ(s.Value, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue