diff --git a/firmware/controllers/actuators/electronic_throttle.cpp b/firmware/controllers/actuators/electronic_throttle.cpp index c54b40c77b..4ad660a94a 100644 --- a/firmware/controllers/actuators/electronic_throttle.cpp +++ b/firmware/controllers/actuators/electronic_throttle.cpp @@ -99,56 +99,55 @@ static bool startupPositionError = false; #define STARTUP_NEUTRAL_POSITION_ERROR_THRESHOLD 5 -static SensorType indexToTpsSensor(size_t index, bool dcMotorIdleValve) { - if (dcMotorIdleValve) { - return SensorType::Tps2; - } - - switch(index) { - case 0: return SensorType::Tps1; - default: return SensorType::Tps2; +static SensorType functionToPositionSensor(etb_function_e func) { + switch(func) { + case ETB_Throttle1: return SensorType::Tps1; + case ETB_Throttle2: return SensorType::Tps2; + case ETB_IdleValve: return SensorType::IdlePosition; + case ETB_Wastegate: return SensorType::WastegatePosition; + default: return SensorType::Invalid; } } -static SensorType indexToTpsSensorPrimary(size_t index) { - switch(index) { - case 0: return SensorType::Tps1Primary; +static SensorType functionToTpsSensorPrimary(etb_function_e func) { + switch(func) { + case ETB_Throttle1: return SensorType::Tps1Primary; default: return SensorType::Tps2Primary; } } -static SensorType indexToTpsSensorSecondary(size_t index) { - switch(index) { - case 0: return SensorType::Tps1Secondary; +static SensorType functionToTpsSensorSecondary(etb_function_e func) { + switch(func) { + case ETB_Throttle1: return SensorType::Tps1Secondary; default: return SensorType::Tps2Secondary; } } #if EFI_TUNER_STUDIO -static TsCalMode indexToCalModePriMin(size_t index) { - switch (index) { - case 0: return TsCalMode::Tps1Min; +static TsCalMode functionToCalModePriMin(etb_function_e func) { + switch (func) { + case ETB_Throttle1: return TsCalMode::Tps1Min; default: return TsCalMode::Tps2Min; } } -static TsCalMode indexToCalModePriMax(size_t index) { - switch (index) { - case 0: return TsCalMode::Tps1Max; +static TsCalMode functionToCalModePriMax(etb_function_e func) { + switch (func) { + case ETB_Throttle1: return TsCalMode::Tps1Max; default: return TsCalMode::Tps2Max; } } -static TsCalMode indexToCalModeSecMin(size_t index) { - switch (index) { - case 0: return TsCalMode::Tps1SecondaryMin; +static TsCalMode functionToCalModeSecMin(etb_function_e func) { + switch (func) { + case ETB_Throttle1: return TsCalMode::Tps1SecondaryMin; default: return TsCalMode::Tps2SecondaryMin; } } -static TsCalMode indexToCalModeSecMax(size_t index) { - switch (index) { - case 0: return TsCalMode::Tps1SecondaryMax; +static TsCalMode functionToCalModeSecMax(etb_function_e func) { + switch (func) { + case ETB_Throttle1: return TsCalMode::Tps1SecondaryMax; default: return TsCalMode::Tps2SecondaryMax; } } @@ -161,12 +160,19 @@ static percent_t currentEtbDuty; // this macro clamps both positive and negative percentages from about -100% to 100% #define ETB_PERCENT_TO_DUTY(x) (clampF(-ETB_DUTY_LIMIT, 0.01f * (x), ETB_DUTY_LIMIT)) -void EtbController::init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) { - m_positionSensor = positionSensor; +bool EtbController::init(etb_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D* pedalMap) { + if (function == ETB_None) { + // if not configured, don't init. + return false; + } + + m_function = function; + m_positionSensor = functionToPositionSensor(function); m_motor = motor; - m_myIndex = ownIndex; m_pid.initPidClass(pidParameters); m_pedalMap = pedalMap; + + return true; } void EtbController::reset() { @@ -192,20 +198,39 @@ void EtbController::setIdlePosition(percent_t pos) { } expected EtbController::getSetpoint() const { + switch (m_function) { + case ETB_Throttle1: + case ETB_Throttle2: + return getSetpointEtb(); + case ETB_IdleValve: + return getSetpointIdleValve(); + case ETB_Wastegate: + return getSetpointWastegate(); + default: + return unexpected; + } +} + +expected EtbController::getSetpointIdleValve() const { + // VW ETB idle mode uses an ETB only for idle (a mini-ETB sets the lower stop, and a normal cable + // can pull the throttle up off the stop.), so we directly control the throttle with the idle position. +#if EFI_TUNER_STUDIO + tsOutputChannels.etbTarget = m_idlePosition; +#endif // EFI_TUNER_STUDIO + return clampF(0, m_idlePosition, 100); +} + +expected EtbController::getSetpointWastegate() const { + // TODO: implement me! + return unexpected; +} + +expected EtbController::getSetpointEtb() const { // A few extra preconditions if throttle control is invalid if (startupPositionError) { return unexpected; } - // VW ETB idle mode uses an ETB only for idle (a mini-ETB sets the lower stop, and a normal cable - // can pull the throttle up off the stop.), so we directly control the throttle with the idle position. - if (CONFIG(dcMotorIdleValve)) { -#if EFI_TUNER_STUDIO - tsOutputChannels.etbTarget = m_idlePosition; -#endif // EFI_TUNER_STUDIO - return clampF(0, m_idlePosition, 100); - } - // If the pedal map hasn't been set, we can't provide a setpoint. if (!m_pedalMap) { return unexpected; @@ -236,7 +261,7 @@ expected EtbController::getSetpoint() const { percent_t targetPosition = interpolateClamped(0, etbIdleAddition, 100, 100, targetFromTable); #if EFI_TUNER_STUDIO - if (m_myIndex == 0) { + if (m_function == ETB_Throttle1) { tsOutputChannels.etbTarget = targetPosition; } #endif // EFI_TUNER_STUDIO @@ -360,15 +385,17 @@ expected EtbController::getClosedLoop(percent_t target, percent_t obs } // Only report the 0th throttle - if (m_myIndex == 0) { + if (m_function == ETB_Throttle1) { #if EFI_TUNER_STUDIO // Error is positive if the throttle needs to open further tsOutputChannels.etb1Error = target - observation; #endif /* EFI_TUNER_STUDIO */ } - // Only allow autotune with stopped engine - if (GET_RPM() == 0 && engine->etbAutoTune) { + // Only allow autotune with stopped engine, and on the first throttle + if (GET_RPM() == 0 + && engine->etbAutoTune + && m_function == ETB_Throttle1) { return getClosedLoopAutotune(observation); } else { // Normal case - use PID to compute closed loop part @@ -379,7 +406,7 @@ expected EtbController::getClosedLoop(percent_t target, percent_t obs void EtbController::setOutput(expected outputValue) { #if EFI_TUNER_STUDIO // Only report first-throttle stats - if (m_myIndex == 0) { + if (m_function == ETB_Throttle1) { tsOutputChannels.etb1DutyCycle = outputValue.value_or(0); } #endif @@ -396,9 +423,14 @@ void EtbController::setOutput(expected outputValue) { } void EtbController::update() { + // If we didn't get initialized, fail fast + if (!m_motor) { + return; + } + #if EFI_TUNER_STUDIO - // Only debug throttle #0 - if (m_myIndex == 0) { + // Only debug throttle #1 + if (m_function == ETB_Throttle1) { // set debug_mode 17 if (engineConfiguration->debugMode == DBG_ELECTRONIC_THROTTLE_PID) { m_pid.postState(&tsOutputChannels); @@ -474,7 +506,10 @@ DISPLAY(DISPLAY_IF(1)) } void EtbController::autoCalibrateTps() { - m_isAutocal = true; + // Only auto calibrate throttles + if (m_function == ETB_Throttle1 || m_function == ETB_Throttle2) { + m_isAutocal = true; + } } #if !EFI_UNIT_TEST @@ -500,14 +535,14 @@ struct EtbImpl final : public EtbController { return; } - size_t myIndex = getMyIndex(); + auto myFunction = getFunction(); // First grab open motor->set(0.5f); motor->enable(); chThdSleepMilliseconds(1000); - float primaryMax = Sensor::getRaw(indexToTpsSensorPrimary(myIndex)) * TPS_TS_CONVERSION; - float secondaryMax = Sensor::getRaw(indexToTpsSensorSecondary(myIndex)) * TPS_TS_CONVERSION; + float primaryMax = Sensor::getRaw(functionToTpsSensorPrimary(myFunction)) * TPS_TS_CONVERSION; + float secondaryMax = Sensor::getRaw(functionToTpsSensorSecondary(myFunction)) * TPS_TS_CONVERSION; // Let it return motor->set(0); @@ -516,24 +551,24 @@ struct EtbImpl final : public EtbController { // Now grab closed motor->set(-0.5f); chThdSleepMilliseconds(1000); - float primaryMin = Sensor::getRaw(indexToTpsSensorPrimary(myIndex)) * TPS_TS_CONVERSION; - float secondaryMin = Sensor::getRaw(indexToTpsSensorSecondary(myIndex)) * TPS_TS_CONVERSION; + float primaryMin = Sensor::getRaw(functionToTpsSensorPrimary(myFunction)) * TPS_TS_CONVERSION; + float secondaryMin = Sensor::getRaw(functionToTpsSensorSecondary(myFunction)) * TPS_TS_CONVERSION; // Finally disable and reset state motor->disable(); // Write out the learned values to TS, waiting briefly after setting each to let TS grab it - tsOutputChannels.calibrationMode = indexToCalModePriMax(myIndex); + tsOutputChannels.calibrationMode = functionToCalModePriMax(myFunction); tsOutputChannels.calibrationValue = primaryMax; chThdSleepMilliseconds(500); - tsOutputChannels.calibrationMode = indexToCalModePriMin(myIndex); + tsOutputChannels.calibrationMode = functionToCalModePriMin(myFunction); tsOutputChannels.calibrationValue = primaryMin; chThdSleepMilliseconds(500); - tsOutputChannels.calibrationMode = indexToCalModeSecMax(myIndex); + tsOutputChannels.calibrationMode = functionToCalModeSecMax(myFunction); tsOutputChannels.calibrationValue = secondaryMax; chThdSleepMilliseconds(500); - tsOutputChannels.calibrationMode = indexToCalModeSecMin(myIndex); + tsOutputChannels.calibrationMode = functionToCalModeSecMin(myFunction); tsOutputChannels.calibrationValue = secondaryMin; chThdSleepMilliseconds(500); @@ -787,18 +822,14 @@ void doInitElectronicThrottle(DECLARE_ENGINE_PARAMETER_SIGNATURE) { addConsoleActionI("etb_freq", setEtbFrequency); #endif /* EFI_PROD_CODE */ - // If you don't have a pedal (or VW idle valve mode), we have no business here. - if (!CONFIG(dcMotorIdleValve) && !Sensor::hasSensor(SensorType::AcceleratorPedalPrimary)) { + // If you don't have a pedal we have no business here. + if (!Sensor::hasSensor(SensorType::AcceleratorPedalPrimary)) { return; } pedal2tpsMap.init(config->pedalToTpsTable, config->pedalToTpsPedalBins, config->pedalToTpsRpmBins); - if (CONFIG(dcMotorIdleValve)) { - engine->etbActualCount = 1; - } else { - engine->etbActualCount = Sensor::hasSensor(SensorType::Tps2) ? 2 : 1; - } + engine->etbActualCount = Sensor::hasSensor(SensorType::Tps2) ? 2 : 1; for (int i = 0 ; i < engine->etbActualCount; i++) { auto motor = initDcMotor(i, CONFIG(etb_use_two_wires) PASS_ENGINE_PARAMETER_SUFFIX); @@ -806,8 +837,10 @@ void doInitElectronicThrottle(DECLARE_ENGINE_PARAMETER_SIGNATURE) { // If this motor is actually set up, init the etb if (motor) { - auto positionSensor = indexToTpsSensor(i, CONFIG(dcMotorIdleValve)); - engine->etbControllers[i]->init(positionSensor, motor, i, &engineConfiguration->etb, &pedal2tpsMap); + // TODO: configure per-motor in config so wastegate/VW idle works + auto func = i == 0 ? ETB_Throttle1 : ETB_Throttle2; + + engine->etbControllers[i]->init(func, motor, &engineConfiguration->etb, &pedal2tpsMap); INJECT_ENGINE_REFERENCE(engine->etbControllers[i]); } } diff --git a/firmware/controllers/actuators/electronic_throttle.h b/firmware/controllers/actuators/electronic_throttle.h index 2e5f349f99..2113e0f2f2 100644 --- a/firmware/controllers/actuators/electronic_throttle.h +++ b/firmware/controllers/actuators/electronic_throttle.h @@ -27,7 +27,10 @@ class Logging; class IEtbController : public ClosedLoopController { public: DECLARE_ENGINE_PTR; - virtual void init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) = 0; + + // Initialize the throttle. + // returns true if the throttle was initialized, false otherwise. + virtual bool init(etb_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D* pedalMap) = 0; virtual void reset() = 0; virtual void setIdlePosition(percent_t pos) = 0; virtual void update() = 0; @@ -36,7 +39,7 @@ public: class EtbController : public IEtbController { public: - void init(SensorType positionSensor, DcMotor *motor, int ownIndex, pid_s *pidParameters, const ValueProvider3D* pedalMap) override; + bool init(etb_function_e function, DcMotor *motor, pid_s *pidParameters, const ValueProvider3D* pedalMap) override; void setIdlePosition(percent_t pos) override; void reset() override; @@ -52,7 +55,11 @@ public: // Helpers for individual parts of throttle control expected observePlant() const override; + expected getSetpoint() const override; + expected getSetpointEtb() const; + expected getSetpointWastegate() const; + expected getSetpointIdleValve() const; expected getOpenLoop(percent_t target) const override; expected getClosedLoop(percent_t setpoint, percent_t observation) override; @@ -70,11 +77,11 @@ protected: // This is set if an automatic TPS calibration should be run bool m_isAutocal = false; - int getMyIndex() const { return m_myIndex; } + etb_function_e getFunction() const { return m_function; } DcMotor* getMotor() { return m_motor; } private: - int m_myIndex = 0; + etb_function_e m_function = ETB_None; SensorType m_positionSensor = SensorType::Invalid; DcMotor *m_motor = nullptr; Pid m_pid; diff --git a/firmware/controllers/actuators/idle_thread.cpp b/firmware/controllers/actuators/idle_thread.cpp index 05612177c2..e25d37910e 100644 --- a/firmware/controllers/actuators/idle_thread.cpp +++ b/firmware/controllers/actuators/idle_thread.cpp @@ -224,10 +224,6 @@ void applyIACposition(percent_t position DECLARE_ENGINE_PARAMETER_SUFFIX) { } else if (CONFIG(useStepperIdle)) { iacMotor.setTargetPosition(duty * engineConfiguration->idleStepperTotalSteps); #endif /* EFI_UNIT_TEST */ - } else if (CONFIG(dcMotorIdleValve)) { -#if EFI_ELECTRONIC_THROTTLE_BODY - setEtbIdlePosition(position PASS_ENGINE_PARAMETER_SUFFIX); -#endif // EFI_ELECTRONIC_THROTTLE_BODY } else { if (!CONFIG(isDoubleSolenoidIdle)) { idleSolenoidOpen.setSimplePwmDutyCycle(duty); diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 013bfb77a4..8b877aaee9 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -997,3 +997,11 @@ typedef enum __attribute__ ((__packed__)) { AFR_AccPedal = 3, AFR_CylFilling = 4, } afr_override_e; + +typedef enum __attribute__ ((__packed__)) { + ETB_None = 0, + ETB_Throttle1 = 1, + ETB_Throttle2 = 2, + ETB_IdleValve = 3, + ETB_Wastegate = 4, +} etb_function_e; diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index d4c1eeb803..22ef1fd3f5 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -895,7 +895,7 @@ custom maf_sensor_type_e 4 bits, S32, @OFFSET@, [0:1], @@maf_sensor_type_e_enum@ bit enableInnovateLC2 bit showHumanReadableWarning bit stftIgnoreErrorMagnitude;+If enabled, adjust at a constant rate instead of a rate proportional to the current lambda error. This mode may be easier to tune, and more tolerant of sensor noise. Use of this mode is required if you have a narrowband O2 sensor.; - bit dcMotorIdleValve;+Used on some German vehicles around late 90s: cable-operated throttle and DC motor idle air valve.\nSet the primary TPS to the cable-operated throttle's sensor\nSet the secondary TPS to the mini ETB's position sensor(s). + bit unused976b11; bit enableSoftwareKnock bit verboseVVTDecoding;enable vvt_details bit invertCamVVTSignal;get invertCamVVTSignal diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index 175f3e8376..9bfabb897a 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -3036,12 +3036,11 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = etbDialogLeft field = "https://rusefi.com/s/etb" - field = "Late 90s German DC Motor idle", dcMotorIdleValve, { throttlePedalPositionAdcChannel == @@ADC_CHANNEL_NONE@@ } field = "Detailed status in console", isVerboseETB field = "Disable ETB Motor", pauseEtbControl ; we need the term about stepper idle in here, because there's a bug in TS that you can't have different visibility ; criteria for the same panel when used in multiple places - panel = hbridgeHardware, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ || (useStepperIdle && useHbridges) || dcMotorIdleValve } + panel = hbridgeHardware, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ || (useStepperIdle && useHbridges) } dialog = etbAutotune, "PID Autotune" field = "First step: calibrate TPS and hit 'Burn'" @@ -3057,7 +3056,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00" dialog = etbDialogRight panel = etbIdleDialog, { throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@ } - panel = etbPidDialog, { (throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@) || dcMotorIdleValve } + panel = etbPidDialog, { (throttlePedalPositionAdcChannel != @@ADC_CHANNEL_NONE@@) } panel = etbAutotune ; Neutral position handling not yet implemented! diff --git a/unit_tests/mocks.h b/unit_tests/mocks.h index 2a44937574..ee29e5085e 100644 --- a/unit_tests/mocks.h +++ b/unit_tests/mocks.h @@ -13,7 +13,7 @@ public: // IEtbController mocks MOCK_METHOD(void, reset, (), ()); MOCK_METHOD(void, update, (), (override)); - MOCK_METHOD(void, init, (SensorType positionSensor, DcMotor* motor, int ownIndex, pid_s* pidParameters, const ValueProvider3D* pedalMap), (override)); + MOCK_METHOD(bool, init, (etb_function_e function, DcMotor* motor, pid_s* pidParameters, const ValueProvider3D* pedalMap), (override)); MOCK_METHOD(void, setIdlePosition, (percent_t pos), (override)); MOCK_METHOD(void, autoCalibrateTps, (), (override)); diff --git a/unit_tests/tests/test_etb.cpp b/unit_tests/tests/test_etb.cpp index 4f6b3f4906..5522ca1b7d 100644 --- a/unit_tests/tests/test_etb.cpp +++ b/unit_tests/tests/test_etb.cpp @@ -45,8 +45,8 @@ TEST(etb, initializationSingleThrottle) { Sensor::setMockValue(SensorType::AcceleratorPedal, 0); Sensor::setMockValue(SensorType::AcceleratorPedalPrimary, 0); - // Expect mock0 to be init with TPS 1, index 0, and PID params - EXPECT_CALL(mocks[0], init(SensorType::Tps1, _, 0, &engineConfiguration->etb, Ne(nullptr))); + // Expect mock0 to be init as throttle 1, and PID params + EXPECT_CALL(mocks[0], init(ETB_Throttle1, _, &engineConfiguration->etb, Ne(nullptr))).WillOnce(Return(true)); EXPECT_CALL(mocks[0], reset); // We do not expect throttle #2 to be initialized @@ -70,42 +70,27 @@ TEST(etb, initializationDualThrottle) { // The presence of a second TPS indicates dual throttle Sensor::setMockValue(SensorType::Tps2, 25.0f); - // Expect mock0 to be init with TPS 1, index 0, and PID params - EXPECT_CALL(mocks[0], init(SensorType::Tps1, _, 0, &engineConfiguration->etb, Ne(nullptr))); + // Expect mock0 to be init as throttle 1, and PID params + EXPECT_CALL(mocks[0], init(ETB_Throttle1, _, &engineConfiguration->etb, Ne(nullptr))).WillOnce(Return(true)); EXPECT_CALL(mocks[0], reset); - // Expect mock1 to be init with TPS 2, index 1, and PID params - EXPECT_CALL(mocks[1], init(SensorType::Tps2, _, 1, &engineConfiguration->etb, Ne(nullptr))); + // Expect mock1 to be init as throttle 2, and PID params + EXPECT_CALL(mocks[1], init(ETB_Throttle2, _, &engineConfiguration->etb, Ne(nullptr))).WillOnce(Return(true)); EXPECT_CALL(mocks[1], reset); doInitElectronicThrottle(PASS_ENGINE_PARAMETER_SIGNATURE); } -TEST(etb, initializationDcMotorIdleValveMode) { - StrictMock mocks[ETB_COUNT]; +TEST(etb, initializationNoFunction) { + StrictMock motor; - WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + EtbController dut; - // Enable VW idle mode - engineConfiguration->dcMotorIdleValve = true; + // When init called with ETB_None, should ignore the provided params and return false + EXPECT_FALSE(dut.init(ETB_None, &motor, nullptr, nullptr)); - for (int i = 0; i < ETB_COUNT; i++) { - engine->etbControllers[i] = &mocks[i]; - EXPECT_CALL(mocks[i], setIdlePosition(33.0f)); - } - - // No accelerator pedal configured - this mode doesn't use it - - // Expect mock0 to be init with TPS 2, index 0, and PID params - EXPECT_CALL(mocks[0], init(SensorType::Tps2, _, 0, &engineConfiguration->etb, Ne(nullptr))); - EXPECT_CALL(mocks[0], reset); - - // We do not expect throttle #2 to be initialized - - doInitElectronicThrottle(PASS_ENGINE_PARAMETER_SIGNATURE); - - - applyIACposition(33.0f PASS_ENGINE_PARAMETER_SUFFIX); + // This should no-op, it shouldn't call motor.set(float duty) + dut.setOutput(0.5f); } TEST(etb, idlePlumbing) { @@ -144,7 +129,7 @@ TEST(etb, testSetpointOnlyPedal) { // Uninitialized ETB must return unexpected (and not deference a null pointer) EXPECT_EQ(etb.getSetpoint(), unexpected); - etb.init(SensorType::Invalid, nullptr, 0, nullptr, &pedalMap); + etb.init(ETB_Throttle1, nullptr, nullptr, &pedalMap); // Check endpoints and midpoint Sensor::setMockValue(SensorType::AcceleratorPedal, 0.0f); @@ -194,7 +179,7 @@ TEST(etb, setpointIdle) { .WillRepeatedly([](float xRpm, float y) { return y; }); - etb.init(SensorType::Invalid, nullptr, 0, nullptr, &pedalMap); + etb.init(ETB_Throttle1, nullptr, nullptr, &pedalMap); // No idle range, should just pass pedal Sensor::setMockValue(SensorType::AcceleratorPedal, 0.0f); @@ -231,14 +216,10 @@ TEST(etb, setpointIdle) { EXPECT_FLOAT_EQ(55, etb.getSetpoint().value_or(-1)); } -TEST(etb, idleVolkswagenMode) { - WITH_ENGINE_TEST_HELPER(TEST_ENGINE); - - // In this mode the idle position should be passed thru as the setpoint directly - engineConfiguration->dcMotorIdleValve = true; - +TEST(etb, setpointIdleValveController) { EtbController etb; - INJECT_ENGINE_REFERENCE(&etb); + + etb.init(ETB_IdleValve, nullptr, nullptr, nullptr); etb.setIdlePosition(0); EXPECT_FLOAT_EQ(0, etb.getSetpoint().value_or(-1)); @@ -258,20 +239,36 @@ TEST(etb, etbTpsSensor) { // Throw some distinct values on the TPS sensors so we can identify that we're getting the correct one Sensor::setMockValue(SensorType::Tps1, 25.0f); Sensor::setMockValue(SensorType::Tps2, 75.0f); + Sensor::setMockValue(SensorType::WastegatePosition, 33.0f); + Sensor::setMockValue(SensorType::IdlePosition, 66.0f); // Test first throttle { EtbController etb; - etb.init(SensorType::Tps1, nullptr, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, nullptr, nullptr, nullptr); EXPECT_EQ(etb.observePlant().Value, 25.0f); } // Test second throttle { EtbController etb; - etb.init(SensorType::Tps2, nullptr, 1, nullptr, nullptr); + etb.init(ETB_Throttle2, nullptr, nullptr, nullptr); EXPECT_EQ(etb.observePlant().Value, 75.0f); } + + // Test wastegate control + { + EtbController etb; + etb.init(ETB_Wastegate, nullptr, nullptr, nullptr); + EXPECT_EQ(etb.observePlant().Value, 33.0f); + } + + // Test idle valve control + { + EtbController etb; + etb.init(ETB_IdleValve, nullptr, nullptr, nullptr); + EXPECT_EQ(etb.observePlant().Value, 66.0f); + } } TEST(etb, setOutputInvalid) { @@ -281,7 +278,7 @@ TEST(etb, setOutputInvalid) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Should be disabled in case of unexpected EXPECT_CALL(motor, disable()); @@ -295,7 +292,7 @@ TEST(etb, setOutputValid) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Should be enabled and value set EXPECT_CALL(motor, enable()); @@ -311,7 +308,7 @@ TEST(etb, setOutputValid2) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Should be enabled and value set EXPECT_CALL(motor, enable()); @@ -327,7 +324,7 @@ TEST(etb, setOutputOutOfRangeHigh) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Should be enabled and value set EXPECT_CALL(motor, enable()); @@ -343,7 +340,7 @@ TEST(etb, setOutputOutOfRangeLow) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Should be enabled and value set EXPECT_CALL(motor, enable()); @@ -359,7 +356,7 @@ TEST(etb, setOutputPauseControl) { EtbController etb; INJECT_ENGINE_REFERENCE(&etb); - etb.init(SensorType::Invalid, &motor, 0, nullptr, nullptr); + etb.init(ETB_Throttle1, &motor, nullptr, nullptr); // Pause control - should get no output engineConfiguration->pauseEtbControl = true; @@ -377,7 +374,7 @@ TEST(etb, closedLoopPid) { pid.minValue = -60; EtbController etb; - etb.init(SensorType::Invalid, nullptr, 0, &pid, nullptr); + etb.init(ETB_Throttle1, nullptr, &pid, nullptr); // Disable autotune for now Engine e;