QP/C  5.9.8
qf_time.c
Go to the documentation of this file.
1 
40 #define QP_IMPL /* this is QP implementation */
41 #include "qf_port.h" /* QF port */
42 #include "qf_pkg.h" /* QF package-scope interface */
43 #include "qassert.h" /* QP embedded systems-friendly assertions */
44 #ifdef Q_SPY /* QS software tracing enabled? */
45  #include "qs_port.h" /* include QS port */
46 #else
47  #include "qs_dummy.h" /* disable the QS software tracing */
48 #endif /* Q_SPY */
49 
50 Q_DEFINE_THIS_MODULE("qf_time")
51 
52 /* Package-scope objects ****************************************************/
53 QTimeEvt QF_timeEvtHead_[QF_MAX_TICK_RATE]; /* heads of time event lists */
54 
55 /****************************************************************************/
72 #ifndef Q_SPY
73 void QF_tickX_(uint_fast8_t const tickRate)
74 #else
75 void QF_tickX_(uint_fast8_t const tickRate, void const * const sender)
76 #endif
77 {
78  QTimeEvt *prev = &QF_timeEvtHead_[tickRate];
80 
82 
83  QS_BEGIN_NOCRIT_(QS_QF_TICK, (void *)0, (void *)0)
84  QS_TEC_((QTimeEvtCtr)(++prev->ctr)); /* tick ctr */
85  QS_U8_((uint8_t)tickRate); /* tick rate */
87 
88  /* scan the linked-list of time events at this rate... */
89  for (;;) {
90  QTimeEvt *t = prev->next; /* advance down the time evt. list */
91 
92  /* end of the list? */
93  if (t == (QTimeEvt *)0) {
94 
95  /* any new time events armed since the last run of QF_tickX_()? */
96  if (QF_timeEvtHead_[tickRate].act != (void *)0) {
97 
98  /* sanity check */
99  Q_ASSERT_ID(110, prev != (QTimeEvt *)0);
100  prev->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act;
101  QF_timeEvtHead_[tickRate].act = (void *)0;
102  t = prev->next; /* switch to the new list */
103  }
104  else {
105  break; /* all currently armed time evts. processed */
106  }
107  }
108 
109  /* time event scheduled for removal? */
110  if (t->ctr == (QTimeEvtCtr)0) {
111  prev->next = t->next;
112  t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */
113  /* do NOT advance the prev pointer */
114  QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */
115 
116  /* prevent merging critical sections, see NOTE1 below */
118  }
119  else {
120  --t->ctr;
121 
122  /* is time event about to expire? */
123  if (t->ctr == (QTimeEvtCtr)0) {
124  QActive *act = (QActive *)t->act; /* temp. for volatile */
125 
126  /* periodic time evt? */
127  if (t->interval != (QTimeEvtCtr)0) {
128  t->ctr = t->interval; /* rearm the time event */
129  prev = t; /* advance to this time event */
130  }
131  /* one-shot time event: automatically disarm */
132  else {
133  prev->next = t->next;
134  t->super.refCtr_ &= (uint8_t)0x7F; /* mark as unlinked */
135  /* do NOT advance the prev pointer */
136 
138  QS_priv_.locFilter[TE_OBJ], t)
139  QS_OBJ_(t); /* this time event object */
140  QS_OBJ_(act); /* the target AO */
141  QS_U8_((uint8_t)tickRate); /* tick rate */
143  }
144 
146  QS_priv_.locFilter[TE_OBJ], t)
147  QS_TIME_(); /* timestamp */
148  QS_OBJ_(t); /* the time event object */
149  QS_SIG_(t->super.sig); /* signal of this time event */
150  QS_OBJ_(act); /* the target AO */
151  QS_U8_((uint8_t)tickRate); /* tick rate */
153 
154  QF_CRIT_EXIT_(); /* exit critical section before posting */
155 
156  /* QACTIVE_POST() asserts internally if the queue overflows */
157  QACTIVE_POST(act, &t->super, sender);
158  }
159  else {
160  prev = t; /* advance to this time event */
161  QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */
162 
163  /* prevent merging critical sections, see NOTE1 below */
165  }
166  }
167  QF_CRIT_ENTRY_(); /* re-enter crit. section to continue */
168  }
169  QF_CRIT_EXIT_();
170 }
171 
172 /*****************************************************************************
173 * NOTE1:
174 * In some QF ports the critical section exit takes effect only on the next
175 * machine instruction. If this case, the next instruction is another entry
176 * to a critical section, the critical section won't be really exited, but
177 * rather the two adjacent critical sections would be merged.
178 *
179 * The QF_CRIT_EXIT_NOP() macro contains minimal code required
180 * to prevent such merging of critical sections in QF ports,
181 * in which it can occur.
182 */
183 
184 
185 /****************************************************************************/
197 bool QF_noTimeEvtsActiveX(uint_fast8_t const tickRate) {
198  bool inactive;
199 
201  Q_REQUIRE_ID(200, tickRate < (uint_fast8_t)QF_MAX_TICK_RATE);
202 
203  if (QF_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
204  inactive = false;
205  }
206  else if ((QF_timeEvtHead_[tickRate].act != (void *)0)) {
207  inactive = false;
208  }
209  else {
210  inactive = true;
211  }
212  return inactive;
213 }
214 
215 /****************************************************************************/
232 void QTimeEvt_ctorX(QTimeEvt * const me, QActive * const act,
233  enum_t const sig, uint_fast8_t tickRate)
234 {
236  Q_REQUIRE_ID(300, (sig >= (enum_t)Q_USER_SIG)
237  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE));
238 
239  me->next = (QTimeEvt *)0;
240  me->ctr = (QTimeEvtCtr)0;
241  me->interval = (QTimeEvtCtr)0;
242  me->super.sig = (QSignal)sig;
243 
244  /* For backwards compatibility with QTimeEvt_ctor(), the active object
245  * pointer can be uninitialized (NULL) and is NOT validated in the
246  * precondition. The active object pointer is validated in preconditions
247  * to QTimeEvt_arm_() and QTimeEvt_rearm().
248  */
249  me->act = act;
250 
251  /* Setting the POOL_ID event attribute to zero is correct only for
252  * events not allocated from event pools, which must be the case
253  * for Time Events.
254  */
255  me->super.poolId_ = (uint8_t)0;
256 
257 
258  /* The reference counter attribute is not used in static events,
259  * so for the Time Events it is reused to hold the tickRate in the
260  * bits [0..6] and the linkedFlag in the MSB (bit [7]). The linkedFlag
261  * is 0 for time events unlinked from any list and 1 otherwise.
262  */
263  me->super.refCtr_ = (uint8_t)tickRate;
264 }
265 
266 /****************************************************************************/
292 void QTimeEvt_armX(QTimeEvt * const me,
293  QTimeEvtCtr const nTicks, QTimeEvtCtr const interval)
294 {
295  uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_
296  & (uint_fast8_t)0x7F;
297  QTimeEvtCtr ctr = me->ctr;
299 
303  Q_REQUIRE_ID(400, (me->act != (void *)0)
304  && (ctr == (QTimeEvtCtr)0)
305  && (nTicks != (QTimeEvtCtr)0)
306  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
307  && (me->super.sig >= (QSignal)Q_USER_SIG));
308 
309  QF_CRIT_ENTRY_();
310  me->ctr = nTicks;
311  me->interval = interval;
312 
313  /* is the time event unlinked?
314  * NOTE: For the duration of a single clock tick of the specified tick
315  * rate a time event can be disarmed and yet still linked into the list,
316  * because un-linking is performed exclusively in the QF_tickX() function.
317  */
318  if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) {
319  me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */
320 
321  /* The time event is initially inserted into the separate
322  * "freshly armed" link list based on QF_timeEvtHead_[tickRate].act.
323  * Only later, inside the QF_tickX() function, the "freshly armed"
324  * list is appended to the main list of armed time events based on
325  * QF_timeEvtHead_[tickRate].next. Again, this is to keep any
326  * changes to the main list exclusively inside the QF_tickX()
327  * function.
328  */
329  me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act;
330  QF_timeEvtHead_[tickRate].act = me;
331  }
332 
334  QS_TIME_(); /* timestamp */
335  QS_OBJ_(me); /* this time event object */
336  QS_OBJ_(me->act); /* the active object */
337  QS_TEC_(nTicks); /* the number of ticks */
338  QS_TEC_(interval); /* the interval */
339  QS_U8_((uint8_t)tickRate); /* tick rate */
341 
342  QF_CRIT_EXIT_();
343 }
344 
345 /****************************************************************************/
362 bool QTimeEvt_disarm(QTimeEvt * const me) {
363  bool wasArmed;
365 
366  QF_CRIT_ENTRY_();
367 
368  /* is the time evt running? */
369  if (me->ctr != (QTimeEvtCtr)0) {
370  wasArmed = true;
371 
373  QS_TIME_(); /* timestamp */
374  QS_OBJ_(me); /* this time event object */
375  QS_OBJ_(me->act); /* the target AO */
376  QS_TEC_(me->ctr); /* the number of ticks */
377  QS_TEC_(me->interval); /* the interval */
378  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/
380 
381  me->ctr = (QTimeEvtCtr)0; /* schedule removal from the list */
382  }
383  /* the time event was already not running */
384  else {
385  wasArmed = false;
386 
388  QS_priv_.locFilter[TE_OBJ], me)
389  QS_TIME_(); /* timestamp */
390  QS_OBJ_(me); /* this time event object */
391  QS_OBJ_(me->act); /* the target AO */
392  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/
394 
395  }
396  QF_CRIT_EXIT_();
397  return wasArmed;
398 }
399 
400 /****************************************************************************/
421 bool QTimeEvt_rearm(QTimeEvt * const me, QTimeEvtCtr const nTicks) {
422  uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_
423  & (uint_fast8_t)0x7F;
424  bool isArmed;
426 
430  Q_REQUIRE_ID(600, (me->act != (void *)0)
431  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
432  && (nTicks != (QTimeEvtCtr)0)
433  && (me->super.sig >= (QSignal)Q_USER_SIG));
434 
435  QF_CRIT_ENTRY_();
436 
437  /* is the time evt not running? */
438  if (me->ctr == (QTimeEvtCtr)0) {
439  isArmed = false;
440 
441  /* is the time event unlinked?
442  * NOTE: For a duration of a single clock tick of the specified
443  * tick rate a time event can be disarmed and yet still linked into
444  * the list, because unlinking is performed exclusively in the
445  * QF_tickX() function.
446  */
447  if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) {
448  me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */
449 
450  /* The time event is initially inserted into the separate
451  * "freshly armed" list based on QF_timeEvtHead_[tickRate].act.
452  * Only later, inside the QF_tickX() function, the "freshly armed"
453  * list is appended to the main list of armed time events based on
454  * QF_timeEvtHead_[tickRate].next. Again, this is to keep any
455  * changes to the main list exclusively inside the QF_tickX()
456  * function.
457  */
458  me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act;
459  QF_timeEvtHead_[tickRate].act = me;
460  }
461  }
462  /* the time event is armed */
463  else {
464  isArmed = true;
465  }
466  me->ctr = nTicks; /* re-load the tick counter (shift the phasing) */
467 
469  QS_TIME_(); /* timestamp */
470  QS_OBJ_(me); /* this time event object */
471  QS_OBJ_(me->act); /* the target AO */
472  QS_TEC_(me->ctr); /* the number of ticks */
473  QS_TEC_(me->interval); /* the interval */
474  QS_2U8_((uint8_t)tickRate,
475  ((isArmed != false) ? (uint8_t)1 : (uint8_t)0));
477 
478  QF_CRIT_EXIT_();
479  return isArmed;
480 }
481 
482 /****************************************************************************/
496 QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const * const me) {
497  QTimeEvtCtr ret;
499 
500  QF_CRIT_ENTRY_();
501  ret = me->ctr;
502 
504  QS_TIME_(); /* timestamp */
505  QS_OBJ_(me); /* this time event object */
506  QS_OBJ_(me->act); /* the target AO */
507  QS_TEC_(ret); /* the current counter */
508  QS_TEC_(me->interval); /* the interval */
509  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F)); /* tick rate */
511 
512  QF_CRIT_EXIT_();
513  return ret;
514 }
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:708
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition: qf.h:807
bool QF_noTimeEvtsActiveX(uint_fast8_t const tickRate)
Returns &#39;true&#39; if there are no armed time events at a given tick rate.
Definition: qf_time.c:197
rearming of a time event
Definition: qs.h:107
bool QTimeEvt_rearm(QTimeEvt *const me, QTimeEvtCtr const nTicks)
Rearm a time event.
Definition: qf_time.c:421
true disarming of an armed time event
Definition: qs.h:106
QSignal sig
signal of the event instance
Definition: qep.h:153
void *volatile act
the active object that receives the time events
Definition: qf.h:460
Time Event structure.
Definition: qf.h:453
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
a time event counter was requested
Definition: qs.h:109
struct QTimeEvt *volatile next
link to the next time event in the list
Definition: qf.h:457
first signal that can be used for user signals
Definition: qep.h:609
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.h:57
#define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_)
Internal macro to begin a QS record without entering critical section.
Definition: qs.h:686
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:101
a time event was armed
Definition: qs.h:103
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: stdint.h:28
bool QTimeEvt_disarm(QTimeEvt *const me)
Disarm a time event.
Definition: qf_time.c:362
attempt to disarm a disarmed QTimeEvt
Definition: qs.h:105
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
Internal (package scope) QF/C interface.
int enum_t
typedef for enumerations used for event signals
Definition: qep.h:75
uint16_t QSignal
QSignal represents the signal of an event.
Definition: qep.h:129
QF_tickX() was called.
Definition: qs.h:102
uint8_t volatile refCtr_
reference counter
Definition: qep.h:155
uint8_t poolId_
pool ID (0 for static event)
Definition: qep.h:154
QActionHandler act
pointer to an action-handler function
Definition: qep.h:250
void QTimeEvt_ctorX(QTimeEvt *const me, QActive *const act, enum_t const sig, uint_fast8_t tickRate)
The extended "constructor" to initialize a Time Event.
Definition: qf_time.c:232
QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const *const me)
Get the current value of the down-counter of a time event.
Definition: qf_time.c:496
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
QTimeEvtCtr interval
the interval for periodic time event (zero for one-shot time event)
Definition: qf.h:478
Customizable and memory-efficient assertions for embedded systems.
#define Q_REQUIRE_ID(id_, test_)
Assertion for checking preconditions with user-specified assertion-id.
Definition: qassert.h:254
#define QS_OBJ_(obj_)
Internal macro to output an unformatted object pointer data element.
Definition: qs.h:744
QTimeEvt QF_timeEvtHead_[QF_MAX_TICK_RATE]
heads of linked lists of time events, one for every clock tick rate
Definition: qf_time.c:53
#define QF_MAX_TICK_RATE
Default value of the macro configurable value in qf_port.h.
Definition: qf.h:75
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:205
void QTimeEvt_armX(QTimeEvt *const me, QTimeEvtCtr const nTicks, QTimeEvtCtr const interval)
Arm a time event (one shot or periodic) for direct event posting.
Definition: qf_time.c:292
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:700
#define QS_U8_(data_)
Internal QS macro to output an unformatted uint8_t data element.
Definition: qs.h:705
Active Object (based on QHsm implementation)
Definition: qf.h:110
time event object
Definition: qs.h:1061
a time event posted itself directly to an AO
Definition: qs.h:108
uint16_t QTimeEvtCtr
type of the Time Event counter, which determines the dynamic range of the time delays measured in clo...
Definition: qf.h:409
void QF_tickX_(uint_fast8_t const tickRate, void const *const sender)
Processes all armed time events at every clock tick.
Definition: qf_time.c:75
QTimeEvtCtr volatile ctr
the internal down-counter of the time event.
Definition: qf.h:469
a time event expired and was disarmed
Definition: qs.h:104
#define QACTIVE_POST(me_, e_, sender_)
Polymorphically posts an event to an active object (FIFO) with delivery guarantee.
Definition: qf.h:252
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81