Add timeout + raw value access for sensors (#1098)

* timeout

* inject stamp

* allow getting raw value

* plumb timeout

* fix tests
This commit is contained in:
Matthew Kennedy 2020-01-12 00:25:23 -08:00 committed by rusefi
parent 85a460f2ba
commit d3d088676b
9 changed files with 72 additions and 16 deletions

View File

@ -1,19 +1,21 @@
#include "functional_sensor.h" #include "functional_sensor.h"
void FunctionalSensor::postRawValue(float inputValue) { 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();
return; return;
} }
m_rawValue = inputValue;
auto r = m_function->convert(inputValue); auto r = m_function->convert(inputValue);
// This has to happen so that we set the valid bit after // This has to happen so that we set the valid bit after
// the value is stored, to prevent the data race of reading // the value is stored, to prevent the data race of reading
// an old invalid value // an old invalid value
if (r.Valid) { if (r.Valid) {
setValidValue(r.Value); setValidValue(r.Value, timestamp);
} else { } else {
invalidate(); invalidate();
} }

View File

@ -25,16 +25,22 @@
*/ */
class FunctionalSensor final : public StoredValueSensor { class FunctionalSensor final : public StoredValueSensor {
public: public:
explicit FunctionalSensor(SensorType type) explicit FunctionalSensor(SensorType type, efitick_t timeoutPeriod)
: StoredValueSensor(type) { } : StoredValueSensor(type, timeoutPeriod) { }
void postRawValue(float inputValue); void postRawValue(float inputValue, efitick_t timestamp);
void setFunction(SensorConverter& func) { void setFunction(SensorConverter& func) {
m_function = &func; m_function = &func;
} }
float getRaw() const override final {
return m_rawValue;
}
private: private:
// Conversion function for this sensor // Conversion function for this sensor
SensorConverter* m_function = nullptr; SensorConverter* m_function = nullptr;
float m_rawValue = 0;
}; };

View File

@ -79,6 +79,23 @@ bool Sensor::Register() {
return {false, 0}; return {false, 0};
} }
/*static*/ float Sensor::getRaw(SensorType type) {
const auto entry = getEntryForType(type);
// Check if this is a valid sensor entry
if (!entry) {
return 0;
}
const auto s = entry->sensor;
if (s) {
return s->getRaw();
}
// We've exhausted all valid ways to return something - sensor not found.
return 0;
}
/*static*/ void Sensor::setMockValue(SensorType type, float value) { /*static*/ void Sensor::setMockValue(SensorType type, float value) {
auto entry = getEntryForType(type); auto entry = getEntryForType(type);

View File

@ -81,6 +81,11 @@ public:
*/ */
static SensorResult get(SensorType type); static SensorResult get(SensorType type);
/*
* Get a raw (unconverted) value from the sensor, if available.
*/
static float getRaw(SensorType type);
/* /*
* Mock a value for a particular sensor. * Mock a value for a particular sensor.
*/ */
@ -114,6 +119,13 @@ private:
// this should be field lookup and simple math. // this should be field lookup and simple math.
virtual SensorResult get() const = 0; virtual SensorResult get() const = 0;
/*
* Get an unconverted value from the sensor, if available.
*/
virtual float getRaw() const {
return 0;
}
SensorType m_type; SensorType m_type;
// Get this sensor's index in the list // Get this sensor's index in the list

View File

@ -4,13 +4,15 @@
* set, then later retrieved by a consumer. * set, then later retrieved by a consumer.
* *
* @date September 12, 2019 * @date September 12, 2019
* @author Matthew Kennedy, (c) 2019 * @author Matthew Kennedy, (c) 2019-2020
*/ */
#pragma once #pragma once
#include "sensor.h" #include "sensor.h"
#include "efitime.h"
/** /**
* @brief Base class for sensors that compute a value on one thread, and want * @brief Base class for sensors that compute a value on one thread, and want
* to make it available to consumers asynchronously. * to make it available to consumers asynchronously.
@ -31,12 +33,21 @@ public:
bool valid = m_isValid; bool valid = m_isValid;
float value = m_value; float value = m_value;
return {valid, value}; if (!valid) {
return {false, value};
}
if (getTimeNowNt() - m_timeoutPeriod > m_lastUpdate) {
return {false, value};
}
return {true, value};
} }
protected: protected:
explicit StoredValueSensor(SensorType type) explicit StoredValueSensor(SensorType type, efitick_t timeoutNt)
: Sensor(type) : Sensor(type)
, m_timeoutPeriod(timeoutNt)
{ {
} }
@ -46,13 +57,17 @@ protected:
} }
// 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) { 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_value = value;
m_isValid = true; m_isValid = true;
m_lastUpdate = timestamp;
} }
private: private:
bool m_isValid = false; bool m_isValid = false;
float m_value = 0.0f; float m_value = 0.0f;
const efitick_t m_timeoutPeriod;
efitick_t m_lastUpdate = 0;
}; };

View File

@ -49,13 +49,15 @@ void AdcSubscription::SubscribeSensor(FunctionalSensor &sensor,
void AdcSubscription::UpdateSubscribers() { void AdcSubscription::UpdateSubscribers() {
ScopePerf perf(PE::AdcSubscriptionUpdateSubscribers); ScopePerf perf(PE::AdcSubscriptionUpdateSubscribers);
auto timestamp = getTimeNowNt();
for (size_t i = 0; i < s_nextEntry; i++) { for (size_t i = 0; i < s_nextEntry; i++) {
auto &entry = s_entries[i]; auto &entry = s_entries[i];
float mcuVolts = getVoltage("sensor", entry.Channel); float mcuVolts = getVoltage("sensor", entry.Channel);
float sensorVolts = mcuVolts * entry.VoltsPerAdcVolt; float sensorVolts = mcuVolts * entry.VoltsPerAdcVolt;
entry.Sensor->postRawValue(sensorVolts); entry.Sensor->postRawValue(sensorVolts, timestamp);
} }
} }

View File

@ -11,7 +11,7 @@
EXTERN_ENGINE; EXTERN_ENGINE;
LinearFunc oilpSensorFunc; LinearFunc oilpSensorFunc;
FunctionalSensor oilpSensor(SensorType::OilPressure); FunctionalSensor oilpSensor(SensorType::OilPressure, /* timeout = */ MS2NT(50));
void initOilPressure() { void initOilPressure() {
// Only register if we have a sensor // Only register if we have a sensor

View File

@ -1,4 +1,5 @@
#include "functional_sensor.h" #include "functional_sensor.h"
#include "global.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -14,7 +15,7 @@ struct DoublerFunc final : public SensorConverter {
class SensorConverted : public ::testing::Test { class SensorConverted : public ::testing::Test {
protected: protected:
SensorConverted() SensorConverted()
: dut(SensorType::Clt) {} : dut(SensorType::Clt, MS2NT(50)) {}
void SetUp() override { void SetUp() override {
dut.setFunction(func); dut.setFunction(func);
@ -38,7 +39,7 @@ TEST_F(SensorConverted, TestValid) {
EXPECT_FALSE(s.Valid); EXPECT_FALSE(s.Valid);
} }
dut.postRawValue(25); dut.postRawValue(25, 0);
// Should be valid, with a value of 25*2 = 50 // Should be valid, with a value of 25*2 = 50
{ {
@ -57,7 +58,7 @@ TEST_F(SensorConverted, TestInvalid) {
EXPECT_FALSE(s.Valid); EXPECT_FALSE(s.Valid);
} }
dut.postRawValue(-25); dut.postRawValue(-25, 0);
// Should be invalid, with a value of -25*2 = 0 // Should be invalid, with a value of -25*2 = 0
{ {

View File

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "stored_value_sensor.h" #include "stored_value_sensor.h"
#include "global.h"
struct MockSensor final : public StoredValueSensor struct MockSensor final : public StoredValueSensor
{ {
MockSensor(SensorType type) : StoredValueSensor(type) MockSensor(SensorType type) : StoredValueSensor(type, MS2NT(50))
{ {
} }
void set(float value) void set(float value)
{ {
setValidValue(value); setValidValue(value, 0);
} }
void invalidate() void invalidate()