General purpose PWM: implementation & tests (#1366)
* config * significant digits * renumber enum, no need for a "none" * ui * impl base * error handle MAP * init & update * don't need arg * don't lie about sensor * fix test build * test stub * initialize * null check * fix clamping * test output * types & enums * don't need param * test getOutput * fix * output pin instead of brain pin * default config
This commit is contained in:
parent
7aa697c256
commit
f128b33694
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
#include "gppwm_channel.h"
|
||||||
|
#include "pwm_generator_logic.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
static GppwmChannel channels[4];
|
||||||
|
static OutputPin pins[4];
|
||||||
|
static SimplePwm outputs[4];
|
||||||
|
|
||||||
|
static gppwm_Map3D_t table1("GPPWM 1");
|
||||||
|
static gppwm_Map3D_t table2("GPPWM 2");
|
||||||
|
static gppwm_Map3D_t table3("GPPWM 3");
|
||||||
|
static gppwm_Map3D_t table4("GPPWM 4");
|
||||||
|
|
||||||
|
static gppwm_Map3D_t* tables[] = {
|
||||||
|
&table1,
|
||||||
|
&table2,
|
||||||
|
&table3,
|
||||||
|
&table4,
|
||||||
|
};
|
||||||
|
|
||||||
|
void initGpPwm(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
for (size_t i = 0; i < efi::size(channels); i++) {
|
||||||
|
auto& cfg = CONFIG(gppwm)[i];
|
||||||
|
|
||||||
|
// If no pin, don't enable this channel.
|
||||||
|
if (cfg.pin == GPIO_UNASSIGNED) continue;
|
||||||
|
|
||||||
|
// Determine frequency and whether PWM is enabled
|
||||||
|
float freq = cfg.pwmFrequency;
|
||||||
|
bool usePwm = freq > 0;
|
||||||
|
|
||||||
|
// Setup pin & pwm
|
||||||
|
pins[i].initPin("gp pwm", cfg.pin);
|
||||||
|
startSimplePwm(&outputs[i], "gp pwm", &engine->executor, &pins[i], freq, 0);
|
||||||
|
|
||||||
|
// Set up this channel's lookup table
|
||||||
|
tables[i]->init(cfg.table, cfg.loadBins, cfg.rpmBins);
|
||||||
|
|
||||||
|
// Finally configure the channel
|
||||||
|
INJECT_ENGINE_REFERENCE(&channels[i]);
|
||||||
|
channels[i].init(usePwm, &outputs[i], tables[i], &cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateGppwm() {
|
||||||
|
for (size_t i = 0; i < efi::size(channels); i++) {
|
||||||
|
channels[i].update();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
void initGpPwm(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
void updateGppwm();
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
#include "gppwm_channel.h"
|
||||||
|
|
||||||
|
#include "engine.h"
|
||||||
|
#include "pwm_generator_logic.h"
|
||||||
|
#include "table_helper.h"
|
||||||
|
#include "expected.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
expected<float> readGppwmChannel(gppwm_channel_e channel DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
switch (channel) {
|
||||||
|
case GPPWM_Tps:
|
||||||
|
return Sensor::get(SensorType::Tps1);
|
||||||
|
case GPPWM_Map: {
|
||||||
|
float map = getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
|
if (cisnan(map)) {
|
||||||
|
return unexpected;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
case GPPWM_Clt:
|
||||||
|
return Sensor::get(SensorType::Clt);
|
||||||
|
case GPPWM_Iat:
|
||||||
|
return Sensor::get(SensorType::Iat);
|
||||||
|
default:
|
||||||
|
return unexpected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GppwmChannel::setOutput(float result) {
|
||||||
|
// Not init yet, nothing to do.
|
||||||
|
if (!m_pwm || !m_config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_usePwm) {
|
||||||
|
// Apply hysteresis with provided values
|
||||||
|
if (m_state && result < m_config->offBelowDuty) {
|
||||||
|
m_state = false;
|
||||||
|
} else if (!m_state && result > m_config->onAboveDuty) {
|
||||||
|
m_state = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = m_state ? 100 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pwm->setSimplePwmDutyCycle(clampF(0, result / 100.0f, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GppwmChannel::init(bool usePwm, SimplePwm* pwm, const ValueProvider3D* table, const gppwm_channel* config) {
|
||||||
|
m_usePwm = usePwm;
|
||||||
|
m_pwm = pwm;
|
||||||
|
m_table = table;
|
||||||
|
m_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GppwmChannel::getOutput() const {
|
||||||
|
expected<float> loadAxisValue = readGppwmChannel(m_config->loadAxis PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
|
// If we couldn't get load axis value, fall back on error value
|
||||||
|
if (!loadAxisValue) {
|
||||||
|
return m_config->dutyIfError;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rpm = GET_RPM();
|
||||||
|
|
||||||
|
float result = m_table->getValue(rpm / RPM_1_BYTE_PACKING_MULT, loadAxisValue.Value);
|
||||||
|
|
||||||
|
if (cisnan(result)) {
|
||||||
|
return m_config->dutyIfError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GppwmChannel::update() {
|
||||||
|
// Without a config, nothing to do.
|
||||||
|
if (!m_config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float output = getOutput();
|
||||||
|
setOutput(output);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gppwm.h"
|
||||||
|
|
||||||
|
class OutputPin;
|
||||||
|
class SimplePwm;
|
||||||
|
class ValueProvider3D;
|
||||||
|
|
||||||
|
class GppwmChannel {
|
||||||
|
public:
|
||||||
|
DECLARE_ENGINE_PTR;
|
||||||
|
|
||||||
|
void init(bool usePwm, SimplePwm* pwm, const ValueProvider3D* table, const gppwm_channel* config);
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
float getOutput() const;
|
||||||
|
void setOutput(float result);
|
||||||
|
|
||||||
|
// Store the current state so we can apply hysteresis
|
||||||
|
bool m_state = false;
|
||||||
|
|
||||||
|
// Configuration fields
|
||||||
|
const gppwm_channel* m_config = nullptr;
|
||||||
|
bool m_usePwm = false;
|
||||||
|
SimplePwm* m_pwm = nullptr;
|
||||||
|
const ValueProvider3D* m_table = nullptr;
|
||||||
|
};
|
|
@ -25,6 +25,7 @@
|
||||||
#include "fsio_impl.h"
|
#include "fsio_impl.h"
|
||||||
#include "perf_trace.h"
|
#include "perf_trace.h"
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
|
#include "gppwm.h"
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
#include "bench_test.h"
|
#include "bench_test.h"
|
||||||
|
@ -140,6 +141,8 @@ void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
runHardcodedFsio(PASS_ENGINE_PARAMETER_SIGNATURE);
|
runHardcodedFsio(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
#endif /* EFI_FSIO */
|
#endif /* EFI_FSIO */
|
||||||
|
|
||||||
|
updateGppwm();
|
||||||
|
|
||||||
cylinderCleanupControl(PASS_ENGINE_PARAMETER_SIGNATURE);
|
cylinderCleanupControl(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
#if (BOARD_TLE8888_COUNT > 0)
|
#if (BOARD_TLE8888_COUNT > 0)
|
||||||
|
|
|
@ -629,6 +629,34 @@ void setDefaultMultisparkParameters(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
engineConfiguration->multisparkMaxSparkingAngle = 30;
|
engineConfiguration->multisparkMaxSparkingAngle = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDefaultGppwmParameters(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
// Same config for all channels
|
||||||
|
for (size_t i = 0; i < efi::size(CONFIG(gppwm)); i++) {
|
||||||
|
auto& cfg = CONFIG(gppwm)[i];
|
||||||
|
|
||||||
|
cfg.pin = GPIO_UNASSIGNED;
|
||||||
|
cfg.dutyIfError = 0;
|
||||||
|
cfg.onAboveDuty = 60;
|
||||||
|
cfg.offBelowDuty = 50;
|
||||||
|
cfg.pwmFrequency = 250;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < efi::size(cfg.loadBins); j++) {
|
||||||
|
uint8_t z = j * 100 / (efi::size(cfg.loadBins) - 1);
|
||||||
|
cfg.loadBins[j] = z;
|
||||||
|
|
||||||
|
// Fill some values in the table
|
||||||
|
for (size_t k = 0; k < efi::size(cfg.rpmBins); k++) {
|
||||||
|
cfg.table[j][k] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < efi::size(cfg.rpmBins); j++) {
|
||||||
|
cfg.rpmBins[j] = 1000 * j / RPM_1_BYTE_PACKING_MULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Global default engine configuration
|
* @brief Global default engine configuration
|
||||||
* This method sets the global engine configuration defaults. These default values are then
|
* This method sets the global engine configuration defaults. These default values are then
|
||||||
|
@ -871,6 +899,8 @@ static void setDefaultEngineConfiguration(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
|
||||||
setDefaultMultisparkParameters(PASS_ENGINE_PARAMETER_SIGNATURE);
|
setDefaultMultisparkParameters(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
|
setDefaultGppwmParameters(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
#if !EFI_UNIT_TEST
|
#if !EFI_UNIT_TEST
|
||||||
engineConfiguration->analogInputDividerCoefficient = 2;
|
engineConfiguration->analogInputDividerCoefficient = 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -101,7 +101,7 @@ typedef float fsio_table_8x8_f32t[FSIO_TABLE_8][FSIO_TABLE_8];
|
||||||
typedef float tps_tps_table_t[TPS_TPS_ACCEL_TABLE][TPS_TPS_ACCEL_TABLE];
|
typedef float tps_tps_table_t[TPS_TPS_ACCEL_TABLE][TPS_TPS_ACCEL_TABLE];
|
||||||
typedef uint8_t fsio_table_8x8_u8t[FSIO_TABLE_8][FSIO_TABLE_8];
|
typedef uint8_t fsio_table_8x8_u8t[FSIO_TABLE_8][FSIO_TABLE_8];
|
||||||
typedef uint8_t boost_table_t[BOOST_LOAD_COUNT][BOOST_RPM_COUNT];
|
typedef uint8_t boost_table_t[BOOST_LOAD_COUNT][BOOST_RPM_COUNT];
|
||||||
typedef uint8_t gppwm_table_t[GPPWM_LOAD_COUNT][GPPWM_RPM_COUNT];
|
typedef uint8_t gppwm_table_t[GPPWM_LOAD_COUNT][GPPWM_RPM_COUNT];
|
||||||
|
|
||||||
|
|
||||||
// this is different type simply to have different hi/low range in rusefi.ini
|
// this is different type simply to have different hi/low range in rusefi.ini
|
||||||
|
|
|
@ -18,6 +18,8 @@ CONTROLLERS_SRC_CPP = \
|
||||||
$(CONTROLLERS_DIR)/actuators/idle_thread.cpp \
|
$(CONTROLLERS_DIR)/actuators/idle_thread.cpp \
|
||||||
$(CONTROLLERS_DIR)/actuators/pwm_tester.cpp \
|
$(CONTROLLERS_DIR)/actuators/pwm_tester.cpp \
|
||||||
$(CONTROLLERS_DIR)/actuators/algo/aux_pid.cpp \
|
$(CONTROLLERS_DIR)/actuators/algo/aux_pid.cpp \
|
||||||
|
$(CONTROLLERS_DIR)/actuators/gppwm/gppwm_channel.cpp \
|
||||||
|
$(CONTROLLERS_DIR)/actuators/gppwm/gppwm.cpp \
|
||||||
$(CONTROLLERS_DIR)/gauges/tachometer.cpp \
|
$(CONTROLLERS_DIR)/gauges/tachometer.cpp \
|
||||||
$(CONTROLLERS_DIR)/gauges/malfunction_indicator.cpp \
|
$(CONTROLLERS_DIR)/gauges/malfunction_indicator.cpp \
|
||||||
$(CONTROLLERS_DIR)/gauges/lcd_controller.cpp \
|
$(CONTROLLERS_DIR)/gauges/lcd_controller.cpp \
|
||||||
|
@ -61,4 +63,5 @@ CONTROLLERS_INC=\
|
||||||
$(CONTROLLERS_DIR)/math \
|
$(CONTROLLERS_DIR)/math \
|
||||||
$(CONTROLLERS_DIR)/generated \
|
$(CONTROLLERS_DIR)/generated \
|
||||||
$(CONTROLLERS_DIR)/actuators \
|
$(CONTROLLERS_DIR)/actuators \
|
||||||
|
$(CONTROLLERS_DIR)/actuators/gppwm \
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "boost_control.h"
|
#include "boost_control.h"
|
||||||
#include "launch_control.h"
|
#include "launch_control.h"
|
||||||
#include "tachometer.h"
|
#include "tachometer.h"
|
||||||
|
#include "gppwm.h"
|
||||||
|
|
||||||
#if EFI_SENSOR_CHART
|
#if EFI_SENSOR_CHART
|
||||||
#include "sensor_chart.h"
|
#include "sensor_chart.h"
|
||||||
|
@ -136,6 +137,8 @@ static void mostCommonInitEngineController(Logging *sharedLogger DECLARE_ENGINE_
|
||||||
initFsioImpl(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
|
initFsioImpl(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
#endif /* EFI_FSIO */
|
#endif /* EFI_FSIO */
|
||||||
|
|
||||||
|
initGpPwm(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
#if EFI_IDLE_CONTROL
|
#if EFI_IDLE_CONTROL
|
||||||
startIdleThread(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
|
startIdleThread(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
#endif /* EFI_IDLE_CONTROL */
|
#endif /* EFI_IDLE_CONTROL */
|
||||||
|
|
|
@ -117,7 +117,7 @@ class SimplePwm : public PwmConfig {
|
||||||
public:
|
public:
|
||||||
SimplePwm();
|
SimplePwm();
|
||||||
explicit SimplePwm(const char *name);
|
explicit SimplePwm(const char *name);
|
||||||
void setSimplePwmDutyCycle(float dutyCycle);
|
virtual void setSimplePwmDutyCycle(float dutyCycle);
|
||||||
pin_state_t pinStates[2];
|
pin_state_t pinStates[2];
|
||||||
SingleChannelStateSequence sr[1];
|
SingleChannelStateSequence sr[1];
|
||||||
float _switchTimes[2];
|
float _switchTimes[2];
|
||||||
|
|
|
@ -297,7 +297,7 @@ end_struct
|
||||||
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:1], @@gppwm_channel_e_enum@@
|
custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:1], @@gppwm_channel_e_enum@@
|
||||||
|
|
||||||
struct gppwm_channel
|
struct gppwm_channel
|
||||||
brain_pin_e pin;+Select a pin to use for PWM or on-off output.;
|
output_pin_e pin;+Select a pin to use for PWM or on-off output.;
|
||||||
uint8_t dutyIfError;+If an error (with a sensor, etc) is detected, this value is used instead of reading from the table.\nThis should be a safe value for whatever hardware is connected to prevent damage.;"%", 1, 0, 0, 100, 0
|
uint8_t dutyIfError;+If an error (with a sensor, etc) is detected, this value is used instead of reading from the table.\nThis should be a safe value for whatever hardware is connected to prevent damage.;"%", 1, 0, 0, 100, 0
|
||||||
uint16_t pwmFrequency;+Select a frequency to run PWM at.\nSet this to 0hz to enable on-off mode.;"hz", 1, 0, 0, 500, 0
|
uint16_t pwmFrequency;+Select a frequency to run PWM at.\nSet this to 0hz to enable on-off mode.;"hz", 1, 0, 0, 500, 0
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
explicit Map3D(const char*name);
|
explicit Map3D(const char*name);
|
||||||
Map3D(const char*name, float multiplier);
|
Map3D(const char*name, float multiplier);
|
||||||
void init(vType table[RPM_BIN_SIZE][LOAD_BIN_SIZE], const kType loadBins[LOAD_BIN_SIZE], const kType rpmBins[RPM_BIN_SIZE]);
|
void init(vType table[RPM_BIN_SIZE][LOAD_BIN_SIZE], const kType loadBins[LOAD_BIN_SIZE], const kType rpmBins[RPM_BIN_SIZE]);
|
||||||
float getValue(float xRpm, float y) const;
|
float getValue(float xRpm, float y) const override;
|
||||||
void setAll(vType value);
|
void setAll(vType value);
|
||||||
vType *pointers[LOAD_BIN_SIZE];
|
vType *pointers[LOAD_BIN_SIZE];
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "electronic_throttle.h"
|
#include "electronic_throttle.h"
|
||||||
#include "dc_motor.h"
|
#include "dc_motor.h"
|
||||||
#include "table_helper.h"
|
#include "table_helper.h"
|
||||||
|
#include "pwm_generator_logic.h"
|
||||||
|
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
@ -37,3 +38,8 @@ class MockVp3d : public ValueProvider3D {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD(float, getValue, (float xRpm, float y), (const, override));
|
MOCK_METHOD(float, getValue, (float xRpm, float y), (const, override));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MockPwm : public SimplePwm {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD(void, setSimplePwmDutyCycle, (float dutyCycle), (override));
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
#include "engine_test_helper.h"
|
||||||
|
#include "gppwm_channel.h"
|
||||||
|
#include "gppwm.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
|
||||||
|
#include "mocks.h"
|
||||||
|
|
||||||
|
using ::testing::InSequence;
|
||||||
|
|
||||||
|
TEST(GpPwm, OutputWithPwm) {
|
||||||
|
GppwmChannel ch;
|
||||||
|
|
||||||
|
gppwm_channel cfg;
|
||||||
|
|
||||||
|
MockPwm pwm;
|
||||||
|
|
||||||
|
// Shouldn't throw with no config
|
||||||
|
EXPECT_NO_THROW(ch.setOutput(10));
|
||||||
|
|
||||||
|
{
|
||||||
|
InSequence i;
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.25f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.75f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
ch.init(true, &pwm, nullptr, &cfg);
|
||||||
|
|
||||||
|
// Set the output - should set directly to PWM
|
||||||
|
ch.setOutput(25.0f);
|
||||||
|
ch.setOutput(75.0f);
|
||||||
|
|
||||||
|
// Test clamping behavior - should clamp to [0, 100]
|
||||||
|
ch.setOutput(-10.0f);
|
||||||
|
ch.setOutput(110.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GpPwm, OutputOnOff) {
|
||||||
|
GppwmChannel ch;
|
||||||
|
|
||||||
|
gppwm_channel cfg;
|
||||||
|
cfg.onAboveDuty = 50;
|
||||||
|
cfg.offBelowDuty = 40;
|
||||||
|
|
||||||
|
MockPwm pwm;
|
||||||
|
|
||||||
|
{
|
||||||
|
InSequence i;
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(1.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(1.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(1.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.0f));
|
||||||
|
EXPECT_CALL(pwm, setSimplePwmDutyCycle(0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
ch.init(false, &pwm, nullptr, &cfg);
|
||||||
|
|
||||||
|
// Test rising edge - these should output 0, 1, 1
|
||||||
|
ch.setOutput(49.0f);
|
||||||
|
ch.setOutput(51.0f);
|
||||||
|
ch.setOutput(49.0f);
|
||||||
|
|
||||||
|
// Test falling edge - these should output 1, 0, 0
|
||||||
|
ch.setOutput(41.0f);
|
||||||
|
ch.setOutput(39.0f);
|
||||||
|
ch.setOutput(41.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(GpPwm, GetOutput) {
|
||||||
|
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
|
||||||
|
GppwmChannel ch;
|
||||||
|
INJECT_ENGINE_REFERENCE(&ch);
|
||||||
|
|
||||||
|
gppwm_channel cfg;
|
||||||
|
cfg.loadAxis = GPPWM_Tps;
|
||||||
|
cfg.dutyIfError = 21.0f;
|
||||||
|
|
||||||
|
MockVp3d table;
|
||||||
|
|
||||||
|
engine->rpmCalculator.mockRpm = 1200;
|
||||||
|
EXPECT_CALL(table, getValue(1200 / RPM_1_BYTE_PACKING_MULT, 35.0f))
|
||||||
|
.WillRepeatedly([](float x, float tps) {
|
||||||
|
return tps;
|
||||||
|
});
|
||||||
|
|
||||||
|
ch.init(false, nullptr, &table, &cfg);
|
||||||
|
|
||||||
|
Sensor::resetAllMocks();
|
||||||
|
|
||||||
|
// Should return dutyIfError
|
||||||
|
EXPECT_FLOAT_EQ(21.0f, ch.getOutput());
|
||||||
|
|
||||||
|
// Set TPS, should return tps value
|
||||||
|
Sensor::setMockValue(SensorType::Tps1, 35.0f);
|
||||||
|
EXPECT_FLOAT_EQ(35.0f, ch.getOutput());
|
||||||
|
}
|
|
@ -49,4 +49,5 @@ TESTS_SRC_CPP = \
|
||||||
tests/sensor/redundant.cpp \
|
tests/sensor/redundant.cpp \
|
||||||
tests/sensor/test_sensor_init.cpp \
|
tests/sensor/test_sensor_init.cpp \
|
||||||
tests/test_closed_loop_controller.cpp \
|
tests/test_closed_loop_controller.cpp \
|
||||||
|
tests/test_gppwm.cpp \
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue