Add timeout + raw value access for sensors (#1098)
* timeout * inject stamp * allow getting raw value * plumb timeout * fix tests
This commit is contained in:
parent
85a460f2ba
commit
d3d088676b
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue