refacto
This commit is contained in:
parent
d58438874e
commit
626f55a08a
|
@ -25,8 +25,6 @@
|
|||
#include "engine_math.h"
|
||||
|
||||
InjectionEvent::InjectionEvent() {
|
||||
isSimultanious = false;
|
||||
ownIndex = 0;
|
||||
memset(outputs, 0, sizeof(outputs));
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,17 @@ class Engine;
|
|||
class InjectionEvent {
|
||||
public:
|
||||
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.
|
||||
* It's more efficient to handle all injectors together if that's the case
|
||||
*/
|
||||
bool isSimultanious;
|
||||
bool isSimultanious = false;
|
||||
InjectorOutputPin *outputs[MAX_WIRES_COUNT];
|
||||
int ownIndex;
|
||||
int ownIndex = 0;
|
||||
DECLARE_ENGINE_PTR;
|
||||
event_trigger_position_s injectionStart;
|
||||
|
||||
|
@ -47,13 +51,16 @@ public:
|
|||
WallFuel wallFuel;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class knows about when to inject fuel
|
||||
*/
|
||||
class FuelSchedule {
|
||||
public:
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,7 @@ CONTROLLERS_SRC_CPP = \
|
|||
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
|
||||
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
|
||||
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
|
||||
$(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \
|
||||
$(CONTROLLERS_DIR)/flash_main.cpp \
|
||||
$(CONTROLLERS_DIR)/bench_test.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));
|
||||
}
|
||||
|
||||
// todo: rename to 'scheduleInjectorOpenAndClose'?
|
||||
void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
||||
int rpm, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t nowNt) {
|
||||
uint32_t eventIndex = 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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?
|
||||
*/
|
||||
|
||||
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 (printFuelDebug) {
|
||||
printf("fuel index=%d injectionDuration=%.2fms adjusted=%.2fms\n",
|
||||
injEventIndex,
|
||||
eventIndex,
|
||||
ENGINE(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
|
||||
if (rpm > 2 * engineConfiguration->cranking.rpm) {
|
||||
const char *outputName = event->outputs[0]->name;
|
||||
const char *outputName = outputs[0]->name;
|
||||
if (prevOutputName == outputName
|
||||
&& engineConfiguration->injectionMode != IM_SIMULTANEOUS
|
||||
&& engineConfiguration->injectionMode != IM_SINGLE_POINT) {
|
||||
|
@ -256,48 +260,48 @@ void handleFuelInjectionEvent(int injEventIndex, InjectionEvent *event,
|
|||
|
||||
#if EFI_PRINTF_FUEL_DETAILS
|
||||
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,
|
||||
(int)MS2US(getCrankshaftRevolutionTimeMs(GET_RPM_VALUE)) / 1000.0);
|
||||
}
|
||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||
|
||||
if (event->isScheduled) {
|
||||
if (isScheduled) {
|
||||
#if EFI_PRINTF_FUEL_DETAILS
|
||||
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);
|
||||
}
|
||||
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
||||
return; // this InjectionEvent is still needed for an extremely long injection scheduled previously
|
||||
}
|
||||
|
||||
event->isScheduled = true;
|
||||
isScheduled = true;
|
||||
|
||||
action_s startAction, endAction;
|
||||
// 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 };
|
||||
endAction = { &endSimultaniousInjection, event };
|
||||
endAction = { &endSimultaniousInjection, this };
|
||||
} else {
|
||||
// sequential or batch
|
||||
startAction = { &turnInjectionPinHigh, event };
|
||||
endAction = { &turnInjectionPinLow, event };
|
||||
startAction = { &turnInjectionPinHigh, this };
|
||||
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);
|
||||
engine->executor.scheduleByTimestampNt(&event->endOfInjectionEvent, turnOffTime, endAction);
|
||||
engine->executor.scheduleByTimestampNt(&endOfInjectionEvent, turnOffTime, endAction);
|
||||
|
||||
#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
|
||||
#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,
|
||||
injectionDuration,
|
||||
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());
|
||||
#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
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
for (int injEventIndex = 0; injEventIndex < CONFIG(specs.cylindersCount); injEventIndex++) {
|
||||
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);
|
||||
}
|
||||
fs->onTriggerTooth(trgEventIndex, rpm, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
}
|
||||
|
||||
#if EFI_PROD_CODE
|
||||
|
@ -473,6 +468,8 @@ static bool isPrimeInjectionPulseSkipped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|||
* See testStartOfCrankingPrimingPulse()
|
||||
*/
|
||||
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.
|
||||
// So we check and update the ignition switch counter in non-volatile backup-RAM
|
||||
#if EFI_PROD_CODE
|
||||
|
@ -490,10 +487,6 @@ void startPrimeInjectionPulse(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|||
ignSwitchCounter = -1;
|
||||
// start prime injection if this is a 'fresh start'
|
||||
if (ignSwitchCounter == 0) {
|
||||
// fill-in the prime event struct
|
||||
#if EFI_UNIT_TEST
|
||||
primeInjEvent.engine = engine;
|
||||
#endif /* EFI_UNIT_TEST */
|
||||
primeInjEvent.ownIndex = 0;
|
||||
primeInjEvent.isSimultanious = true;
|
||||
|
||||
|
|
|
@ -103,151 +103,6 @@ void setSingleCoilDwell(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
|||
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) {
|
||||
if (engineConfiguration->useConstantDwellDuringCranking) {
|
||||
return engineConfiguration->ignitionDwellForCrankingMs;
|
||||
|
|
|
@ -17,6 +17,7 @@ TEST(injectionScheduling, NormalDutyCycle) {
|
|||
efitick_t nowNt = 1000000;
|
||||
|
||||
InjectionEvent event;
|
||||
INJECT_ENGINE_REFERENCE(&event);
|
||||
InjectorOutputPin pin;
|
||||
pin.injectorIndex = 0;
|
||||
event.outputs[0] = &pin;
|
||||
|
@ -36,5 +37,5 @@ TEST(injectionScheduling, NormalDutyCycle) {
|
|||
|
||||
engine->rpmCalculator.oneDegreeUs = 100;
|
||||
|
||||
handleFuelInjectionEvent(0, &event, 1000, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
event.onTriggerTooth(0, 1000, nowNt);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue