rusEFI
The most advanced open source ECU
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 (int 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

Definition at line 5 of file trigger_scheduler.cpp.

5  {
6  assertNotInListMethodBody(head, element, nextToothEvent)
7 }

Referenced by schedule().

Here is the caller graph for this function:

◆ getElementAtIndexForUnitTest()

AngleBasedEvent * TriggerScheduler::getElementAtIndexForUnitTest ( int  index)

Definition at line 149 of file trigger_scheduler.cpp.

149  {
150  AngleBasedEvent * current;
151 
152  LL_FOREACH2(m_angleBasedEventsHead, current, nextToothEvent)
153  {
154  if (index == 0)
155  return current;
156  index--;
157  }
158  criticalError("getElementAtIndexForUnitText: null");
159  return nullptr;
160 }
AngleBasedEvent * m_angleBasedEventsHead

◆ schedule() [1/2]

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

Definition at line 47 of file trigger_scheduler.cpp.

47  {
48  if (event->getAngle() < 0) {
49  // at the moment we expect API consumer to wrap angle. shall we do the wrapping in the enginePhase setter?
50  // i.e. what is the best level to take care of the range constraint?
51  criticalError("Negative angle %s %f", msg, event->getAngle());
52  }
53 
54  event->action = action;
55 
56  {
57  chibios_rt::CriticalSectionLocker csl;
58 
59  // TODO: This is O(n), consider some other way of detecting if in a list,
60  // and consider doubly linked or other list tricks.
61 
63  // Use Append to retain some semblance of event ordering in case of
64  // time skew. Thus on events are always followed by off events.
65  LL_APPEND2(m_angleBasedEventsHead, event, nextToothEvent);
66  }
67  }
68 }
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 9 of file trigger_scheduler.cpp.

9  {
10  event->setAngle(angle);
11 
12  schedule(msg, event, action);
13 }
void schedule(const char *msg, AngleBasedEvent *event, angle_t angle, action_s action)

Referenced by scheduleOrQueue().

Here is the caller graph for this function:

◆ scheduleEventsUntilNextTriggerTooth()

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

Definition at line 70 of file trigger_scheduler.cpp.

71  {
72 
73  if (!isValidRpm(rpm)) {
74  // this might happen for instance in case of a single trigger event after a pause
75  return;
76  }
77 
78  AngleBasedEvent *current, *tmp, *keephead;
79  AngleBasedEvent *keeptail = nullptr;
80 
81  {
82  chibios_rt::CriticalSectionLocker csl;
83 
84  keephead = m_angleBasedEventsHead;
85  m_angleBasedEventsHead = nullptr;
86  }
87 
88  LL_FOREACH_SAFE2(keephead, current, tmp, nextToothEvent)
89  {
90  if (current->shouldSchedule(currentPhase, nextPhase)) {
91  // time to fire a spark which was scheduled previously
92 
93  // Yes this looks like O(n^2), but that's only over the entire engine
94  // cycle. It's really O(mn + nn) where m = # of teeth and n = # events
95  // fired per cycle. The number of teeth outweigh the number of events, at
96  // least for 60-2.... So odds are we're only firing an event or two per
97  // tooth, which means the outer loop is really only O(n). And if we are
98  // firing many events per teeth, then it's likely the events before this
99  // one also fired and thus the call to LL_DELETE2 is closer to O(1).
100  LL_DELETE2(keephead, current, nextToothEvent);
101 
102  scheduling_s * sDown = &current->eventScheduling;
103 
104 #if SPARK_EXTREME_LOGGING
105  efiPrintf("time to invoke [%.1f, %.1f) %d %d",
106  currentPhase, nextPhase, getRevolutionCounter(), time2print(getTimeNowUs()));
107 #endif /* SPARK_EXTREME_LOGGING */
108 
109  // In case this event was scheduled by overdwell protection, cancel it so
110  // we can re-schedule at the correct time
111  // [tag:overdwell]
112  engine->executor.cancel(sDown);
113 
115  sDown,
116  edgeTimestamp,
117  current->getAngleFromNow(currentPhase),
118  current->action
119  );
120  } else {
121  keeptail = current; // Used for fast list concatenation
122  }
123  }
124 
125  if (keephead) {
126  chibios_rt::CriticalSectionLocker csl;
127 
128  // Put any new entries onto the end of the keep list
130  m_angleBasedEventsHead = keephead;
131  }
132 }
SingleTimerExecutor executor
Definition: engine.h:241
void cancel(scheduling_s *scheduling) override
efitimeus_t getTimeNowUs()
Definition: efitime.cpp:26
int time2print(int64_t time)
Definition: efitime.h:25
Engine * engine
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 21 of file trigger_scheduler.cpp.

25  {
26  event->setAngle(angle);
27 
28  // *kludge* naming mess: if (shouldSchedule) { scheduleByAngle } else { schedule } see header for more details
29  if (event->shouldSchedule(currentPhase, nextPhase)) {
30  // if we're due now, just schedule the event
32  &event->eventScheduling,
33  edgeTimestamp,
34  event->getAngleFromNow(currentPhase),
35  action
36  );
37 
38  return true;
39  } else {
40  // If not due now, add it to the queue to be scheduled later
41  schedule(msg, event, action);
42 
43  return false;
44  }
45 }
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: