45 #define _MAX_IDLE_TASKS 4
47 #define _SCHD_PRIO_SLOTS 8
48 #define _SCHD_PRIO_MASK ( ( 1 << _SCHD_PRIO_SLOTS ) - 1 )
49 #define _SCHD_NORM_SLOTS 8
50 #define _SCHD_NORM_MASK ( ( ( 1 << _SCHD_PRIO_SLOTS ) - 1 ) << _SCHD_PRIO_SLOTS )
52 #define _SCHD_TOTAL_SLOTS ( _SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS )
55 #define _SCHD_F_ENABLED 0x01
56 #define _SCHD_F_ONETIME 0x02
60 static uint32_t _schdReq;
62 static uint32_t _schdTimeOut;
63 static bool _schdTimerRun =
false;
71 #ifdef SCHD_TRACE_LOAD
78 static SchdEntry _schdEntries[_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS];
80 #ifdef SCHD_TRACE_LOAD
81 static SchdEntry _idleTaskEntry = { .name =
"IdleTask" };
84 static int _schdNormCnt;
85 static int _schdPrioCnt;
88 static int _idleTaskCount = 0;
89 static SchdTaskF _idleTasks[_MAX_IDLE_TASKS];
94 #ifndef SCHD_TRACE_LOAD
97 bool _schdRegister(
SchdTaskF task,
bool priority,
int * taskId,
const char * fName)
103 if (_schdPrioCnt < _SCHD_PRIO_SLOTS)
113 if (_schdNormCnt < _SCHD_NORM_SLOTS)
115 id = _schdNormCnt + _SCHD_PRIO_SLOTS;
123 _schdEntries[id].func = task;
124 _schdEntries[id].flags = _SCHD_F_ENABLED;
125 _schdEntries[id].interval = 0;
126 #ifdef SCHD_TRACE_LOAD
127 _schdEntries[id].name = fName;
128 _schdEntries[id].count = 0;
129 _schdEntries[id].time = 0;
137 if (_idleTaskCount == _MAX_IDLE_TASKS)
return false;
138 if (idleTask == NULL)
return false;
140 _idleTasks[_idleTaskCount++] = idleTask;
144 static bool schdCheckTaskId(
int taskId) {
145 if (taskId < 0 )
return false;
147 if (taskId < _SCHD_PRIO_SLOTS)
149 return taskId < _schdPrioCnt;
153 return taskId < _schdNormCnt + _SCHD_PRIO_SLOTS;
158 static void schdTimeOutCheck()
161 if (!_schdTimerRun)
return;
163 if (!
timeOut(_schdTimeOut))
return;
167 for (i = 0; i < _SCHD_TOTAL_SLOTS; ++i)
169 if (_schdEntries[i].interval > 0 && (_schdEntries[i].flags & _SCHD_F_ENABLED))
171 if (
timeOut(_schdEntries[i].next))
174 if (_schdEntries[i].flags & _SCHD_F_ONETIME) {
175 _schdEntries[i].interval = 0;
177 _schdEntries[i].next += _schdEntries[i].interval;
180 if (first ||
CLT(_schdEntries[i].next, _schdTimeOut, 32)) {
181 _schdTimeOut = _schdEntries[i].next;
187 _schdTimerRun =
false;
191 static void schdTimerInit(
int taskId) {
192 _schdEntries[taskId].next =
timeOutInit(_schdEntries[taskId].interval);
193 if (!_schdTimerRun ||
CLT(_schdEntries[taskId].next, _schdTimeOut, 32))
195 _schdTimerRun =
true;
196 _schdTimeOut = _schdEntries[taskId].next;
205 assert (schdCheckTaskId(taskId));
207 _schdEntries[taskId].interval = delay;
208 _schdEntries[taskId].flags |= _SCHD_F_ONETIME;
209 schdTimerInit(taskId);
214 assert( interval > 0 );
216 assert (schdCheckTaskId(taskId));
218 _schdEntries[taskId].interval = interval;
219 _schdEntries[taskId].flags &= ~_SCHD_F_ONETIME;
220 schdTimerInit(taskId);
225 assert (schdCheckTaskId(taskId));
227 _schdEntries[taskId].interval = 0;
229 _schdEntries[taskId].flags &= ~_SCHD_F_ONETIME;
236 assert (schdCheckTaskId(taskId));
237 if (_schdEntries[taskId].flags & _SCHD_F_ENABLED) _schdReq |= 1 << taskId;
244 if (!schdCheckTaskId(taskId))
return;
245 if (_schdEntries[taskId].flags & _SCHD_F_ENABLED) _schdReq |= 1 << taskId;
250 assert (schdCheckTaskId(taskId));
253 _schdEntries[taskId].flags |= _SCHD_F_ENABLED;
254 if (_schdEntries[taskId].interval > 0) schdTimerInit(taskId);
256 _schdEntries[taskId].flags &= ~_SCHD_F_ENABLED;
263 return _schdReq != 0;
271 int normPrioId = _SCHD_PRIO_SLOTS;
275 int hPrC = 0, lPrC = 0;
280 if ((_schdReq & _SCHD_PRIO_MASK) && hPrC < MAX_PRIO)
283 if (_schdReq & (1 << highPrioId)) {
285 _schdReq &= ~(1 << highPrioId);
288 _schdEntries[highPrioId].func();
289 #ifndef SCHD_TRACE_LOAD
293 _schdEntries[highPrioId].count++;
297 highPrioId = ( highPrioId + 1 ) % _schdPrioCnt;
298 }
else if ((_schdReq & _SCHD_NORM_MASK) && lPrC < MAX_PRIO)
302 if (_schdReq & (1 << normPrioId)) {
304 _schdReq &= ~(1 << normPrioId);
307 _schdEntries[normPrioId].func();
308 #ifndef SCHD_TRACE_LOAD
312 _schdEntries[normPrioId].count++;
315 normPrioId = ( ( normPrioId + 1 - _SCHD_PRIO_SLOTS ) % _schdNormCnt )
317 }
else if (_idleTaskCount != 0)
321 for (
int i = 0; i < _idleTaskCount; i++) {
324 #ifdef SCHD_TRACE_LOAD
326 _idleTaskEntry.count++;
336 #ifdef SCHD_TRACE_LOAD
338 static void schdDisplayTrace(
SchdEntry * e)
340 uint32_t avr = e->count > 0 ? (e->time * 1000) / e->count : 0;
343 printf(
"%22s %10lu %10lu %8lu\n", (uint32_t)e->name, e->time, e->count, avr);
346 void schdShowTraces() {
348 puts(
"Name Tot [ms] Count Avr [us]");
349 puts(
"---------------------- ---------- ---------- --------");
351 for (
SchdEntry * e = &_schdEntries[0]; e < (&_schdEntries[_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS - 1]); ++e)
353 if (e->name != NULL) schdDisplayTrace(e);
355 schdDisplayTrace(&_idleTaskEntry);
359 static void schdResetTrace(
SchdEntry * e)
365 void schdResetTraces() {
366 for (
SchdEntry * e = _schdEntries; e < (_schdEntries + (_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS)); ++e)
370 schdResetTrace(&_idleTaskEntry);
#define CLT(A, B, BITS)
Cyclic comparison function Less Than.
int timerMark(int section)
Starts the timing of a new section, the previous section is returned, or -1 if it is the first...
void schdRunPeriodic(int taskId, int interval)
Schedule a task to run periodically.
static void __irqEnable()
Enabled IRQ's on a global level.
void schdRunForever()
Invoked in the main, starts the scheduler.
Low level routines for LM32, including interrupt handling.
bool schdRegister(SchdTaskF task, bool priority, int *taskId)
Register a task with the scheduler.
#define TIMER_SECT_IDLE
time spend being idle
static void __irqDisable()
Disables IRQ's on a global level.
Simple task scheduler for tasks.
bool schdTasksPending()
Checks if there are any tasks pending.
void(* SchdTaskF)()
Task function typedef.
void schdStop(int taskId)
Stop a scheduled task.
void schdRun(int taskId)
Run a task 'now'.
static uint32_t timeOutInit(uint32_t msec)
Initializes a timeout with the specified no of msecs.
void schdRunDelay(int taskId, int interval)
Schedule a task to run after a delay.
static bool timeOut(uint32_t to)
Checks whether or not the timeout has expired.
Manages the global system error.
void schdRunIRQ(int taskId)
Schedule a task from an IRQ.
bool schdAddIdleTask(SchdTaskF idleTask)
Adds an idle task, the task which is executed when there is nothing else to do.
#define E_OUTOFMEMORY
Generic error: There is no more memory.
This module is responsible for distributing error codes.
void timerInit()
Initializes the timer.
bool errSet(uint32_t code, const char *error, const char *name)
Sets an error.
#define ERROR(CODE,...)
Expands an error code to an error code with a description (if ERROR_W_DESCR is declared).
#define TIMER_SECT_TASK
time spend executing a task
void schdSetEnable(int taskId, bool enabled)
Enable of disable a task.