QP/C  5.8.2
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 /****************************************************************************/
99 #ifndef Q_SPY
100 bool QActive_post_(QActive * const me, QEvt const * const e,
101  uint_fast16_t const margin)
102 #else
103 bool QActive_post_(QActive * const me, QEvt const * const e,
104  uint_fast16_t const margin, void const * const sender)
105 #endif
106 {
107  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
108  bool status;
110 
112  Q_REQUIRE_ID(100, e != (QEvt const *)0);
113 
114  QF_CRIT_ENTRY_();
115  nFree = me->eQueue.nFree; /* get volatile into the temporary */
116 
117  /* margin available? */
118  if (nFree > (QEQueueCtr)margin) {
119 
121  QS_TIME_(); /* timestamp */
122  QS_OBJ_(sender); /* the sender object */
123  QS_SIG_(e->sig); /* the signal of the event */
124  QS_OBJ_(me); /* this active object (recipient) */
125  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
126  QS_EQC_(nFree); /* number of free entries */
127  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
129 
130  /* is it a pool event? */
131  if (e->poolId_ != (uint8_t)0) {
132  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
133  }
134 
135  --nFree; /* one free entry just used up */
136  me->eQueue.nFree = nFree; /* update the volatile */
137  if (me->eQueue.nMin > nFree) {
138  me->eQueue.nMin = nFree; /* update minimum so far */
139  }
140 
141  /* empty queue? */
142  if (me->eQueue.frontEvt == (QEvt const *)0) {
143  me->eQueue.frontEvt = e; /* deliver event directly */
144  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
145  }
146  /* queue is not empty, insert event into the ring-buffer */
147  else {
148  /* insert event into the ring buffer (FIFO) */
149  QF_PTR_AT_(me->eQueue.ring, me->eQueue.head) = e;
150  if (me->eQueue.head == (QEQueueCtr)0) { /* need to wrap head? */
151  me->eQueue.head = me->eQueue.end; /* wrap around */
152  }
153  --me->eQueue.head; /* advance the head (counter clockwise) */
154  }
155  QF_CRIT_EXIT_();
156 
157  status = true; /* event posted successfully */
158  }
159  else {
163  Q_ASSERT_ID(110, margin != (uint_fast16_t)0);
164 
166  QS_TIME_(); /* timestamp */
167  QS_OBJ_(sender); /* the sender object */
168  QS_SIG_(e->sig); /* the signal of the event */
169  QS_OBJ_(me); /* this active object (recipient) */
170  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
171  QS_EQC_(nFree); /* number of free entries */
172  QS_EQC_(margin); /* margin requested */
174 
175  QF_CRIT_EXIT_();
176 
177  QF_gc(e); /* recycle the event to avoid a leak */
178  status = false; /* event not posted */
179  }
180 
181  return status;
182 }
183 
184 /****************************************************************************/
198 void QActive_postLIFO_(QActive * const me, QEvt const * const e) {
199  QEvt const *frontEvt; /* temporary to avoid UB for volatile access */
200  QEQueueCtr nFree; /* temporary to avoid UB for volatile access */
202 
203  QF_CRIT_ENTRY_();
204  nFree = me->eQueue.nFree; /* get volatile into the temporary */
205 
206  /* the queue must be able to accept the event (cannot overflow) */
207  Q_ASSERT_ID(210, nFree != (QEQueueCtr)0);
208 
210  QS_TIME_(); /* timestamp */
211  QS_SIG_(e->sig); /* the signal of this event */
212  QS_OBJ_(me); /* this active object */
213  QS_2U8_(e->poolId_, e->refCtr_);/* pool Id & ref Count of the event */
214  QS_EQC_(nFree); /* number of free entries */
215  QS_EQC_(me->eQueue.nMin); /* min number of free entries */
217 
218  /* is it a pool event? */
219  if (e->poolId_ != (uint8_t)0) {
220  QF_EVT_REF_CTR_INC_(e); /* increment the reference counter */
221  }
222 
223  --nFree; /* one free entry just used up */
224  me->eQueue.nFree = nFree; /* update the volatile */
225  if (me->eQueue.nMin > nFree) {
226  me->eQueue.nMin = nFree; /* update minimum so far */
227  }
228 
229  frontEvt = me->eQueue.frontEvt; /* read volatile into the temporary */
230  me->eQueue.frontEvt = e; /* deliver the event directly to the front */
231 
232  /* was the queue empty? */
233  if (frontEvt == (QEvt const *)0) {
234  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
235  }
236  /* queue was not empty, leave the event in the ring-buffer */
237  else {
238  ++me->eQueue.tail;
239  /* need to wrap the tail? */
240  if (me->eQueue.tail == me->eQueue.end) {
241  me->eQueue.tail = (QEQueueCtr)0; /* wrap around */
242  }
243 
244  QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail) = frontEvt;
245  }
246  QF_CRIT_EXIT_();
247 }
248 
249 /****************************************************************************/
262 QEvt const *QActive_get_(QActive * const me) {
263  QEQueueCtr nFree;
264  QEvt const *e;
266  QF_CRIT_ENTRY_();
267 
268  QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
269 
270  e = me->eQueue.frontEvt; /* always remove event from the front location */
271  nFree= me->eQueue.nFree + (QEQueueCtr)1; /* get volatile into tmp */
272  me->eQueue.nFree = nFree; /* update the number of free */
273 
274  /* any events in the ring buffer? */
275  if (nFree <= me->eQueue.end) {
276 
277  /* remove event from the tail */
278  me->eQueue.frontEvt = QF_PTR_AT_(me->eQueue.ring, me->eQueue.tail);
279  if (me->eQueue.tail == (QEQueueCtr)0) { /* need to wrap the tail? */
280  me->eQueue.tail = me->eQueue.end; /* wrap around */
281  }
282  --me->eQueue.tail;
283 
285  QS_TIME_(); /* timestamp */
286  QS_SIG_(e->sig); /* the signal of this event */
287  QS_OBJ_(me); /* this active object */
288  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
289  QS_EQC_(nFree); /* number of free entries */
291  }
292  else {
293  me->eQueue.frontEvt = (QEvt const *)0; /* queue becomes empty */
294 
295  /* all entries in the queue must be free (+1 for fronEvt) */
296  Q_ASSERT_ID(310, nFree == (me->eQueue.end + (QEQueueCtr)1));
297 
299  QS_TIME_(); /* timestamp */
300  QS_SIG_(e->sig); /* the signal of this event */
301  QS_OBJ_(me); /* this active object */
302  QS_2U8_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
304  }
305  QF_CRIT_EXIT_();
306  return e;
307 }
308 
309 /****************************************************************************/
328  uint_fast16_t min;
330 
331  Q_REQUIRE_ID(400, (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
332  && (QF_active_[prio] != (QActive *)0));
333 
334  QF_CRIT_ENTRY_();
335  min = (uint_fast16_t)QF_active_[prio]->eQueue.nMin;
336  QF_CRIT_EXIT_();
337 
338  return min;
339 }
340 
341 
342 /****************************************************************************/
343 /****************************************************************************/
344 static void QTicker_init_(QHsm * const me, QEvt const * const e);
345 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e);
346 #ifdef Q_SPY
347 
348  static bool QTicker_post_(QActive * const me, QEvt const * const e,
349  uint_fast16_t const margin, void const * const sender);
350 #else
351  static bool QTicker_post_(QActive * const me, QEvt const * const e,
352  uint_fast16_t const margin);
353 #endif
354 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e);
355 
356 /*..........................................................................*/
358 void QTicker_ctor(QTicker * const me, uint8_t tickRate) {
359  static QActiveVtbl const vtbl = { /* QActiveVtbl virtual table */
360  { &QTicker_init_,
361  &QTicker_dispatch_ },
363  &QTicker_post_,
364  &QTicker_postLIFO_
365  };
366  QActive_ctor(me, Q_STATE_CAST(0)); /* superclass' ctor */
367  me->super.vptr = &vtbl.super; /* hook the vptr */
368 
369  /* reuse eQueue.head for tick-rate */
370  me->eQueue.head = (QEQueueCtr)tickRate;
371 }
372 /*..........................................................................*/
373 static void QTicker_init_(QHsm * const me, QEvt const * const e) {
374  (void)me;
375  (void)e;
376  ((QActive *)me)->eQueue.tail = (QEQueueCtr)0;
377 }
378 /*..........................................................................*/
379 static void QTicker_dispatch_(QHsm * const me, QEvt const * const e) {
380  QEQueueCtr n;
382 
383  (void)e; /* unused parameter */
384 
385  QF_CRIT_ENTRY_();
386  n = ((QActive *)me)->eQueue.tail; /* # ticks since last call */
387  ((QActive *)me)->eQueue.tail = (QEQueueCtr)0; /* clear the # ticks */
388  QF_CRIT_EXIT_();
389 
390  for (; n > (QEQueueCtr)0; --n) {
391  QF_TICK_X(((QActive const *)me)->eQueue.head, me);
392  }
393 }
394 /*..........................................................................*/
395 #ifndef Q_SPY
396 static bool QTicker_post_(QActive * const me, QEvt const * const e,
397  uint_fast16_t const margin)
398 #else
399 static bool QTicker_post_(QActive * const me, QEvt const * const e,
400  uint_fast16_t const margin,
401  void const * const sender)
402 #endif
403 {
405 
406  (void)e; /* unused parameter */
407  (void)margin; /* unused parameter */
408 
409  QF_CRIT_ENTRY_();
410  if (me->eQueue.frontEvt == (QEvt const *)0) {
411 
412  static QEvt const tickEvt = { (QSignal)0, (uint8_t)0, (uint8_t)0 };
413  me->eQueue.frontEvt = &tickEvt; /* deliver event directly */
414  --me->eQueue.nFree; /* one less free event */
415 
416  QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
417  }
418 
419  ++me->eQueue.tail; /* account for one more tick event */
420 
422  QS_TIME_(); /* timestamp */
423  QS_OBJ_(sender); /* the sender object */
424  QS_SIG_((QSignal)0); /* the signal of the event */
425  QS_OBJ_(me); /* this active object */
426  QS_2U8_((uint8_t)0, (uint8_t)0); /* pool Id & refCtr of the evt */
427  QS_EQC_((uint8_t)0); /* number of free entries */
428  QS_EQC_((uint8_t)0); /* min number of free entries */
430 
431  QF_CRIT_EXIT_();
432 
433  return true; /* the event is always posted correctly */
434 }
435 /*..........................................................................*/
436 static void QTicker_postLIFO_(QActive * const me, QEvt const * const e) {
437  (void)me;
438  (void)e;
439  Q_ERROR_ID(900);
440 }
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:682
#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:282
void QTicker_ctor(QTicker *const me, uint8_t tickRate)
"constructor" of QTicker
Definition: qf_actq.c:358
#define QF_TICK_X(tickRate_, sender_)
Invoke the system clock tick processing QF_tickX_().
Definition: qf.h:618
#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:399
AO got an event and its queue is still 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:161
#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
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
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition: qep.h:227
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:130
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:327
void QF_gc(QEvt const *const e)
Recycle a dynamic event.
Definition: qf_dyn.c:211
Event structure.
Definition: qep.h:153
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:130
Definition: qep.h:281
#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:248
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:169
#define QS_OBJ_(obj_)
Internal macro to output an unformatted object pointer data element.
Definition: qs.h:718
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:262
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:182
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:674
void QActive_postLIFO_(QActive *const me, QEvt const *const e)
Implementation of the active object post LIFO operation.
Definition: qf_actq.c:198
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:103
void const * aoObjFilter
active object for QF local filter
Definition: qs.h:1049
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:162
uint8_t poolId_
pool ID (0 for static event)
Definition: qep.h:155
uint8_t volatile refCtr_
reference counter
Definition: qep.h:156
#define Q_ERROR_ID(id_)
Assertion with user-specified assertion-id for a wrong path.
Definition: qassert.h:186
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81