QP/C  5.9.5
qf_actq.c
Go to the documentation of this file.
1 
44 #define QP_IMPL /* this is QP implementation */
45 #include "qf_port.h" /* QF port */
46 #include "qf_pkg.h" /* QF package-scope interface */
47 #include "qassert.h" /* QP embedded systems-friendly assertions */
48 #ifdef Q_SPY /* QS software tracing enabled? */
49  #include "qs_port.h" /* include QS port */
50 #else
51  #include "qs_dummy.h" /* disable the QS software tracing */
52 #endif /* Q_SPY */
53 
54 Q_DEFINE_THIS_MODULE("qf_actq")
55 
56 
57 /****************************************************************************/
97 #ifndef Q_SPY
98 bool QActive_post_(QActive * const me, QEvt const * const e,
99  uint_fast16_t const margin)
100 #else
101 bool QActive_post_(QActive * const me, QEvt const * const e,
102  uint_fast16_t const margin, void const * const sender)
103 #endif
104 {
105  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
106  bool status;
108 
110  Q_REQUIRE_ID(100, e != (QEvt const *)0);
111 
112  QF_CRIT_ENTRY_();
113  nFree = me->eQueue.nFree; /* get volatile into the temporary */
114 
115  /* margin available? */
116  if (((margin == QF_NO_MARGIN) && (nFree > (QEQueueCtr)0))
117  || (nFree > (QEQueueCtr)margin))
118  {
119 
121  QS_priv_.locFilter[AO_OBJ], me)
122  QS_TIME_(); /* timestamp */
123  QS_OBJ_(sender); /* the sender object */
124  QS_SIG_(e->sig); /* the signal of the event */
125  QS_OBJ_(me); /* this active object (recipient) */
126  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
127  QS_EQC_(nFree); /* number of free entries */
128  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
130 
131  /* is it a pool event? */
132  if (e->poolId_ != (uint8_t)0) {
133  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
134  }
135 
136  --nFree; /* one free entry just used up */
137  me->eQueue.nFree = nFree; /* update the volatile */
138  if (me->eQueue.nMin > nFree) {
139  me->eQueue.nMin = nFree; /* update minimum so far */
140  }
141 
142  /* empty queue? */
143  if (me->eQueue.frontEvt == (QEvt const *)0) {
144  me->eQueue.frontEvt = e; /* deliver event directly */
145  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
146  }
147  /* queue is not empty, insert event into the ring-buffer */
148  else {
149  /* insert event into the ring buffer (FIFO) */
150  QF_PTR_AT_(me->eQueue.ring, me->eQueue.head) = e;
151  if (me->eQueue.head == (QEQueueCtr)0) { /* need to wrap head? */
152  me->eQueue.head = me->eQueue.end; /* wrap around */
153  }
154  --me->eQueue.head; /* advance the head (counter clockwise) */
155  }
156  QF_CRIT_EXIT_();
157 
158  status = true; /* event posted successfully */
159  }
160  else {
164  Q_ASSERT_ID(110, margin != QF_NO_MARGIN);
165 
167  QS_priv_.locFilter[AO_OBJ], me)
168  QS_TIME_(); /* timestamp */
169  QS_OBJ_(sender); /* the sender object */
170  QS_SIG_(e->sig); /* the signal of the event */
171  QS_OBJ_(me); /* this active object (recipient) */
172  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
173  QS_EQC_(nFree); /* number of free entries */
174  QS_EQC_(margin); /* margin requested */
176 
177  QF_CRIT_EXIT_();
178 
179  QF_gc(e); /* recycle the event to avoid a leak */
180  status = false; /* event not posted */
181  }
182 
183  return status;
184 }
185 
186 /****************************************************************************/
200 void QActive_postLIFO_(QActive * const me, QEvt const * const e) {
201  QEvt const *frontEvt; /* temporary to avoid UB for volatile access */
202  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
204 
205  QF_CRIT_ENTRY_();
206  nFree = me->eQueue.nFree; /* get volatile into the temporary */
207 
208  /* the queue must be able to accept the event (cannot overflow) */
209  Q_ASSERT_ID(210, nFree != (QEQueueCtr)0);
210 
212  QS_TIME_(); /* timestamp */
213  QS_SIG_(e->sig); /* the signal of this event */
214  QS_OBJ_(me); /* this active object */
215  QS_2U8_(e->poolId_, e->refCtr_);/* pool Id & ref Count of the event */
216  QS_EQC_(nFree); /* number of free entries */
217  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
219 
220  /* is it a pool event? */
221  if (e->poolId_ != (uint8_t)0) {
222  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
223  }
224 
225  --nFree; /* one free entry just used up */
226  me->eQueue.nFree = nFree; /* update the volatile */
227  if (me->eQueue.nMin > nFree) {
228  me->eQueue.nMin = nFree; /* update minimum so far */
229  }
230 
231  frontEvt = me->eQueue.frontEvt; /* read volatile into the temporary */
232  me->eQueue.frontEvt = e; /* deliver the event directly to the front */
233 
234  /* was the queue empty? */
235  if (frontEvt == (QEvt const *)0) {
236  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
237  }
238  /* queue was not empty, leave the event in the ring-buffer */
239  else {
240  ++me->eQueue.tail;
241  /* need to wrap the tail? */
242  if (me->eQueue.tail == me->eQueue.end) {
243  me->eQueue.tail = (QEQueueCtr)0; /* wrap around */
244  }
245 
246  QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail) = frontEvt;
247  }
248  QF_CRIT_EXIT_();
249 }
250 
251 /****************************************************************************/
264 QEvt const *QActive_get_(QActive * const me) {
265  QEQueueCtr nFree;
266  QEvt const *e;
268  QF_CRIT_ENTRY_();
269 
270  QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
271 
272  e = me->eQueue.frontEvt; /* always remove event from the front location */
273  nFree = me->eQueue.nFree + (QEQueueCtr)1; /* get volatile into tmp */
274  me->eQueue.nFree = nFree; /* update the number of free */
275 
276  /* any events in the ring buffer? */
277  if (nFree <= me->eQueue.end) {
278 
279  /* remove event from the tail */
280  me->eQueue.frontEvt = QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail);
281  if (me->eQueue.tail == (QEQueueCtr)0) { /* need to wrap the tail? */
282  me->eQueue.tail = me->eQueue.end; /* wrap around */
283  }
284  --me->eQueue.tail;
285 
287  QS_TIME_(); /* timestamp */
288  QS_SIG_(e->sig); /* the signal of this event */
289  QS_OBJ_(me); /* this active object */
290  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
291  QS_EQC_(nFree); /* number of free entries */
293  }
294  else {
295  me->eQueue.frontEvt = (QEvt const *)0; /* queue becomes empty */
296 
297  /* all entries in the queue must be free (+1 for fronEvt) */
298  Q_ASSERT_ID(310, nFree == (me->eQueue.end + (QEQueueCtr)1));
299 
301  QS_priv_.locFilter[AO_OBJ], me)
302  QS_TIME_(); /* timestamp */
303  QS_SIG_(e->sig); /* the signal of this event */
304  QS_OBJ_(me); /* this active object */
305  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
307  }
308  QF_CRIT_EXIT_();
309  return e;
310 }
311 
312 /****************************************************************************/
331  uint_fast16_t min;
333 
334  Q_REQUIRE_ID(400, (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
335  && (QF_active_[prio] != (QActive *)0));
336 
337  QF_CRIT_ENTRY_();
338  min = (uint_fast16_t)QF_active_[prio]->eQueue.nMin;
339  QF_CRIT_EXIT_();
340 
341  return min;
342 }
343 
344 
345 /****************************************************************************/
346 /****************************************************************************/
355 #define QTICKER_CAST(me_) ((QTicker *)(me_))
356 
357 static void QTicker_init_(QHsm * const me, QEvt const * const e);
358 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e);
359 #ifdef Q_SPY
360 
361  static bool QTicker_post_(QActive * const me, QEvt const * const e,
362  uint_fast16_t const margin, void const * const sender);
363 #else
364  static bool QTicker_post_(QActive * const me, QEvt const * const e,
365  uint_fast16_t const margin);
366 #endif
367 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e);
368 
369 /*..........................................................................*/
371 void QTicker_ctor(QTicker * const me, uint8_t tickRate) {
372  static QActiveVtbl const vtbl = { /* QActiveVtbl virtual table */
373  { &QTicker_init_,
374  &QTicker_dispatch_ },
376  &QTicker_post_,
377  &QTicker_postLIFO_
378  };
379  QActive_ctor(me, Q_STATE_CAST(0)); /* superclass' ctor */
380  me->super.vptr = &vtbl.super; /* hook the vptr */
381 
382  /* reuse eQueue.head for tick-rate */
383  me->eQueue.head = (QEQueueCtr)tickRate;
384 }
385 /*..........................................................................*/
386 static void QTicker_init_(QHsm * const me, QEvt const * const e) {
387  (void)me;
388  (void)e;
389  QTICKER_CAST(me)->eQueue.tail = (QEQueueCtr)0;
390 }
391 /*..........................................................................*/
392 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e) {
393  QEQueueCtr n;
395 
396  (void)e; /* unused parameter */
397 
398  QF_CRIT_ENTRY_();
399  n = QTICKER_CAST(me)->eQueue.tail; /* # ticks since last call */
400  QTICKER_CAST(me)->eQueue.tail = (QEQueueCtr)0; /* clear the # ticks */
401  QF_CRIT_EXIT_();
402 
403  for (; n > (QEQueueCtr)0; --n) {
404  QF_TICK_X((uint_fast8_t)QTICKER_CAST(me)->eQueue.head, me);
405  }
406 }
407 /*..........................................................................*/
408 #ifndef Q_SPY
409 static bool QTicker_post_(QActive * const me, QEvt const * const e,
410  uint_fast16_t const margin)
411 #else
412 static bool QTicker_post_(QActive * const me, QEvt const * const e,
413  uint_fast16_t const margin,
414  void const * const sender)
415 #endif
416 {
418 
419  (void)e; /* unused parameter */
420  (void)margin; /* unused parameter */
421 
422  QF_CRIT_ENTRY_();
423  if (me->eQueue.frontEvt == (QEvt const *)0) {
424 
425  static QEvt const tickEvt = { (QSignal)0, (uint8_t)0, (uint8_t)0 };
426  me->eQueue.frontEvt = &tickEvt; /* deliver event directly */
427  --me->eQueue.nFree; /* one less free event */
428 
429  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
430  }
431 
432  ++me->eQueue.tail; /* account for one more tick event */
433 
435  QS_TIME_(); /* timestamp */
436  QS_OBJ_(sender); /* the sender object */
437  QS_SIG_((QSignal)0); /* the signal of the event */
438  QS_OBJ_(me); /* this active object */
439  QS_2U8_((uint8_t)0, (uint8_t)0); /* pool Id & refCtr of the evt */
440  QS_EQC_((uint8_t)0); /* number of free entries */
441  QS_EQC_((uint8_t)0); /* min number of free entries */
443 
444  QF_CRIT_EXIT_();
445 
446  return true; /* the event is always posted correctly */
447 }
448 /*..........................................................................*/
449 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e) {
450  (void)me;
451  (void)e;
452  Q_ERROR_ID(900);
453 }
#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
struct QHsmVtbl const * vptr
virtual pointer
Definition: qep.h:281
void QTicker_ctor(QTicker *const me, uint8_t tickRate)
"constructor" of QTicker
Definition: qf_actq.c:371
#define QTICKER_CAST(me_)
Perform downcast to QTicker pointer.
Definition: qf_actq.c:355
#define QF_TICK_X(tickRate_, sender_)
Invoke the system clock tick processing QF_tickX_().
Definition: qf.h:619
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
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:412
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:160
#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
QSignal sig
signal of the event instance
Definition: qep.h:153
#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:330
void QF_gc(QEvt const *const e)
Recycle a dynamic event.
Definition: qf_dyn.c:217
Event structure.
Definition: qep.h:152
attempt to post an evt to AO failed
Definition: qs.h:116
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
Definition: qep.h:280
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
QHsm super
inherits QHsm
Definition: qf.h:111
QEvt const * QActive_get_(QActive *const me)
Get an event from the event queue of an active object.
Definition: qf_actq.c:264
#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:631
void QActive_postLIFO_(QActive *const me, QEvt const *const e)
Implementation of the active object post LIFO operation.
Definition: qf_actq.c:200
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:101
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
struct QHsmVtbl super
inherits QHsmVtbl
Definition: qf.h:161
uint8_t poolId_
pool ID (0 for static event)
Definition: qep.h:154
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
uint8_t volatile refCtr_
reference counter
Definition: qep.h:155
#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