mirror of https://github.com/FOME-Tech/fome-fw.git
Separate out scheduleOrQueue into it's own standalone scheduler. (#3573)
It's a large enough entity that it shouldn't be buried in ignition logic.
This commit is contained in:
parent
f1ab9d7054
commit
aba4e5167e
|
@ -26,6 +26,7 @@
|
||||||
#include "idle_thread.h"
|
#include "idle_thread.h"
|
||||||
#include "injector_model.h"
|
#include "injector_model.h"
|
||||||
#include "launch_control.h"
|
#include "launch_control.h"
|
||||||
|
#include "trigger_scheduler.h"
|
||||||
#include "type_list.h"
|
#include "type_list.h"
|
||||||
|
|
||||||
#ifndef EFI_UNIT_TEST
|
#ifndef EFI_UNIT_TEST
|
||||||
|
@ -128,6 +129,7 @@ public:
|
||||||
#if EFI_IDLE_CONTROL
|
#if EFI_IDLE_CONTROL
|
||||||
IdleController,
|
IdleController,
|
||||||
#endif
|
#endif
|
||||||
|
TriggerScheduler,
|
||||||
EngineModule // dummy placeholder so the previous entries can all have commas
|
EngineModule // dummy placeholder so the previous entries can all have commas
|
||||||
> engineModules;
|
> engineModules;
|
||||||
|
|
||||||
|
@ -213,12 +215,6 @@ public:
|
||||||
|
|
||||||
bool needToStopEngine(efitick_t nowNt) const;
|
bool needToStopEngine(efitick_t nowNt) const;
|
||||||
bool etbAutoTune = false;
|
bool etbAutoTune = false;
|
||||||
/**
|
|
||||||
* That's the linked list of pending events scheduled in relation to trigger
|
|
||||||
* At the moment we iterate over the whole list while looking for events for specific trigger index
|
|
||||||
* We can make it an array of lists per trigger index, but that would take some RAM and probably not needed yet.
|
|
||||||
*/
|
|
||||||
AngleBasedEvent *angleBasedEventsHead = nullptr;
|
|
||||||
/**
|
/**
|
||||||
* this is based on isEngineChartEnabled and engineSnifferRpmThreshold settings
|
* this is based on isEngineChartEnabled and engineSnifferRpmThreshold settings
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,7 +25,7 @@ static void plainPinTurnOff(NamedOutputPin *output) {
|
||||||
|
|
||||||
|
|
||||||
static void scheduleOpen(AuxActor *current) {
|
static void scheduleOpen(AuxActor *current) {
|
||||||
scheduleOrQueue(¤t->open,
|
engine->module<TriggerScheduler>()->scheduleOrQueue(¤t->open,
|
||||||
TRIGGER_EVENT_UNDEFINED,
|
TRIGGER_EVENT_UNDEFINED,
|
||||||
getTimeNowNt(),
|
getTimeNowNt(),
|
||||||
current->extra + engine->engineState.auxValveStart,
|
current->extra + engine->engineState.auxValveStart,
|
||||||
|
@ -43,7 +43,7 @@ void auxPlainPinTurnOn(AuxActor *current) {
|
||||||
|
|
||||||
fixAngle(duration, "duration", CUSTOM_ERR_6557);
|
fixAngle(duration, "duration", CUSTOM_ERR_6557);
|
||||||
|
|
||||||
scheduleOrQueue(¤t->close,
|
engine->module<TriggerScheduler>()->scheduleOrQueue(¤t->close,
|
||||||
TRIGGER_EVENT_UNDEFINED,
|
TRIGGER_EVENT_UNDEFINED,
|
||||||
getTimeNowNt(),
|
getTimeNowNt(),
|
||||||
current->extra + engine->engineState.auxValveEnd,
|
current->extra + engine->engineState.auxValveEnd,
|
||||||
|
|
|
@ -422,6 +422,10 @@ void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp) {
|
||||||
* specified duration of time
|
* specified duration of time
|
||||||
*/
|
*/
|
||||||
handleFuel(limitedFuel, trgEventIndex, rpm, edgeTimestamp);
|
handleFuel(limitedFuel, trgEventIndex, rpm, edgeTimestamp);
|
||||||
|
|
||||||
|
engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth(
|
||||||
|
rpm, trgEventIndex, edgeTimestamp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For spark we schedule both start of coil charge and actual spark based on trigger angle
|
* For spark we schedule both start of coil charge and actual spark based on trigger angle
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -280,68 +280,6 @@ void turnSparkPinHigh(IgnitionEvent *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool assertNotInIgnitionList(AngleBasedEvent *head, AngleBasedEvent *element) {
|
|
||||||
assertNotInListMethodBody(AngleBasedEvent, head, element, nextToothEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if event corresponds to current tooth and was time-based scheduler
|
|
||||||
* false if event was put into queue for scheduling at a later tooth
|
|
||||||
*/
|
|
||||||
bool scheduleOrQueue(AngleBasedEvent *event,
|
|
||||||
uint32_t trgEventIndex,
|
|
||||||
efitick_t edgeTimestamp,
|
|
||||||
angle_t angle,
|
|
||||||
action_s action) {
|
|
||||||
event->position.setAngle(angle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Here's the status as of Jan 2020:
|
|
||||||
* Once we hit the last trigger tooth prior to needed event, schedule it by time. We use as much trigger position angle as possible
|
|
||||||
* and only use less precise RPM-based time calculation for the last portion of the angle, the one between two teeth closest to the
|
|
||||||
* desired angle moment.
|
|
||||||
*/
|
|
||||||
if (trgEventIndex != TRIGGER_EVENT_UNDEFINED && event->position.triggerEventIndex == trgEventIndex) {
|
|
||||||
/**
|
|
||||||
* Spark should be fired before the next trigger event - time-based delay is best precision possible
|
|
||||||
*/
|
|
||||||
scheduling_s * sDown = &event->scheduling;
|
|
||||||
|
|
||||||
scheduleByAngle(
|
|
||||||
sDown,
|
|
||||||
edgeTimestamp,
|
|
||||||
event->position.angleOffsetFromTriggerEvent,
|
|
||||||
action
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
event->action = action;
|
|
||||||
/**
|
|
||||||
* Spark should be scheduled in relation to some future trigger event, this way we get better firing precision
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
|
||||||
|
|
||||||
// TODO: This is O(n), consider some other way of detecting if in a list,
|
|
||||||
// and consider doubly linked or other list tricks.
|
|
||||||
|
|
||||||
if (!assertNotInIgnitionList(engine->angleBasedEventsHead, event)) {
|
|
||||||
// Use Append to retain some semblance of event ordering in case of
|
|
||||||
// time skew. Thus on events are always followed by off events.
|
|
||||||
LL_APPEND2(engine->angleBasedEventsHead, event, nextToothEvent);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if SPARK_EXTREME_LOGGING
|
|
||||||
efiPrintf("isPending thus not adding to queue index=%d rev=%d now=%d",
|
|
||||||
trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs());
|
|
||||||
#endif /* SPARK_EXTREME_LOGGING */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scheduleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, IgnitionEvent *event,
|
static void scheduleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, IgnitionEvent *event,
|
||||||
int rpm, efitick_t edgeTimestamp) {
|
int rpm, efitick_t edgeTimestamp) {
|
||||||
|
|
||||||
|
@ -400,7 +338,9 @@ static void scheduleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, Igniti
|
||||||
efiAssertVoid(CUSTOM_ERR_6591, !cisnan(sparkAngle), "findAngle#4");
|
efiAssertVoid(CUSTOM_ERR_6591, !cisnan(sparkAngle), "findAngle#4");
|
||||||
assertAngleRange(sparkAngle, "findAngle#a5", CUSTOM_ERR_6549);
|
assertAngleRange(sparkAngle, "findAngle#a5", CUSTOM_ERR_6549);
|
||||||
|
|
||||||
bool scheduled = scheduleOrQueue(&event->sparkEvent, trgEventIndex, edgeTimestamp, sparkAngle, { fireSparkAndPrepareNextSchedule, event });
|
bool scheduled = engine->module<TriggerScheduler>()->scheduleOrQueue(
|
||||||
|
&event->sparkEvent, trgEventIndex, edgeTimestamp, sparkAngle,
|
||||||
|
{ fireSparkAndPrepareNextSchedule, event });
|
||||||
|
|
||||||
if (scheduled) {
|
if (scheduled) {
|
||||||
#if SPARK_EXTREME_LOGGING
|
#if SPARK_EXTREME_LOGGING
|
||||||
|
@ -475,60 +415,6 @@ static void prepareIgnitionSchedule() {
|
||||||
initializeIgnitionActions();
|
initializeIgnitionActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scheduleAllSparkEventsUntilNextTriggerTooth(uint32_t trgEventIndex, efitick_t edgeTimestamp) {
|
|
||||||
AngleBasedEvent *current, *tmp, *keephead;
|
|
||||||
AngleBasedEvent *keeptail = nullptr;
|
|
||||||
|
|
||||||
{
|
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
|
||||||
|
|
||||||
keephead = engine->angleBasedEventsHead;
|
|
||||||
engine->angleBasedEventsHead = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent)
|
|
||||||
{
|
|
||||||
if (current->position.triggerEventIndex == trgEventIndex) {
|
|
||||||
// time to fire a spark which was scheduled previously
|
|
||||||
|
|
||||||
// Yes this looks like O(n^2), but that's only over the entire engine
|
|
||||||
// cycle. It's really O(mn + nn) where m = # of teeth and n = # events
|
|
||||||
// fired per cycle. The number of teeth outweigh the number of events, at
|
|
||||||
// least for 60-2.... So odds are we're only firing an event or two per
|
|
||||||
// tooth, which means the outer loop is really only O(n). And if we are
|
|
||||||
// firing many events per teeth, then it's likely the events before this
|
|
||||||
// one also fired and thus the call to LL_DELETE2 is closer to O(1).
|
|
||||||
LL_DELETE2(keephead, current, nextToothEvent);
|
|
||||||
|
|
||||||
scheduling_s * sDown = ¤t->scheduling;
|
|
||||||
|
|
||||||
#if SPARK_EXTREME_LOGGING
|
|
||||||
efiPrintf("time to invoke ind=%d %d %d", trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs());
|
|
||||||
#endif /* SPARK_EXTREME_LOGGING */
|
|
||||||
|
|
||||||
// In case this event was scheduled by overdwell protection, cancel it so we can re-schedule at the correct time
|
|
||||||
engine->executor.cancel(sDown);
|
|
||||||
|
|
||||||
scheduleByAngle(
|
|
||||||
sDown,
|
|
||||||
edgeTimestamp,
|
|
||||||
current->position.angleOffsetFromTriggerEvent,
|
|
||||||
current->action
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
keeptail = current; // Used for fast list concatenation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keephead) {
|
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
|
||||||
|
|
||||||
// Put any new entries onto the end of the keep list
|
|
||||||
keeptail->nextToothEvent = engine->angleBasedEventsHead;
|
|
||||||
engine->angleBasedEventsHead = keephead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp
|
void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -548,7 +434,6 @@ void onTriggerEventSparkLogic(bool limitedSpark, uint32_t trgEventIndex, int rpm
|
||||||
* Ignition schedule is defined once per revolution
|
* Ignition schedule is defined once per revolution
|
||||||
* See initializeIgnitionActions()
|
* See initializeIgnitionActions()
|
||||||
*/
|
*/
|
||||||
scheduleAllSparkEventsUntilNextTriggerTooth(trgEventIndex, edgeTimestamp);
|
|
||||||
|
|
||||||
|
|
||||||
// scheduleSimpleMsg(&logger, "eventId spark ", eventIndex);
|
// scheduleSimpleMsg(&logger, "eventId spark ", eventIndex);
|
||||||
|
|
|
@ -15,10 +15,3 @@ percent_t getCoilDutyCycle(int rpm);
|
||||||
void initializeIgnitionActions();
|
void initializeIgnitionActions();
|
||||||
|
|
||||||
int isIgnitionTimingError(void);
|
int isIgnitionTimingError(void);
|
||||||
|
|
||||||
#define TRIGGER_EVENT_UNDEFINED INT32_MAX
|
|
||||||
bool scheduleOrQueue(AngleBasedEvent *event,
|
|
||||||
uint32_t trgEventIndex,
|
|
||||||
efitick_t edgeTimestamp,
|
|
||||||
angle_t angle,
|
|
||||||
action_s action);
|
|
||||||
|
|
|
@ -6,3 +6,4 @@ SYSTEMSRC_CPP = \
|
||||||
$(PROJECT_DIR)/controllers/system/periodic_task.cpp \
|
$(PROJECT_DIR)/controllers/system/periodic_task.cpp \
|
||||||
$(PROJECT_DIR)/controllers/system/dc_motor.cpp \
|
$(PROJECT_DIR)/controllers/system/dc_motor.cpp \
|
||||||
$(PROJECT_DIR)/controllers/system/timer/scheduler.cpp \
|
$(PROJECT_DIR)/controllers/system/timer/scheduler.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/system/timer/trigger_scheduler.cpp \
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "event_queue.h"
|
||||||
|
#include "os_access.h"
|
||||||
|
|
||||||
|
bool TriggerScheduler::assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element) {
|
||||||
|
assertNotInListMethodBody(AngleBasedEvent, head, element, nextToothEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if event corresponds to current tooth and was time-based scheduler
|
||||||
|
* false if event was put into queue for scheduling at a later tooth
|
||||||
|
*/
|
||||||
|
bool TriggerScheduler::scheduleOrQueue(AngleBasedEvent *event,
|
||||||
|
uint32_t trgEventIndex,
|
||||||
|
efitick_t edgeTimestamp,
|
||||||
|
angle_t angle,
|
||||||
|
action_s action) {
|
||||||
|
event->position.setAngle(angle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here's the status as of Jan 2020:
|
||||||
|
* Once we hit the last trigger tooth prior to needed event, schedule it by time. We use
|
||||||
|
* as much trigger position angle as possible and only use less precise RPM-based time
|
||||||
|
* calculation for the last portion of the angle, the one between two teeth closest to the
|
||||||
|
* desired angle moment.
|
||||||
|
*/
|
||||||
|
if (trgEventIndex != TRIGGER_EVENT_UNDEFINED && event->position.triggerEventIndex == trgEventIndex) {
|
||||||
|
/**
|
||||||
|
* Spark should be fired before the next trigger event - time-based delay is best precision possible
|
||||||
|
*/
|
||||||
|
scheduling_s * sDown = &event->scheduling;
|
||||||
|
|
||||||
|
scheduleByAngle(
|
||||||
|
sDown,
|
||||||
|
edgeTimestamp,
|
||||||
|
event->position.angleOffsetFromTriggerEvent,
|
||||||
|
action
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
event->action = action;
|
||||||
|
/**
|
||||||
|
* Spark should be scheduled in relation to some future trigger event, this way we get better firing precision
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
// TODO: This is O(n), consider some other way of detecting if in a list,
|
||||||
|
// and consider doubly linked or other list tricks.
|
||||||
|
|
||||||
|
if (!assertNotInList(m_angleBasedEventsHead, event)) {
|
||||||
|
// Use Append to retain some semblance of event ordering in case of
|
||||||
|
// time skew. Thus on events are always followed by off events.
|
||||||
|
LL_APPEND2(m_angleBasedEventsHead, event, nextToothEvent);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if SPARK_EXTREME_LOGGING
|
||||||
|
efiPrintf("isPending thus not adding to queue index=%d rev=%d now=%d",
|
||||||
|
trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs());
|
||||||
|
#endif /* SPARK_EXTREME_LOGGING */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
|
||||||
|
uint32_t trgEventIndex,
|
||||||
|
efitick_t edgeTimestamp) {
|
||||||
|
|
||||||
|
// Not sure why we check ignitionEnabled; it's left over from when this code lived in
|
||||||
|
// spark_logic.cpp, but I think it should be removed.
|
||||||
|
if (!isValidRpm(rpm) || !engineConfiguration->isIgnitionEnabled) {
|
||||||
|
// this might happen for instance in case of a single trigger event after a pause
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AngleBasedEvent *current, *tmp, *keephead;
|
||||||
|
AngleBasedEvent *keeptail = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
keephead =m_angleBasedEventsHead;
|
||||||
|
m_angleBasedEventsHead = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent)
|
||||||
|
{
|
||||||
|
if (current->position.triggerEventIndex == trgEventIndex) {
|
||||||
|
// time to fire a spark which was scheduled previously
|
||||||
|
|
||||||
|
// Yes this looks like O(n^2), but that's only over the entire engine
|
||||||
|
// cycle. It's really O(mn + nn) where m = # of teeth and n = # events
|
||||||
|
// fired per cycle. The number of teeth outweigh the number of events, at
|
||||||
|
// least for 60-2.... So odds are we're only firing an event or two per
|
||||||
|
// tooth, which means the outer loop is really only O(n). And if we are
|
||||||
|
// firing many events per teeth, then it's likely the events before this
|
||||||
|
// one also fired and thus the call to LL_DELETE2 is closer to O(1).
|
||||||
|
LL_DELETE2(keephead, current, nextToothEvent);
|
||||||
|
|
||||||
|
scheduling_s * sDown = ¤t->scheduling;
|
||||||
|
|
||||||
|
#if SPARK_EXTREME_LOGGING
|
||||||
|
efiPrintf("time to invoke ind=%d %d %d",
|
||||||
|
trgEventIndex, getRevolutionCounter(), (int)getTimeNowUs());
|
||||||
|
#endif /* SPARK_EXTREME_LOGGING */
|
||||||
|
|
||||||
|
// In case this event was scheduled by overdwell protection, cancel it so
|
||||||
|
// we can re-schedule at the correct time
|
||||||
|
engine->executor.cancel(sDown);
|
||||||
|
|
||||||
|
scheduleByAngle(
|
||||||
|
sDown,
|
||||||
|
edgeTimestamp,
|
||||||
|
current->position.angleOffsetFromTriggerEvent,
|
||||||
|
current->action
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
keeptail = current; // Used for fast list concatenation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keephead) {
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
|
||||||
|
// Put any new entries onto the end of the keep list
|
||||||
|
keeptail->nextToothEvent = m_angleBasedEventsHead;
|
||||||
|
m_angleBasedEventsHead = keephead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if EFI_UNIT_TEST
|
||||||
|
// todo: reduce code duplication with another 'getElementAtIndexForUnitText'
|
||||||
|
AngleBasedEvent * TriggerScheduler::getElementAtIndexForUnitTest(int index) {
|
||||||
|
AngleBasedEvent * current;
|
||||||
|
|
||||||
|
LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
return current;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
firmwareError(OBD_PCM_Processor_Fault, "getElementAtIndexForUnitText: null");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif /* EFI_UNIT_TEST */
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TRIGGER_EVENT_UNDEFINED INT32_MAX
|
||||||
|
|
||||||
|
class TriggerScheduler : public EngineModule {
|
||||||
|
public:
|
||||||
|
bool scheduleOrQueue(AngleBasedEvent *event,
|
||||||
|
uint32_t trgEventIndex,
|
||||||
|
efitick_t edgeTimestamp,
|
||||||
|
angle_t angle,
|
||||||
|
action_s action);
|
||||||
|
|
||||||
|
void scheduleEventsUntilNextTriggerTooth(int rpm,
|
||||||
|
uint32_t trgEventIndex,
|
||||||
|
efitick_t edgeTimestamp);
|
||||||
|
|
||||||
|
// For unit tests
|
||||||
|
AngleBasedEvent * getElementAtIndexForUnitTest(int index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* That's the linked list of pending events scheduled in relation to trigger
|
||||||
|
* At the moment we iterate over the whole list while looking for events for specific
|
||||||
|
* trigger index We can make it an array of lists per trigger index, but that would take
|
||||||
|
* some RAM and probably not needed yet.
|
||||||
|
*/
|
||||||
|
AngleBasedEvent *m_angleBasedEventsHead = nullptr;
|
||||||
|
};
|
|
@ -305,27 +305,12 @@ scheduling_s * EngineTestHelper::assertEvent5(const char *msg, int index, void *
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: reduce code duplication with another 'getElementAtIndexForUnitText'
|
|
||||||
static AngleBasedEvent * getElementAtIndexForUnitText(int index, Engine *engine) {
|
|
||||||
AngleBasedEvent * current;
|
|
||||||
|
|
||||||
LL_FOREACH2(engine->angleBasedEventsHead, current, nextToothEvent)
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
return current;
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
#if EFI_UNIT_TEST
|
|
||||||
firmwareError(OBD_PCM_Processor_Fault, "getElementAtIndexForUnitText: null");
|
|
||||||
#endif /* EFI_UNIT_TEST */
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AngleBasedEvent * EngineTestHelper::assertTriggerEvent(const char *msg,
|
AngleBasedEvent * EngineTestHelper::assertTriggerEvent(const char *msg,
|
||||||
int index, AngleBasedEvent *expected,
|
int index, AngleBasedEvent *expected,
|
||||||
void *callback,
|
void *callback,
|
||||||
int triggerEventIndex, angle_t angleOffsetFromTriggerEvent) {
|
int triggerEventIndex, angle_t angleOffsetFromTriggerEvent) {
|
||||||
AngleBasedEvent * event = getElementAtIndexForUnitText(index, &engine);
|
AngleBasedEvent * event =
|
||||||
|
engine.module<TriggerScheduler>()->getElementAtIndexForUnitTest(index);
|
||||||
|
|
||||||
assertEqualsM4(msg, " callback up/down", (void*)event->action.getCallback() == (void*) callback, 1);
|
assertEqualsM4(msg, " callback up/down", (void*)event->action.getCallback() == (void*) callback, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue