QP/C  7.2.2
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_actq.c
Go to the documentation of this file.
1/*$file${src::qf::qf_actq.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
2/*
3* Model: qpc.qm
4* File: ${src::qf::qf_actq.c}
5*
6* This code has been generated by QM 5.2.5 <www.state-machine.com/qm>.
7* DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8*
9* This code is covered by the following QP license:
10* License # : LicenseRef-QL-dual
11* Issued to : Any user of the QP/C real-time embedded framework
12* Framework(s) : qpc
13* Support ends : 2023-12-31
14* License scope:
15*
16* Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17*
18* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
19*
20* This software is dual-licensed under the terms of the open source GNU
21* General Public License version 3 (or any later version), or alternatively,
22* under the terms of one of the closed source Quantum Leaps commercial
23* licenses.
24*
25* The terms of the open source GNU General Public License version 3
26* can be found at: <www.gnu.org/licenses/gpl-3.0>
27*
28* The terms of the closed source Quantum Leaps commercial licenses
29* can be found at: <www.state-machine.com/licensing>
30*
31* Redistributions in source code must retain this top-level comment block.
32* Plagiarizing this software to sidestep the license obligations is illegal.
33*
34* Contact information:
35* <www.state-machine.com/licensing>
36* <info@state-machine.com>
37*/
38/*$endhead${src::qf::qf_actq.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
39/*! @file
40* @brief ::QActive native queue operations (based on ::QEQueue)
41*
42* @note
43* This `qf_actq.c` source file needs to be included in the application
44* build only when the native ::QEQueue queue is used for ::QActive objects
45* (instead of a message queue of an RTOS).
46*/
47#define QP_IMPL /* this is QP implementation */
48#include "qf_port.h" /* QF port */
49#include "qf_pkg.h" /* QF package-scope interface */
50#include "qassert.h" /* QP embedded systems-friendly assertions */
51#ifdef Q_SPY /* QS software tracing enabled? */
52 #include "qs_port.h" /* QS port */
53 #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
54#else
55 #include "qs_dummy.h" /* disable the QS software tracing */
56#endif /* Q_SPY */
57
58Q_DEFINE_THIS_MODULE("qf_actq")
59
60/*==========================================================================*/
61/*$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
62/* Check for the minimum required QP version */
63#if (QP_VERSION < 700U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
64#error qpc version 7.0.0 or higher required
65#endif
66/*$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
67
68/*$define${QF::QActive::post_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
69
70/*${QF::QActive::post_} ....................................................*/
71/*! @private @memberof QActive */
72bool QActive_post_(QActive * const me,
73 QEvt const * const e,
74 uint_fast16_t const margin,
75 void const * const sender)
76{
77 #ifndef Q_SPY
78 Q_UNUSED_PAR(sender);
79 #endif
80
81 Q_REQUIRE_ID(100, e != (QEvt *)0);
82
84 QF_CRIT_E_();
85 QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into temporary */
86
87 /* test-probe#1 for faking queue overflow */
88 QS_TEST_PROBE_DEF(&QActive_post_)
90 nFree = 0U;
91 )
92
93 bool status;
94 if (margin == QF_NO_MARGIN) {
95 if (nFree > 0U) {
96 status = true; /* can post */
97 }
98 else {
99 status = false; /* cannot post */
100 Q_ERROR_CRIT_(190); /* must be able to post the event */
101 }
102 }
103 else if (nFree > (QEQueueCtr)margin) {
104 status = true; /* can post */
105 }
106 else {
107 status = false; /* cannot post, but don't assert */
108 }
109
110 /* is it a dynamic event? */
111 if (e->poolId_ != 0U) {
112 QEvt_refCtr_inc_(e); /* increment the reference counter */
113 }
114
115 if (status) { /* can post the event? */
116
117 --nFree; /* one free entry just used up */
118 me->eQueue.nFree = nFree; /* update the original */
119 if (me->eQueue.nMin > nFree) {
120 me->eQueue.nMin = nFree; /* increase minimum so far */
121 }
122
124 QS_TIME_PRE_(); /* timestamp */
125 QS_OBJ_PRE_(sender); /* the sender object */
126 QS_SIG_PRE_(e->sig); /* the signal of the event */
127 QS_OBJ_PRE_(me); /* this active object (recipient) */
128 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
129 QS_EQC_PRE_(nFree); /* number of free entries */
130 QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
132
133 #ifdef Q_UTEST
134 /* callback to examine the posted event under the same conditions
135 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
136 * the local filter for this AO ('me->prio') is set
137 */
138 if (QS_LOC_CHECK_(me->prio)) {
139 /* callback to examine the posted event */
140 QS_onTestPost(sender, me, e, status);
141 }
142 #endif
143
144 /* empty queue? */
145 if (me->eQueue.frontEvt == (QEvt *)0) {
146 me->eQueue.frontEvt = e; /* deliver event directly */
147 QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
148 }
149 /* queue is not empty, insert event into the ring-buffer */
150 else {
151 /* insert event into the ring buffer (FIFO) */
152 me->eQueue.ring[me->eQueue.head] = e;
153
154 if (me->eQueue.head == 0U) { /* need to wrap head? */
155 me->eQueue.head = me->eQueue.end; /* wrap around */
156 }
157 --me->eQueue.head; /* advance the head (counter clockwise) */
158 }
159
160 QF_CRIT_X_();
161 }
162 else { /* cannot post the event */
163
165 QS_TIME_PRE_(); /* timestamp */
166 QS_OBJ_PRE_(sender); /* the sender object */
167 QS_SIG_PRE_(e->sig); /* the signal of the event */
168 QS_OBJ_PRE_(me); /* this active object (recipient) */
169 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
170 QS_EQC_PRE_(nFree); /* number of free entries */
171 QS_EQC_PRE_(margin); /* margin requested */
173
174 #ifdef Q_UTEST
175 /* callback to examine the posted event under the same conditions
176 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
177 * the local filter for this AO ('me->prio') is set
178 */
179 if (QS_LOC_CHECK_(me->prio)) {
180 QS_onTestPost(sender, me, e, status);
181 }
182 #endif
183
184 QF_CRIT_X_();
185
186 #if (QF_MAX_EPOOL > 0U)
187 QF_gc(e); /* recycle the event to avoid a leak */
188 #endif
189 }
190
191 return status;
192}
193/*$enddef${QF::QActive::post_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
194/*$define${QF::QActive::postLIFO_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
195
196/*${QF::QActive::postLIFO_} ................................................*/
197/*! @private @memberof QActive */
198void QActive_postLIFO_(QActive * const me,
199 QEvt const * const e)
200{
202 QF_CRIT_E_();
203 QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into temporary */
204
205 /* test-probe#1 for faking queue overflow */
206 QS_TEST_PROBE_DEF(&QActive_postLIFO_)
208 nFree = 0U;
209 )
210
211 Q_REQUIRE_CRIT_(200, nFree != 0U);
212
213 /* is it a dynamic event? */
214 if (e->poolId_ != 0U) {
215 QEvt_refCtr_inc_(e); /* increment the reference counter */
216 }
217
218 --nFree; /* one free entry just used up */
219 me->eQueue.nFree = nFree; /* update the original */
220 if (me->eQueue.nMin > nFree) {
221 me->eQueue.nMin = nFree; /* update minimum so far */
222 }
223
225 QS_TIME_PRE_(); /* timestamp */
226 QS_SIG_PRE_(e->sig); /* the signal of this event */
227 QS_OBJ_PRE_(me); /* this active object */
228 QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count */
229 QS_EQC_PRE_(nFree); /* # free entries */
230 QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
232
233 #ifdef Q_UTEST
234 /* callback to examine the posted event under the same conditions
235 * as producing the #QS_QF_ACTIVE_POST trace record, which are:
236 * the local filter for this AO ('me->prio') is set
237 */
238 if (QS_LOC_CHECK_(me->prio)) {
239 QS_onTestPost((QActive *)0, me, e, true);
240 }
241 #endif
242
243 QEvt const * const frontEvt = me->eQueue.frontEvt;
244 me->eQueue.frontEvt = e; /* deliver the event directly to the front */
245
246 /* was the queue empty? */
247 if (frontEvt == (QEvt *)0) {
248 QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
249 }
250 /* queue was not empty, leave the event in the ring-buffer */
251 else {
252 ++me->eQueue.tail;
253 /* need to wrap the tail? */
254 if (me->eQueue.tail == me->eQueue.end) {
255 me->eQueue.tail = 0U; /* wrap around */
256 }
257
258 me->eQueue.ring[me->eQueue.tail] = frontEvt;
259 }
260 QF_CRIT_X_();
261}
262/*$enddef${QF::QActive::postLIFO_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
263/*$define${QF::QActive::get_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
264
265/*${QF::QActive::get_} .....................................................*/
266/*! @private @memberof QActive */
267QEvt const * QActive_get_(QActive * const me) {
269 QF_CRIT_E_();
270 QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
271
272 /* always remove event from the front */
273 QEvt const * const e = me->eQueue.frontEvt;
274 QEQueueCtr const nFree = me->eQueue.nFree + 1U; /* get volatile into tmp */
275 me->eQueue.nFree = nFree; /* update the number of free */
276
277 /* any events in the ring buffer? */
278 if (nFree <= me->eQueue.end) {
279
280 /* remove event from the tail */
281 me->eQueue.frontEvt = me->eQueue.ring[me->eQueue.tail];
282 if (me->eQueue.tail == 0U) { /* need to wrap the tail? */
283 me->eQueue.tail = me->eQueue.end; /* wrap around */
284 }
285 --me->eQueue.tail;
286
288 QS_TIME_PRE_(); /* timestamp */
289 QS_SIG_PRE_(e->sig); /* the signal of this event */
290 QS_OBJ_PRE_(me); /* this active object */
291 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
292 QS_EQC_PRE_(nFree); /* # free entries */
294 }
295 else {
296 me->eQueue.frontEvt = (QEvt *)0; /* queue becomes empty */
297
298 /* all entries in the queue must be free (+1 for fronEvt) */
299 Q_ASSERT_CRIT_(310, nFree == (me->eQueue.end + 1U));
300
302 QS_TIME_PRE_(); /* timestamp */
303 QS_SIG_PRE_(e->sig); /* the signal of this event */
304 QS_OBJ_PRE_(me); /* this active object */
305 QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
307 }
308 QF_CRIT_X_();
309 return e;
310}
311/*$enddef${QF::QActive::get_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
312
313/*$define${QF::QF-base::getQueueMin} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
314
315/*${QF::QF-base::getQueueMin} ..............................................*/
316/*! @static @public @memberof QF */
317uint_fast16_t QF_getQueueMin(uint_fast8_t const prio) {
318 Q_REQUIRE_ID(400, (prio <= QF_MAX_ACTIVE)
319 && (QActive_registry_[prio] != (QActive *)0));
321 QF_CRIT_E_();
322 uint_fast16_t const min =
323 (uint_fast16_t)QActive_registry_[prio]->eQueue.nMin;
324 QF_CRIT_X_();
325
326 return min;
327}
328/*$enddef${QF::QF-base::getQueueMin} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
329
330/*==========================================================================*/
331/*! Perform downcast to QTicker pointer.
332*
333* @details
334* This macro encapsulates the downcast to (QTicker *), which is used in
335* QTicker_init_() and QTicker_dispatch_(). Such casts violate MISRA-C 2012
336* Rule 11.3(req) "cast from pointer to object type to pointer to different
337* object type".
338*
339* @trace
340* - @tr{DVP-QP-MC3-R11_03A}
341* - @tr{DVP-QP-PCLP-826}
342*/
343#define QTICKER_CAST_(me_) ((QActive *)(me_))
344
345/*$define${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
346
347/*${QF::QTicker} ...........................................................*/
348
349/*${QF::QTicker::ctor} .....................................................*/
350/*! @public @memberof QTicker */
351void QTicker_ctor(QTicker * const me,
352 uint_fast8_t const tickRate)
353{
354 static QActiveVtable const vtable = { /* QActive virtual table */
355 { &QTicker_init_,
356 &QTicker_dispatch_
357 #ifdef Q_SPY
358 ,&QHsm_getStateHandler_
359 #endif
360 },
362 &QTicker_post_,
363 &QTicker_postLIFO_
364 };
365 QActive_ctor(&me->super, Q_STATE_CAST(0)); /* superclass' ctor */
366 me->super.super.vptr = &vtable.super; /* hook the vptr */
367
368 /* reuse eQueue.head for tick-rate */
369 me->super.eQueue.head = (QEQueueCtr)tickRate;
370}
371
372/*${QF::QTicker::init_} ....................................................*/
373/*! @private @memberof QTicker */
374void QTicker_init_(
375 QHsm * const me,
376 void const * const par,
377 uint_fast8_t const qs_id)
378{
379 Q_UNUSED_PAR(me);
380 Q_UNUSED_PAR(par);
381 Q_UNUSED_PAR(qs_id);
382
383 QTICKER_CAST_(me)->eQueue.tail = 0U;
384}
385
386/*${QF::QTicker::dispatch_} ................................................*/
387/*! @private @memberof QTicker */
388void QTicker_dispatch_(
389 QHsm * const me,
390 QEvt const * const e,
391 uint_fast8_t const qs_id)
392{
393 Q_UNUSED_PAR(e);
394 Q_UNUSED_PAR(qs_id);
395
397 QF_CRIT_E_();
398 QEQueueCtr nTicks = QTICKER_CAST_(me)->eQueue.tail; /* save # of ticks */
399 QTICKER_CAST_(me)->eQueue.tail = 0U; /* clear # ticks */
400 QF_CRIT_X_();
401
402 for (; nTicks > 0U; --nTicks) {
403 QTimeEvt_tick_((uint_fast8_t)QTICKER_CAST_(me)->eQueue.head, me);
404 }
405}
406
407/*${QF::QTicker::post_} ....................................................*/
408/*! @private @memberof QTicker */
409bool QTicker_post_(
410 QActive * const me,
411 QEvt const * const e,
412 uint_fast16_t const margin,
413 void const * const sender)
414{
415 Q_UNUSED_PAR(e);
416 Q_UNUSED_PAR(margin);
417 #ifndef Q_SPY
418 Q_UNUSED_PAR(sender);
419 #endif
420
422 QF_CRIT_E_();
423 if (me->eQueue.frontEvt == (QEvt *)0) {
424
425 static QEvt const tickEvt = { 0U, 0U, 0U };
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_PRE_(); /* timestamp */
436 QS_OBJ_PRE_(sender); /* the sender object */
437 QS_SIG_PRE_(0U); /* the signal of the event */
438 QS_OBJ_PRE_(me); /* this active object */
439 QS_2U8_PRE_(0U, 0U); /* pool Id & refCtr of the evt */
440 QS_EQC_PRE_(0U); /* number of free entries */
441 QS_EQC_PRE_(0U); /* min number of free entries */
443
444 QF_CRIT_X_();
445
446 return true; /* the event is always posted correctly */
447}
448
449/*${QF::QTicker::postLIFO_} ................................................*/
450/*! @private @memberof QTicker */
451void QTicker_postLIFO_(
452 QActive * const me,
453 QEvt const * const e)
454{
455 Q_UNUSED_PAR(me);
456 Q_UNUSED_PAR(e);
457
458 Q_ERROR_ID(900);
459}
460/*$enddef${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
Customizable and memory-efficient Design by Contract (DbC) for embedded systems.
#define Q_REQUIRE_ID(id_, expr_)
Definition: qassert.h:240
#define Q_ERROR_ID(id_)
Definition: qassert.h:125
#define Q_UNUSED_PAR(par_)
Definition: qep.h:1108
#define Q_STATE_CAST(handler_)
Definition: qep.h:1089
uint16_t QEQueueCtr
Definition: qequeue.h:70
#define QF_NO_MARGIN
Definition: qf.h:1834
#define QTICKER_CAST_(me_)
Definition: qf_actq.c:343
Internal (package scope) QF/C interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.h:113
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.h:161
#define QF_CRIT_X_()
Definition: qf_pkg.h:143
#define Q_REQUIRE_CRIT_(id_, test_)
Definition: qf_pkg.h:173
#define QF_CRIT_E_()
Definition: qf_pkg.h:128
#define Q_ERROR_CRIT_(id_)
Definition: qf_pkg.h:180
QF/C sample port with all configurable options.
#define QF_MAX_ACTIVE
Definition: qf_port.h:71
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition: qk.h:270
#define QACTIVE_EQUEUE_WAIT_(me_)
Definition: qk.h:251
void QS_onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
#define QS_TIME_PRE_()
Definition: qs.h:1313
@ QS_QF_ACTIVE_POST_LIFO
Definition: qs.h:180
@ QS_QF_ACTIVE_GET
Definition: qs.h:181
@ QS_QF_ACTIVE_POST_ATTEMPT
Definition: qs.h:224
#define QS_TEST_PROBE_DEF(fun_)
Definition: qs.h:1877
#define QS_LOC_CHECK_(qs_id_)
Definition: qs.h:1178
@ QS_QF_ACTIVE_POST
Definition: qs.h:179
#define QS_TEST_PROBE_ID(id_, code_)
Definition: qs.h:1889
@ QS_QF_ACTIVE_GET_LAST
Definition: qs.h:182
Internal (package scope) QS/C interface.
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_pkg.h:136
#define QS_OBJ_PRE_(obj_)
Definition: qs_pkg.h:209
#define QS_END_NOCRIT_PRE_()
Definition: qs_pkg.h:149
#define QS_2U8_PRE_(data1_, data2_)
Definition: qs_pkg.h:163
#define QS_SIG_PRE_(sig_)
Definition: qs_pkg.h:195
#define QS_EQC_PRE_(ctr_)
Definition: qs_pkg.h:245
QS/C sample port with all configurable options.
void QActive_start_(QActive *const me, QPrioSpec const prioSpec, QEvt const **const qSto, uint_fast16_t const qLen, void *const stkSto, uint_fast16_t const stkSize, void const *const par)
Definition: qutest.c:213
Active object class (based on the QHsm implementation strategy)
Definition: qf.h:426
QHsm super
Definition: qf.h:428
QF_EQUEUE_TYPE eQueue
Definition: qf.h:446
uint8_t prio
Definition: qf.h:480
Virtual table for the QActive class.
Definition: qf.h:992
struct QHsmVtable super
Definition: qf.h:993
Event class.
Definition: qep.h:171
QSignal sig
Definition: qep.h:180
uint8_t poolId_
Definition: qep.h:190
uint8_t volatile refCtr_
Definition: qep.h:198
Hierarchical State Machine class.
Definition: qep.h:364
struct QHsmVtable const * vptr
Definition: qep.h:373
"Ticker" Active Object class
Definition: qf.h:1424
QActive super
Definition: qf.h:1426