diff --git a/firmware/controllers/sensors/converters/func_chain.h b/firmware/controllers/sensors/converters/func_chain.h index ac502a11f7..164d5bd349 100644 --- a/firmware/controllers/sensors/converters/func_chain.h +++ b/firmware/controllers/sensors/converters/func_chain.h @@ -22,7 +22,7 @@ class FuncChain<> { protected: SensorResult convert(float input) const { // Base case is the identity function - return {true, input}; + return input; } void showInfo(Logging* logger, float testInputValue) const { @@ -48,7 +48,7 @@ public: if (currentStep.Valid) { return TBase::convert(currentStep.Value); } else { - return {false, 0}; + return unexpected; } } diff --git a/firmware/controllers/sensors/converters/resistance_func.cpp b/firmware/controllers/sensors/converters/resistance_func.cpp index 04fc06123f..6553258be3 100644 --- a/firmware/controllers/sensors/converters/resistance_func.cpp +++ b/firmware/controllers/sensors/converters/resistance_func.cpp @@ -13,18 +13,18 @@ void ResistanceFunc::configure(float supplyVoltage, float pullupResistor) { SensorResult ResistanceFunc::convert(float raw) const { // If the voltage is very low, the sensor is a dead short. if (raw < 0.05f) { - return {false, 0.0f}; + return unexpected; } // If the voltage is very high (98% VCC), the sensor is open circuit. if (raw > (m_supplyVoltage * 0.98f)) { - return {false, 1e6}; + return unexpected; } // Voltage is in a sensible range - convert float resistance = m_pullupResistor / (m_supplyVoltage / raw - 1); - return {true, resistance}; + return resistance; } void ResistanceFunc::showInfo(Logging* logger, float testInputValue) const { diff --git a/firmware/controllers/sensors/converters/thermistor_func.cpp b/firmware/controllers/sensors/converters/thermistor_func.cpp index b58a746d8a..362d3ff5a5 100644 --- a/firmware/controllers/sensors/converters/thermistor_func.cpp +++ b/firmware/controllers/sensors/converters/thermistor_func.cpp @@ -13,7 +13,7 @@ SensorResult ThermistorFunc::convert(float ohms) const { // This resistance should have already been validated - only // thing we can check is that it's non-negative if (ohms <= 0) { - return {false, 0}; + return unexpected; } float lnR = logf(ohms); @@ -26,7 +26,7 @@ SensorResult ThermistorFunc::convert(float ohms) const { float celsius = convertKelvinToCelcius(kelvin); - return {true, celsius}; + return celsius; } void ThermistorFunc::configure(thermistor_conf_s &cfg) { diff --git a/firmware/controllers/sensors/sensor.cpp b/firmware/controllers/sensors/sensor.cpp index c79d63ea29..33796d950a 100644 --- a/firmware/controllers/sensors/sensor.cpp +++ b/firmware/controllers/sensors/sensor.cpp @@ -92,7 +92,7 @@ bool Sensor::Register() { // Next check for mock if (entry->useMock) { - return {true, entry->mockValue}; + return entry->mockValue; } // Get the sensor out of the entry @@ -103,7 +103,7 @@ bool Sensor::Register() { } // We've exhausted all valid ways to return something - sensor not found. - return {false, 0}; + return unexpected; } /*static*/ float Sensor::getRaw(SensorType type) { diff --git a/firmware/controllers/sensors/sensor.h b/firmware/controllers/sensors/sensor.h index 13c850a91b..2eafcd79a1 100644 --- a/firmware/controllers/sensors/sensor.h +++ b/firmware/controllers/sensors/sensor.h @@ -48,23 +48,11 @@ #pragma once #include "sensor_type.h" +#include "expected.h" #include -struct SensorResult { - const bool Valid; - const float Value; - - // Implicit conversion operator to bool, so you can do things like if (myResult) { ... } - constexpr explicit operator bool() const { - return Valid; - } - - // Easy default value handling - constexpr float value_or(float valueIfInvalid) const { - return Valid ? Value : valueIfInvalid; - } -}; +using SensorResult = expected; // Fwd declare - nobody outside of Sensor.cpp needs to see inside this type struct SensorRegistryEntry; @@ -156,7 +144,7 @@ private: return 0; } - SensorType m_type; + const SensorType m_type; // Get this sensor's index in the list constexpr size_t getIndex() { diff --git a/firmware/controllers/sensors/stored_value_sensor.h b/firmware/controllers/sensors/stored_value_sensor.h index 6920f14cbd..5e101c8d62 100644 --- a/firmware/controllers/sensors/stored_value_sensor.h +++ b/firmware/controllers/sensors/stored_value_sensor.h @@ -41,7 +41,7 @@ public: return {false, value}; } - return {true, value}; + return value; } protected: diff --git a/firmware/util/expected.h b/firmware/util/expected.h new file mode 100644 index 0000000000..66a0230eff --- /dev/null +++ b/firmware/util/expected.h @@ -0,0 +1,43 @@ +/** + * @file expected.h + * @brief This utility class provides a way for a function to accept or return a value that may be invalid. + * + * For example, suppose there needs to be a solution for prevention of divide by zero. One could write this function: + * + * expected my_divide(int num, int denom) { + * if (denom == 0) return unexpected; + * return num / denom; + * } + * + * @date April 18, 2020 + * @author Matthew Kennedy, (c) 2020 + */ + +#pragma once + +template +struct expected { + const bool Valid; + const TValue Value; + + constexpr expected(bool valid, TValue value) : Valid(valid), Value(value) {} + + // Implicit constructor to convert from TValue (for valid values, so an expected behaves like a T) + constexpr expected(TValue validValue) + : Valid(true) + , Value(validValue) + { + } + + // Implicit conversion operator to bool, so you can do things like if (myResult) { ... } + constexpr explicit operator bool() const { + return Valid; + } + + // Easy default value handling + constexpr float value_or(TValue valueIfInvalid) const { + return Valid ? Value : valueIfInvalid; + } +}; + +constexpr expected unexpected = {false, 0.0f}; diff --git a/unit_tests/tests/sensor/func_chain.cpp b/unit_tests/tests/sensor/func_chain.cpp index b325a95675..875df1579d 100644 --- a/unit_tests/tests/sensor/func_chain.cpp +++ b/unit_tests/tests/sensor/func_chain.cpp @@ -4,19 +4,19 @@ struct AddOne final : public SensorConverter { SensorResult convert(float input) const { - return {true, input + 1}; + return input + 1; } }; struct SubOne final : public SensorConverter { SensorResult convert(float input) const { - return {true, input - 1}; + return input - 1; } }; struct Doubler final : public SensorConverter { SensorResult convert(float input) const { - return {true, input * 2}; + return input * 2; } };