KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
scheduler.c
1 /*
2  * KM3NeT CLB v2 Firmware
3  * ----------------------
4  *
5  * Copyright 2013 KM3NeT Collaboration
6  *
7  * All Rights Reserved.
8  *
9  *
10  * File : scheduler.c
11  * Created : 10 apr. 2013
12  * Author : Vincent van Beveren
13  */
14 
15 #ifdef __MINGW32__
16 #include "windows.h"
17 #undef ERROR
18 #undef E_OUTOFMEMORY
19 #endif
20 
21 
22 
23 
24 #include "kernel/scheduler.h"
25 
26 #include <stdint.h>
27 #include <assert.h>
28 #include <stdio.h>
29 
30 #include "errorcode.h"
31 
32 #ifdef __WIN32__
33 // #define __irqDisable()
34 // #define __irqEnable()
35 #else
36 #include "lm32soc/lm32.h"
37 #endif
38 
39 
40 #include "kernel/err.h"
41 #include "kernel/tm.h"
42 #include "kernel/timer.h"
43 
44 
45 #define _MAX_IDLE_TASKS 4
46 
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 )
51 
52 #define _SCHD_TOTAL_SLOTS ( _SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS )
53 
54 
55 #define _SCHD_F_ENABLED 0x01
56 #define _SCHD_F_ONETIME 0x02
57 
58 #define MAX_PRIO 40
59 
60 static uint32_t _schdReq;
61 
62 static uint32_t _schdTimeOut;
63 static bool _schdTimerRun = false;
64 
65 typedef struct
66 {
67  SchdTaskF func;
68  uint32_t flags;
69  uint32_t interval;
70  uint32_t next;
71 #ifdef SCHD_TRACE_LOAD
72  const char * name;
73  uint32_t time;
74  uint32_t count;
75 #endif
76 } SchdEntry;
77 
78 static SchdEntry _schdEntries[_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS];
79 
80 #ifdef SCHD_TRACE_LOAD
81 static SchdEntry _idleTaskEntry = { .name = "IdleTask" };
82 #endif
83 
84 static int _schdNormCnt;
85 static int _schdPrioCnt;
86 
87 
88 static int _idleTaskCount = 0;
89 static SchdTaskF _idleTasks[_MAX_IDLE_TASKS];
90 
91 
92 
93 
94 #ifndef SCHD_TRACE_LOAD
95 bool schdRegister(SchdTaskF task, bool priority, int * taskId)
96 #else
97 bool _schdRegister(SchdTaskF task, bool priority, int * taskId, const char * fName)
98 #endif
99 {
100  int id;
101  if (priority) {
102 
103  if (_schdPrioCnt < _SCHD_PRIO_SLOTS)
104  {
105  id = _schdPrioCnt;
106  _schdPrioCnt++;
107  }
108  else
109  {
110  return errSet(ERROR(E_OUTOFMEMORY));
111  }
112  } else {
113  if (_schdNormCnt < _SCHD_NORM_SLOTS)
114  {
115  id = _schdNormCnt + _SCHD_PRIO_SLOTS;
116  _schdNormCnt++;
117  }
118  else
119  {
120  return errSet(ERROR(E_OUTOFMEMORY));
121  }
122  }
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;
130 #endif
131  *taskId = id;
132  return true;
133 }
134 
136 {
137  if (_idleTaskCount == _MAX_IDLE_TASKS) return false;
138  if (idleTask == NULL) return false;
139 
140  _idleTasks[_idleTaskCount++] = idleTask;
141  return true;
142 }
143 
144 static bool schdCheckTaskId(int taskId) {
145  if (taskId < 0 ) return false;
146 
147  if (taskId < _SCHD_PRIO_SLOTS)
148  {
149  return taskId < _schdPrioCnt;
150  }
151  else
152  {
153  return taskId < _schdNormCnt + _SCHD_PRIO_SLOTS;
154  }
155 }
156 
157 
158 static void schdTimeOutCheck()
159 {
160  // nothing to run.
161  if (!_schdTimerRun) return;
162  // no time-out yet.
163  if (!timeOut(_schdTimeOut)) return;
164 
165  int i;
166  bool first = true;
167  for (i = 0; i < _SCHD_TOTAL_SLOTS; ++i)
168  {
169  if (_schdEntries[i].interval > 0 && (_schdEntries[i].flags & _SCHD_F_ENABLED))
170  {
171  if (timeOut(_schdEntries[i].next))
172  {
173  _schdReq |= 1 << i;
174  if (_schdEntries[i].flags & _SCHD_F_ONETIME) {
175  _schdEntries[i].interval = 0;
176  } else {
177  _schdEntries[i].next += _schdEntries[i].interval;
178  }
179  }
180  if (first || CLT(_schdEntries[i].next, _schdTimeOut, 32)) {
181  _schdTimeOut = _schdEntries[i].next;
182  first = false;
183  }
184  }
185  }
186  if (first) {
187  _schdTimerRun = false;
188  }
189 }
190 
191 static void schdTimerInit(int taskId) {
192  _schdEntries[taskId].next = timeOutInit(_schdEntries[taskId].interval);
193  if (!_schdTimerRun || CLT(_schdEntries[taskId].next, _schdTimeOut, 32))
194  {
195  _schdTimerRun = true;
196  _schdTimeOut = _schdEntries[taskId].next;
197  }
198 
199 }
200 
201 void schdRunDelay(int taskId, int delay)
202 {
203  assert( delay > 0 );
204 
205  assert (schdCheckTaskId(taskId));
206 
207  _schdEntries[taskId].interval = delay;
208  _schdEntries[taskId].flags |= _SCHD_F_ONETIME;
209  schdTimerInit(taskId);
210 }
211 
212 void schdRunPeriodic(int taskId, int interval)
213 {
214  assert( interval > 0 );
215 
216  assert (schdCheckTaskId(taskId));
217 
218  _schdEntries[taskId].interval = interval;
219  _schdEntries[taskId].flags &= ~_SCHD_F_ONETIME;
220  schdTimerInit(taskId);
221 }
222 
223 void schdStop(int taskId)
224 {
225  assert (schdCheckTaskId(taskId));
226  // clear interval
227  _schdEntries[taskId].interval = 0;
228  // disable ONETIME if set
229  _schdEntries[taskId].flags &= ~_SCHD_F_ONETIME;
230 
231 }
232 
233 void schdRun(int taskId)
234 {
235  __irqDisable();
236  assert (schdCheckTaskId(taskId));
237  if (_schdEntries[taskId].flags & _SCHD_F_ENABLED) _schdReq |= 1 << taskId;
238  __irqEnable();
239 }
240 
241 
242 void schdRunIRQ(int taskId)
243 {
244  if (!schdCheckTaskId(taskId)) return;
245  if (_schdEntries[taskId].flags & _SCHD_F_ENABLED) _schdReq |= 1 << taskId;
246 }
247 
248 void schdSetEnable(int taskId, bool enabled)
249 {
250  assert (schdCheckTaskId(taskId));
251  if (enabled)
252  {
253  _schdEntries[taskId].flags |= _SCHD_F_ENABLED;
254  if (_schdEntries[taskId].interval > 0) schdTimerInit(taskId);
255  } else {
256  _schdEntries[taskId].flags &= ~_SCHD_F_ENABLED;
257  }
258 }
259 
261 {
262  schdTimeOutCheck();
263  return _schdReq != 0;
264 }
265 
266 
267 
269 {
270  int highPrioId = 0;
271  int normPrioId = _SCHD_PRIO_SLOTS;
272 
273  timerInit();
275  int hPrC = 0, lPrC = 0;
276  while (true)
277  {
278  schdTimeOutCheck();
279 
280  if ((_schdReq & _SCHD_PRIO_MASK) && hPrC < MAX_PRIO)
281  {
282 
283  if (_schdReq & (1 << highPrioId)) {
284  __irqDisable();
285  _schdReq &= ~(1 << highPrioId);
286  __irqEnable();
288  _schdEntries[highPrioId].func();
289 #ifndef SCHD_TRACE_LOAD
291 #else
292  _schdEntries[highPrioId].time += timerMark(TIMER_SECT_IDLE);
293  _schdEntries[highPrioId].count++;
294 #endif
295  }
296  hPrC++;
297  highPrioId = ( highPrioId + 1 ) % _schdPrioCnt;
298  } else if ((_schdReq & _SCHD_NORM_MASK) && lPrC < MAX_PRIO)
299  {
300  hPrC = 0;
301  lPrC++;
302  if (_schdReq & (1 << normPrioId)) {
303  __irqDisable();
304  _schdReq &= ~(1 << normPrioId);
305  __irqEnable();
307  _schdEntries[normPrioId].func();
308 #ifndef SCHD_TRACE_LOAD
310 #else
311  _schdEntries[normPrioId].time += timerMark(TIMER_SECT_IDLE);
312  _schdEntries[normPrioId].count++;
313 #endif
314  }
315  normPrioId = ( ( normPrioId + 1 - _SCHD_PRIO_SLOTS ) % _schdNormCnt )
316  + _SCHD_PRIO_SLOTS;
317  } else if (_idleTaskCount != 0)
318  {
319  lPrC = 0;
321  for (int i = 0; i < _idleTaskCount; i++) {
322  _idleTasks[i]();
323  }
324 #ifdef SCHD_TRACE_LOAD
325  _idleTaskEntry.time += timerMark(TIMER_SECT_IDLE);
326  _idleTaskEntry.count++;
327 #endif
328  }
329 
330 #ifdef __MINGW32__
331  Sleep(1);
332 #endif
333  }
334 }
335 
336 #ifdef SCHD_TRACE_LOAD
337 
338 static void schdDisplayTrace(SchdEntry * e)
339 {
340  uint32_t avr = e->count > 0 ? (e->time * 1000) / e->count : 0;
341  //uint32_t avr = e->time * 1000;
342  //if (e->count > 0) avr /= e->count;
343  printf("%22s %10lu %10lu %8lu\n", (uint32_t)e->name, e->time, e->count, avr);
344 }
345 
346 void schdShowTraces() {
347 
348  puts("Name Tot [ms] Count Avr [us]");
349  puts("---------------------- ---------- ---------- --------");
350 
351  for (SchdEntry * e = &_schdEntries[0]; e < (&_schdEntries[_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS - 1]); ++e)
352  {
353  if (e->name != NULL) schdDisplayTrace(e);
354  }
355  schdDisplayTrace(&_idleTaskEntry);
356 }
357 
358 
359 static void schdResetTrace(SchdEntry * e)
360 {
361  e->count = 0;
362  e->time = 0;
363 }
364 
365 void schdResetTraces() {
366  for (SchdEntry * e = _schdEntries; e < (_schdEntries + (_SCHD_PRIO_SLOTS + _SCHD_NORM_SLOTS)); ++e)
367  {
368  schdResetTrace(e);
369  }
370  schdResetTrace(&_idleTaskEntry);
371 }
372 
373 #endif
#define CLT(A, B, BITS)
Cyclic comparison function Less Than.
Definition: macro.h:90
int timerMark(int section)
Starts the timing of a new section, the previous section is returned, or -1 if it is the first...
Definition: timer.c:53
void schdRunPeriodic(int taskId, int interval)
Schedule a task to run periodically.
Definition: scheduler.c:212
static void __irqEnable()
Enabled IRQ&#39;s on a global level.
Definition: lm32.h:75
void schdRunForever()
Invoked in the main, starts the scheduler.
Definition: scheduler.c:268
Low level routines for LM32, including interrupt handling.
bool schdRegister(SchdTaskF task, bool priority, int *taskId)
Register a task with the scheduler.
Definition: scheduler.c:95
#define TIMER_SECT_IDLE
time spend being idle
Definition: timer.h:33
static void __irqDisable()
Disables IRQ&#39;s on a global level.
Definition: lm32.h:62
Simple task scheduler for tasks.
bool schdTasksPending()
Checks if there are any tasks pending.
Definition: scheduler.c:260
void(* SchdTaskF)()
Task function typedef.
Definition: scheduler.h:47
void schdStop(int taskId)
Stop a scheduled task.
Definition: scheduler.c:223
void schdRun(int taskId)
Run a task &#39;now&#39;.
Definition: scheduler.c:233
static uint32_t timeOutInit(uint32_t msec)
Initializes a timeout with the specified no of msecs.
Definition: tm.h:53
void schdRunDelay(int taskId, int interval)
Schedule a task to run after a delay.
Definition: scheduler.c:201
static bool timeOut(uint32_t to)
Checks whether or not the timeout has expired.
Definition: tm.h:77
Manages the global system error.
void schdRunIRQ(int taskId)
Schedule a task from an IRQ.
Definition: scheduler.c:242
bool schdAddIdleTask(SchdTaskF idleTask)
Adds an idle task, the task which is executed when there is nothing else to do.
Definition: scheduler.c:135
Simple timer functions.
Definition: scheduler.c:65
#define E_OUTOFMEMORY
Generic error: There is no more memory.
Definition: errorcode.h:107
This module is responsible for distributing error codes.
void timerInit()
Initializes the timer.
Definition: timer.c:27
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
Definition: timer.h:34
void schdSetEnable(int taskId, bool enabled)
Enable of disable a task.
Definition: scheduler.c:248