two modes trigger scheduler (#4598)

* two modes trigger scheduler

* asOld

* hpfp
This commit is contained in:
Matthew Kennedy 2022-09-20 02:28:23 -07:00 committed by GitHub
parent d5dd3f5df4
commit 4e78c4c922
8 changed files with 91 additions and 31 deletions

View File

@ -13,15 +13,36 @@
#include "fl_stack.h" #include "fl_stack.h"
#include "trigger_structure.h" #include "trigger_structure.h"
class AngleBasedEvent { struct AngleBasedEventOld;
public:
struct AngleBasedEventBase {
scheduling_s scheduling; scheduling_s scheduling;
event_trigger_position_s position;
action_s action; action_s action;
/** /**
* Trigger-based scheduler maintains a linked list of all pending tooth-based events. * Trigger-based scheduler maintains a linked list of all pending tooth-based events.
*/ */
AngleBasedEvent *nextToothEvent = nullptr; AngleBasedEventBase *nextToothEvent = nullptr;
virtual bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const = 0;
virtual float getAngleFromNow(float currentPhase) const = 0;
virtual AngleBasedEventOld* asOld() { return nullptr; }
};
struct AngleBasedEventOld : public AngleBasedEventBase {
event_trigger_position_s position;
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
float getAngleFromNow(float currentPhase) const override;
AngleBasedEventOld* asOld() override { return this; }
};
struct AngleBasedEventNew : public AngleBasedEventBase {
float enginePhase;
bool shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const override;
float getAngleFromNow(float currentPhase) const override;
}; };
#define MAX_OUTPUTS_FOR_IGNITION 2 #define MAX_OUTPUTS_FOR_IGNITION 2
@ -31,7 +52,7 @@ public:
IgnitionEvent(); IgnitionEvent();
IgnitionOutputPin *outputs[MAX_OUTPUTS_FOR_IGNITION]; IgnitionOutputPin *outputs[MAX_OUTPUTS_FOR_IGNITION];
scheduling_s dwellStartTimer; scheduling_s dwellStartTimer;
AngleBasedEvent sparkEvent; AngleBasedEventOld sparkEvent;
scheduling_s trailingSparkCharge; scheduling_s trailingSparkCharge;
scheduling_s trailingSparkFire; scheduling_s trailingSparkFire;
@ -79,8 +100,8 @@ public:
int valveIndex; int valveIndex;
angle_t extra; angle_t extra;
AngleBasedEvent open; AngleBasedEventOld open;
AngleBasedEvent close; AngleBasedEventOld close;
}; };

View File

@ -84,7 +84,7 @@ public:
#if !EFI_UNIT_TEST #if !EFI_UNIT_TEST
private: private:
#endif // EFI_UNIT_TEST #endif // EFI_UNIT_TEST
AngleBasedEvent m_event; AngleBasedEventOld m_event;
HpfpQuantity m_quantity; HpfpQuantity m_quantity;
HpfpLobe m_lobe; HpfpLobe m_lobe;

View File

@ -304,7 +304,7 @@ void mainTriggerCallback(uint32_t trgEventIndex, efitick_t edgeTimestamp, angle_
handleFuel(trgEventIndex, rpm, edgeTimestamp, currentPhase, nextPhase); handleFuel(trgEventIndex, rpm, edgeTimestamp, currentPhase, nextPhase);
engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth( engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth(
rpm, trgEventIndex, edgeTimestamp); rpm, trgEventIndex, edgeTimestamp, currentPhase, nextPhase);
/** /**
* 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

View File

@ -2,9 +2,8 @@
#include "event_queue.h" #include "event_queue.h"
bool TriggerScheduler::assertNotInList(AngleBasedEventBase *head, AngleBasedEventBase *element) {
bool TriggerScheduler::assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element) { assertNotInListMethodBody(AngleBasedEventBase, head, element, nextToothEvent)
assertNotInListMethodBody(AngleBasedEvent, head, element, nextToothEvent)
} }
/** /**
@ -17,7 +16,7 @@ bool TriggerScheduler::assertNotInList(AngleBasedEvent *head, AngleBasedEvent *e
* @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(AngleBasedEvent *event, bool TriggerScheduler::scheduleOrQueue(AngleBasedEventOld *event,
uint32_t trgEventIndex, uint32_t trgEventIndex,
efitick_t edgeTimestamp, efitick_t edgeTimestamp,
angle_t angle, angle_t angle,
@ -73,17 +72,30 @@ bool TriggerScheduler::scheduleOrQueue(AngleBasedEvent *event,
} }
} }
bool TriggerScheduler::scheduleOrQueue(AngleBasedEventNew *event,
uint32_t trgEventIndex,
efitick_t edgeTimestamp,
angle_t angle,
action_s action) {
event->enginePhase = angle;
event->action = action;
// TODO: implement me!
return false;
}
void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm, void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
uint32_t trgEventIndex, uint32_t trgEventIndex,
efitick_t edgeTimestamp) { efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
if (!isValidRpm(rpm)) { if (!isValidRpm(rpm)) {
// this might happen for instance in case of a single trigger event after a pause // this might happen for instance in case of a single trigger event after a pause
return; return;
} }
AngleBasedEvent *current, *tmp, *keephead; AngleBasedEventBase *current, *tmp, *keephead;
AngleBasedEvent *keeptail = nullptr; AngleBasedEventBase *keeptail = nullptr;
{ {
chibios_rt::CriticalSectionLocker csl; chibios_rt::CriticalSectionLocker csl;
@ -94,7 +106,7 @@ void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent) LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent)
{ {
if (current->position.triggerEventIndex == trgEventIndex) { if (current->shouldSchedule(trgEventIndex, currentPhase, nextPhase)) {
// time to fire a spark which was scheduled previously // time to fire a spark which was scheduled previously
// Yes this looks like O(n^2), but that's only over the entire engine // Yes this looks like O(n^2), but that's only over the entire engine
@ -120,7 +132,7 @@ void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
scheduleByAngle( scheduleByAngle(
sDown, sDown,
edgeTimestamp, edgeTimestamp,
current->position.angleOffsetFromTriggerEvent, current->getAngleFromNow(currentPhase),
current->action current->action
); );
} else { } else {
@ -137,10 +149,28 @@ void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
} }
} }
bool AngleBasedEventOld::shouldSchedule(uint32_t trgEventIndex, float /*currentPhase*/, float /*nextPhase*/) const {
return position.triggerEventIndex == trgEventIndex;
}
float AngleBasedEventOld::getAngleFromNow(float /*currentPhase*/) const {
return position.angleOffsetFromTriggerEvent;
}
bool AngleBasedEventNew::shouldSchedule(uint32_t trgEventIndex, float currentPhase, float nextPhase) const {
// TODO: implement me!
return true;
}
float AngleBasedEventNew::getAngleFromNow(float currentPhase) const {
// TODO: implement me!
return 0;
}
#if EFI_UNIT_TEST #if EFI_UNIT_TEST
// todo: reduce code duplication with another 'getElementAtIndexForUnitText' // todo: reduce code duplication with another 'getElementAtIndexForUnitText'
AngleBasedEvent * TriggerScheduler::getElementAtIndexForUnitTest(int index) { AngleBasedEventBase * TriggerScheduler::getElementAtIndexForUnitTest(int index) {
AngleBasedEvent * current; AngleBasedEventBase * current;
LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent) LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent)
{ {

View File

@ -4,7 +4,13 @@
class TriggerScheduler : public EngineModule { class TriggerScheduler : public EngineModule {
public: public:
bool scheduleOrQueue(AngleBasedEvent *event, bool scheduleOrQueue(AngleBasedEventOld *event,
uint32_t trgEventIndex,
efitick_t edgeTimestamp,
angle_t angle,
action_s action);
bool scheduleOrQueue(AngleBasedEventNew *event,
uint32_t trgEventIndex, uint32_t trgEventIndex,
efitick_t edgeTimestamp, efitick_t edgeTimestamp,
angle_t angle, angle_t angle,
@ -12,13 +18,14 @@ public:
void scheduleEventsUntilNextTriggerTooth(int rpm, void scheduleEventsUntilNextTriggerTooth(int rpm,
uint32_t trgEventIndex, uint32_t trgEventIndex,
efitick_t edgeTimestamp); efitick_t edgeTimestamp,
float currentPhase, float nextPhase);
// For unit tests // For unit tests
AngleBasedEvent * getElementAtIndexForUnitTest(int index); AngleBasedEventBase * getElementAtIndexForUnitTest(int index);
private: private:
bool assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element); bool assertNotInList(AngleBasedEventBase *head, AngleBasedEventBase *element);
/** /**
* That's the linked list of pending events scheduled in relation to trigger * That's the linked list of pending events scheduled in relation to trigger
@ -26,5 +33,5 @@ private:
* trigger index We can make it an array of lists per trigger index, but that would take * trigger index We can make it an array of lists per trigger index, but that would take
* some RAM and probably not needed yet. * some RAM and probably not needed yet.
*/ */
AngleBasedEvent *m_angleBasedEventsHead = nullptr; AngleBasedEventBase *m_angleBasedEventsHead = nullptr;
}; };

View File

@ -308,13 +308,15 @@ scheduling_s * EngineTestHelper::assertEvent5(const char *msg, int index, void *
return event; return event;
} }
AngleBasedEvent * EngineTestHelper::assertTriggerEvent(const char *msg, AngleBasedEventBase * EngineTestHelper::assertTriggerEvent(const char *msg,
int index, AngleBasedEvent *expected, int index, AngleBasedEventBase *expected,
void *callback, void *callback,
int triggerEventIndex, angle_t angleOffsetFromTriggerEvent) { int triggerEventIndex, angle_t angleOffsetFromTriggerEvent) {
AngleBasedEvent * event = AngleBasedEventBase * event2 =
engine.module<TriggerScheduler>()->getElementAtIndexForUnitTest(index); engine.module<TriggerScheduler>()->getElementAtIndexForUnitTest(index);
auto event = event2->asOld();
assertEqualsM4(msg, " callback up/down", (void*)event->action.getCallback() == (void*) callback, 1); assertEqualsM4(msg, " callback up/down", (void*)event->action.getCallback() == (void*) callback, 1);
assertEqualsM4(msg, " trigger", triggerEventIndex, event->position.triggerEventIndex); assertEqualsM4(msg, " trigger", triggerEventIndex, event->position.triggerEventIndex);

View File

@ -84,7 +84,7 @@ public:
scheduling_s * assertEvent5(const char *msg, int index, void *callback, efitimeus_t expectedTimestamp); scheduling_s * assertEvent5(const char *msg, int index, void *callback, efitimeus_t expectedTimestamp);
scheduling_s * assertScheduling(const char *msg, int index, scheduling_s *expected, void *callback, efitimeus_t expectedTimestamp); scheduling_s * assertScheduling(const char *msg, int index, scheduling_s *expected, void *callback, efitimeus_t expectedTimestamp);
AngleBasedEvent * assertTriggerEvent(const char *msg, int index, AngleBasedEvent *expected, void *callback, int triggerEventIndex, angle_t angleOffsetFromTriggerEvent); AngleBasedEventBase * assertTriggerEvent(const char *msg, int index, AngleBasedEventBase *expected, void *callback, int triggerEventIndex, angle_t angleOffsetFromTriggerEvent);
void assertEvent(const char *msg, int index, void *callback, efitimeus_t momentX, InjectionEvent *event); void assertEvent(const char *msg, int index, void *callback, efitimeus_t momentX, InjectionEvent *event);
void assertInjectorUpEvent(const char *msg, int eventIndex, efitimeus_t momentX, long injectorIndex); void assertInjectorUpEvent(const char *msg, int eventIndex, efitimeus_t momentX, long injectorIndex);

View File

@ -277,7 +277,7 @@ TEST(HPFP, Schedule) {
// Make the previous event happen, schedule the next. // Make the previous event happen, schedule the next.
engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth( engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth(
1000, 1, tick_per_deg * 0); 1000, 1, tick_per_deg * 0, 0, 0);
// Mock executor doesn't run events, so we run it manually // Mock executor doesn't run events, so we run it manually
HpfpController::pinTurnOff(&hpfp); HpfpController::pinTurnOff(&hpfp);
@ -287,7 +287,7 @@ TEST(HPFP, Schedule) {
// Make it happen // Make it happen
engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth( engine->module<TriggerScheduler>()->scheduleEventsUntilNextTriggerTooth(
1000, 2, tick_per_deg * 180); 1000, 2, tick_per_deg * 180, 0, 0);
// Since we have a mock scheduler, lets insert the correct timestamp in the scheduling // Since we have a mock scheduler, lets insert the correct timestamp in the scheduling
// struct. // struct.