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 f2cad9076c
commit af7e4f6fe5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 91 additions and 31 deletions

View File

@ -13,15 +13,36 @@
#include "fl_stack.h"
#include "trigger_structure.h"
class AngleBasedEvent {
public:
struct AngleBasedEventOld;
struct AngleBasedEventBase {
scheduling_s scheduling;
event_trigger_position_s position;
action_s action;
/**
* 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
@ -31,7 +52,7 @@ public:
IgnitionEvent();
IgnitionOutputPin *outputs[MAX_OUTPUTS_FOR_IGNITION];
scheduling_s dwellStartTimer;
AngleBasedEvent sparkEvent;
AngleBasedEventOld sparkEvent;
scheduling_s trailingSparkCharge;
scheduling_s trailingSparkFire;
@ -79,8 +100,8 @@ public:
int valveIndex;
angle_t extra;
AngleBasedEvent open;
AngleBasedEvent close;
AngleBasedEventOld open;
AngleBasedEventOld close;
};

View File

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

View File

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

View File

@ -2,9 +2,8 @@
#include "event_queue.h"
bool TriggerScheduler::assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element) {
assertNotInListMethodBody(AngleBasedEvent, head, element, nextToothEvent)
bool TriggerScheduler::assertNotInList(AngleBasedEventBase *head, AngleBasedEventBase *element) {
assertNotInListMethodBody(AngleBasedEventBase, 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
* 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,
efitick_t edgeTimestamp,
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,
uint32_t trgEventIndex,
efitick_t edgeTimestamp) {
efitick_t edgeTimestamp, float currentPhase, float nextPhase) {
if (!isValidRpm(rpm)) {
// this might happen for instance in case of a single trigger event after a pause
return;
}
AngleBasedEvent *current, *tmp, *keephead;
AngleBasedEvent *keeptail = nullptr;
AngleBasedEventBase *current, *tmp, *keephead;
AngleBasedEventBase *keeptail = nullptr;
{
chibios_rt::CriticalSectionLocker csl;
@ -94,7 +106,7 @@ void TriggerScheduler::scheduleEventsUntilNextTriggerTooth(int rpm,
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
// 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(
sDown,
edgeTimestamp,
current->position.angleOffsetFromTriggerEvent,
current->getAngleFromNow(currentPhase),
current->action
);
} 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
// todo: reduce code duplication with another 'getElementAtIndexForUnitText'
AngleBasedEvent * TriggerScheduler::getElementAtIndexForUnitTest(int index) {
AngleBasedEvent * current;
AngleBasedEventBase * TriggerScheduler::getElementAtIndexForUnitTest(int index) {
AngleBasedEventBase * current;
LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent)
{

View File

@ -4,7 +4,13 @@
class TriggerScheduler : public EngineModule {
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,
efitick_t edgeTimestamp,
angle_t angle,
@ -12,13 +18,14 @@ public:
void scheduleEventsUntilNextTriggerTooth(int rpm,
uint32_t trgEventIndex,
efitick_t edgeTimestamp);
efitick_t edgeTimestamp,
float currentPhase, float nextPhase);
// For unit tests
AngleBasedEvent * getElementAtIndexForUnitTest(int index);
AngleBasedEventBase * getElementAtIndexForUnitTest(int index);
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
@ -26,5 +33,5 @@ private:
* 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;
AngleBasedEventBase *m_angleBasedEventsHead = nullptr;
};

View File

@ -308,13 +308,15 @@ scheduling_s * EngineTestHelper::assertEvent5(const char *msg, int index, void *
return event;
}
AngleBasedEvent * EngineTestHelper::assertTriggerEvent(const char *msg,
int index, AngleBasedEvent *expected,
AngleBasedEventBase * EngineTestHelper::assertTriggerEvent(const char *msg,
int index, AngleBasedEventBase *expected,
void *callback,
int triggerEventIndex, angle_t angleOffsetFromTriggerEvent) {
AngleBasedEvent * event =
AngleBasedEventBase * event2 =
engine.module<TriggerScheduler>()->getElementAtIndexForUnitTest(index);
auto event = event2->asOld();
assertEqualsM4(msg, " callback up/down", (void*)event->action.getCallback() == (void*) callback, 1);
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 * 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 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.
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
HpfpController::pinTurnOff(&hpfp);
@ -287,7 +287,7 @@ TEST(HPFP, Schedule) {
// Make it happen
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
// struct.