2019-09-21 11:33:38 -07:00
|
|
|
/**
|
|
|
|
* @file sensor.h
|
|
|
|
* @brief Base class for sensors. Inherit this class to implement a new type of sensor.
|
|
|
|
*
|
|
|
|
* This file defines the basis for all sensor inputs to the ECU, and provides a registry
|
|
|
|
* so that consumers may be agnostic to how each sensor may work.
|
|
|
|
*
|
|
|
|
* HOW TO ADD A NEW SENSOR TYPE:
|
|
|
|
*
|
|
|
|
* 1. Add an entry to the enum in sensor_type.h. Be sure to add it ABOVE the placeholder
|
|
|
|
* at the end of the list.
|
|
|
|
*
|
|
|
|
* 2. In the init/sensor folder, create/modify logic to create an instance of the new sensor,
|
|
|
|
* configure it if necessary, and call its Register() function if it should be enabled.
|
|
|
|
* See init_oil_pressure.cpp for a minimal example.
|
|
|
|
*
|
|
|
|
* 3. Consume the new sensor with instance(s) of SensorConsumer<SensorType::MyNewSensor>
|
|
|
|
*
|
|
|
|
* Consumers:
|
|
|
|
*
|
|
|
|
* tl;dr: Use a SensorConsumer. See sensor_consumer.h
|
|
|
|
*
|
|
|
|
* All a consumer does is look up whether a particular sensor is present in the table,
|
|
|
|
* and if so, asks it for the current reading. This could synchronously perform sensor
|
|
|
|
* acquisition and conversion (not recommended), or use a previously stored value (recommended!).
|
|
|
|
* This functionality is implemented in sensor_consumer.h, and sensor.cpp.
|
|
|
|
*
|
|
|
|
* Providers:
|
|
|
|
* Instantiate a subclass of Sensor, and implement the Get() function.
|
|
|
|
* Call Register() to install the new sensor in the registry, preparing it for use.
|
|
|
|
*
|
|
|
|
* Mocking:
|
|
|
|
* The sensor table supports mocking each sensors value. Call Sensor::SetMockValue to
|
|
|
|
* set a mock value for a particular sensor, and Sensor::ResetMockValue or
|
|
|
|
* Sensor::ResetAllMocks to reset one or all stored mock values.
|
|
|
|
*
|
|
|
|
* Composite Sensors:
|
|
|
|
* Some sensors may be implemented as composite sensors, ie sensors that depend on other
|
|
|
|
* sensors to determine their reading. For example, the throttle pedal may have a pair of
|
|
|
|
* potentiometers that provide redundancy for the pedal's position. Each one may be its
|
|
|
|
* own sensor, then with one "master" sensors that combines the results of the others, and
|
|
|
|
* provides validation of whether the readings agree.
|
|
|
|
*
|
|
|
|
* @date September 12, 2019
|
|
|
|
* @author Matthew Kennedy, (c) 2019
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "sensor_type.h"
|
2020-04-18 22:53:04 -07:00
|
|
|
#include "expected.h"
|
2019-09-21 11:33:38 -07:00
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
2020-04-18 22:53:04 -07:00
|
|
|
using SensorResult = expected<float>;
|
2019-09-21 11:33:38 -07:00
|
|
|
|
|
|
|
// Fwd declare - nobody outside of Sensor.cpp needs to see inside this type
|
2020-12-11 09:50:10 -08:00
|
|
|
class SensorRegistryEntry;
|
2019-09-21 11:33:38 -07:00
|
|
|
|
|
|
|
class Sensor {
|
|
|
|
public:
|
|
|
|
// Register this sensor in the sensor registry.
|
|
|
|
// Returns true if registration succeeded, or false if
|
|
|
|
// another sensor of the same type is already registered.
|
2020-08-31 19:50:01 -07:00
|
|
|
bool Register();
|
2019-09-21 11:33:38 -07:00
|
|
|
|
2020-03-30 15:29:42 -07:00
|
|
|
// Print information about this sensor
|
2021-04-18 17:02:32 -07:00
|
|
|
virtual void showInfo(const char* sensorName) const = 0;
|
2020-03-30 15:29:42 -07:00
|
|
|
|
|
|
|
// Print information about all sensors
|
2021-04-18 17:02:32 -07:00
|
|
|
static void showAllSensorInfo();
|
2020-03-30 15:29:42 -07:00
|
|
|
|
2020-12-05 07:16:52 -08:00
|
|
|
// Print information about a particular sensor
|
2021-04-18 17:02:32 -07:00
|
|
|
static void showInfo(SensorType type);
|
2020-12-05 07:16:52 -08:00
|
|
|
|
2019-09-21 11:33:38 -07:00
|
|
|
// Remove all sensors from the sensor registry - tread carefully if you use this outside of a unit test
|
|
|
|
static void resetRegistry();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Static helper for sensor lookup
|
|
|
|
*/
|
|
|
|
static const Sensor *getSensorOfType(SensorType type);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a reading from the specified sensor.
|
|
|
|
*/
|
|
|
|
static SensorResult get(SensorType type);
|
|
|
|
|
2020-01-12 00:25:23 -08:00
|
|
|
/*
|
|
|
|
* Get a raw (unconverted) value from the sensor, if available.
|
|
|
|
*/
|
|
|
|
static float getRaw(SensorType type);
|
|
|
|
|
2020-12-06 11:55:06 -08:00
|
|
|
/*
|
|
|
|
* Get whether a sensor is redundant (a composite of multiple other sensors that can check consistency between them)
|
|
|
|
*/
|
|
|
|
static bool isRedundant(SensorType type);
|
|
|
|
|
2020-04-02 05:04:12 -07:00
|
|
|
/*
|
|
|
|
* Query whether there is a sensor of a particular type currently registered.
|
|
|
|
*/
|
|
|
|
static bool hasSensor(SensorType type);
|
|
|
|
|
2019-09-21 11:33:38 -07:00
|
|
|
/*
|
|
|
|
* Mock a value for a particular sensor.
|
|
|
|
*/
|
2020-12-08 03:24:20 -08:00
|
|
|
static void setMockValue(SensorType type, float value, bool mockRedundant = false);
|
2019-09-21 11:33:38 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mock a value for a particular sensor.
|
|
|
|
*/
|
|
|
|
static void setMockValue(int type, float value);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset mock for a particular sensor.
|
|
|
|
*/
|
|
|
|
static void resetMockValue(SensorType type);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset mocking for all sensors.
|
|
|
|
*/
|
|
|
|
static void resetAllMocks();
|
|
|
|
|
2020-04-02 05:02:44 -07:00
|
|
|
/*
|
|
|
|
* Get a friendly name for the sensor.
|
|
|
|
* For example, CLT, IAT, Throttle Position 2, etc.
|
|
|
|
*/
|
|
|
|
const char* getSensorName() { return getSensorName(m_type); }
|
2020-12-08 03:24:20 -08:00
|
|
|
static const char* getSensorName(SensorType type);
|
2020-04-02 05:02:44 -07:00
|
|
|
|
2020-09-03 18:47:50 -07:00
|
|
|
// Retrieve the current reading from the sensor.
|
|
|
|
//
|
|
|
|
// Override this in a particular sensor's implementation. As reading sensors is in many hot paths,
|
|
|
|
// it is unwise to synchronously read the sensor or do anything otherwise costly here. At the most,
|
|
|
|
// this should be field lookup and simple math.
|
|
|
|
virtual SensorResult get() const = 0;
|
|
|
|
|
2021-03-12 20:32:41 -08:00
|
|
|
// Retrieve whether the sensor is present. Some sensors may be registered but not present, ie if inintialization failed.
|
|
|
|
virtual bool hasSensor() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-05 07:16:52 -08:00
|
|
|
/*
|
|
|
|
* Get an unconverted value from the sensor, if available.
|
|
|
|
*/
|
|
|
|
virtual float getRaw() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-06 11:55:06 -08:00
|
|
|
/*
|
|
|
|
* Get whether this sensor is redundant (backed by multiple other sensors)
|
|
|
|
*/
|
|
|
|
virtual bool isRedundant() const {
|
|
|
|
// By default sensors are not redundant
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-21 11:33:38 -07:00
|
|
|
protected:
|
|
|
|
// Protected constructor - only subclasses call this
|
|
|
|
explicit Sensor(SensorType type)
|
|
|
|
: m_type(type) {}
|
|
|
|
|
|
|
|
private:
|
2020-04-18 22:53:04 -07:00
|
|
|
const SensorType m_type;
|
2019-09-21 11:33:38 -07:00
|
|
|
|
|
|
|
// Get this sensor's index in the list
|
|
|
|
constexpr size_t getIndex() {
|
|
|
|
return getIndex(m_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the index in the list for a sensor of particular type
|
|
|
|
static constexpr size_t getIndex(SensorType type) {
|
|
|
|
return static_cast<size_t>(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Static helper for sensor lookup
|
|
|
|
*/
|
|
|
|
static SensorRegistryEntry *getEntryForType(SensorType type);
|
|
|
|
};
|