diff --git a/firmware/controllers/math/engine_math.cpp b/firmware/controllers/math/engine_math.cpp index 38bd003840..eadbe4f606 100644 --- a/firmware/controllers/math/engine_math.cpp +++ b/firmware/controllers/math/engine_math.cpp @@ -151,24 +151,23 @@ bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFF efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false); assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554); - int injectorIndex; - injection_mode_e mode = engine->getCurrentInjectionMode(PASS_ENGINE_PARAMETER_SIGNATURE); + int injectorIndex; if (mode == IM_SIMULTANEOUS || mode == IM_SINGLE_POINT) { + // These modes only have one injector injectorIndex = 0; - } else if (mode == IM_SEQUENTIAL) { + } else if (mode == IM_SEQUENTIAL || (mode == IM_BATCH && CONFIG(twoWireBatchInjection))) { + // Map order index -> cylinder index (firing order) injectorIndex = getCylinderId(i PASS_ENGINE_PARAMETER_SUFFIX) - 1; } else if (mode == IM_BATCH) { - // does not look exactly right, not too consistent with IM_SEQUENTIAL + // Loop over the first half of the firing order twice injectorIndex = i % (engineConfiguration->specs.cylindersCount / 2); } else { firmwareError(CUSTOM_OBD_UNEXPECTED_INJECTION_MODE, "Unexpected injection mode %d", mode); injectorIndex = 0; } - bool isSimultanious = mode == IM_SIMULTANEOUS; - assertAngleRange(baseAngle, "addFbaseAngle", CUSTOM_ADD_BASE); int cylindersCount = CONFIG(specs.cylindersCount); @@ -186,13 +185,18 @@ bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFF /** * also fire the 2nd half of the injectors so that we can implement a batch mode on individual wires */ - int secondIndex = injectorIndex + (CONFIG(specs.cylindersCount) / 2); + // Compute the position of this cylinder's twin in the firing order + // Each injector gets fired as a primary (the same as sequential), but also + // fires the injector 360 degrees later in the firing order. + int secondOrder = (i + (CONFIG(specs.cylindersCount) / 2)) % CONFIG(specs.cylindersCount); + int secondIndex = getCylinderId(secondOrder PASS_ENGINE_PARAMETER_SUFFIX) - 1; secondOutput = &enginePins.injectors[secondIndex]; } else { - secondOutput = NULL; + secondOutput = nullptr; } InjectorOutputPin *output = &enginePins.injectors[injectorIndex]; + bool isSimultanious = mode == IM_SIMULTANEOUS; if (!isSimultanious && !output->isInitialized()) { // todo: extract method for this index math diff --git a/unit_tests/tests/trigger/test_trigger_decoder.cpp b/unit_tests/tests/trigger/test_trigger_decoder.cpp index 8ccef8dc43..58d33dcfe5 100644 --- a/unit_tests/tests/trigger/test_trigger_decoder.cpp +++ b/unit_tests/tests/trigger/test_trigger_decoder.cpp @@ -566,12 +566,27 @@ TEST(misc, testTriggerDecoder) { extern fuel_Map3D_t fuelMap; -static void assertInjectionEvent(const char *msg, InjectionEvent *ev, int injectorIndex, int eventIndex, angle_t angleOffset) { +static void assertInjectionEventBase(const char *msg, InjectionEvent *ev, int injectorIndex, int eventIndex, angle_t angleOffset) { ASSERT_EQ(injectorIndex, ev->outputs[0]->injectorIndex) << msg << "inj index"; assertEqualsM4(msg, " event index", eventIndex, ev->injectionStart.triggerEventIndex); assertEqualsM4(msg, " event offset", angleOffset, ev->injectionStart.angleOffsetFromTriggerEvent); } +static void assertInjectionEvent(const char *msg, InjectionEvent *ev, int injectorIndex, int eventIndex, angle_t angleOffset) { + assertInjectionEventBase(msg, ev, injectorIndex, eventIndex, angleOffset); + + // There should NOT be a second injector configured + EXPECT_EQ(nullptr, ev->outputs[1]); +} + +static void assertInjectionEventBatch(const char *msg, InjectionEvent *ev, int injectorIndex, int secondInjectorIndex, int eventIndex, angle_t angleOffset) { + assertInjectionEventBase(msg, ev, injectorIndex, eventIndex, angleOffset); + + // There should be a second injector - confirm it's the correct one + ASSERT_NE(nullptr, ev->outputs[1]); + EXPECT_EQ(secondInjectorIndex, ev->outputs[1]->injectorIndex); +} + static void setTestBug299(EngineTestHelper *eth) { setupSimpleTestEngineWithMafAndTT_ONE_trigger(eth); Engine *engine = ð->engine; @@ -959,9 +974,57 @@ TEST(big, testFuelSchedulerBug299smallAndMedium) { doTestFuelSchedulerBug299smallAndMedium(1000); } -TEST(big, testDifferentInjectionModes) { - printf("*************************************************** testDifferentInjectionModes\r\n"); +TEST(big, testTwoWireBatch) { + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð); + engineConfiguration->injectionMode = IM_BATCH; + engineConfiguration->twoWireBatchInjection = true; + + eth.fireTriggerEventsWithDuration(20); + // still no RPM since need to cycles measure cycle duration + eth.fireTriggerEventsWithDuration(20); + eth.clearQueue(); + + /** + * Trigger up - scheduling fuel for full engine cycle + */ + eth.fireRise(20); + + FuelSchedule * t = &ENGINE(injectionEvents); + + assertInjectionEventBatch("#0", &t->elements[0], 0, 3, 1, 153); // Cyl 1 and 4 + assertInjectionEventBatch("#1_i_@", &t->elements[1], 2, 1, 1, 153 + 180); // Cyl 3 and 2 + assertInjectionEventBatch("#2@", &t->elements[2], 3, 0, 0, 153); // Cyl 4 and 1 + assertInjectionEventBatch("inj#3@", &t->elements[3], 1, 2, 0, 153 + 180); // Cyl 2 and 3 +} + + +TEST(big, testSequential) { + WITH_ENGINE_TEST_HELPER(TEST_ENGINE); + setupSimpleTestEngineWithMafAndTT_ONE_trigger(ð); + + engineConfiguration->injectionMode = IM_SEQUENTIAL; + + eth.fireTriggerEventsWithDuration(20); + // still no RPM since need to cycles measure cycle duration + eth.fireTriggerEventsWithDuration(20); + eth.clearQueue(); + + /** + * Trigger up - scheduling fuel for full engine cycle + */ + eth.fireRise(20); + + FuelSchedule * t = &ENGINE(injectionEvents); + + assertInjectionEvent("#0", &t->elements[0], 0, 1, 126); // Cyl 1 + assertInjectionEvent("#1_i_@", &t->elements[1], 2, 1, 126 + 180); // Cyl 3 + assertInjectionEvent("#2@", &t->elements[2], 3, 0, 126); // Cyl 4 + assertInjectionEvent("inj#3@", &t->elements[3], 1, 0, 126 + 180); // Cyl 2 +} + +TEST(big, testDifferentInjectionModes) { WITH_ENGINE_TEST_HELPER(TEST_ENGINE); setTestBug299(ð); ASSERT_EQ( 4, engine->executor.size()) << "Lqs#0";