TriggerScheduler cleanup (#4844)
* TriggerScheduler cleanup * remove TRIGGER_EVENT_UNDEFINED * remove dead overload of scheduleOrQueue Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
parent
9e3b7fabfe
commit
769cdd32ca
|
@ -23,6 +23,8 @@ struct AngleBasedEventBase {
|
||||||
*/
|
*/
|
||||||
AngleBasedEventBase *nextToothEvent = nullptr;
|
AngleBasedEventBase *nextToothEvent = nullptr;
|
||||||
|
|
||||||
|
virtual void setAngle(angle_t angle) = 0;
|
||||||
|
|
||||||
virtual bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const = 0;
|
virtual bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const = 0;
|
||||||
virtual float getAngleFromNow(float currentPhase) const = 0;
|
virtual float getAngleFromNow(float currentPhase) const = 0;
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ public:
|
||||||
struct AngleBasedEventOld : public AngleBasedEventBase {
|
struct AngleBasedEventOld : public AngleBasedEventBase {
|
||||||
event_trigger_position_s position;
|
event_trigger_position_s position;
|
||||||
|
|
||||||
|
void setAngle(angle_t angle) override;
|
||||||
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
|
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
|
||||||
float getAngleFromNow(float currentPhase) const override;
|
float getAngleFromNow(float currentPhase) const override;
|
||||||
|
|
||||||
|
@ -53,7 +56,9 @@ struct AngleBasedEventOld : public AngleBasedEventBase {
|
||||||
struct AngleBasedEventNew : public AngleBasedEventBase {
|
struct AngleBasedEventNew : public AngleBasedEventBase {
|
||||||
float enginePhase;
|
float enginePhase;
|
||||||
|
|
||||||
|
void setAngle(angle_t angle) override;
|
||||||
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
|
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
|
||||||
|
bool shouldSchedule(float currentPhase, float nextPhase) const;
|
||||||
float getAngleFromNow(float currentPhase) const override;
|
float getAngleFromNow(float currentPhase) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,7 @@ static void plainPinTurnOff(NamedOutputPin *output) {
|
||||||
|
|
||||||
|
|
||||||
static void scheduleOpen(AuxActor *current) {
|
static void scheduleOpen(AuxActor *current) {
|
||||||
engine->module<TriggerScheduler>()->scheduleOrQueue(¤t->open,
|
engine->module<TriggerScheduler>()->schedule(¤t->open,
|
||||||
TRIGGER_EVENT_UNDEFINED,
|
|
||||||
getTimeNowNt(),
|
|
||||||
current->extra + engine->engineState.auxValveStart,
|
current->extra + engine->engineState.auxValveStart,
|
||||||
{ auxPlainPinTurnOn, current }
|
{ auxPlainPinTurnOn, current }
|
||||||
);
|
);
|
||||||
|
@ -43,9 +41,7 @@ void auxPlainPinTurnOn(AuxActor *current) {
|
||||||
|
|
||||||
fixAngle(duration, "duration", CUSTOM_ERR_6557);
|
fixAngle(duration, "duration", CUSTOM_ERR_6557);
|
||||||
|
|
||||||
engine->module<TriggerScheduler>()->scheduleOrQueue(¤t->close,
|
engine->module<TriggerScheduler>()->schedule(¤t->close,
|
||||||
TRIGGER_EVENT_UNDEFINED,
|
|
||||||
getTimeNowNt(),
|
|
||||||
current->extra + engine->engineState.auxValveEnd,
|
current->extra + engine->engineState.auxValveEnd,
|
||||||
{ plainPinTurnOff, output }
|
{ plainPinTurnOff, output }
|
||||||
);
|
);
|
||||||
|
|
|
@ -201,8 +201,8 @@ void HpfpController::scheduleNextCycle() {
|
||||||
/**
|
/**
|
||||||
* We are good to use just one m_event instance because new events are scheduled when we turn off valve.
|
* We are good to use just one m_event instance because new events are scheduled when we turn off valve.
|
||||||
*/
|
*/
|
||||||
engine->module<TriggerScheduler>()->scheduleOrQueue(
|
engine->module<TriggerScheduler>()->schedule(
|
||||||
&m_event, TRIGGER_EVENT_UNDEFINED, 0,
|
&m_event,
|
||||||
di_nextStart,
|
di_nextStart,
|
||||||
{ pinTurnOn, this });
|
{ pinTurnOn, this });
|
||||||
|
|
||||||
|
@ -211,8 +211,8 @@ void HpfpController::scheduleNextCycle() {
|
||||||
// Schedule this, even if we aren't opening the valve this time, since this
|
// Schedule this, even if we aren't opening the valve this time, since this
|
||||||
// will schedule the next lobe.
|
// will schedule the next lobe.
|
||||||
// todo: would it have been cleaner to schedule 'scheduleNextCycle' directly?
|
// todo: would it have been cleaner to schedule 'scheduleNextCycle' directly?
|
||||||
engine->module<TriggerScheduler>()->scheduleOrQueue(
|
engine->module<TriggerScheduler>()->schedule(
|
||||||
&m_event, TRIGGER_EVENT_UNDEFINED, 0, lobe,
|
&m_event, lobe,
|
||||||
{ pinTurnOff, this });
|
{ pinTurnOff, this });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,7 @@ void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp, angle_
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
onTriggerEventSparkLogic(trgEventIndex, rpm, edgeTimestamp, currentPhase, nextPhase);
|
onTriggerEventSparkLogic(rpm, edgeTimestamp, currentPhase, nextPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* EFI_ENGINE_CONTROL */
|
#endif /* EFI_ENGINE_CONTROL */
|
||||||
|
|
|
@ -317,7 +317,7 @@ void turnSparkPinHigh(IgnitionEvent *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scheduleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, IgnitionEvent *event,
|
static void scheduleSparkEvent(bool limitedSpark, IgnitionEvent *event,
|
||||||
int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
||||||
|
|
||||||
angle_t sparkAngle = event->sparkAngle;
|
angle_t sparkAngle = event->sparkAngle;
|
||||||
|
@ -374,17 +374,17 @@ static void scheduleSparkEvent(bool limitedSpark, uint32_t trgEventIndex, Igniti
|
||||||
assertAngleRange(sparkAngle, "findAngle#a5", CUSTOM_ERR_6549);
|
assertAngleRange(sparkAngle, "findAngle#a5", CUSTOM_ERR_6549);
|
||||||
|
|
||||||
bool scheduled = engine->module<TriggerScheduler>()->scheduleOrQueue(
|
bool scheduled = engine->module<TriggerScheduler>()->scheduleOrQueue(
|
||||||
&event->sparkEvent, trgEventIndex, edgeTimestamp, sparkAngle,
|
&event->sparkEvent, edgeTimestamp, sparkAngle,
|
||||||
{ fireSparkAndPrepareNextSchedule, event },
|
{ fireSparkAndPrepareNextSchedule, event },
|
||||||
currentPhase, nextPhase);
|
currentPhase, nextPhase);
|
||||||
|
|
||||||
if (scheduled) {
|
if (scheduled) {
|
||||||
#if SPARK_EXTREME_LOGGING
|
#if SPARK_EXTREME_LOGGING
|
||||||
efiPrintf("scheduling sparkDown ind=%d %d %s now=%d later id=%d", trgEventIndex, getRevolutionCounter(), event->getOutputForLoggins()->name, (int)getTimeNowUs(), event->sparkId);
|
efiPrintf("scheduling sparkDown %d %s now=%d later id=%d", getRevolutionCounter(), event->getOutputForLoggins()->name, (int)getTimeNowUs(), event->sparkId);
|
||||||
#endif /* FUEL_MATH_EXTREME_LOGGING */
|
#endif /* FUEL_MATH_EXTREME_LOGGING */
|
||||||
} else {
|
} else {
|
||||||
#if SPARK_EXTREME_LOGGING
|
#if SPARK_EXTREME_LOGGING
|
||||||
efiPrintf("to queue sparkDown ind=%d %d %s now=%d for id=%d angle=%.1f", trgEventIndex, getRevolutionCounter(), event->getOutputForLoggins()->name, (int)getTimeNowUs(), event->sparkId, sparkAngle);
|
efiPrintf("to queue sparkDown %d %s now=%d for id=%d angle=%.1f", getRevolutionCounter(), event->getOutputForLoggins()->name, (int)getTimeNowUs(), event->sparkId, sparkAngle);
|
||||||
#endif /* SPARK_EXTREME_LOGGING */
|
#endif /* SPARK_EXTREME_LOGGING */
|
||||||
|
|
||||||
if (!limitedSpark && engine->enableOverdwellProtection) {
|
if (!limitedSpark && engine->enableOverdwellProtection) {
|
||||||
|
@ -451,7 +451,7 @@ static void prepareIgnitionSchedule() {
|
||||||
initializeIgnitionActions();
|
initializeIgnitionActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTriggerEventSparkLogic(uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
void onTriggerEventSparkLogic(int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
|
||||||
ScopePerf perf(PE::OnTriggerEventSparkLogic);
|
ScopePerf perf(PE::OnTriggerEventSparkLogic);
|
||||||
|
|
||||||
if (!isValidRpm(rpm) || !engineConfiguration->isIgnitionEnabled) {
|
if (!isValidRpm(rpm) || !engineConfiguration->isIgnitionEnabled) {
|
||||||
|
@ -498,7 +498,7 @@ void onTriggerEventSparkLogic(uint32_t trgEventIndex, int rpm, efitick_t edgeTim
|
||||||
}
|
}
|
||||||
#endif // EFI_LAUNCH_CONTROL
|
#endif // EFI_LAUNCH_CONTROL
|
||||||
|
|
||||||
scheduleSparkEvent(limitedSpark, trgEventIndex, event, rpm, edgeTimestamp, currentPhase, nextPhase);
|
scheduleSparkEvent(limitedSpark, event, rpm, edgeTimestamp, currentPhase, nextPhase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void onTriggerEventSparkLogic(uint32_t trgEventIndex, int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase);
|
void onTriggerEventSparkLogic(int rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase);
|
||||||
void turnSparkPinHigh(IgnitionEvent *event);
|
void turnSparkPinHigh(IgnitionEvent *event);
|
||||||
void fireSparkAndPrepareNextSchedule(IgnitionEvent *event);
|
void fireSparkAndPrepareNextSchedule(IgnitionEvent *event);
|
||||||
int getNumberOfSparks(ignition_mode_e mode);
|
int getNumberOfSparks(ignition_mode_e mode);
|
||||||
|
|
|
@ -6,81 +6,26 @@ bool TriggerScheduler::assertNotInList(AngleBasedEventBase *head, AngleBasedEven
|
||||||
assertNotInListMethodBody(AngleBasedEventBase, head, element, nextToothEvent)
|
assertNotInListMethodBody(AngleBasedEventBase, head, element, nextToothEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TriggerScheduler::schedule(AngleBasedEventBase* event, angle_t angle, action_s action) {
|
||||||
|
event->setAngle(angle);
|
||||||
|
|
||||||
|
schedule(event, action);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules 'action' to occur at engine cycle angle 'angle'.
|
* Schedules 'action' to occur at engine cycle angle 'angle'.
|
||||||
*
|
*
|
||||||
* If you know when a recent trigger occured, you can pass it in as 'trgEventIndex' and
|
|
||||||
* 'edgeTimestamp'. Otherwise pass in TRIGGER_EVENT_UNDEFINED and the work will be scheduled on
|
|
||||||
* the next trigger edge.
|
|
||||||
*
|
|
||||||
* @return true if event corresponds to current tooth and was time-based scheduler
|
* @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
|
* false if event was put into queue for scheduling at a later tooth
|
||||||
*/
|
*/
|
||||||
bool TriggerScheduler::scheduleOrQueue(AngleBasedEventOld *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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
engine->outputChannels.systemEventReuse++; // not atomic/not volatile but good enough for just debugging
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TriggerScheduler::scheduleOrQueue(AngleBasedEventNew *event,
|
bool TriggerScheduler::scheduleOrQueue(AngleBasedEventNew *event,
|
||||||
uint32_t trgEventIndex,
|
|
||||||
efitick_t edgeTimestamp,
|
efitick_t edgeTimestamp,
|
||||||
angle_t angle,
|
angle_t angle,
|
||||||
action_s action,
|
action_s action,
|
||||||
float currentPhase, float nextPhase) {
|
float currentPhase, float nextPhase) {
|
||||||
event->enginePhase = angle;
|
event->setAngle(angle);
|
||||||
|
|
||||||
if (event->shouldSchedule(trgEventIndex, currentPhase, nextPhase)) {
|
if (event->shouldSchedule(currentPhase, nextPhase)) {
|
||||||
// if we're due now, just schedule the event
|
// if we're due now, just schedule the event
|
||||||
scheduleByAngle(
|
scheduleByAngle(
|
||||||
&event->scheduling,
|
&event->scheduling,
|
||||||
|
@ -91,26 +36,28 @@ bool TriggerScheduler::scheduleOrQueue(AngleBasedEventNew *event,
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Not due at this tooth, add to the list to execute later
|
// If not due now, add it to the queue to be scheduled later
|
||||||
event->action = action;
|
schedule(event, action);
|
||||||
|
|
||||||
{
|
return false;
|
||||||
chibios_rt::CriticalSectionLocker csl;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This is O(n), consider some other way of detecting if in a list,
|
void TriggerScheduler::schedule(AngleBasedEventBase* event, action_s action) {
|
||||||
// and consider doubly linked or other list tricks.
|
event->action = action;
|
||||||
|
|
||||||
if (!assertNotInList(m_angleBasedEventsHead, event)) {
|
{
|
||||||
// Use Append to retain some semblance of event ordering in case of
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
// time skew. Thus on events are always followed by off events.
|
|
||||||
LL_APPEND2(m_angleBasedEventsHead, event, nextToothEvent);
|
|
||||||
|
|
||||||
return false;
|
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
|
void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
|
||||||
|
@ -177,6 +124,10 @@ void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AngleBasedEventOld::setAngle(angle_t angle) {
|
||||||
|
position.setAngle(angle);
|
||||||
|
}
|
||||||
|
|
||||||
bool AngleBasedEventOld::shouldSchedule(uint32_t trgEventIndex, float /*currentPhase*/, float /*nextPhase*/) const {
|
bool AngleBasedEventOld::shouldSchedule(uint32_t trgEventIndex, float /*currentPhase*/, float /*nextPhase*/) const {
|
||||||
return position.triggerEventIndex == trgEventIndex;
|
return position.triggerEventIndex == trgEventIndex;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +136,15 @@ float AngleBasedEventOld::getAngleFromNow(float /*currentPhase*/) const {
|
||||||
return position.angleOffsetFromTriggerEvent;
|
return position.angleOffsetFromTriggerEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AngleBasedEventNew::setAngle(angle_t angle) {
|
||||||
|
this->enginePhase = angle;
|
||||||
|
}
|
||||||
|
|
||||||
bool AngleBasedEventNew::shouldSchedule(uint32_t /*trgEventIndex*/, float currentPhase, float nextPhase) const {
|
bool AngleBasedEventNew::shouldSchedule(uint32_t /*trgEventIndex*/, float currentPhase, float nextPhase) const {
|
||||||
|
return shouldSchedule(currentPhase, nextPhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AngleBasedEventNew::shouldSchedule(float currentPhase, float nextPhase) const {
|
||||||
return isPhaseInRange(this->enginePhase, currentPhase, nextPhase);
|
return isPhaseInRange(this->enginePhase, currentPhase, nextPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TRIGGER_EVENT_UNDEFINED INT32_MAX
|
|
||||||
|
|
||||||
class TriggerScheduler : public EngineModule {
|
class TriggerScheduler : public EngineModule {
|
||||||
public:
|
public:
|
||||||
bool scheduleOrQueue(AngleBasedEventOld *event,
|
void schedule(AngleBasedEventBase* event, angle_t angle, action_s action);
|
||||||
uint32_t trgEventIndex,
|
|
||||||
efitick_t edgeTimestamp,
|
|
||||||
angle_t angle,
|
|
||||||
action_s action);
|
|
||||||
|
|
||||||
bool scheduleOrQueue(AngleBasedEventNew *event,
|
bool scheduleOrQueue(AngleBasedEventNew *event,
|
||||||
uint32_t trgEventIndex,
|
|
||||||
efitick_t edgeTimestamp,
|
efitick_t edgeTimestamp,
|
||||||
angle_t angle,
|
angle_t angle,
|
||||||
action_s action,
|
action_s action,
|
||||||
|
@ -26,6 +19,8 @@ public:
|
||||||
AngleBasedEventBase * getElementAtIndexForUnitTest(int index);
|
AngleBasedEventBase * getElementAtIndexForUnitTest(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void schedule(AngleBasedEventBase* event, action_s action);
|
||||||
|
|
||||||
bool assertNotInList(AngleBasedEventBase *head, AngleBasedEventBase *element);
|
bool assertNotInList(AngleBasedEventBase *head, AngleBasedEventBase *element);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue