Staged injection support; use two sets of injectors on the same engine fix #5247
This commit is contained in:
parent
0938239974
commit
8f42f8ccc8
|
@ -33,6 +33,7 @@ Release template (copy/paste this for new release):
|
|||
|
||||
### Added
|
||||
- Allow brief operation over 100% injector duty cycle and add configurable duty cycle limits #4798
|
||||
- Staged injection support #5247
|
||||
|
||||
### Removed
|
||||
- Narrow to Wideband approximation
|
||||
|
|
|
@ -627,6 +627,7 @@ void updateTunerStudioState() {
|
|||
|
||||
#if EFI_ENGINE_CONTROL
|
||||
tsOutputChannels->injectorDutyCycle = minF(/*let's avoid scaled "uint8_t, 2" overflow*/127, getInjectorDutyCycle(rpm));
|
||||
tsOutputChannels->injectorDutyCycleStage2 = getInjectorDutyCycleStage2(rpm);
|
||||
#endif
|
||||
|
||||
efitimesec_t timeSeconds = getTimeNowS();
|
||||
|
|
|
@ -8,8 +8,15 @@
|
|||
|
||||
#if EFI_ENGINE_CONTROL
|
||||
|
||||
void turnInjectionPinHigh(InjectionEvent *event) {
|
||||
void turnInjectionPinHigh(uintptr_t arg) {
|
||||
efitick_t nowNt = getTimeNowNt();
|
||||
|
||||
// clear last bit to recover the pointer
|
||||
InjectionEvent *event = reinterpret_cast<InjectionEvent*>(arg & ~(1UL));
|
||||
|
||||
// extract last bit
|
||||
bool stage2Active = arg & 1;
|
||||
|
||||
for (size_t i = 0; i < efi::size(event->outputs); i++) {
|
||||
InjectorOutputPin *output = event->outputs[i];
|
||||
|
||||
|
@ -17,6 +24,16 @@ void turnInjectionPinHigh(InjectionEvent *event) {
|
|||
output->open(nowNt);
|
||||
}
|
||||
}
|
||||
|
||||
if (stage2Active) {
|
||||
for (size_t i = 0; i < efi::size(event->outputsStage2); i++) {
|
||||
InjectorOutputPin *output = event->outputsStage2[i];
|
||||
|
||||
if (output) {
|
||||
output->open(nowNt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FuelSchedule::FuelSchedule() {
|
||||
|
@ -150,6 +167,7 @@ bool InjectionEvent::update() {
|
|||
}
|
||||
|
||||
InjectorOutputPin *secondOutput;
|
||||
InjectorOutputPin* secondOutputStage2;
|
||||
|
||||
if (mode == IM_BATCH) {
|
||||
/**
|
||||
|
@ -161,8 +179,10 @@ bool InjectionEvent::update() {
|
|||
int secondOrder = (ownIndex + (engineConfiguration->cylindersCount / 2)) % engineConfiguration->cylindersCount;
|
||||
int secondIndex = ID2INDEX(getCylinderId(secondOrder));
|
||||
secondOutput = &enginePins.injectors[secondIndex];
|
||||
secondOutputStage2 = &enginePins.injectorsStage2[secondIndex];
|
||||
} else {
|
||||
secondOutput = nullptr;
|
||||
secondOutputStage2 = nullptr;
|
||||
}
|
||||
|
||||
InjectorOutputPin *output = &enginePins.injectors[injectorIndex];
|
||||
|
@ -173,6 +193,9 @@ bool InjectionEvent::update() {
|
|||
// Stash the cylinder number so we can select the correct fueling bank later
|
||||
cylinderNumber = injectorIndex;
|
||||
|
||||
outputsStage2[0] = &enginePins.injectorsStage2[injectorIndex];
|
||||
outputsStage2[1] = secondOutputStage2;
|
||||
|
||||
if (!isSimultaneous && !output->isInitialized()) {
|
||||
// todo: extract method for this index math
|
||||
warning(ObdCode::CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->getName());
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
float injectionStartAngle = 0;
|
||||
};
|
||||
|
||||
void turnInjectionPinHigh(InjectionEvent *event);
|
||||
void turnInjectionPinHigh(uintptr_t arg);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,6 +64,17 @@ void turnInjectionPinLow(InjectionEvent *event) {
|
|||
event->update();
|
||||
}
|
||||
|
||||
void turnInjectionPinLowStage2(InjectionEvent* event) {
|
||||
efitick_t nowNt = getTimeNowNt();
|
||||
|
||||
for (size_t i = 0; i < efi::size(event->outputsStage2); i++) {
|
||||
InjectorOutputPin *output = event->outputsStage2[i];
|
||||
if (output) {
|
||||
output->close(nowNt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InjectionEvent::onTriggerTooth(efitick_t nowNt, float currentPhase, float nextPhase) {
|
||||
auto eventAngle = injectionStartAngle;
|
||||
|
||||
|
@ -77,38 +88,51 @@ void InjectionEvent::onTriggerTooth(efitick_t nowNt, float currentPhase, float n
|
|||
|
||||
// Perform wall wetting adjustment on fuel mass, not duration, so that
|
||||
// it's correct during fuel pressure (injector flow) or battery voltage (deadtime) transients
|
||||
// TODO: is it correct to wall wet on both pulses?
|
||||
injectionMassGrams = wallFuel.adjust(injectionMassGrams);
|
||||
const floatms_t injectionDuration = engine->module<InjectorModelPrimary>()->getInjectionDuration(injectionMassGrams);
|
||||
|
||||
// Disable staging in simultaneous mode
|
||||
float stage2Fraction = isSimultaneous ? 0 : getEngineState()->injectionStage2Fraction;
|
||||
|
||||
// Compute fraction of fuel on stage 2, remainder goes on stage 1
|
||||
const float injectionMassStage2 = stage2Fraction * injectionMassGrams;
|
||||
float injectionMassStage1 = injectionMassGrams - injectionMassStage2;
|
||||
|
||||
#if EFI_VEHICLE_SPEED
|
||||
{
|
||||
// Log this fuel as consumed
|
||||
|
||||
bool isCranking = getEngineRotationState()->isCranking();
|
||||
int numberOfInjections = isCranking ? getNumberOfInjections(engineConfiguration->crankingInjectionMode) : getNumberOfInjections(engineConfiguration->injectionMode);
|
||||
|
||||
float actualInjectedMass = numberOfInjections * (injectionMassStage1 + injectionMassStage2);
|
||||
|
||||
engine->module<TripOdometer>()->consumeFuel(actualInjectedMass, nowNt);
|
||||
}
|
||||
#endif // EFI_VEHICLE_SPEED
|
||||
|
||||
const floatms_t injectionDurationStage1 = engine->module<InjectorModelPrimary>()->getInjectionDuration(injectionMassStage1);
|
||||
const floatms_t injectionDurationStage2 = injectionMassStage2 > 0 ? engine->module<InjectorModelSecondary>()->getInjectionDuration(injectionMassStage2) : 0;
|
||||
|
||||
#if EFI_PRINTF_FUEL_DETAILS
|
||||
if (printFuelDebug) {
|
||||
printf("fuel injectionDuration=%.2fms adjusted=%.2fms\n",
|
||||
getEngineState()->injectionDuration,
|
||||
injectionDuration);
|
||||
injectionDurationStage1);
|
||||
}
|
||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||
|
||||
#if EFI_VEHICLE_SPEED
|
||||
bool isCranking = getEngineRotationState()->isCranking();
|
||||
/**
|
||||
* todo: pre-calculate 'numberOfInjections'
|
||||
* see also injectorDutyCycle
|
||||
*/
|
||||
int numberOfInjections = isCranking ? getNumberOfInjections(engineConfiguration->crankingInjectionMode) : getNumberOfInjections(engineConfiguration->injectionMode);
|
||||
|
||||
engine->module<TripOdometer>()->consumeFuel(injectionMassGrams * numberOfInjections, nowNt);
|
||||
#endif // EFI_VEHICLE_SPEED
|
||||
|
||||
if (this->cylinderNumber == 0) {
|
||||
engine->outputChannels.actualLastInjection = injectionDuration;
|
||||
engine->outputChannels.actualLastInjection = injectionDurationStage1;
|
||||
engine->outputChannels.actualLastInjectionStage2 = injectionDurationStage2;
|
||||
}
|
||||
|
||||
if (cisnan(injectionDuration)) {
|
||||
if (cisnan(injectionDurationStage1) || cisnan(injectionDurationStage2)) {
|
||||
warning(ObdCode::CUSTOM_OBD_NAN_INJECTION, "NaN injection pulse");
|
||||
return;
|
||||
}
|
||||
if (injectionDuration < 0) {
|
||||
warning(ObdCode::CUSTOM_OBD_NEG_INJECTION, "Negative injection pulse %.2f", injectionDuration);
|
||||
if (injectionDurationStage1 < 0) {
|
||||
warning(ObdCode::CUSTOM_OBD_NEG_INJECTION, "Negative injection pulse %.2f", injectionDurationStage1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -116,48 +140,70 @@ void InjectionEvent::onTriggerTooth(efitick_t nowNt, float currentPhase, float n
|
|||
// Durations under 50us-ish aren't safe for the scheduler
|
||||
// as their order may be swapped, resulting in a stuck open injector
|
||||
// see https://github.com/rusefi/rusefi/pull/596 for more details
|
||||
if (injectionDuration < 0.050f)
|
||||
if (injectionDurationStage1 < 0.050f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
floatus_t durationUs = MS2US(injectionDuration);
|
||||
floatus_t durationUsStage1 = MS2US(injectionDurationStage1);
|
||||
floatus_t durationUsStage2 = MS2US(injectionDurationStage2);
|
||||
|
||||
// Only bother with the second stage if it's long enough to be relevant
|
||||
bool hasStage2Injection = durationUsStage2 > 50;
|
||||
|
||||
#if EFI_PRINTF_FUEL_DETAILS
|
||||
if (printFuelDebug) {
|
||||
InjectorOutputPin *output = outputs[0];
|
||||
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->getName(), (int)durationUs,
|
||||
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->getName(), (int)durationUsStage1,
|
||||
(int)MS2US(getCrankshaftRevolutionTimeMs(Sensor::getOrZero(SensorType::Rpm))) / 1000.0);
|
||||
}
|
||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||
|
||||
action_s startAction, endAction;
|
||||
action_s startAction, endActionStage1, endActionStage2;
|
||||
// We use different callbacks based on whether we're running sequential mode or not - everything else is the same
|
||||
if (isSimultaneous) {
|
||||
startAction = startSimultaneousInjection;
|
||||
endAction = { &endSimultaneousInjection, this };
|
||||
endActionStage1 = { &endSimultaneousInjection, this };
|
||||
} else {
|
||||
uintptr_t startActionPtr = reinterpret_cast<uintptr_t>(this);
|
||||
|
||||
if (hasStage2Injection) {
|
||||
// Set the low bit in the arg if there's a secondary injection to start too
|
||||
startActionPtr |= 1;
|
||||
}
|
||||
|
||||
// sequential or batch
|
||||
startAction = { &turnInjectionPinHigh, this };
|
||||
endAction = { &turnInjectionPinLow, this };
|
||||
startAction = { &turnInjectionPinHigh, startActionPtr };
|
||||
endActionStage1 = { &turnInjectionPinLow, this };
|
||||
endActionStage2 = { &turnInjectionPinLowStage2, this };
|
||||
}
|
||||
|
||||
// Correctly wrap injection start angle
|
||||
float angleFromNow = eventAngle - currentPhase;
|
||||
if (angleFromNow < 0) {
|
||||
angleFromNow += getEngineState()->engineCycle;
|
||||
}
|
||||
|
||||
// Schedule opening (stage 1 + stage 2 open together)
|
||||
efitick_t startTime = scheduleByAngle(nullptr, nowNt, angleFromNow, startAction);
|
||||
efitick_t turnOffTime = startTime + US2NT((int)durationUs);
|
||||
getExecutorInterface()->scheduleByTimestampNt("inj", nullptr, turnOffTime, endAction);
|
||||
|
||||
// Schedule closing stage 1
|
||||
efitick_t turnOffTimeStage1 = startTime + US2NT((int)durationUsStage1);
|
||||
getExecutorInterface()->scheduleByTimestampNt("inj", nullptr, turnOffTimeStage1, endActionStage1);
|
||||
|
||||
// Schedule closing stage 2 (if applicable)
|
||||
if (hasStage2Injection && endActionStage2) {
|
||||
efitick_t turnOffTimeStage2 = startTime + US2NT((int)durationUsStage2);
|
||||
getExecutorInterface()->scheduleByTimestampNt("inj stage 2", nullptr, turnOffTimeStage2, endActionStage2);
|
||||
}
|
||||
|
||||
#if EFI_UNIT_TEST
|
||||
printf("scheduling injection angle=%.2f/delay=%.2f injectionDuration=%.2f\r\n", angleFromNow, NT2US(startTime - nowNt), injectionDuration);
|
||||
printf("scheduling injection angle=%.2f/delay=%d injectionDuration=%d %d\r\n", angleFromNow, (int)NT2US(startTime - nowNt), (int)durationUsStage1, (int)durationUsStage2);
|
||||
#endif
|
||||
#if EFI_DEFAILED_LOGGING
|
||||
efiPrintf("handleFuel pin=%s eventIndex %d duration=%.2fms %d", outputs[0]->name,
|
||||
injEventIndex,
|
||||
injectionDuration,
|
||||
injectionDurationStage1,
|
||||
getRevolutionCounter());
|
||||
efiPrintf("handleFuel pin=%s delay=%.2f %d", outputs[0]->name, NT2US(startTime - nowNt),
|
||||
getRevolutionCounter());
|
||||
|
|
|
@ -15,3 +15,4 @@ void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp, angle_
|
|||
|
||||
void endSimultaneousInjection(InjectionEvent *event);
|
||||
void turnInjectionPinLow(InjectionEvent *event);
|
||||
void turnInjectionPinLowStage2(InjectionEvent* event);
|
||||
|
|
|
@ -343,12 +343,6 @@ void EnginePins::startInjectionPins() {
|
|||
output->initPin(output->getName(), engineConfiguration->injectionPinsStage2[i],
|
||||
engineConfiguration->injectionPinMode);
|
||||
}
|
||||
|
||||
output = &enginePins.injectorsStage2[i];
|
||||
if (isPinOrModeChanged(injectionPinsStage2[i], injectionPinMode)) {
|
||||
output->initPin(output->getName(), engineConfiguration->injectionPinsStage2[i],
|
||||
engineConfiguration->injectionPinMode);
|
||||
}
|
||||
}
|
||||
#endif /* EFI_PROD_CODE */
|
||||
}
|
||||
|
|
|
@ -1284,6 +1284,12 @@ curve = rangeMatrix, "Range Switch Input Matrix"
|
|||
yBins = gppwm4_loadBins, gppwmYAxis4
|
||||
zBins = gppwm4_table
|
||||
|
||||
table = stagedInjectionTbl, stagedInjectionMap, "Staged Injection %", 1
|
||||
xyLabels = "RPM", ""
|
||||
xBins = injectorStagingRpmBins, RPMValue
|
||||
yBins = injectorStagingLoadBins, fuelingLoad
|
||||
zBins = injectorStagingTable
|
||||
|
||||
table = tcuSolenoidTableTbl, tcuSolenoidTableMap, "Solenoids Active By Gear", 1
|
||||
xBins = gearCountArray, tcuCurrentGear
|
||||
yBins = solenoidCountArray, tcuCurrentGear
|
||||
|
@ -1495,7 +1501,9 @@ gaugeCategory = Fueling
|
|||
iatCorrectionGauge = running_intakeTemperatureCoefficient, @@GAUGE_NAME_FUEL_IAT_CORR@@, "mult", 0, 3, 0, 0, 3, 3, 2, 2
|
||||
cltCorrectionGauge = running_coolantTemperatureCoefficient, @@GAUGE_NAME_FUEL_CLT_CORR@@, "mult", 0, 3, 0, 0, 3, 3, 2, 2
|
||||
injectorDutyCycleGauge=injectorDutyCycle, @@GAUGE_NAME_FUEL_INJ_DUTY@@,"%", 0, 120, 10, 10, 100, 100, 1, 1
|
||||
injectorDutyCycleStg2Gauge=injectorDutyCycleStage2, @@GAUGE_NAME_FUEL_INJ_DUTY_STAGE_2@@,"%", 0, 120, 10, 10, 100, 100, 1, 1
|
||||
actualLastInjectionGauge = actualLastInjection, @@GAUGE_NAME_FUEL_LAST_INJECTION@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
|
||||
actualLastInjectionStg2Gauge = actualLastInjectionStage2, @@GAUGE_NAME_FUEL_LAST_INJECTION_STAGE_2@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
|
||||
veValueGauge = veValue, "fuel: VE", "", 0, 120, 10, 10, 100, 100, 1, 1
|
||||
|
||||
injectorLagMsGauge = m_deadtime, @@GAUGE_NAME_INJECTOR_LAG@@, "mSec", 0, 10, 0, 0, 10, 10, 3, 1
|
||||
|
@ -1737,6 +1745,7 @@ menuDialog = main
|
|||
subMenu = injectionSettings, "Injection hardware", 0, {isInjectionEnabled == 1}
|
||||
subMenu = cylinderBankSelect, "Cylinder bank selection", 0, {isInjectionEnabled == 1}
|
||||
subMenu = injectorNonlinear, "Injector small-pulse correction", 0, {isInjectionEnabled == 1}
|
||||
subMenu = stagedInjection, "Staged injection", 0, {isInjectionEnabled}
|
||||
|
||||
groupMenu = "Cylinder fuel trims"
|
||||
groupChildMenu = fuelTrimTbl1, "Fuel trim cyl 1"
|
||||
|
@ -2587,6 +2596,26 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_
|
|||
field = "Offset cyl 11", timing_offset_cylinder11, {cylindersCount > 10}
|
||||
field = "Offset cyl 12", timing_offset_cylinder12, {cylindersCount > 11}
|
||||
|
||||
dialog = stagedInjectionLeft, "", yAxis
|
||||
field = "Enable", enableStagedInjection, {isInjectionEnabled}
|
||||
field = ""
|
||||
field = "Injection Stage 2 Output 1", injectionPinsStage21, {isInjectionEnabled && enableStagedInjection}
|
||||
field = "Injection Stage 2 Output 2", injectionPinsStage22, {isInjectionEnabled && enableStagedInjection && injectionMode != 3 && cylindersCount > 1}
|
||||
field = "Injection Stage 2 Output 3", injectionPinsStage23, {isInjectionEnabled && enableStagedInjection && injectionMode != @@injection_mode_e_IM_SINGLE_POINT@@ && cylindersCount > 2}
|
||||
field = "Injection Stage 2 Output 4", injectionPinsStage24, {isInjectionEnabled && enableStagedInjection && injectionMode != 3 && cylindersCount > 3}
|
||||
field = "Injection Stage 2 Output 5 ", injectionPinsStage25, {isInjectionEnabled && enableStagedInjection && injectionMode != @@injection_mode_e_IM_SINGLE_POINT@@ && cylindersCount > 4}
|
||||
field = "Injection Stage 2 Output 6 ", injectionPinsStage26, {isInjectionEnabled && enableStagedInjection && injectionMode != @@injection_mode_e_IM_SINGLE_POINT@@ && cylindersCount > 5}
|
||||
field = "Injection Stage 2 Output 7 ", injectionPinsStage27, {isInjectionEnabled && enableStagedInjection && injectionMode != 3 && cylindersCount > 6}
|
||||
field = "Injection Stage 2 Output 8 ", injectionPinsStage28, {isInjectionEnabled && enableStagedInjection && injectionMode != 3 && cylindersCount > 7}
|
||||
field = "Injection Stage 2 Output 9 ", injectionPinsStage29, {isInjectionEnabled && enableStagedInjection && cylindersCount > 8}
|
||||
field = "Injection Stage 2 Output 10 ", injectionPinsStage210, {isInjectionEnabled && enableStagedInjection && cylindersCount > 9}
|
||||
field = "Injection Stage 2 Output 11 ", injectionPinsStage211, {isInjectionEnabled && enableStagedInjection && cylindersCount > 10}
|
||||
field = "Injection Stage 2 Output 12 ", injectionPinsStage212, {isInjectionEnabled && enableStagedInjection && cylindersCount > 11}
|
||||
|
||||
dialog = stagedInjection, "", xAxis
|
||||
panel = stagedInjectionLeft
|
||||
panel = stagedInjectionTbl, {isInjectionEnabled && enableStagedInjection}
|
||||
|
||||
dialog = multisparkDwellParams, "Delay & Dwell"
|
||||
field = "Spark duration", multisparkSparkDuration, {multisparkEnable}
|
||||
field = "Subsequent spark dwell", multisparkDwell, {multisparkEnable}
|
||||
|
|
|
@ -6,6 +6,15 @@ using ::testing::_;
|
|||
using ::testing::StrictMock;
|
||||
using ::testing::InSequence;
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Not;
|
||||
using ::testing::Property;
|
||||
using ::testing::Truly;
|
||||
|
||||
static bool ActionArgumentHasLowBitSet(const action_s& a) {
|
||||
return (reinterpret_cast<uintptr_t>(a.getArgument()) & 1) != 0;
|
||||
}
|
||||
|
||||
TEST(injectionScheduling, InjectionIsScheduled) {
|
||||
StrictMock<MockExecutor> mockExec;
|
||||
|
||||
|
@ -33,11 +42,61 @@ TEST(injectionScheduling, InjectionIsScheduled) {
|
|||
// rising edge 5 degrees from now
|
||||
float nt5deg = USF2NT(engine->rpmCalculator.oneDegreeUs * 5);
|
||||
efitick_t startTime = nowNt + nt5deg;
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, Not(Truly(ActionArgumentHasLowBitSet))));
|
||||
// falling edge 20ms later
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), Property(&action_s::getArgument, Eq(&event))));
|
||||
}
|
||||
|
||||
// Event scheduled at 125 degrees
|
||||
event.injectionStartAngle = 125;
|
||||
|
||||
// We are at 120 degrees now, next tooth 130
|
||||
event.onTriggerTooth(nowNt, 120, 130);
|
||||
}
|
||||
|
||||
TEST(injectionScheduling, InjectionIsScheduledDualStage) {
|
||||
StrictMock<MockExecutor> mockExec;
|
||||
StrictMock<MockInjectorModel2> im;
|
||||
|
||||
EngineTestHelper eth(engine_type_e::TEST_ENGINE);
|
||||
engine->executor.setMockExecutor(&mockExec);
|
||||
engine->module<InjectorModelPrimary>().set(&im);
|
||||
engine->module<InjectorModelSecondary>().set(&im);
|
||||
|
||||
efitick_t nowNt = 1000000;
|
||||
|
||||
InjectionEvent event;
|
||||
InjectorOutputPin pin;
|
||||
pin.injectorIndex = 0;
|
||||
event.outputs[0] = &pin;
|
||||
|
||||
engine->rpmCalculator.oneDegreeUs = 100;
|
||||
|
||||
// Some nonzero fuel quantity on both stages
|
||||
engine->engineState.injectionMass[0] = 50;
|
||||
engine->engineState.injectionStage2Fraction = 0.2;
|
||||
|
||||
{
|
||||
InSequence is;
|
||||
|
||||
// Primary injection duration of 20ms, secondary 10ms
|
||||
EXPECT_CALL(im, getInjectionDuration(40)).WillOnce(Return(20.0f));
|
||||
EXPECT_CALL(im, getInjectionDuration(10)).WillOnce(Return(10.0f));
|
||||
}
|
||||
|
||||
{
|
||||
InSequence is;
|
||||
|
||||
// Should schedule one normal injection:
|
||||
// rising edge 5 degrees from now
|
||||
float nt5deg = USF2NT(engine->rpmCalculator.oneDegreeUs * 5);
|
||||
efitick_t startTime = nowNt + nt5deg;
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, Truly(ActionArgumentHasLowBitSet)));
|
||||
// falling edge (primary) 20ms later
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), Property(&action_s::getArgument, Eq(&event))));
|
||||
// falling edge (secondary) 10ms later
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(10), Property(&action_s::getArgument, Eq(&event))));
|
||||
}
|
||||
|
||||
// Event scheduled at 125 degrees
|
||||
event.injectionStartAngle = 125;
|
||||
|
@ -73,9 +132,9 @@ TEST(injectionScheduling, InjectionIsScheduledBeforeWraparound) {
|
|||
// rising edge 5 degrees from now
|
||||
float nt5deg = USF2NT(engine->rpmCalculator.oneDegreeUs * 5);
|
||||
efitick_t startTime = nowNt + nt5deg;
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, Not(Truly(ActionArgumentHasLowBitSet))));
|
||||
// falling edge 20ms later
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), Property(&action_s::getArgument, Eq(&event))));
|
||||
}
|
||||
|
||||
// Event scheduled at 715 degrees
|
||||
|
@ -112,9 +171,9 @@ TEST(injectionScheduling, InjectionIsScheduledAfterWraparound) {
|
|||
// rising edge 15 degrees from now
|
||||
float nt5deg = USF2NT(engine->rpmCalculator.oneDegreeUs * 15);
|
||||
efitick_t startTime = nowNt + nt5deg;
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime, Not(Truly(ActionArgumentHasLowBitSet))));
|
||||
// falling edge 20ms later
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), _));
|
||||
EXPECT_CALL(mockExec, scheduleByTimestampNt(testing::NotNull(), _, startTime + MS2NT(20), Property(&action_s::getArgument, Eq(&event))));
|
||||
}
|
||||
|
||||
// Event scheduled at 5 degrees
|
||||
|
|
Loading…
Reference in New Issue