QP/C  7.4.0-rc.3
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} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qf::qf_actq.c}
5//
6// This code has been generated by QM 6.2.0 <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 : 2025-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qf::qf_actq.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.h" // QP port
45#include "qp_pkg.h" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.h" // QS port
49 #include "qs_pkg.h" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.h" // disable the QS software tracing
52#endif // Q_SPY
53
54Q_DEFINE_THIS_MODULE("qf_actq")
55
56//============================================================================
57//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
58// Check for the minimum required QP version
59#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
60#error qpc version 7.3.0 or higher required
61#endif
62//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63//$define${QF::QActive::post_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
64
65//${QF::QActive::post_} ......................................................
66//! @private @memberof QActive
67bool QActive_post_(QActive * const me,
68 QEvt const * const e,
69 uint_fast16_t const margin,
70 void const * const sender)
71{
72 #ifndef Q_SPY
73 Q_UNUSED_PAR(sender);
74 #endif
75
76 #ifdef Q_UTEST // test?
77 #if Q_UTEST != 0 // testing QP-stub?
78 if (me->super.temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
79 return QActiveDummy_fakePost_(me, e, margin, sender);
80 }
81 #endif
82 #endif
83
86 QF_MEM_SYS();
87
88 #ifndef Q_UNSAFE
89 Q_REQUIRE_INCRIT(100, QEvt_verify_(e));
90
91 uint8_t const pcopy = (uint8_t)(~me->prio_dis);
92 Q_INVARIANT_INCRIT(102, me->prio == pcopy);
93 #endif
94
95 QEQueueCtr nFree = me->eQueue.nFree; // get volatile into temporary
96
97 // test-probe#1 for faking queue overflow
98 QS_TEST_PROBE_DEF(&QActive_post_)
100 nFree = 0U;
101 )
102
103 bool status;
104 if (margin == QF_NO_MARGIN) {
105 if (nFree > 0U) {
106 status = true; // can post
107 }
108 else {
109 status = false; // cannot post
110 Q_ERROR_INCRIT(110); // must be able to post the event
111 }
112 }
113 else if (nFree > (QEQueueCtr)margin) {
114 status = true; // can post
115 }
116 else {
117 status = false; // cannot post, but don't assert
118 }
119
120 // is it a mutable event?
121 if (QEvt_getPoolNum_(e) != 0U) {
122 QEvt_refCtr_inc_(e); // increment the reference counter
123 }
124
125 if (status) { // can post the event?
126
127 --nFree; // one free entry just used up
128 me->eQueue.nFree = nFree; // update the original
129 if (me->eQueue.nMin > nFree) {
130 me->eQueue.nMin = nFree; // increase minimum so far
131 }
132
133 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, me->prio)
134 QS_TIME_PRE_(); // timestamp
135 QS_OBJ_PRE_(sender); // the sender object
136 QS_SIG_PRE_(e->sig); // the signal of the event
137 QS_OBJ_PRE_(me); // this active object (recipient)
138 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
139 QS_EQC_PRE_(nFree); // # free entries
140 QS_EQC_PRE_(me->eQueue.nMin); // min # free entries
141 QS_END_PRE_()
142
143 #ifdef Q_UTEST
144 // callback to examine the posted event under the same conditions
145 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
146 // the local filter for this AO ('me->prio') is set
147 if (QS_LOC_CHECK_(me->prio)) {
148 QF_MEM_APP();
149 QF_CRIT_EXIT();
150
151 QS_onTestPost(sender, me, e, status);
152
153 QF_CRIT_ENTRY();
154 QF_MEM_SYS();
155 }
156 #endif
157
158 if (me->eQueue.frontEvt == (QEvt *)0) { // empty queue?
159 me->eQueue.frontEvt = e; // deliver event directly
160
161 #ifdef QXK_H_
162 if (me->super.state.act == Q_ACTION_CAST(0)) { // eXtended?
163 QXTHREAD_EQUEUE_SIGNAL_(me); // signal the event queue
164 }
165 else {
166 QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
167 }
168 #else
169 QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
170 #endif
171 }
172 // queue is not empty, insert event into the ring-buffer
173 else {
174 // insert event into the ring buffer (FIFO)
175 me->eQueue.ring[me->eQueue.head] = e;
176
177 if (me->eQueue.head == 0U) { // need to wrap head?
178 me->eQueue.head = me->eQueue.end; // wrap around
179 }
180 --me->eQueue.head; // advance the head (counter clockwise)
181 }
182
183 QF_MEM_APP();
184 QF_CRIT_EXIT();
185 }
186 else { // cannot post the event
187
188 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, me->prio)
189 QS_TIME_PRE_(); // timestamp
190 QS_OBJ_PRE_(sender); // the sender object
191 QS_SIG_PRE_(e->sig); // the signal of the event
192 QS_OBJ_PRE_(me); // this active object (recipient)
193 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
194 QS_EQC_PRE_(nFree); // # free entries
195 QS_EQC_PRE_(margin); // margin requested
196 QS_END_PRE_()
197
198 #ifdef Q_UTEST
199 // callback to examine the posted event under the same conditions
200 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
201 // the local filter for this AO ('me->prio') is set
202 if (QS_LOC_CHECK_(me->prio)) {
203 QF_MEM_APP();
204 QF_CRIT_EXIT();
205
206 QS_onTestPost(sender, me, e, status);
207
208 QF_CRIT_ENTRY();
209 QF_MEM_SYS();
210 }
211 #endif
212
213 QF_MEM_APP();
214 QF_CRIT_EXIT();
215
216 #if (QF_MAX_EPOOL > 0U)
217 QF_gc(e); // recycle the event to avoid a leak
218 #endif
219 }
220
221 return status;
222}
223//$enddef${QF::QActive::post_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
224//$define${QF::QActive::postLIFO_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
225
226//${QF::QActive::postLIFO_} ..................................................
227//! @private @memberof QActive
228void QActive_postLIFO_(QActive * const me,
229 QEvt const * const e)
230{
231 #ifdef Q_UTEST // test?
232 #if Q_UTEST != 0 // testing QP-stub?
233 if (me->super.temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
234 QActiveDummy_fakePostLIFO_(me, e);
235 return;
236 }
237 #endif
238 #endif
239
242 QF_MEM_SYS();
243
244 #ifndef Q_UNSAFE
245 Q_REQUIRE_INCRIT(200, QEvt_verify_(e));
246
247 uint8_t const pcopy = (uint8_t)(~me->prio_dis);
248 Q_INVARIANT_INCRIT(202, me->prio == pcopy);
249 #endif
250
251 #ifdef QXK_H_
253 #endif
254
255 QEQueueCtr nFree = me->eQueue.nFree; // get volatile into temporary
256
257 // test-probe#1 for faking queue overflow
258 QS_TEST_PROBE_DEF(&QActive_postLIFO_)
260 nFree = 0U;
261 )
262
263 Q_REQUIRE_INCRIT(201, nFree != 0U);
264
265 if (QEvt_getPoolNum_(e) != 0U) { // is it a mutable event?
266 QEvt_refCtr_inc_(e); // increment the reference counter
267 }
268
269 --nFree; // one free entry just used up
270 me->eQueue.nFree = nFree; // update the original
271 if (me->eQueue.nMin > nFree) {
272 me->eQueue.nMin = nFree; // update minimum so far
273 }
274
275 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_LIFO, me->prio)
276 QS_TIME_PRE_(); // timestamp
277 QS_SIG_PRE_(e->sig); // the signal of this event
278 QS_OBJ_PRE_(me); // this active object
279 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_);// poolNum & refCtr
280 QS_EQC_PRE_(nFree); // # free entries
281 QS_EQC_PRE_(me->eQueue.nMin); // min # free entries
282 QS_END_PRE_()
283
284 #ifdef Q_UTEST
285 // callback to examine the posted event under the same conditions
286 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
287 // the local filter for this AO ('me->prio') is set
288 if (QS_LOC_CHECK_(me->prio)) {
289 QF_MEM_APP();
290 QF_CRIT_EXIT();
291
292 QS_onTestPost((QActive *)0, me, e, true);
293
295 QF_MEM_SYS();
296 }
297 #endif
298
299 QEvt const * const frontEvt = me->eQueue.frontEvt;
300 me->eQueue.frontEvt = e; // deliver the event directly to the front
301
302 if (frontEvt == (QEvt *)0) { // was the queue empty?
303 QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
304 }
305 else { // queue was not empty, leave the event in the ring-buffer
306 ++me->eQueue.tail;
307 if (me->eQueue.tail == me->eQueue.end) { // need to wrap the tail?
308 me->eQueue.tail = 0U; // wrap around
309 }
310
311 me->eQueue.ring[me->eQueue.tail] = frontEvt;
312 }
313
314 QF_MEM_APP();
315 QF_CRIT_EXIT();
316}
317//$enddef${QF::QActive::postLIFO_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
318//$define${QF::QActive::get_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
319
320//${QF::QActive::get_} .......................................................
321//! @private @memberof QActive
322QEvt const * QActive_get_(QActive * const me) {
325 QF_MEM_SYS();
326
327 QACTIVE_EQUEUE_WAIT_(me); // wait for event to arrive directly
328
329 // always remove event from the front
330 QEvt const * const e = me->eQueue.frontEvt;
331 Q_INVARIANT_INCRIT(312, QEvt_verify_(e));
332
333 QEQueueCtr const nFree = me->eQueue.nFree + 1U; // get volatile into tmp
334 me->eQueue.nFree = nFree; // update the # free
335
336 if (nFree <= me->eQueue.end) { // any events in the ring buffer?
337 // remove event from the tail
338 me->eQueue.frontEvt = me->eQueue.ring[me->eQueue.tail];
339 if (me->eQueue.tail == 0U) { // need to wrap the tail?
340 me->eQueue.tail = me->eQueue.end; // wrap around
341 }
342 --me->eQueue.tail;
343
344 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, me->prio)
345 QS_TIME_PRE_(); // timestamp
346 QS_SIG_PRE_(e->sig); // the signal of this event
347 QS_OBJ_PRE_(me); // this active object
348 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
349 QS_EQC_PRE_(nFree); // # free entries
350 QS_END_PRE_()
351 }
352 else {
353 me->eQueue.frontEvt = (QEvt *)0; // queue becomes empty
354
355 // all entries in the queue must be free (+1 for fronEvt)
356 Q_ASSERT_INCRIT(310, nFree == (me->eQueue.end + 1U));
357
358 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, me->prio)
359 QS_TIME_PRE_(); // timestamp
360 QS_SIG_PRE_(e->sig); // the signal of this event
361 QS_OBJ_PRE_(me); // this active object
362 QS_2U8_PRE_(QEvt_getPoolNum_(e), e->refCtr_); // poolNum & refCtr
363 QS_END_PRE_()
364 }
365
366 QF_MEM_APP();
367 QF_CRIT_EXIT();
368
369 return e;
370}
371//$enddef${QF::QActive::get_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
372
373//$define${QF::QF-base::getQueueMin} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
374
375//${QF::QF-base::getQueueMin} ................................................
376//! @static @public @memberof QF
377uint_fast16_t QF_getQueueMin(uint_fast8_t const prio) {
380 Q_REQUIRE_INCRIT(400, (prio <= QF_MAX_ACTIVE)
381 && (QActive_registry_[prio] != (QActive *)0));
382 uint_fast16_t const min =
383 (uint_fast16_t)QActive_registry_[prio]->eQueue.nMin;
384 QF_CRIT_EXIT();
385
386 return min;
387}
388//$enddef${QF::QF-base::getQueueMin} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
389//$define${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
390
391//${QF::QTicker} .............................................................
392
393//${QF::QTicker::ctor} .......................................................
394//! @public @memberof QTicker
395void QTicker_ctor(QTicker * const me,
396 uint_fast8_t const tickRate)
397{
398 QActive_ctor(&me->super, Q_STATE_CAST(0)); // superclass' ctor
399
400 static struct QAsmVtable const vtable = { // QTicker virtual table
401 &QTicker_init_,
402 &QTicker_dispatch_,
403 &QHsm_isIn_
404 #ifdef Q_SPY
405 ,&QHsm_getStateHandler_
406 #endif
407 };
408 me->super.super.vptr = &vtable; // hook the vptr
409
410 // reuse eQueue.head for tick-rate
411 me->super.eQueue.head = (QEQueueCtr)tickRate;
412}
413
414//${QF::QTicker::init_} ......................................................
415//! @private @memberof QTicker
416void QTicker_init_(
417 QAsm * const me,
418 void const * const par,
419 uint_fast8_t const qsId)
420{
421 Q_UNUSED_PAR(me);
422 Q_UNUSED_PAR(par);
423 Q_UNUSED_PAR(qsId);
424
427 QF_MEM_SYS();
428
429 QACTIVE_CAST_(me)->eQueue.tail = 0U;
430
431 QF_MEM_APP();
432 QF_CRIT_EXIT();
433}
434
435//${QF::QTicker::dispatch_} ..................................................
436//! @private @memberof QTicker
437void QTicker_dispatch_(
438 QAsm * const me,
439 QEvt const * const e,
440 uint_fast8_t const qsId)
441{
442 Q_UNUSED_PAR(e);
443 Q_UNUSED_PAR(qsId);
444
447 QF_MEM_SYS();
448
449 QEQueueCtr nTicks = QACTIVE_CAST_(me)->eQueue.tail; // save # of ticks
450 QACTIVE_CAST_(me)->eQueue.tail = 0U; // clear # ticks
451
452 QF_MEM_APP();
453 QF_CRIT_EXIT();
454
455 for (; nTicks > 0U; --nTicks) {
456 QTimeEvt_tick_((uint_fast8_t)QACTIVE_CAST_(me)->eQueue.head, me);
457 }
458}
459
460//${QF::QTicker::trig_} ......................................................
461//! @private @memberof QTicker
462void QTicker_trig_(
463 QActive * const me,
464 void const * const sender)
465{
466 #ifndef Q_SPY
467 Q_UNUSED_PAR(sender);
468 #endif
469
472 QF_MEM_SYS();
473
474 if (me->eQueue.frontEvt == (QEvt *)0) {
475
476 static QEvt const tickEvt = QEVT_INITIALIZER(0);
477 me->eQueue.frontEvt = &tickEvt; // deliver event directly
478 --me->eQueue.nFree; // one less free event
479
480 QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
481 }
482
483 ++me->eQueue.tail; // account for one more tick event
484
485 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, me->prio)
486 QS_TIME_PRE_(); // timestamp
487 QS_OBJ_PRE_(sender); // the sender object
488 QS_SIG_PRE_(0U); // the signal of the event
489 QS_OBJ_PRE_(me); // this active object
490 QS_2U8_PRE_(0U, 0U); // poolNum & refCtr
491 QS_EQC_PRE_(0U); // # free entries
492 QS_EQC_PRE_(0U); // min # free entries
493 QS_END_PRE_()
494
495 QF_MEM_APP();
496 QF_CRIT_EXIT();
497}
498//$enddef${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
uint16_t QEQueueCtr
Definition qequeue.h:53
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition qk.h:170
#define QACTIVE_EQUEUE_WAIT_(me_)
Definition qk.h:165
#define QF_MEM_APP()
Definition qp.h:1288
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:536
#define QF_NO_MARGIN
Special value of margin that causes asserting failure in case event allocation or event posting fails...
Definition qp.h:1158
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition qp.h:530
#define Q_ACTION_CAST(action_)
Perform cast to QActionHandler.
Definition qp.h:533
#define QF_MEM_SYS()
Definition qp.h:1283
#define QEVT_INITIALIZER(sig_)
Initializer for immutable (constant) QEvt instances.
Definition qp.h:459
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64)
Definition qp_config.h:118
Internal (package scope) QP/C interface.
#define QACTIVE_CAST_(ptr_)
Definition qp_pkg.h:96
Sample QP/C port.
#define QS_TIME_PRE_()
Definition qs.h:450
@ QS_QF_ACTIVE_POST_LIFO
an event was posted (LIFO) directly to AO
Definition qs.h:98
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition qs.h:99
@ QS_QF_ACTIVE_POST_ATTEMPT
attempt to post an evt to AO failed
Definition qs.h:142
#define QS_TEST_PROBE_DEF(fun_)
Definition qs.h:846
@ QS_QF_ACTIVE_POST
an event was posted (FIFO) directly to AO
Definition qs.h:97
#define QS_TEST_PROBE_ID(id_, code_)
Definition qs.h:852
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition qs.h:100
#define QS_LOC_CHECK_(qsId_)
Definition qs.h:382
QS/C package-scope interface.
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:154
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define Q_ERROR_INCRIT(id_)
Definition qsafe.h:76
#define QF_CRIT_STAT
Definition qsafe.h:54
Active object class (based on the QHsm implementation strategy)
Definition qp.h:804
uint8_t prio_dis
Definition qp.h:831
QACTIVE_EQUEUE_TYPE eQueue
Port-dependent event-queue type (often QEQueue)
Definition qp.h:826
QAsm super
Definition qp.h:806
uint8_t prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.h:809
Abstract State Machine class (state machine interface)
Definition qp.h:280
struct QAsmVtable const * vptr
Virtual pointer inherited by all QAsm subclasses (see also Object Orientation)
Definition qp.h:284
union QAsmAttr state
Current state (pointer to the current state-handler function)
Definition qp.h:289
union QAsmAttr temp
Temporary storage for target/act-table etc.
Definition qp.h:292
Virtual table for the QAsm class.
Definition qp.h:301
Event class.
Definition qp.h:145
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:149
uint8_t volatile refCtr_
Reference counter (for mutable events and 0 for immutable (static) events)
Definition qp.h:154
"Ticker" Active Object class
Definition qp.h:1046
QActive super
Definition qp.h:1048
QStateHandler fun
Definition qp.h:268
QActionHandler act
Definition qp.h:269