From e46d9f0c9990a97e2961aa0a9dbe7c5258a3d60c Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Thu, 14 May 2020 04:44:32 -0700 Subject: [PATCH] Fix 100% duty injection (#1431) * skip turn-off for high duty * mock executor injection * test * switch to hard cut * test no longer relevant --- .../engine_cycle/main_trigger_callback.cpp | 7 +++- .../engine_cycle/main_trigger_callback.h | 4 ++ unit_tests/global_execution_queue.cpp | 21 ++++++++++ unit_tests/global_execution_queue.h | 3 ++ unit_tests/mocks.h | 7 ++++ unit_tests/tests/tests.mk | 1 + .../trigger/test_injection_scheduling.cpp | 40 +++++++++++++++++++ 7 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 unit_tests/tests/trigger/test_injection_scheduling.cpp diff --git a/firmware/controllers/engine_cycle/main_trigger_callback.cpp b/firmware/controllers/engine_cycle/main_trigger_callback.cpp index ecb999e941..fca28931cf 100644 --- a/firmware/controllers/engine_cycle/main_trigger_callback.cpp +++ b/firmware/controllers/engine_cycle/main_trigger_callback.cpp @@ -168,7 +168,7 @@ void turnInjectionPinLow(InjectionEvent *event) { ENGINE(injectionEvents.addFuelEventsForCylinder(event->ownIndex PASS_ENGINE_PARAMETER_SUFFIX)); } -static ALWAYS_INLINE void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event, +void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event, int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) { /** @@ -310,6 +310,11 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn return; } + // If duty cycle is high, impose a fuel cut rev limiter. + // This is safer than attempting to limp along with injectors or a pump that are out of flow. + if (getInjectorDutyCycle(rpm PASS_ENGINE_PARAMETER_SUFFIX) > 96.0f) { + return; + } /** * Ignition events are defined by addFuelEvents() according to selected diff --git a/firmware/controllers/engine_cycle/main_trigger_callback.h b/firmware/controllers/engine_cycle/main_trigger_callback.h index d4f1c33d4d..a61e0ca5f4 100644 --- a/firmware/controllers/engine_cycle/main_trigger_callback.h +++ b/firmware/controllers/engine_cycle/main_trigger_callback.h @@ -24,3 +24,7 @@ void turnInjectionPinLow(InjectionEvent *event); // reset injection switch counter if the engine started spinning void updatePrimeInjectionPulseState(DECLARE_ENGINE_PARAMETER_SIGNATURE); + +// Internal use only - exposed for tests +void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event, + int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX); diff --git a/unit_tests/global_execution_queue.cpp b/unit_tests/global_execution_queue.cpp index 24cdd0df54..4b20117b3d 100644 --- a/unit_tests/global_execution_queue.cpp +++ b/unit_tests/global_execution_queue.cpp @@ -14,6 +14,12 @@ void TestExecutor::scheduleForLater(scheduling_s *scheduling, int delayUs, actio if (debugSignalExecutor) { printf("scheduleTask %d\r\n", delayUs); } + + if (m_mockExecutor) { + m_mockExecutor->scheduleForLater(scheduling, delayUs, action); + return; + } + scheduleByTimestamp(scheduling, getTimeNowUs() + delayUs, action); } @@ -37,9 +43,24 @@ void TestExecutor::scheduleByTimestamp(scheduling_s *scheduling, efitimeus_t tim if (debugSignalExecutor) { printf("scheduleByTime %d\r\n", timeUs); } + + if (m_mockExecutor) { + m_mockExecutor->scheduleByTimestamp(scheduling, timeUs, action); + return; + } + schedulingQueue.insertTask(scheduling, timeUs, action); } void TestExecutor::scheduleByTimestampNt(scheduling_s* scheduling, efitick_t timeNt, action_s action) { + if (m_mockExecutor) { + m_mockExecutor->scheduleByTimestampNt(scheduling, timeNt, action); + return; + } + scheduleByTimestamp(scheduling, NT2US(timeNt), action); } + +void TestExecutor::setMockExecutor(ExecutorInterface* exec) { + m_mockExecutor = exec; +} diff --git a/unit_tests/global_execution_queue.h b/unit_tests/global_execution_queue.h index f568ad9954..c5ecec4435 100644 --- a/unit_tests/global_execution_queue.h +++ b/unit_tests/global_execution_queue.h @@ -19,6 +19,9 @@ public: int executeAll(efitime_t now); int size(); scheduling_s* getForUnitTest(int index); + + void setMockExecutor(ExecutorInterface* exec); private: EventQueue schedulingQueue; + ExecutorInterface* m_mockExecutor = nullptr; }; diff --git a/unit_tests/mocks.h b/unit_tests/mocks.h index a3dca2df88..0aa45f47bf 100644 --- a/unit_tests/mocks.h +++ b/unit_tests/mocks.h @@ -40,3 +40,10 @@ class MockPwm : public SimplePwm { public: MOCK_METHOD(void, setSimplePwmDutyCycle, (float dutyCycle), (override)); }; + +class MockExecutor : public TestExecutor { +public: + MOCK_METHOD(void, scheduleByTimestamp, (scheduling_s *scheduling, efitimeus_t timeUs, action_s action), (override)); + MOCK_METHOD(void, scheduleByTimestampNt, (scheduling_s *scheduling, efitime_t timeUs, action_s action), (override)); + MOCK_METHOD(void, scheduleForLater, (scheduling_s *scheduling, int delayUs, action_s action), (override)); +}; diff --git a/unit_tests/tests/tests.mk b/unit_tests/tests/tests.mk index b54a80cad1..e4f0be8697 100644 --- a/unit_tests/tests/tests.mk +++ b/unit_tests/tests/tests.mk @@ -5,6 +5,7 @@ TESTS_SRC_CPP = \ tests/trigger/test_trigger_multi_sync.cpp \ tests/trigger/test_cam_vvt_input.cpp \ tests/trigger/test_2jz_vvt.cpp \ + tests/trigger/test_injection_scheduling.cpp \ tests/test_util.cpp \ tests/test_ion.cpp \ tests/test_aux_valves.cpp \ diff --git a/unit_tests/tests/trigger/test_injection_scheduling.cpp b/unit_tests/tests/trigger/test_injection_scheduling.cpp new file mode 100644 index 0000000000..071338461b --- /dev/null +++ b/unit_tests/tests/trigger/test_injection_scheduling.cpp @@ -0,0 +1,40 @@ +#include "engine_test_helper.h" +#include "main_trigger_callback.h" + +#include +#include "mocks.h" + +using ::testing::_; +using ::testing::StrictMock; +using ::testing::InSequence; + +TEST(injectionScheduling, NormalDutyCycle) { + StrictMock mockExec; + + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + engine->executor.setMockExecutor(&mockExec); + + efitick_t nowNt = 1000000; + + InjectionEvent event; + InjectorOutputPin pin; + pin.injectorIndex = 0; + event.outputs[0] = &pin; + + // Injection duration of 20ms + engine->injectionDuration = 20.0f; + + { + InSequence is; + + // Should schedule one normal injection: + // rising edge now + EXPECT_CALL(mockExec, scheduleByTimestampNt(&event.signalTimerUp, nowNt + 0, _)); + // falling edge 10ms later + EXPECT_CALL(mockExec, scheduleByTimestampNt(&event.endOfInjectionEvent, nowNt + MS2NT(20), _)); + } + + engine->rpmCalculator.oneDegreeUs = 100; + + handleFuelInjectionEvent(0, &event, 1000, nowNt PASS_ENGINE_PARAMETER_SUFFIX); +}