QP/C  5.8.2
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_.teObjFilter, 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_TIME_(); /* timestamp */
147  QS_OBJ_(t); /* the time event object */
148  QS_SIG_(t->super.sig); /* signal of this time event */
149  QS_OBJ_(act); /* the target AO */
150  QS_U8_((uint8_t)tickRate); /* tick rate */
152 
153  QF_CRIT_EXIT_(); /* exit critical section before posting */
154 
155  /* QACTIVE_POST() asserts internally if the queue overflows */
156  QACTIVE_POST(act, &t->super, sender);
157  }
158  else {
159  prev = t; /* advance to this time event */
160  QF_CRIT_EXIT_(); /* exit crit. section to reduce latency */
161 
162  /* prevent merging critical sections, see NOTE1 below */
164  }
165  }
166  QF_CRIT_ENTRY_(); /* re-enter crit. section to continue */
167  }
168  QF_CRIT_EXIT_();
169 }
170 
171 /*****************************************************************************
172 * NOTE1:
173 * In some QF ports the critical section exit takes effect only on the next
174 * machine instruction. If this case, the next instruction is another entry
175 * to a critical section, the critical section won't be really exited, but
176 * rather the two adjacent critical sections would be merged.
177 *
178 * The QF_CRIT_EXIT_NOP() macro contains minimal code required
179 * to prevent such merging of critical sections in QF ports,
180 * in which it can occur.
181 */
182 
183 
184 /****************************************************************************/
196 bool QF_noTimeEvtsActiveX(uint_fast8_t const tickRate) {
197  bool inactive;
198 
200  Q_REQUIRE_ID(200, tickRate < (uint_fast8_t)QF_MAX_TICK_RATE);
201 
202  if (QF_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
203  inactive = false;
204  }
205  else if ((QF_timeEvtHead_[tickRate].act != (void *)0)) {
206  inactive = false;
207  }
208  else {
209  inactive = true;
210  }
211  return inactive;
212 }
213 
214 /****************************************************************************/
231 void QTimeEvt_ctorX(QTimeEvt * const me, QActive * const act,
232  enum_t const sig, uint_fast8_t tickRate)
233 {
235  Q_REQUIRE_ID(300, (sig >= (enum_t)Q_USER_SIG)
236  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE));
237 
238  me->next = (QTimeEvt *)0;
239  me->ctr = (QTimeEvtCtr)0;
240  me->interval = (QTimeEvtCtr)0;
241  me->super.sig = (QSignal)sig;
242 
243  /* For backwards compatibility with QTimeEvt_ctor(), the active object
244  * pointer can be uninitialized (NULL) and is NOT validated in the
245  * precondition. The active object pointer is validated in preconditions
246  * to QTimeEvt_arm_() and QTimeEvt_rearm().
247  */
248  me->act = act;
249 
250  /* Setting the POOL_ID event attribute to zero is correct only for
251  * events not allocated from event pools, which must be the case
252  * for Time Events.
253  */
254  me->super.poolId_ = (uint8_t)0;
255 
256 
257  /* The reference counter attribute is not used in static events,
258  * so for the Time Events it is reused to hold the tickRate in the
259  * bits [0..6] and the linkedFlag in the MSB (bit [7]). The linkedFlag
260  * is 0 for time events unlinked from any list and 1 otherwise.
261  */
262  me->super.refCtr_ = (uint8_t)tickRate;
263 }
264 
265 /****************************************************************************/
291 void QTimeEvt_armX(QTimeEvt * const me,
292  QTimeEvtCtr const nTicks, QTimeEvtCtr const interval)
293 {
294  uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_
295  & (uint_fast8_t)0x7F;
296  QTimeEvtCtr ctr = me->ctr;
298 
302  Q_REQUIRE_ID(400, (me->act != (void *)0)
303  && (ctr == (QTimeEvtCtr)0)
304  && (nTicks != (QTimeEvtCtr)0)
305  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
306  && (me->super.sig >= (QSignal)Q_USER_SIG));
307 
308  QF_CRIT_ENTRY_();
309  me->ctr = nTicks;
310  me->interval = interval;
311 
312  /* is the time event unlinked?
313  * NOTE: For the duration of a single clock tick of the specified tick
314  * rate a time event can be disarmed and yet still linked into the list,
315  * because un-linking is performed exclusively in the QF_tickX() function.
316  */
317  if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) {
318  me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */
319 
320  /* The time event is initially inserted into the separate
321  * "freshly armed" link list based on QF_timeEvtHead_[tickRate].act.
322  * Only later, inside the QF_tickX() function, the "freshly armed"
323  * list is appended to the main list of armed time events based on
324  * QF_timeEvtHead_[tickRate].next. Again, this is to keep any
325  * changes to the main list exclusively inside the QF_tickX()
326  * function.
327  */
328  me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act;
329  QF_timeEvtHead_[tickRate].act = me;
330  }
331 
333  QS_TIME_(); /* timestamp */
334  QS_OBJ_(me); /* this time event object */
335  QS_OBJ_(me->act); /* the active object */
336  QS_TEC_(nTicks); /* the number of ticks */
337  QS_TEC_(interval); /* the interval */
338  QS_U8_((uint8_t)tickRate); /* tick rate */
340 
341  QF_CRIT_EXIT_();
342 }
343 
344 /****************************************************************************/
361 bool QTimeEvt_disarm(QTimeEvt * const me) {
362  bool wasArmed;
364 
365  QF_CRIT_ENTRY_();
366 
367  /* is the time evt running? */
368  if (me->ctr != (QTimeEvtCtr)0) {
369  wasArmed = true;
370 
372  QS_TIME_(); /* timestamp */
373  QS_OBJ_(me); /* this time event object */
374  QS_OBJ_(me->act); /* the target AO */
375  QS_TEC_(me->ctr); /* the number of ticks */
376  QS_TEC_(me->interval); /* the interval */
377  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/
379 
380  me->ctr = (QTimeEvtCtr)0; /* schedule removal from the list */
381  }
382  /* the time event was already not running */
383  else {
384  wasArmed = false;
385 
387  QS_priv_.teObjFilter, me)
388  QS_TIME_(); /* timestamp */
389  QS_OBJ_(me); /* this time event object */
390  QS_OBJ_(me->act); /* the target AO */
391  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F));/*tick rate*/
393 
394  }
395  QF_CRIT_EXIT_();
396  return wasArmed;
397 }
398 
399 /****************************************************************************/
420 bool QTimeEvt_rearm(QTimeEvt * const me, QTimeEvtCtr const nTicks) {
421  uint_fast8_t tickRate = (uint_fast8_t)me->super.refCtr_
422  & (uint_fast8_t)0x7F;
423  bool isArmed;
425 
429  Q_REQUIRE_ID(600, (me->act != (void *)0)
430  && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
431  && (nTicks != (QTimeEvtCtr)0)
432  && (me->super.sig >= (QSignal)Q_USER_SIG));
433 
434  QF_CRIT_ENTRY_();
435 
436  /* is the time evt not running? */
437  if (me->ctr == (QTimeEvtCtr)0) {
438  isArmed = false;
439 
440  /* is the time event unlinked?
441  * NOTE: For a duration of a single clock tick of the specified
442  * tick rate a time event can be disarmed and yet still linked into
443  * the list, because unlinking is performed exclusively in the
444  * QF_tickX() function.
445  */
446  if ((me->super.refCtr_ & (uint8_t)0x80) == (uint8_t)0) {
447  me->super.refCtr_ |= (uint8_t)0x80; /* mark as linked */
448 
449  /* The time event is initially inserted into the separate
450  * "freshly armed" list based on QF_timeEvtHead_[tickRate].act.
451  * Only later, inside the QF_tickX() function, the "freshly armed"
452  * list is appended to the main list of armed time events based on
453  * QF_timeEvtHead_[tickRate].next. Again, this is to keep any
454  * changes to the main list exclusively inside the QF_tickX()
455  * function.
456  */
457  me->next = (QTimeEvt *)QF_timeEvtHead_[tickRate].act;
458  QF_timeEvtHead_[tickRate].act = me;
459  }
460  }
461  /* the time event is armed */
462  else {
463  isArmed = true;
464  }
465  me->ctr = nTicks; /* re-load the tick counter (shift the phasing) */
466 
468  QS_TIME_(); /* timestamp */
469  QS_OBJ_(me); /* this time event object */
470  QS_OBJ_(me->act); /* the target AO */
471  QS_TEC_(me->ctr); /* the number of ticks */
472  QS_TEC_(me->interval); /* the interval */
473  QS_2U8_((uint8_t)tickRate,
474  ((isArmed != false) ? (uint8_t)1 : (uint8_t)0));
476 
477  QF_CRIT_EXIT_();
478  return isArmed;
479 }
480 
481 /****************************************************************************/
495 QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const * const me) {
496  QTimeEvtCtr ret;
498 
499  QF_CRIT_ENTRY_();
500  ret = me->ctr;
501 
503  QS_TIME_(); /* timestamp */
504  QS_OBJ_(me); /* this time event object */
505  QS_OBJ_(me->act); /* the target AO */
506  QS_TEC_(ret); /* the current counter */
507  QS_TEC_(me->interval); /* the interval */
508  QS_U8_((uint8_t)(me->super.refCtr_ & (uint8_t)0x7F)); /* tick rate */
510 
511  QF_CRIT_EXIT_();
512  return ret;
513 }
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:682
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition: qf.h:785
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:196
rearming of a time event
Definition: qs.h:107
void *volatile act
the active object that receives the time events
Definition: qf.h:446
bool QTimeEvt_rearm(QTimeEvt *const me, QTimeEvtCtr const nTicks)
Rearm a time event.
Definition: qf_time.c:420
true disarming of an armed time event
Definition: qs.h:106
Time Event structure.
Definition: qf.h:439
#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
first signal that can be used for user signals
Definition: qep.h:613
#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:660
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:95
a time event was armed
Definition: qs.h:103
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: stdint.h:28
QSignal sig
signal of the event instance
Definition: qep.h:154
bool QTimeEvt_disarm(QTimeEvt *const me)
Disarm a time event.
Definition: qf_time.c:361
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:76
QTimeEvtCtr interval
the interval for periodic time event (zero for one-shot time event)
Definition: qf.h:464
uint16_t QSignal
QSignal represents the signal of an event.
Definition: qep.h:130
struct QTimeEvt *volatile next
link to the next time event in the list
Definition: qf.h:443
QF_tickX() was called.
Definition: qs.h:102
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:231
QTimeEvtCtr QTimeEvt_ctr(QTimeEvt const *const me)
Get the current value of the down-counter of a time event.
Definition: qf_time.c:495
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:130
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:248
#define QS_OBJ_(obj_)
Internal macro to output an unformatted object pointer data element.
Definition: qs.h:718
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:182
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:291
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:674
#define QS_U8_(data_)
Internal QS macro to output an unformatted uint8_t data element.
Definition: qs.h:679
void const * teObjFilter
time event for QF local filter
Definition: qs.h:1052
Active Object (based on QHsm implementation)
Definition: qf.h:110
a time event posted itself directly to an AO
Definition: qs.h:108
QTimeEvtCtr volatile ctr
the internal down-counter of the time event.
Definition: qf.h:455
uint8_t poolId_
pool ID (0 for static event)
Definition: qep.h:155
uint16_t QTimeEvtCtr
type of the Time Event counter, which determines the dynamic range of the time delays measured in clo...
Definition: qf.h:398
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
uint8_t volatile refCtr_
reference counter
Definition: qep.h:156
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:245
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81