QP/C  5.9.8
qf_actq.c
Go to the documentation of this file.
1 
45 #define QP_IMPL /* this is QP implementation */
46 #include "qf_port.h" /* QF port */
47 #include "qf_pkg.h" /* QF package-scope interface */
48 #include "qassert.h" /* QP embedded systems-friendly assertions */
49 #ifdef Q_SPY /* QS software tracing enabled? */
50  #include "qs_port.h" /* include QS port */
51 #else
52  #include "qs_dummy.h" /* disable the QS software tracing */
53 #endif /* Q_SPY */
54 
55 Q_DEFINE_THIS_MODULE("qf_actq")
56 
57 
58 /****************************************************************************/
89 #ifndef Q_SPY
90 bool QActive_post_(QActive * const me, QEvt const * const e,
91  uint_fast16_t const margin)
92 #else
93 bool QActive_post_(QActive * const me, QEvt const * const e,
94  uint_fast16_t const margin, void const * const sender)
95 #endif
96 {
97  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
98  bool status;
100 
102  Q_REQUIRE_ID(100, e != (QEvt const *)0);
103 
104  QF_CRIT_ENTRY_();
105  nFree = me->eQueue.nFree; /* get volatile into the temporary */
106 
107  /* margin available? */
108  if (((margin == QF_NO_MARGIN) && (nFree > (QEQueueCtr)0))
109  || (nFree > (QEQueueCtr)margin))
110  {
111 
113  QS_priv_.locFilter[AO_OBJ], me)
114  QS_TIME_(); /* timestamp */
115  QS_OBJ_(sender); /* the sender object */
116  QS_SIG_(e->sig); /* the signal of the event */
117  QS_OBJ_(me); /* this active object (recipient) */
118  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
119  QS_EQC_(nFree); /* number of free entries */
120  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
122 
123  /* is it a pool event? */
124  if (e->poolId_ != (uint8_t)0) {
125  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
126  }
127 
128  --nFree; /* one free entry just used up */
129  me->eQueue.nFree = nFree; /* update the volatile */
130  if (me->eQueue.nMin > nFree) {
131  me->eQueue.nMin = nFree; /* update minimum so far */
132  }
133 
134  /* empty queue? */
135  if (me->eQueue.frontEvt == (QEvt const *)0) {
136  me->eQueue.frontEvt = e; /* deliver event directly */
137  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
138  }
139  /* queue is not empty, insert event into the ring-buffer */
140  else {
141  /* insert event into the ring buffer (FIFO) */
142  QF_PTR_AT_(me->eQueue.ring, me->eQueue.head) = e;
143  if (me->eQueue.head == (QEQueueCtr)0) { /* need to wrap head? */
144  me->eQueue.head = me->eQueue.end; /* wrap around */
145  }
146  --me->eQueue.head; /* advance the head (counter clockwise) */
147  }
148  QF_CRIT_EXIT_();
149 
150  status = true; /* event posted successfully */
151  }
152  else {
156  Q_ASSERT_ID(110, margin != QF_NO_MARGIN);
157 
159  QS_priv_.locFilter[AO_OBJ], me)
160  QS_TIME_(); /* timestamp */
161  QS_OBJ_(sender); /* the sender object */
162  QS_SIG_(e->sig); /* the signal of the event */
163  QS_OBJ_(me); /* this active object (recipient) */
164  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
165  QS_EQC_(nFree); /* number of free entries */
166  QS_EQC_(margin); /* margin requested */
168 
169  QF_CRIT_EXIT_();
170 
171  QF_gc(e); /* recycle the event to avoid a leak */
172  status = false; /* event not posted */
173  }
174 
175  return status;
176 }
177 
178 /****************************************************************************/
193 void QActive_postLIFO_(QActive * const me, QEvt const * const e) {
194  QEvt const *frontEvt; /* temporary to avoid UB for volatile access */
195  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
197 
198  QF_CRIT_ENTRY_();
199  nFree = me->eQueue.nFree; /* get volatile into the temporary */
200 
201  /* the queue must be able to accept the event (cannot overflow) */
202  Q_ASSERT_ID(210, nFree != (QEQueueCtr)0);
203 
205  QS_TIME_(); /* timestamp */
206  QS_SIG_(e->sig); /* the signal of this event */
207  QS_OBJ_(me); /* this active object */
208  QS_2U8_(e->poolId_, e->refCtr_);/* pool Id & ref Count of the event */
209  QS_EQC_(nFree); /* number of free entries */
210  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
212 
213  /* is it a pool event? */
214  if (e->poolId_ != (uint8_t)0) {
215  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
216  }
217 
218  --nFree; /* one free entry just used up */
219  me->eQueue.nFree = nFree; /* update the volatile */
220  if (me->eQueue.nMin > nFree) {
221  me->eQueue.nMin = nFree; /* update minimum so far */
222  }
223 
224  frontEvt = me->eQueue.frontEvt; /* read volatile into the temporary */
225  me->eQueue.frontEvt = e; /* deliver the event directly to the front */
226 
227  /* was the queue empty? */
228  if (frontEvt == (QEvt const *)0) {
229  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
230  }
231  /* queue was not empty, leave the event in the ring-buffer */
232  else {
233  ++me->eQueue.tail;
234  /* need to wrap the tail? */
235  if (me->eQueue.tail == me->eQueue.end) {
236  me->eQueue.tail = (QEQueueCtr)0; /* wrap around */
237  }
238 
239  QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail) = frontEvt;
240  }
241  QF_CRIT_EXIT_();
242 }
243 
244 /****************************************************************************/
266 QEvt const *QActive_get_(QActive * const me) {
267  QEQueueCtr nFree;
268  QEvt const *e;
270  QF_CRIT_ENTRY_();
271 
272  QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
273 
274  e = me->eQueue.frontEvt; /* always remove event from the front location */
275  nFree = me->eQueue.nFree + (QEQueueCtr)1; /* get volatile into tmp */
276  me->eQueue.nFree = nFree; /* update the number of free */
277 
278  /* any events in the ring buffer? */
279  if (nFree <= me->eQueue.end) {
280 
281  /* remove event from the tail */
282  me->eQueue.frontEvt = QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail);
283  if (me->eQueue.tail == (QEQueueCtr)0) { /* need to wrap the tail? */
284  me->eQueue.tail = me->eQueue.end; /* wrap around */
285  }
286  --me->eQueue.tail;
287 
289  QS_TIME_(); /* timestamp */
290  QS_SIG_(e->sig); /* the signal of this event */
291  QS_OBJ_(me); /* this active object */
292  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
293  QS_EQC_(nFree); /* number of free entries */
295  }
296  else {
297  me->eQueue.frontEvt = (QEvt const *)0; /* queue becomes empty */
298 
299  /* all entries in the queue must be free (+1 for fronEvt) */
300  Q_ASSERT_ID(310, nFree == (me->eQueue.end + (QEQueueCtr)1));
301 
303  QS_priv_.locFilter[AO_OBJ], me)
304  QS_TIME_(); /* timestamp */
305  QS_SIG_(e->sig); /* the signal of this event */
306  QS_OBJ_(me); /* this active object */
307  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
309  }
310  QF_CRIT_EXIT_();
311  return e;
312 }
313 
314 /****************************************************************************/
334  uint_fast16_t min;
336 
337  Q_REQUIRE_ID(400, (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
338  && (QF_active_[prio] != (QActive *)0));
339 
340  QF_CRIT_ENTRY_();
341  min = (uint_fast16_t)QF_active_[prio]->eQueue.nMin;
342  QF_CRIT_EXIT_();
343 
344  return min;
345 }
346 
347 
348 /****************************************************************************/
349 /****************************************************************************/
358 #define QTICKER_CAST(me_) ((QTicker *)(me_))
359 
360 static void QTicker_init_(QHsm * const me, QEvt const * const e);
361 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e);
362 #ifdef Q_SPY
363 
364  static bool QTicker_post_(QActive * const me, QEvt const * const e,
365  uint_fast16_t const margin, void const * const sender);
366 #else
367  static bool QTicker_post_(QActive * const me, QEvt const * const e,
368  uint_fast16_t const margin);
369 #endif
370 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e);
371 
372 /*..........................................................................*/
374 void QTicker_ctor(QTicker * const me, uint8_t tickRate) {
375  static QActiveVtbl const vtbl = { /* QActiveVtbl virtual table */
376  { &QTicker_init_,
377  &QTicker_dispatch_ },
379  &QTicker_post_,
380  &QTicker_postLIFO_
381  };
382  QActive_ctor(me, Q_STATE_CAST(0)); /* superclass' ctor */
383  me->super.vptr = &vtbl.super; /* hook the vptr */
384 
385  /* reuse eQueue.head for tick-rate */
386  me->eQueue.head = (QEQueueCtr)tickRate;
387 }
388 /*..........................................................................*/
389 static void QTicker_init_(QHsm * const me, QEvt const * const e) {
390  (void)me;
391  (void)e;
392  QTICKER_CAST(me)->eQueue.tail = (QEQueueCtr)0;
393 }
394 /*..........................................................................*/
395 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e) {
396  QEQueueCtr n;
398 
399  (void)e; /* unused parameter */
400 
401  QF_CRIT_ENTRY_();
402  n = QTICKER_CAST(me)->eQueue.tail; /* # ticks since last call */
403  QTICKER_CAST(me)->eQueue.tail = (QEQueueCtr)0; /* clear the # ticks */
404  QF_CRIT_EXIT_();
405 
406  for (; n > (QEQueueCtr)0; --n) {
407  QF_TICK_X((uint_fast8_t)QTICKER_CAST(me)->eQueue.head, me);
408  }
409 }
410 /*..........................................................................*/
411 #ifndef Q_SPY
412 static bool QTicker_post_(QActive * const me, QEvt const * const e,
413  uint_fast16_t const margin)
414 #else
415 static bool QTicker_post_(QActive * const me, QEvt const * const e,
416  uint_fast16_t const margin,
417  void const * const sender)
418 #endif
419 {
421 
422  (void)e; /* unused parameter */
423  (void)margin; /* unused parameter */
424 
425  QF_CRIT_ENTRY_();
426  if (me->eQueue.frontEvt == (QEvt const *)0) {
427 
428  static QEvt const tickEvt = { (QSignal)0, (uint8_t)0, (uint8_t)0 };
429  me->eQueue.frontEvt = &tickEvt; /* deliver event directly */
430  --me->eQueue.nFree; /* one less free event */
431 
432  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
433  }
434 
435  ++me->eQueue.tail; /* account for one more tick event */
436 
438  QS_TIME_(); /* timestamp */
439  QS_OBJ_(sender); /* the sender object */
440  QS_SIG_((QSignal)0); /* the signal of the event */
441  QS_OBJ_(me); /* this active object */
442  QS_2U8_((uint8_t)0, (uint8_t)0); /* pool Id & refCtr of the evt */
443  QS_EQC_((uint8_t)0); /* number of free entries */
444  QS_EQC_((uint8_t)0); /* min number of free entries */
446 
447  QF_CRIT_EXIT_();
448 
449  return true; /* the event is always posted correctly */
450 }
451 /*..........................................................................*/
452 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e) {
453  (void)me;
454  (void)e;
455  Q_ERROR_ID(900);
456 }
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:708
#define QACTIVE_EQUEUE_WAIT_(me_)
Platform-dependent macro defining how QF should block the calling task when the QF native queue is em...
Definition: macros.h:56
void QTicker_ctor(QTicker *const me, uint8_t tickRate)
"constructor" of QTicker
Definition: qf_actq.c:374
#define QTICKER_CAST(me_)
Perform downcast to QTicker pointer.
Definition: qf_actq.c:358
QSignal sig
signal of the event instance
Definition: qep.h:153
#define QF_TICK_X(tickRate_, sender_)
Invoke the system clock tick processing QF_tickX_().
Definition: qf.h:633
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
struct QHsmVtbl const * vptr
virtual pointer
Definition: qep.h:281
AO got an event and its queue is empty.
Definition: qs.h:88
static bool QTicker_post_(QActive *const me, QEvt const *const e, uint_fast16_t const margin, void const *const sender)
virtual function to asynchronously post (FIFO) an event to an AO
Definition: qf_actq.c:415
AO got an event and its queue is not empty.
Definition: qs.h:87
an event was posted (FIFO) directly to AO
Definition: qs.h:85
Virtual table for the QActive class.
Definition: qf.h:166
#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
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: stdint.h:28
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition: qep.h:226
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
Internal (package scope) QF/C interface.
uint16_t QSignal
QSignal represents the signal of an event.
Definition: qep.h:129
uint_fast16_t QF_getQueueMin(uint_fast8_t const prio)
This function returns the minimum of free entries of the given event queue.
Definition: qf_actq.c:333
void QF_gc(QEvt const *const e)
Recycle a dynamic event.
Definition: qf_dyn.c:217
Event structure.
Definition: qep.h:152
QHsm super
inherits QHsm
Definition: qf.h:111
uint8_t volatile refCtr_
reference counter
Definition: qep.h:155
attempt to post an evt to AO failed
Definition: qs.h:116
uint8_t poolId_
pool ID (0 for static event)
Definition: qep.h:154
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
Definition: qep.h:280
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
active object
Definition: qs.h:1058
#define QF_EVT_REF_CTR_INC_(e_)
increment the refCtr of an event e_ casting const away
Definition: qf_pkg.h:108
unsigned int uint_fast16_t
fast at-least 16-bit unsigned int
Definition: stdint.h:37
#define QF_MAX_ACTIVE
The maximum number of active objects in the application.
Definition: qf_port.h:58
void QActive_ctor(QActive *const me, QStateHandler initial)
protected "constructor" of an QActive active object
Definition: qf_qact.c:65
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
void QActive_start_(QActive *const me, uint_fast8_t prio, QEvt const *qSto[], uint_fast16_t qLen, void *stkSto, uint_fast16_t stkSize, QEvt const *ie)
Implementation of the active object start operation.
Definition: qk.c:162
#define QS_OBJ_(obj_)
Internal macro to output an unformatted object pointer data element.
Definition: qs.h:744
an event was posted (LIFO) directly to AO
Definition: qs.h:86
#define QF_PTR_AT_(base_, i_)
access element at index i_ from the base pointer base_
Definition: qf_pkg.h:114
struct QHsmVtbl super
inherits QHsmVtbl
Definition: qf.h:167
QEvt const * QActive_get_(QActive *const me)
Get an event from the event queue of an active object.
Definition: qf_actq.c:266
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:205
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:700
#define QF_NO_MARGIN
special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition: qf.h:645
void QActive_postLIFO_(QActive *const me, QEvt const *const e)
Implementation of the active object post LIFO operation.
Definition: qf_actq.c:193
bool QActive_post_(QActive *const me, QEvt const *const e, uint_fast16_t const margin, void const *const sender)
Implementation of the active object post (FIFO) operation.
Definition: qf_actq.c:93
uint_fast8_t QEQueueCtr
The data type to store the ring-buffer counters based on the macro QF_EQUEUE_CTR_SIZE.
Definition: qequeue.h:76
Active Object (based on QHsm implementation)
Definition: qf.h:110
QActive * QF_active_[QF_MAX_ACTIVE+1]
array of registered active objects
Definition: qf_act.c:53
#define Q_ERROR_ID(id_)
Assertion with user-specified assertion-id for a wrong path.
Definition: qassert.h:192
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81