Debuggability in the new sensor world (#1238)

* rename to avoid conflict

* fix efilib

* add sensor printing

* makefile

* that check was already there

* const

* const

* fix tests

* formatting

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-03-30 15:29:42 -07:00 committed by GitHub
parent 057b447d3d
commit 483d4a2204
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 118 additions and 28 deletions

View File

@ -123,7 +123,7 @@ void initDataStructures(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
static void mostCommonInitEngineController(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) { static void mostCommonInitEngineController(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) {
#if !EFI_UNIT_TEST #if !EFI_UNIT_TEST
initSensors(); initNewSensors(sharedLogger);
#endif /* EFI_UNIT_TEST */ #endif /* EFI_UNIT_TEST */
initSensors(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX); initSensors(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
@ -368,11 +368,9 @@ static void printAnalogChannelInfoExt(const char *name, adc_channel_e hwChannel,
} }
static void printAnalogChannelInfo(const char *name, adc_channel_e hwChannel) { static void printAnalogChannelInfo(const char *name, adc_channel_e hwChannel) {
if (hwChannel != EFI_ADC_NONE) {
#if HAL_USE_ADC #if HAL_USE_ADC
printAnalogChannelInfoExt(name, hwChannel, getVoltage("print", hwChannel PASS_ENGINE_PARAMETER_SUFFIX), engineConfiguration->analogInputDividerCoefficient); printAnalogChannelInfoExt(name, hwChannel, getVoltage("print", hwChannel PASS_ENGINE_PARAMETER_SUFFIX), engineConfiguration->analogInputDividerCoefficient);
#endif /* HAL_USE_ADC */ #endif /* HAL_USE_ADC */
}
} }
static void printAnalogInfo(void) { static void printAnalogInfo(void) {

View File

@ -29,6 +29,8 @@ public:
return {valid, result}; return {valid, result};
} }
void showInfo(Logging* logger, const char* sensorName) const override {}
private: private:
float (*m_func)(); float (*m_func)();
}; };

View File

@ -38,6 +38,8 @@ public:
return m_rawValue; return m_rawValue;
} }
void showInfo(Logging* logger, const char* sensorName) const override;
private: private:
// Conversion function for this sensor // Conversion function for this sensor
SensorConverter* m_function = nullptr; SensorConverter* m_function = nullptr;

View File

@ -21,6 +21,8 @@ public:
m_proxiedSensor = proxiedSensor; m_proxiedSensor = proxiedSensor;
} }
void showInfo(Logging* logger, const char* sensorName) const override;
private: private:
SensorResult get() const { SensorResult get() const {
return Sensor::get(m_proxiedSensor); return Sensor::get(m_proxiedSensor);

View File

@ -1,4 +1,6 @@
#include "sensor.h" #include "sensor.h"
#include "efilib.h"
#include "loggingcentral.h"
// This struct represents one sensor in the registry. // This struct represents one sensor in the registry.
// It stores whether the sensor should use a mock value, // It stores whether the sensor should use a mock value,
@ -12,6 +14,30 @@ struct SensorRegistryEntry {
static SensorRegistryEntry s_sensorRegistry[static_cast<size_t>(SensorType::PlaceholderLast)] = {}; static SensorRegistryEntry s_sensorRegistry[static_cast<size_t>(SensorType::PlaceholderLast)] = {};
static const char* s_sensorNames[] = {
"Invalid",
"CLT",
"IAT",
"Oil Pressure",
"TPS 1",
"TPS 1 Primary",
"TPS 1 Secondary",
"TPS 2",
"TPS 2 Primary",
"TPS 2 Secondary",
"Acc Pedal",
"Acc Pedal Primary",
"Acc Pedal Secondary",
"Driver Acc Intent"
};
static_assert(efi::size(s_sensorNames) == efi::size(s_sensorNames));
bool Sensor::Register() { bool Sensor::Register() {
// Get a ref to where we should be // Get a ref to where we should be
auto &entry = s_sensorRegistry[getIndex()]; auto &entry = s_sensorRegistry[getIndex()];
@ -28,10 +54,8 @@ bool Sensor::Register() {
} }
/*static*/ void Sensor::resetRegistry() { /*static*/ void Sensor::resetRegistry() {
constexpr size_t len = sizeof(s_sensorRegistry) / sizeof(s_sensorRegistry[0]);
// Clear all entries // Clear all entries
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < efi::size(s_sensorRegistry); i++) {
auto &entry = s_sensorRegistry[i]; auto &entry = s_sensorRegistry[i];
entry.sensor = nullptr; entry.sensor = nullptr;
@ -123,12 +147,34 @@ bool Sensor::Register() {
} }
/*static*/ void Sensor::resetAllMocks() { /*static*/ void Sensor::resetAllMocks() {
constexpr size_t len = sizeof(s_sensorRegistry) / sizeof(s_sensorRegistry[0]);
// Reset all mocks // Reset all mocks
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < efi::size(s_sensorRegistry); i++) {
auto &entry = s_sensorRegistry[i]; auto &entry = s_sensorRegistry[i];
entry.useMock = false; entry.useMock = false;
} }
} }
/*static*/ const char* Sensor::getSensorName(SensorType type) {
return s_sensorNames[static_cast<size_t>(type)];
}
// Print information about all sensors
/*static*/ void Sensor::showAllSensorInfo(Logging* logger) {
for (size_t i = 1; i < efi::size(s_sensorRegistry); i++) {
auto& entry = s_sensorRegistry[i];
const char* name = s_sensorNames[i];
if (entry.useMock) {
scheduleMsg(logger, "Sensor \"%s\" mocked with value %.2f", name, entry.mockValue);
} else {
const auto sensor = entry.sensor;
if (sensor) {
sensor->showInfo(logger, name);
} else {
scheduleMsg(logger, "Sensor \"%s\" is not configured.", name);
}
}
}
}

View File

@ -68,6 +68,7 @@ struct SensorResult {
// Fwd declare - nobody outside of Sensor.cpp needs to see inside this type // Fwd declare - nobody outside of Sensor.cpp needs to see inside this type
struct SensorRegistryEntry; struct SensorRegistryEntry;
class Logging;
class Sensor { class Sensor {
public: public:
@ -78,6 +79,12 @@ public:
// done internally! // done internally!
[[nodiscard]] bool Register(); [[nodiscard]] bool Register();
// Print information about this sensor
virtual void showInfo(Logging* logger, const char* sensorName) const = 0;
// Print information about all sensors
static void showAllSensorInfo(Logging* logger);
// Remove all sensors from the sensor registry - tread carefully if you use this outside of a unit test // Remove all sensors from the sensor registry - tread carefully if you use this outside of a unit test
static void resetRegistry(); static void resetRegistry();
@ -121,6 +128,8 @@ protected:
explicit Sensor(SensorType type) explicit Sensor(SensorType type)
: m_type(type) {} : m_type(type) {}
static const char* getSensorName(SensorType type);
private: private:
// Retrieve the current reading from the sensor. // Retrieve the current reading from the sensor.
// //

View File

@ -0,0 +1,13 @@
#include "proxy_sensor.h"
#include "functional_sensor.h"
#include "efilib.h"
#include "loggingcentral.h"
void ProxySensor::showInfo(Logging* logger, const char* sensorName) const {
scheduleMsg(logger, "Sensor \"%s\" proxied from sensor \"%s\"", sensorName, getSensorName(m_proxiedSensor));
}
void FunctionalSensor::showInfo(Logging* logger, const char* sensorName) const {
const auto [valid, value] = get();
scheduleMsg(logger, "Sensor \"%s\": Raw value: %.2f Valid: %d Converted value %.2f", sensorName, m_rawValue, valid, value);
}

View File

@ -11,6 +11,7 @@ CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cp
$(PROJECT_DIR)/controllers/sensors/maf2map.cpp \ $(PROJECT_DIR)/controllers/sensors/maf2map.cpp \
$(PROJECT_DIR)/controllers/sensors/hip9011_lookup.cpp \ $(PROJECT_DIR)/controllers/sensors/hip9011_lookup.cpp \
$(PROJECT_DIR)/controllers/sensors/sensor.cpp \ $(PROJECT_DIR)/controllers/sensors/sensor.cpp \
$(PROJECT_DIR)/controllers/sensors/sensor_info_printing.cpp \
$(PROJECT_DIR)/controllers/sensors/functional_sensor.cpp \ $(PROJECT_DIR)/controllers/sensors/functional_sensor.cpp \
$(PROJECT_DIR)/controllers/sensors/converters/linear_func.cpp \ $(PROJECT_DIR)/controllers/sensors/converters/linear_func.cpp \
$(PROJECT_DIR)/controllers/sensors/converters/resistance_func.cpp \ $(PROJECT_DIR)/controllers/sensors/converters/resistance_func.cpp \

View File

@ -4,8 +4,10 @@
#pragma once #pragma once
class Logging;
// Call this once at startup to initialize, configure, and subscribe sensors // Call this once at startup to initialize, configure, and subscribe sensors
void initSensors(); void initNewSensors(Logging* logger);
// Call this whenever the configuration may have changed, so any sensors // Call this whenever the configuration may have changed, so any sensors
// can be reconfigured with the new settings. // can be reconfigured with the new settings.

View File

@ -6,18 +6,18 @@
#include "init.h" #include "init.h"
#include "sensor.h" #include "sensor.h"
static void initSensorCli(); static void initSensorCli(Logging* logger);
// Sensor init/config // Sensor init/config
void initTps(); void initTps();
void initOilPressure(); void initOilPressure();
void initSensors() { void initNewSensors(Logging* logger) {
initTps(); initTps();
initOilPressure(); initOilPressure();
// Init CLI functionality for sensors (mocking) // Init CLI functionality for sensors (mocking)
initSensorCli(); initSensorCli(logger);
} }
// Sensor reconfiguration // Sensor reconfiguration
@ -29,8 +29,19 @@ void reconfigureSensors() {
reconfigureOilPressure(); reconfigureOilPressure();
} }
static Logging* s_logger;
// Mocking/testing helpers // Mocking/testing helpers
static void initSensorCli() { static void initSensorCli(Logging* logger) {
s_logger = logger;
addConsoleActionIF("set_sensor_mock", Sensor::setMockValue); addConsoleActionIF("set_sensor_mock", Sensor::setMockValue);
addConsoleAction("reset_sensor_mocks", Sensor::resetAllMocks); addConsoleAction("reset_sensor_mocks", Sensor::resetAllMocks);
addConsoleAction("show_sensors", []() { Sensor::showAllSensorInfo(s_logger); });
addConsoleActionI("show_sensor",
[](int idx) {
if (auto s = Sensor::getSensorOfType(static_cast<SensorType>(idx))) {
s->showAllSensorInfo(s_logger);
}
});
} }

View File

@ -45,19 +45,6 @@ int indexOf(const char *string, char ch);
float atoff(const char *string); float atoff(const char *string);
int atoi(const char *string); int atoi(const char *string);
#if defined(__cplusplus) && defined(__OPTIMIZE__)
#include <type_traits>
// "g++ -O2" version, adds more strict type check and yet no "strict-aliasing" warnings!
#define cisnan(f) ({ \
static_assert(sizeof(f) == sizeof(int32_t)); \
union cisnanu_t { std::remove_reference_t<decltype(f)> __f; int32_t __i; } __cisnan_u = { f }; \
__cisnan_u.__i == 0x7FC00000; \
})
#else
// "g++ -O0" or other C++/C compilers
#define cisnan(f) (*(((int*) (&f))) == 0x7FC00000)
#endif /* __cplusplus && __OPTIMIZE__ */
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
int absI(int32_t value); int absI(int32_t value);
@ -124,4 +111,17 @@ constexpr void copyArrayPartial(TElement (&dest)[NDest], const TElement (&src)[N
#endif /* __cplusplus */ #endif /* __cplusplus */
#if defined(__cplusplus) && defined(__OPTIMIZE__)
#include <type_traits>
// "g++ -O2" version, adds more strict type check and yet no "strict-aliasing" warnings!
#define cisnan(f) ({ \
static_assert(sizeof(f) == sizeof(int32_t)); \
union cisnanu_t { std::remove_reference_t<decltype(f)> __f; int32_t __i; } __cisnan_u = { f }; \
__cisnan_u.__i == 0x7FC00000; \
})
#else
// "g++ -O0" or other C++/C compilers
#define cisnan(f) (*(((int*) (&f))) == 0x7FC00000)
#endif /* __cplusplus && __OPTIMIZE__ */
#endif /* EFILIB_H_ */ #endif /* EFILIB_H_ */

View File

@ -7,6 +7,8 @@
#ifndef UTIL_LOGGINGCENTRAL_H_ #ifndef UTIL_LOGGINGCENTRAL_H_
#define UTIL_LOGGINGCENTRAL_H_ #define UTIL_LOGGINGCENTRAL_H_
class Logging;
void initLoggingCentral(void); void initLoggingCentral(void);
char * swapOutputBuffers(int *actualOutputBufferSize); char * swapOutputBuffers(int *actualOutputBufferSize);
void scheduleMsg(Logging *logging, const char *fmt, ...); void scheduleMsg(Logging *logging, const char *fmt, ...);

View File

@ -18,4 +18,6 @@ struct MockSensor final : public StoredValueSensor
{ {
StoredValueSensor::invalidate(); StoredValueSensor::invalidate();
} }
void showInfo(Logging* logger, const char* name) const override {}
}; };