rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes
TriggerScheduler Class Reference

#include <trigger_scheduler.h>

Inheritance diagram for TriggerScheduler:
Inheritance graph
[legend]
Collaboration diagram for TriggerScheduler:
Collaboration graph
[legend]

Public Member Functions

void schedule (const char *msg, AngleBasedEvent *event, angle_t angle, action_s action)
 
bool scheduleOrQueue (const char *msg, AngleBasedEvent *event, efitick_t edgeTimestamp, angle_t angle, action_s action, float currentPhase, float nextPhase)
 
void scheduleEventsUntilNextTriggerTooth (float rpm, efitick_t edgeTimestamp, float currentPhase, float nextPhase)
 
AngleBasedEventgetElementAtIndexForUnitTest (int index)
 
- Public Member Functions inherited from EngineModule
virtual void onConfigurationChange (engine_configuration_s const *)
 
virtual void onSlowCallback ()
 
virtual void onFastCallback ()
 
virtual void onIgnitionStateChanged (bool)
 
virtual bool needsDelayedShutoff ()
 

Private Member Functions

void schedule (const char *msg, AngleBasedEvent *event, action_s action)
 
bool assertNotInList (AngleBasedEvent *head, AngleBasedEvent *element)
 

Private Attributes

AngleBasedEventm_angleBasedEventsHead = nullptr
 

Detailed Description

Definition at line 5 of file trigger_scheduler.h.

Member Function Documentation

◆ assertNotInList()

bool TriggerScheduler::assertNotInList ( AngleBasedEvent head,
AngleBasedEvent element 
)
private

for example, this might happen in case of sudden RPM change if event was not scheduled by angle but was scheduled by time. In case of scheduling by time with slow RPM the whole next fast revolution might be within the wait

Definition at line 5 of file trigger_scheduler.cpp.

5 {
6 /* this code is just to validate state, no functional load*/
7 decltype(head) current;
8 int counter = 0;
9 LL_FOREACH2(head, current, nextToothEvent) {
10 if (++counter > QUEUE_LENGTH_LIMIT) {
12 return false;
13 }
14
15 if (current == element) {
16 /**
17 * for example, this might happen in case of sudden RPM change if event
18 * was not scheduled by angle but was scheduled by time. In case of scheduling
19 * by time with slow RPM the whole next fast revolution might be within the wait
20 */
21 warning(ObdCode::CUSTOM_RE_ADDING_INTO_EXECUTION_QUEUE, "re-adding element into event_queue");
22 return true;
23 }
24 }
25
26 return false;
27}
bool warning(ObdCode code, const char *fmt,...)
void firmwareError(ObdCode code, const char *fmt,...)
@ CUSTOM_RE_ADDING_INTO_EXECUTION_QUEUE
@ CUSTOM_ERR_LOOPED_QUEUE

Referenced by schedule().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getElementAtIndexForUnitTest()

AngleBasedEvent * TriggerScheduler::getElementAtIndexForUnitTest ( int  index)

Definition at line 169 of file trigger_scheduler.cpp.

169 {
170 AngleBasedEvent * current;
171
172 LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent)
173 {
174 if (index == 0)
175 return current;
176 index--;
177 }
178 criticalError("getElementAtIndexForUnitText: null");
179 return nullptr;
180}
AngleBasedEvent * m_angleBasedEventsHead

◆ schedule() [1/2]

void TriggerScheduler::schedule ( const char msg,
AngleBasedEvent event,
action_s  action 
)
private

Definition at line 67 of file trigger_scheduler.cpp.

67 {
68 if (event->getAngle() < 0) {
69 // at the moment we expect API consumer to wrap angle. shall we do the wrapping in the enginePhase setter?
70 // i.e. what is the best level to take care of the range constraint?
71 criticalError("Negative angle %s %f", msg, event->getAngle());
72 }
73
74 event->action = action;
75
76 {
77 chibios_rt::CriticalSectionLocker csl;
78
79 // TODO: This is O(n), consider some other way of detecting if in a list,
80 // and consider doubly linked or other list tricks.
81
83 // Use Append to retain some semblance of event ordering in case of
84 // time skew. Thus on events are always followed by off events.
85 LL_APPEND2(m_angleBasedEventsHead, event, nextToothEvent);
86 }
87 }
88}
bool assertNotInList(AngleBasedEvent *head, AngleBasedEvent *element)
angle_t getAngle() const
Here is the call graph for this function:

◆ schedule() [2/2]

void TriggerScheduler::schedule ( const char msg,
AngleBasedEvent event,
angle_t  angle,
action_s  action 
)

Definition at line 29 of file trigger_scheduler.cpp.

29 {
30 event->setAngle(angle);
31
32 schedule(msg, event, action);
33}
void schedule(const char *msg, AngleBasedEvent *event, angle_t angle, action_s action)

Referenced by schedule(), and scheduleOrQueue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ scheduleEventsUntilNextTriggerTooth()

void TriggerScheduler::scheduleEventsUntilNextTriggerTooth ( float  rpm,
efitick_t  edgeTimestamp,
float  currentPhase,
float  nextPhase 
)

Definition at line 90 of file trigger_scheduler.cpp.

91 {
92
93 if (!isValidRpm(rpm)) {
94 // this might happen for instance in case of a single trigger event after a pause
95 return;
96 }
97
98 AngleBasedEvent *current, *tmp, *keephead;
99 AngleBasedEvent *keeptail = nullptr;
100
101 {
102 chibios_rt::CriticalSectionLocker csl;
103
104 keephead = m_angleBasedEventsHead;
105 m_angleBasedEventsHead = nullptr;
106 }
107
108 LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent)
109 {
110 if (current->shouldSchedule(currentPhase, nextPhase)) {
111 // time to fire a spark which was scheduled previously
112
113 // Yes this looks like O(n^2), but that's only over the entire engine
114 // cycle. It's really O(mn + nn) where m = # of teeth and n = # events
115 // fired per cycle. The number of teeth outweigh the number of events, at
116 // least for 60-2.... So odds are we're only firing an event or two per
117 // tooth, which means the outer loop is really only O(n). And if we are
118 // firing many events per teeth, then it's likely the events before this
119 // one also fired and thus the call to LL_DELETE2 is closer to O(1).
120 LL_DELETE2(keephead, current, nextToothEvent);
121
122 scheduling_s * sDown = &current->eventScheduling;
123
124#if SPARK_EXTREME_LOGGING
125 efiPrintf("time to invoke [%.1f, %.1f) %d %d",
126 currentPhase, nextPhase, getRevolutionCounter(), time2print(getTimeNowUs()));
127#endif /* SPARK_EXTREME_LOGGING */
128
129 // In case this event was scheduled by overdwell protection, cancel it so
130 // we can re-schedule at the correct time
131 // [tag:overdwell]
132 engine->scheduler.cancel(sDown);
133
135 sDown,
136 edgeTimestamp,
137 current->getAngleFromNow(currentPhase),
138 current->action
139 );
140 } else {
141 keeptail = current; // Used for fast list concatenation
142 }
143 }
144
145 if (keephead) {
146 chibios_rt::CriticalSectionLocker csl;
147
148 // Put any new entries onto the end of the keep list
150 m_angleBasedEventsHead = keephead;
151 }
152}
SingleTimerExecutor scheduler
Definition engine.h:254
void cancel(scheduling_s *scheduling) override
Cancel the specified scheduling_s so that, if currently scheduled, it does not execute.
efitimeus_t getTimeNowUs()
Definition efitime.cpp:26
int time2print(int64_t time)
Definition efitime.h:25
static Engine *const engine
Definition engine.h:386
efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s action)
bool shouldSchedule(float currentPhase, float nextPhase) const
float getAngleFromNow(float currentPhase) const
AngleBasedEvent * nextToothEvent
scheduling_s eventScheduling
Here is the call graph for this function:

◆ scheduleOrQueue()

bool TriggerScheduler::scheduleOrQueue ( const char msg,
AngleBasedEvent event,
efitick_t  edgeTimestamp,
angle_t  angle,
action_s  action,
float  currentPhase,
float  nextPhase 
)

Schedules 'action' to occur at engine cycle angle 'angle'.

Returns
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

Definition at line 41 of file trigger_scheduler.cpp.

45 {
46 event->setAngle(angle);
47
48 // *kludge* naming mess: if (shouldSchedule) { scheduleByAngle } else { schedule } see header for more details
49 if (event->shouldSchedule(currentPhase, nextPhase)) {
50 // if we're due now, just schedule the event
52 &event->eventScheduling,
53 edgeTimestamp,
54 event->getAngleFromNow(currentPhase),
55 action
56 );
57
58 return true;
59 } else {
60 // If not due now, add it to the queue to be scheduled later
61 schedule(msg, event, action);
62
63 return false;
64 }
65}
Here is the call graph for this function:

Field Documentation

◆ m_angleBasedEventsHead

AngleBasedEvent* TriggerScheduler::m_angleBasedEventsHead = nullptr
private

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.

Definition at line 38 of file trigger_scheduler.h.

Referenced by getElementAtIndexForUnitTest(), schedule(), and scheduleEventsUntilNextTriggerTooth().


The documentation for this class was generated from the following files: