refacto
This commit is contained in:
parent
d58438874e
commit
626f55a08a
|
@ -25,8 +25,6 @@
|
||||||
#include "engine_math.h"
|
#include "engine_math.h"
|
||||||
|
|
||||||
InjectionEvent::InjectionEvent() {
|
InjectionEvent::InjectionEvent() {
|
||||||
isSimultanious = false;
|
|
||||||
ownIndex = 0;
|
|
||||||
memset(outputs, 0, sizeof(outputs));
|
memset(outputs, 0, sizeof(outputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,17 @@ class Engine;
|
||||||
class InjectionEvent {
|
class InjectionEvent {
|
||||||
public:
|
public:
|
||||||
InjectionEvent();
|
InjectionEvent();
|
||||||
|
|
||||||
|
// Call this every decoded trigger tooth. It will schedule any relevant events for this injector.
|
||||||
|
void onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a performance optimization for IM_SIMULTANEOUS fuel strategy.
|
* This is a performance optimization for IM_SIMULTANEOUS fuel strategy.
|
||||||
* It's more efficient to handle all injectors together if that's the case
|
* It's more efficient to handle all injectors together if that's the case
|
||||||
*/
|
*/
|
||||||
bool isSimultanious;
|
bool isSimultanious = false;
|
||||||
InjectorOutputPin *outputs[MAX_WIRES_COUNT];
|
InjectorOutputPin *outputs[MAX_WIRES_COUNT];
|
||||||
int ownIndex;
|
int ownIndex = 0;
|
||||||
DECLARE_ENGINE_PTR;
|
DECLARE_ENGINE_PTR;
|
||||||
event_trigger_position_s injectionStart;
|
event_trigger_position_s injectionStart;
|
||||||
|
|
||||||
|
@ -47,13 +51,16 @@ public:
|
||||||
WallFuel wallFuel;
|
WallFuel wallFuel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class knows about when to inject fuel
|
* This class knows about when to inject fuel
|
||||||
*/
|
*/
|
||||||
class FuelSchedule {
|
class FuelSchedule {
|
||||||
public:
|
public:
|
||||||
FuelSchedule();
|
FuelSchedule();
|
||||||
|
|
||||||
|
// Call this every trigger tooth. It will schedule all required injector events.
|
||||||
|
void onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this method schedules all fuel events for an engine cycle
|
* this method schedules all fuel events for an engine cycle
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,6 +34,7 @@ CONTROLLERS_SRC_CPP = \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
|
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
|
||||||
|
$(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \
|
||||||
$(CONTROLLERS_DIR)/flash_main.cpp \
|
$(CONTROLLERS_DIR)/flash_main.cpp \
|
||||||
$(CONTROLLERS_DIR)/bench_test.cpp \
|
$(CONTROLLERS_DIR)/bench_test.cpp \
|
||||||
$(CONTROLLERS_DIR)/can/obd2.cpp \
|
$(CONTROLLERS_DIR)/can/obd2.cpp \
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
/**
|
||||||
|
* @file fuel_schedule.cpp
|
||||||
|
*
|
||||||
|
* Handles injection scheduling
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "engine.h"
|
||||||
|
#include "engine_math.h"
|
||||||
|
#include "event_registry.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
#if EFI_ENGINE_CONTROL
|
||||||
|
|
||||||
|
FuelSchedule::FuelSchedule() {
|
||||||
|
clear();
|
||||||
|
for (int cylinderIndex = 0; cylinderIndex < MAX_INJECTION_OUTPUT_COUNT; cylinderIndex++) {
|
||||||
|
InjectionEvent *ev = &elements[cylinderIndex];
|
||||||
|
ev->ownIndex = cylinderIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::clear() {
|
||||||
|
isReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::resetOverlapping() {
|
||||||
|
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
||||||
|
enginePins.injectors[i].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns false in case of error, true if success
|
||||||
|
*/
|
||||||
|
bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, engine!=NULL, "engine is NULL", false);
|
||||||
|
|
||||||
|
floatus_t oneDegreeUs = ENGINE(rpmCalculator.oneDegreeUs); // local copy
|
||||||
|
if (cisnan(oneDegreeUs)) {
|
||||||
|
// in order to have fuel schedule we need to have current RPM
|
||||||
|
// wonder if this line slows engine startup?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injection phase is scheduled by injection end, so we need to step the angle back
|
||||||
|
* for the duration of the injection
|
||||||
|
*
|
||||||
|
* todo: since this method is not invoked within trigger event handler and
|
||||||
|
* engineState.injectionOffset is calculated from the same utility timer should we more that logic here?
|
||||||
|
*/
|
||||||
|
floatms_t fuelMs = ENGINE(injectionDuration);
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false);
|
||||||
|
angle_t injectionDuration = MS2US(fuelMs) / oneDegreeUs;
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDuration), "NaN injectionDuration", false);
|
||||||
|
assertAngleRange(injectionDuration, "injectionDuration_r", CUSTOM_INJ_DURATION);
|
||||||
|
floatus_t injectionOffset = ENGINE(engineState.injectionOffset);
|
||||||
|
if (cisnan(injectionOffset)) {
|
||||||
|
// injection offset map not ready - we are not ready to schedule fuel events
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
angle_t baseAngle = injectionOffset - injectionDuration;
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false);
|
||||||
|
assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554);
|
||||||
|
|
||||||
|
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 || (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) {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertAngleRange(baseAngle, "addFbaseAngle", CUSTOM_ADD_BASE);
|
||||||
|
|
||||||
|
int cylindersCount = CONFIG(specs.cylindersCount);
|
||||||
|
if (cylindersCount < 1) {
|
||||||
|
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
||||||
|
warning(CUSTOM_OBD_ZERO_CYLINDER_COUNT, "Invalid cylinder count: %d", cylindersCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float angle = baseAngle
|
||||||
|
+ i * ENGINE(engineCycle) / cylindersCount;
|
||||||
|
|
||||||
|
InjectorOutputPin *secondOutput;
|
||||||
|
if (mode == IM_BATCH && CONFIG(twoWireBatchInjection)) {
|
||||||
|
/**
|
||||||
|
* also fire the 2nd half of the injectors so that we can implement a batch mode on individual wires
|
||||||
|
*/
|
||||||
|
// 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 = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectorOutputPin *output = &enginePins.injectors[injectorIndex];
|
||||||
|
bool isSimultanious = mode == IM_SIMULTANEOUS;
|
||||||
|
|
||||||
|
if (!isSimultanious && !output->isInitialized()) {
|
||||||
|
// todo: extract method for this index math
|
||||||
|
warning(CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectionEvent *ev = &elements[i];
|
||||||
|
ev->ownIndex = i;
|
||||||
|
INJECT_ENGINE_REFERENCE(ev);
|
||||||
|
fixAngle(angle, "addFuel#1", CUSTOM_ERR_6554);
|
||||||
|
|
||||||
|
ev->outputs[0] = output;
|
||||||
|
ev->outputs[1] = secondOutput;
|
||||||
|
|
||||||
|
ev->isSimultanious = isSimultanious;
|
||||||
|
|
||||||
|
if (TRIGGER_WAVEFORM(getSize()) < 1) {
|
||||||
|
warning(CUSTOM_ERR_NOT_INITIALIZED_TRIGGER, "uninitialized TriggerWaveform");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "findAngle#3", false);
|
||||||
|
assertAngleRange(angle, "findAngle#a33", CUSTOM_ERR_6544);
|
||||||
|
ev->injectionStart.setAngle(angle PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
#if EFI_UNIT_TEST
|
||||||
|
printf("registerInjectionEvent angle=%.2f trgIndex=%d inj %d\r\n", angle, ev->injectionStart.triggerEventIndex, injectorIndex);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::addFuelEvents(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
for (int cylinderIndex = 0; cylinderIndex < CONFIG(specs.cylindersCount); cylinderIndex++) {
|
||||||
|
InjectionEvent *ev = &elements[cylinderIndex];
|
||||||
|
ev->ownIndex = cylinderIndex; // todo: is this assignment needed here? we now initialize in constructor
|
||||||
|
bool result = addFuelEventsForCylinder(cylinderIndex PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuelSchedule::onTriggerTooth(size_t toothIndex, int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
for (int i = 0; i < CONFIG(specs.cylindersCount); i++) {
|
||||||
|
elements[i].onTriggerTooth(toothIndex, rpm, nowNt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -187,9 +187,13 @@ void turnInjectionPinLow(InjectionEvent *event) {
|
||||||
ENGINE(injectionEvents.addFuelEventsForCylinder(event->ownIndex PASS_ENGINE_PARAMETER_SUFFIX));
|
ENGINE(injectionEvents.addFuelEventsForCylinder(event->ownIndex PASS_ENGINE_PARAMETER_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: rename to 'scheduleInjectorOpenAndClose'?
|
void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t nowNt) {
|
||||||
void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
uint32_t eventIndex = injectionStart.triggerEventIndex;
|
||||||
int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
// right after trigger change we are still using old & invalid fuel schedule. good news is we do not change trigger on the fly in real life
|
||||||
|
// efiAssertVoid(CUSTOM_ERR_ASSERT_VOID, eventIndex < ENGINE(triggerShape.getLength()), "handleFuel/event sch index");
|
||||||
|
if (eventIndex != trgEventIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* todo: this is a bit tricky with batched injection. is it? Does the same
|
* todo: this is a bit tricky with batched injection. is it? Does the same
|
||||||
|
@ -197,11 +201,11 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
* x2 or /2?
|
* x2 or /2?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const floatms_t injectionDuration = event->wallFuel.adjust(ENGINE(injectionDuration) PASS_ENGINE_PARAMETER_SUFFIX);
|
const floatms_t injectionDuration = wallFuel.adjust(ENGINE(injectionDuration) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
printf("fuel index=%d injectionDuration=%.2fms adjusted=%.2fms\n",
|
printf("fuel index=%d injectionDuration=%.2fms adjusted=%.2fms\n",
|
||||||
injEventIndex,
|
eventIndex,
|
||||||
ENGINE(injectionDuration),
|
ENGINE(injectionDuration),
|
||||||
injectionDuration);
|
injectionDuration);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +249,7 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
|
|
||||||
// we are ignoring low RPM in order not to handle "engine was stopped to engine now running" transition
|
// we are ignoring low RPM in order not to handle "engine was stopped to engine now running" transition
|
||||||
if (rpm > 2 * engineConfiguration->cranking.rpm) {
|
if (rpm > 2 * engineConfiguration->cranking.rpm) {
|
||||||
const char *outputName = event->outputs[0]->name;
|
const char *outputName = outputs[0]->name;
|
||||||
if (prevOutputName == outputName
|
if (prevOutputName == outputName
|
||||||
&& engineConfiguration->injectionMode != IM_SIMULTANEOUS
|
&& engineConfiguration->injectionMode != IM_SIMULTANEOUS
|
||||||
&& engineConfiguration->injectionMode != IM_SINGLE_POINT) {
|
&& engineConfiguration->injectionMode != IM_SINGLE_POINT) {
|
||||||
|
@ -256,48 +260,48 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||||
|
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
InjectorOutputPin *output = event->outputs[0];
|
InjectorOutputPin *output = outputs[0];
|
||||||
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->name, (int)durationUs,
|
printf("handleFuelInjectionEvent fuelout %s injection_duration %dus engineCycleDuration=%.1fms\t\n", output->name, (int)durationUs,
|
||||||
(int)MS2US(getCrankshaftRevolutionTimeMs(GET_RPM_VALUE)) / 1000.0);
|
(int)MS2US(getCrankshaftRevolutionTimeMs(GET_RPM_VALUE)) / 1000.0);
|
||||||
}
|
}
|
||||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||||
|
|
||||||
if (event->isScheduled) {
|
if (isScheduled) {
|
||||||
#if EFI_PRINTF_FUEL_DETAILS
|
#if EFI_PRINTF_FUEL_DETAILS
|
||||||
if (printFuelDebug) {
|
if (printFuelDebug) {
|
||||||
InjectorOutputPin *output = event->outputs[0];
|
InjectorOutputPin *output = outputs[0];
|
||||||
printf("handleFuelInjectionEvent still used %s now=%.1fms\r\n", output->name, (int)getTimeNowUs() / 1000.0);
|
printf("handleFuelInjectionEvent still used %s now=%.1fms\r\n", output->name, (int)getTimeNowUs() / 1000.0);
|
||||||
}
|
}
|
||||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||||
return; // this InjectionEvent is still needed for an extremely long injection scheduled previously
|
return; // this InjectionEvent is still needed for an extremely long injection scheduled previously
|
||||||
}
|
}
|
||||||
|
|
||||||
event->isScheduled = true;
|
isScheduled = true;
|
||||||
|
|
||||||
action_s startAction, endAction;
|
action_s startAction, endAction;
|
||||||
// We use different callbacks based on whether we're running sequential mode or not - everything else is the same
|
// We use different callbacks based on whether we're running sequential mode or not - everything else is the same
|
||||||
if (event->isSimultanious) {
|
if (isSimultanious) {
|
||||||
startAction = { &startSimultaniousInjection, engine };
|
startAction = { &startSimultaniousInjection, engine };
|
||||||
endAction = { &endSimultaniousInjection, event };
|
endAction = { &endSimultaniousInjection, this };
|
||||||
} else {
|
} else {
|
||||||
// sequential or batch
|
// sequential or batch
|
||||||
startAction = { &turnInjectionPinHigh, event };
|
startAction = { &turnInjectionPinHigh, this };
|
||||||
endAction = { &turnInjectionPinLow, event };
|
endAction = { &turnInjectionPinLow, this };
|
||||||
}
|
}
|
||||||
|
|
||||||
efitick_t startTime = scheduleByAngle(&event->signalTimerUp, nowNt, event->injectionStart.angleOffsetFromTriggerEvent, startAction PASS_ENGINE_PARAMETER_SUFFIX);
|
efitick_t startTime = scheduleByAngle(&signalTimerUp, nowNt, injectionStart.angleOffsetFromTriggerEvent, startAction PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
efitick_t turnOffTime = startTime + US2NT((int)durationUs);
|
efitick_t turnOffTime = startTime + US2NT((int)durationUs);
|
||||||
engine->executor.scheduleByTimestampNt(&event->endOfInjectionEvent, turnOffTime, endAction);
|
engine->executor.scheduleByTimestampNt(&endOfInjectionEvent, turnOffTime, endAction);
|
||||||
|
|
||||||
#if EFI_UNIT_TEST
|
#if EFI_UNIT_TEST
|
||||||
printf("scheduling injection angle=%.2f/delay=%.2f injectionDuration=%.2f\r\n", event->injectionStart.angleOffsetFromTriggerEvent, NT2US(startTime - nowNt), injectionDuration);
|
printf("scheduling injection angle=%.2f/delay=%.2f injectionDuration=%.2f\r\n", injectionStart.angleOffsetFromTriggerEvent, NT2US(startTime - nowNt), injectionDuration);
|
||||||
#endif
|
#endif
|
||||||
#if EFI_DEFAILED_LOGGING
|
#if EFI_DEFAILED_LOGGING
|
||||||
scheduleMsg(logger, "handleFuel pin=%s eventIndex %d duration=%.2fms %d", event->outputs[0]->name,
|
scheduleMsg(logger, "handleFuel pin=%s eventIndex %d duration=%.2fms %d", outputs[0]->name,
|
||||||
injEventIndex,
|
injEventIndex,
|
||||||
injectionDuration,
|
injectionDuration,
|
||||||
getRevolutionCounter());
|
getRevolutionCounter());
|
||||||
scheduleMsg(logger, "handleFuel pin=%s delay=%.2f %d", event->outputs[0]->name, NT2US(startTime - nowNt),
|
scheduleMsg(logger, "handleFuel pin=%s delay=%.2f %d", outputs[0]->name, NT2US(startTime - nowNt),
|
||||||
getRevolutionCounter());
|
getRevolutionCounter());
|
||||||
#endif /* EFI_DEFAILED_LOGGING */
|
#endif /* EFI_DEFAILED_LOGGING */
|
||||||
}
|
}
|
||||||
|
@ -322,7 +326,7 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ignition events are defined by addFuelEvents() according to selected
|
* Injection events are defined by addFuelEvents() according to selected
|
||||||
* fueling strategy
|
* fueling strategy
|
||||||
*/
|
*/
|
||||||
FuelSchedule *fs = &ENGINE(injectionEvents);
|
FuelSchedule *fs = &ENGINE(injectionEvents);
|
||||||
|
@ -342,16 +346,7 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn
|
||||||
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int injEventIndex = 0; injEventIndex < CONFIG(specs.cylindersCount); injEventIndex++) {
|
fs->onTriggerTooth(trgEventIndex, rpm, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
InjectionEvent *event = &fs->elements[injEventIndex];
|
|
||||||
uint32_t eventIndex = event->injectionStart.triggerEventIndex;
|
|
||||||
// right after trigger change we are still using old & invalid fuel schedule. good news is we do not change trigger on the fly in real life
|
|
||||||
// efiAssertVoid(CUSTOM_ERR_ASSERT_VOID, eventIndex < ENGINE(triggerShape.getLength()), "handleFuel/event sch index");
|
|
||||||
if (eventIndex != trgEventIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
handleFuelInjectionEvent(injEventIndex, event, rpm, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
|
@ -473,6 +468,8 @@ static bool isPrimeInjectionPulseSkipped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
* See testStartOfCrankingPrimingPulse()
|
* See testStartOfCrankingPrimingPulse()
|
||||||
*/
|
*/
|
||||||
void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
|
INJECT_ENGINE_REFERENCE(&primeInjEvent);
|
||||||
|
|
||||||
// First, we need a protection against 'fake' ignition switch on and off (i.e. no engine started), to avoid repeated prime pulses.
|
// First, we need a protection against 'fake' ignition switch on and off (i.e. no engine started), to avoid repeated prime pulses.
|
||||||
// So we check and update the ignition switch counter in non-volatile backup-RAM
|
// So we check and update the ignition switch counter in non-volatile backup-RAM
|
||||||
#if EFI_PROD_CODE
|
#if EFI_PROD_CODE
|
||||||
|
@ -490,10 +487,6 @@ void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
ignSwitchCounter = -1;
|
ignSwitchCounter = -1;
|
||||||
// start prime injection if this is a 'fresh start'
|
// start prime injection if this is a 'fresh start'
|
||||||
if (ignSwitchCounter == 0) {
|
if (ignSwitchCounter == 0) {
|
||||||
// fill-in the prime event struct
|
|
||||||
#if EFI_UNIT_TEST
|
|
||||||
primeInjEvent.engine = engine;
|
|
||||||
#endif /* EFI_UNIT_TEST */
|
|
||||||
primeInjEvent.ownIndex = 0;
|
primeInjEvent.ownIndex = 0;
|
||||||
primeInjEvent.isSimultanious = true;
|
primeInjEvent.isSimultanious = true;
|
||||||
|
|
||||||
|
|
|
@ -103,151 +103,6 @@ void setSingleCoilDwell(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
||||||
engineConfiguration->sparkDwellValues[7] = 0;
|
engineConfiguration->sparkDwellValues[7] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EFI_ENGINE_CONTROL
|
|
||||||
|
|
||||||
FuelSchedule::FuelSchedule() {
|
|
||||||
clear();
|
|
||||||
for (int cylinderIndex = 0; cylinderIndex < MAX_INJECTION_OUTPUT_COUNT; cylinderIndex++) {
|
|
||||||
InjectionEvent *ev = &elements[cylinderIndex];
|
|
||||||
ev->ownIndex = cylinderIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::clear() {
|
|
||||||
isReady = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::resetOverlapping() {
|
|
||||||
for (size_t i = 0; i < efi::size(enginePins.injectors); i++) {
|
|
||||||
enginePins.injectors[i].reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns false in case of error, true if success
|
|
||||||
*/
|
|
||||||
bool FuelSchedule::addFuelEventsForCylinder(int i DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, engine!=NULL, "engine is NULL", false);
|
|
||||||
|
|
||||||
floatus_t oneDegreeUs = ENGINE(rpmCalculator.oneDegreeUs); // local copy
|
|
||||||
if (cisnan(oneDegreeUs)) {
|
|
||||||
// in order to have fuel schedule we need to have current RPM
|
|
||||||
// wonder if this line slows engine startup?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* injection phase is scheduled by injection end, so we need to step the angle back
|
|
||||||
* for the duration of the injection
|
|
||||||
*
|
|
||||||
* todo: since this method is not invoked within trigger event handler and
|
|
||||||
* engineState.injectionOffset is calculated from the same utility timer should we more that logic here?
|
|
||||||
*/
|
|
||||||
floatms_t fuelMs = ENGINE(injectionDuration);
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelMs), "NaN fuelMs", false);
|
|
||||||
angle_t injectionDuration = MS2US(fuelMs) / oneDegreeUs;
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(injectionDuration), "NaN injectionDuration", false);
|
|
||||||
assertAngleRange(injectionDuration, "injectionDuration_r", CUSTOM_INJ_DURATION);
|
|
||||||
floatus_t injectionOffset = ENGINE(engineState.injectionOffset);
|
|
||||||
if (cisnan(injectionOffset)) {
|
|
||||||
// injection offset map not ready - we are not ready to schedule fuel events
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
angle_t baseAngle = injectionOffset - injectionDuration;
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseAngle), "NaN baseAngle", false);
|
|
||||||
assertAngleRange(baseAngle, "baseAngle_r", CUSTOM_ERR_6554);
|
|
||||||
|
|
||||||
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 || (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) {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertAngleRange(baseAngle, "addFbaseAngle", CUSTOM_ADD_BASE);
|
|
||||||
|
|
||||||
int cylindersCount = CONFIG(specs.cylindersCount);
|
|
||||||
if (cylindersCount < 1) {
|
|
||||||
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
|
||||||
warning(CUSTOM_OBD_ZERO_CYLINDER_COUNT, "Invalid cylinder count: %d", cylindersCount);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float angle = baseAngle
|
|
||||||
+ i * ENGINE(engineCycle) / cylindersCount;
|
|
||||||
|
|
||||||
InjectorOutputPin *secondOutput;
|
|
||||||
if (mode == IM_BATCH && CONFIG(twoWireBatchInjection)) {
|
|
||||||
/**
|
|
||||||
* also fire the 2nd half of the injectors so that we can implement a batch mode on individual wires
|
|
||||||
*/
|
|
||||||
// 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 = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectorOutputPin *output = &enginePins.injectors[injectorIndex];
|
|
||||||
bool isSimultanious = mode == IM_SIMULTANEOUS;
|
|
||||||
|
|
||||||
if (!isSimultanious && !output->isInitialized()) {
|
|
||||||
// todo: extract method for this index math
|
|
||||||
warning(CUSTOM_OBD_INJECTION_NO_PIN_ASSIGNED, "no_pin_inj #%s", output->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectionEvent *ev = &elements[i];
|
|
||||||
ev->ownIndex = i;
|
|
||||||
INJECT_ENGINE_REFERENCE(ev);
|
|
||||||
fixAngle(angle, "addFuel#1", CUSTOM_ERR_6554);
|
|
||||||
|
|
||||||
ev->outputs[0] = output;
|
|
||||||
ev->outputs[1] = secondOutput;
|
|
||||||
|
|
||||||
ev->isSimultanious = isSimultanious;
|
|
||||||
|
|
||||||
if (TRIGGER_WAVEFORM(getSize()) < 1) {
|
|
||||||
warning(CUSTOM_ERR_NOT_INITIALIZED_TRIGGER, "uninitialized TriggerWaveform");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "findAngle#3", false);
|
|
||||||
assertAngleRange(angle, "findAngle#a33", CUSTOM_ERR_6544);
|
|
||||||
ev->injectionStart.setAngle(angle PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
#if EFI_UNIT_TEST
|
|
||||||
printf("registerInjectionEvent angle=%.2f trgIndex=%d inj %d\r\n", angle, ev->injectionStart.triggerEventIndex, injectorIndex);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuelSchedule::addFuelEvents(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
||||||
clear();
|
|
||||||
|
|
||||||
for (int cylinderIndex = 0; cylinderIndex < CONFIG(specs.cylindersCount); cylinderIndex++) {
|
|
||||||
InjectionEvent *ev = &elements[cylinderIndex];
|
|
||||||
ev->ownIndex = cylinderIndex; // todo: is this assignment needed here? we now initialize in constructor
|
|
||||||
bool result = addFuelEventsForCylinder(cylinderIndex PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
if (!result)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isReady = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static floatms_t getCrankingSparkDwell(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
static floatms_t getCrankingSparkDwell(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
if (engineConfiguration->useConstantDwellDuringCranking) {
|
if (engineConfiguration->useConstantDwellDuringCranking) {
|
||||||
return engineConfiguration->ignitionDwellForCrankingMs;
|
return engineConfiguration->ignitionDwellForCrankingMs;
|
||||||
|
|
|
@ -17,6 +17,7 @@ TEST(injectionScheduling, NormalDutyCycle) {
|
||||||
efitick_t nowNt = 1000000;
|
efitick_t nowNt = 1000000;
|
||||||
|
|
||||||
InjectionEvent event;
|
InjectionEvent event;
|
||||||
|
INJECT_ENGINE_REFERENCE(&event);
|
||||||
InjectorOutputPin pin;
|
InjectorOutputPin pin;
|
||||||
pin.injectorIndex = 0;
|
pin.injectorIndex = 0;
|
||||||
event.outputs[0] = &pin;
|
event.outputs[0] = &pin;
|
||||||
|
@ -36,5 +37,5 @@ TEST(injectionScheduling, NormalDutyCycle) {
|
||||||
|
|
||||||
engine->rpmCalculator.oneDegreeUs = 100;
|
engine->rpmCalculator.oneDegreeUs = 100;
|
||||||
|
|
||||||
handleFuelInjectionEvent(0, &event, 1000, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
event.onTriggerTooth(0, 1000, nowNt);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue