QP/C Real-Time Embedded Framework (RTEF)
This model is used to generate the whole QP/C source code.
Copyright (c) 2005 Quantum Leaps, LLC. All rights reserved.
Q u a n t u m L e a P s
------------------------
Modern Embedded Software
SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
The QP/C software is dual-licensed under the terms of the open-source GNU
General Public License (GPL) or under the terms of one of the closed-
source Quantum Leaps commercial licenses.
Redistributions in source code must retain this top-level comment block.
Plagiarizing this software to sidestep the license obligations is illegal.
NOTE:
The GPL (see <www.gnu.org/licenses/gpl-3.0>) does NOT permit the
incorporation of the QP/C software into proprietary programs. Please
contact Quantum Leaps for commercial licensing options, which expressly
supersede the GPL and are designed explicitly for licensees interested
in using QP/C in closed-source proprietary applications.
Quantum Leaps contact information:
<www.state-machine.com/licensing>
<info@state-machine.com>
public
qpc
2025-12-31
Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
Q u a n t u m L e a P s
------------------------
Modern Embedded Software
SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
The QP/C software is dual-licensed under the terms of the open-source GNU
General Public License (GPL) or under the terms of one of the closed-
source Quantum Leaps commercial licenses.
Redistributions in source code must retain this top-level comment block.
Plagiarizing this software to sidestep the license obligations is illegal.
NOTE:
The GPL does NOT permit the incorporation of this code into proprietary
programs. Please contact Quantum Leaps for commercial licensing options,
which expressly supersede the GPL and are designed explicitly for
closed-source distribution.
Quantum Leaps contact information:
<www.state-machine.com/licensing>
<info@state-machine.com>
#2BACD81DCE8ED122C193E4F48A14170D660DFF1E
\
static char const Q_this_module_[] = name_;
\
((expr_) ? ((void)0) : Q_onError(&Q_this_module_[0], (id_)))
\
(Q_onError(&Q_this_module_[0], (id_)))
do { \
QF_CRIT_STAT \
QF_CRIT_ENTRY(); \
(expr_) ? ((void)0) : Q_onError(&Q_this_module_[0], (id_)); \
QF_CRIT_EXIT(); \
} while (false)
do { \
QF_CRIT_STAT \
QF_CRIT_ENTRY(); \
Q_onError(&Q_this_module_[0], (id_)); \
QF_CRIT_EXIT(); \
} while (false)
((void)0)
((void)0)
((void)0)
((void)0)
Q_DEFINE_THIS_MODULE(__FILE__)
Q_ASSERT_ID(__LINE__, (expr_))
Q_ERROR_ID(__LINE__)
Q_ASSERT_ID((id_), (expr_))
Q_ASSERT(expr_)
Q_ASSERT_INCRIT((id_), (expr_))
Q_ASSERT_ID((id_), (expr_))
Q_ASSERT(expr_)
Q_ASSERT_INCRIT((id_), (expr_))
Q_ASSERT_ID((id_), (expr_))
Q_ASSERT(expr_)
Q_ASSERT_INCRIT((id_), (expr_))
extern char Q_static_assert_[(expr_) ? 1 : -1]
_Noreturn void
(sizeof(array_) / sizeof((array_)[0U]))
//! the current QP version number string in ROM, based on #QP_VERSION_STR
= QP_VERSION_STR;
//! @class QEvt
//! @public @memberof QEvt
//! @private @memberof QEvt
//! @private @memberof QEvt
= {
QEVT_INITIALIZER(Q_EMPTY_SIG),
QEVT_INITIALIZER(Q_ENTRY_SIG),
QEVT_INITIALIZER(Q_EXIT_SIG),
QEVT_INITIALIZER(Q_INIT_SIG)
};
//! @public @memberof QEvt
//! @public @memberof QEvt
me->sig = (QSignal)sig;
me->evtTag_ = 0x0FU;
me->refCtr_ = 0U;
//! @public @memberof QEvt
//! @public @memberof QEvt
(void)dummy;
return me;
const
//! @private @memberof QEvt
//! @private @memberof QEvt
uint8_t rc = me->refCtr_;
return (rc <= 2U*QF_MAX_ACTIVE)
&& (((me->evtTag_ ^ rc) & 0x0FU) == 0x0FU);
const
//! @private @memberof QEvt
//! @private @memberof QEvt
return (uint_fast8_t)(me->evtTag_ >> 4U);
//! All possible values returned from state/action handlers
//! @note
//! The order of enumeration matters for algorithmic correctness.
{
// unhandled and need to "bubble up"
Q_RET_SUPER, //!< event passed to superstate to handle
Q_RET_UNHANDLED, //!< event unhandled due to guard
// handled and do not need to "bubble up"
Q_RET_HANDLED, //!< event handled (internal transition)
Q_RET_IGNORED, //!< event silently ignored (bubbled up to top)
// entry/exit
Q_RET_ENTRY, //!< state entry action executed
Q_RET_EXIT, //!< state exit action executed
// no side effects
Q_RET_NULL, //!< return value without any effect
// transitions need to execute transition-action table in ::QMsm
Q_RET_TRAN, //!< regular transition
Q_RET_TRAN_INIT, //!< initial transition in a state
// transitions that additionally clobber me->state
Q_RET_TRAN_HIST, //!< transition to history of a given state
};
)(void * const me, QEvt const * const e);
)(void * const me);
// forward declaration
)(struct QXThread * const me);
{
struct QMState const *superstate; //!< @private @memberof QMState
QStateHandler const stateHandler; //!< @private @memberof QMState
QActionHandler const entryAction; //!< @private @memberof QMState
QActionHandler const exitAction; //!< @private @memberof QMState
QActionHandler const initAction; //!< @private @memberof QMState
} QMState;
{
QMState const *target; //!< @private @memberof QMTranActTable
QActionHandler const act[1]; //!< @private @memberof QMTranActTable
} QMTranActTable;
{
QStateHandler fun; //!< @private @memberof QAsmAttr
QActionHandler act; //!< @private @memberof QAsmAttr
QXThreadHandler thr; //!< @private @memberof QAsmAttr
QMTranActTable const *tatbl; //!< @private @memberof QAsmAttr
struct QMState const *obj; //!< @private @memberof QAsmAttr
#ifndef Q_UNSAFE
uintptr_t uint; //!< @private @memberof QAsmAttr
#endif
};
//! @class QAsm
//! @protected @memberof QAsm
//! @protected @memberof QAsm
//! @protected @memberof QAsm
//! @protected @memberof QAsm
//! @protected @memberof QAsm
me->vptr = (QAsmVtable *)0;
me->state.fun = Q_STATE_CAST(0);
me->temp.fun = Q_STATE_CAST(0);
{
void (*init)(QAsm * const me, void const * const e,
uint_fast8_t const qsId);
void (*dispatch)(QAsm * const me, QEvt const * const e,
uint_fast8_t const qsId);
bool (*isIn)(QAsm * const me, QStateHandler const s);
#ifdef Q_SPY
QStateHandler (*getStateHandler)(QAsm * const me);
#endif // Q_SPY
};
//! @class QHsm
//! @extends QAsm
State machine implementation strategy suitable for
manual coding
//! @protected @memberof QHsm
//! @protected @memberof QHsm
static struct QAsmVtable const vtable = { // QAsm virtual table
&QHsm_init_,
&QHsm_dispatch_,
&QHsm_isIn_
#ifdef Q_SPY
,&QHsm_getStateHandler_
#endif
};
// do not call the QAsm_ctor() here
me->super.vptr = &vtable;
me->super.state.fun = Q_STATE_CAST(&QHsm_top);
me->super.temp.fun = initial;
//! @private @memberof QHsm
//! @private @memberof QHsm
QF_CRIT_STAT
QState r;
// produce QS dictionary for QHsm_top()
#ifdef Q_SPY
QS_CRIT_ENTRY();
QS_MEM_SYS();
if ((QS_priv_.flags & 0x01U) == 0U) {
QS_priv_.flags |= 0x01U;
r = Q_RET_HANDLED;
}
else {
r = Q_RET_IGNORED;
}
QS_MEM_APP();
QS_CRIT_EXIT();
if (r == Q_RET_HANDLED) {
QS_FUN_DICTIONARY(&QHsm_top);
}
#else
Q_UNUSED_PAR(qsId);
#endif // def Q_SPY
QStateHandler t = me->state.fun;
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(200, (me->vptr != (struct QAsmVtable *)0)
&& (me->temp.fun != Q_STATE_CAST(0))
&& (t == Q_STATE_CAST(&QHsm_top)));
QF_CRIT_EXIT();
// execute the top-most initial tran.
r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
QF_CRIT_ENTRY();
// the top-most initial tran. must be taken
Q_ASSERT_INCRIT(210, r == Q_RET_TRAN);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t); // the source state
QS_FUN_PRE(me->temp.fun); // the target of the initial tran.
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
// drill down into the state hierarchy with initial transitions...
do {
QStateHandler path[QHSM_MAX_NEST_DEPTH_]; // tran. entry path array
int_fast8_t ip = 0; // tran. entry path index
path[0] = me->temp.fun;
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
// note: ip is the fixed upper loop bound
while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
++ip;
path[ip] = me->temp.fun;
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
}
QF_CRIT_ENTRY();
// too many state nesting levels or "malformed" HSM
Q_ENSURE_INCRIT(220, ip < QHSM_MAX_NEST_DEPTH_);
QF_CRIT_EXIT();
me->temp.fun = path[0];
// retrace the entry path in reverse (desired) order...
// note: ip is the fixed upper loop bound
do {
// enter path[ip]
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
== Q_RET_HANDLED)
{
QS_STATE_ENTRY_(path[ip], qsId);
}
--ip;
} while (ip >= 0);
t = path[0]; // current state becomes the new source
r = QHSM_RESERVED_EVT_(t, Q_INIT_SIG); // execute initial tran.
#ifdef Q_SPY
if (r == Q_RET_TRAN) {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t); // the source state
QS_FUN_PRE(me->temp.fun); // the target of the initial tran.
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
#endif // Q_SPY
} while (r == Q_RET_TRAN);
QF_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_INIT_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t); // the new active state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
me->state.fun = t; // change the current active state
#ifndef Q_UNSAFE
me->temp.uint = ~me->state.uint;
#endif
//! @private @memberof QHsm
//! @private @memberof QHsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QStateHandler s = me->state.fun;
QStateHandler t = s;
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(300,
(e != (QEvt *)0)
&& (s != Q_STATE_CAST(0))
&& (me->state.uint == (uintptr_t)(~me->temp.uint)));
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(301, QEvt_verify_(e));
#endif
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_DISPATCH, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s); // the current state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
// process the event hierarchically...
QState r;
me->temp.fun = s;
int_fast8_t ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
do {
s = me->temp.fun;
r = (*s)(me, e); // invoke state handler s
if (r == Q_RET_UNHANDLED) { // unhandled due to a guard?
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_UNHANDLED, qsId)
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s); // the current state
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s
}
--ip;
} while ((r == Q_RET_SUPER) && (ip > 0));
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(310, ip > 0);
QF_CRIT_EXIT();
if (r >= Q_RET_TRAN) { // tran. (regular or history) taken?
#ifdef Q_SPY
if (r == Q_RET_TRAN_HIST) { // tran. to history?
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_TRAN_HIST, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s); // tran. to history source
QS_FUN_PRE(me->temp.fun); // tran. to history target
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
#endif // Q_SPY
QStateHandler path[QHSM_MAX_NEST_DEPTH_];
path[0] = me->temp.fun; // tran. target
path[1] = t; // current state
path[2] = s; // tran. source
// exit current state to tran. source s...
ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
for (; (t != s) && (ip > 0); t = me->temp.fun) {
// exit from t
if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
QS_STATE_EXIT_(t, qsId);
// find superstate of t
(void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
}
--ip;
}
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(320, ip > 0);
QF_CRIT_EXIT();
ip = QHsm_tran_(me, path, qsId); // take the tran.
// execute state entry actions in the desired order...
// note: ip is the fixed upper loop bound
for (; ip >= 0; --ip) {
// enter path[ip]
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
== Q_RET_HANDLED)
{
QS_STATE_ENTRY_(path[ip], qsId);
}
}
t = path[0]; // stick the target into register
me->temp.fun = t; // update the next state
// drill into the target hierarchy...
while (QHSM_RESERVED_EVT_(t, Q_INIT_SIG) == Q_RET_TRAN) {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t); // the source (pseudo)state
QS_FUN_PRE(me->temp.fun); // the target of the tran.
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
ip = 0;
path[0] = me->temp.fun;
// find superstate
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
// note: ip is the fixed upper loop bound
while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
++ip;
path[ip] = me->temp.fun;
// find superstate
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
}
QF_CRIT_ENTRY();
// too many state nesting levels or "malformed" HSM
Q_ENSURE_INCRIT(330, ip < QHSM_MAX_NEST_DEPTH_);
QF_CRIT_EXIT();
me->temp.fun = path[0];
// retrace the entry path in reverse (correct) order...
// note: ip is the fixed upper loop bound
do {
// enter path[ip]
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
== Q_RET_HANDLED)
{
QS_STATE_ENTRY_(path[ip], qsId);
}
--ip;
} while (ip >= 0);
t = path[0]; // current state becomes the new source
}
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s); // the source of the tran.
QS_FUN_PRE(t); // the new active state
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
#ifdef Q_SPY
else if (r == Q_RET_HANDLED) {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_INTERN_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s); // the source state
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
else {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_IGNORED, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(me->state.fun); // the current state
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
#endif // Q_SPY
me->state.fun = t; // change the current active state
#ifndef Q_UNSAFE
me->temp.uint = ~me->state.uint;
#endif
//! @private @memberof QHsm
//! @private @memberof QHsm
return me->state.fun;
//! @private @memberof QHsm
//! @private @memberof QHsm
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_INVARIANT_INCRIT(602,
me->state.uint == (uintptr_t)(~me->temp.uint));
QF_CRIT_EXIT();
bool inState = false; // assume that this HSM is not in 'state'
// scan the state hierarchy bottom-up
QStateHandler s = me->state.fun;
int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_ + 1; // fixed upper loop bound
QState r = Q_RET_SUPER;
for (; (r != Q_RET_IGNORED) && (lbound > 0); --lbound) {
if (s == state) { // do the states match?
inState = true; // 'true' means that match found
break; // break out of the for-loop
}
else {
r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
s = me->temp.fun;
}
}
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(690, lbound > 0);
QF_CRIT_EXIT();
#ifndef Q_UNSAFE
me->temp.uint = ~me->state.uint;
#endif
return inState; // return the status
const
//! @public @memberof QHsm
//! @public @memberof QHsm
return me->super.state.fun;
//! @public @memberof QHsm
//! @public @memberof QHsm
QStateHandler child = me->super.state.fun; // start with current state
bool isFound = false; // start with the child not found
// establish stable state configuration
me->super.temp.fun = child;
QState r;
int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
do {
// is this the parent of the current child?
if (me->super.temp.fun == parent) {
isFound = true; // child is found
r = Q_RET_IGNORED; // break out of the loop
}
else {
child = me->super.temp.fun;
r = QHSM_RESERVED_EVT_(me->super.temp.fun, Q_EMPTY_SIG);
}
--lbound;
} while ((r != Q_RET_IGNORED) // the top state not reached
&& (lbound > 0));
#ifndef Q_UNSAFE
me->super.temp.uint = ~me->super.state.uint;
#else
Q_UNUSED_PAR(isFound);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
// NOTE: the following postcondition can only succeed when
// (lbound > 0), so no extra check is necessary.
Q_ENSURE_INCRIT(890, isFound);
QF_CRIT_EXIT();
return child;
//! @private @memberof QHsm
//! @private @memberof QHsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
int_fast8_t ip = -1; // tran. entry path index
QStateHandler t = path[0];
QStateHandler const s = path[2];
QF_CRIT_STAT
// (a) check source==target (tran. to self)...
if (s == t) {
// exit source s
if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
QS_STATE_EXIT_(s, qsId);
}
ip = 0; // enter the target
}
else {
// find superstate of target
(void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
t = me->temp.fun;
// (b) check source==target->super...
if (s == t) {
ip = 0; // enter the target
}
else {
// find superstate of src
(void)QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
// (c) check source->super==target->super...
if (me->temp.fun == t) {
// exit source s
if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
QS_STATE_EXIT_(s, qsId);
}
ip = 0; // enter the target
}
else {
// (d) check source->super==target...
if (me->temp.fun == path[0]) {
// exit source s
if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
QS_STATE_EXIT_(s, qsId);
}
}
else {
// (e) check rest of source==target->super->super..
// and store the entry path along the way
int_fast8_t iq = 0; // indicate that LCA was found
ip = 1; // enter target and its superstate
path[1] = t; // save the superstate of target
t = me->temp.fun; // save source->super
// find target->super->super...
// note: ip is the fixed upper loop bound
QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG);
while ((r == Q_RET_SUPER)
&& (ip < (QHSM_MAX_NEST_DEPTH_ - 1)))
{
++ip;
path[ip] = me->temp.fun; // store the entry path
if (me->temp.fun == s) { // is it the source?
iq = 1; // indicate that the LCA found
--ip; // do not enter the source
r = Q_RET_HANDLED; // terminate the loop
}
else { // it is not the source, keep going up
r = QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
}
}
QF_CRIT_ENTRY();
// NOTE: The following postcondition succeeds only when
// ip < QHSM_MAX_NEST_DEPTH, so no additional check is necessary
// too many state nesting levels or "malformed" HSM.
Q_ENSURE_INCRIT(510, r != Q_RET_SUPER);
QF_CRIT_EXIT();
// the LCA not found yet?
if (iq == 0) {
// exit source s
if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG)
== Q_RET_HANDLED)
{
QS_STATE_EXIT_(s, qsId);
}
// (f) check the rest of source->super
// == target->super->super...
iq = ip;
r = Q_RET_IGNORED; // indicate that the LCA NOT found
// note: iq is the fixed upper loop bound
do {
if (t == path[iq]) { // is this the LCA?
r = Q_RET_HANDLED; // indicate the LCA found
ip = iq - 1; // do not enter the LCA
iq = -1; // cause termination of the loop
}
else {
--iq; // try lower superstate of target
}
} while (iq >= 0);
// the LCA not found yet?
if (r != Q_RET_HANDLED) {
// (g) check each source->super->...
// for each target->super...
r = Q_RET_IGNORED; // keep looping
int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_;
do {
// exit from t
if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG)
== Q_RET_HANDLED)
{
QS_STATE_EXIT_(t, qsId);
// find superstate of t
(void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
}
t = me->temp.fun; // set to super of t
iq = ip;
do {
// is this the LCA?
if (t == path[iq]) {
ip = iq - 1; // do not enter the LCA
iq = -1; // break out of inner loop
r = Q_RET_HANDLED; // break outer loop
}
else {
--iq;
}
} while (iq >= 0);
--lbound;
} while ((r != Q_RET_HANDLED) && (lbound > 0));
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(530, lbound > 0);
QF_CRIT_EXIT();
}
}
}
}
}
}
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(590, ip < QHSM_MAX_NEST_DEPTH_);
QF_CRIT_EXIT();
return ip;
const
//! @protected @memberof QAsm
//! @protected @memberof QAsm
Q_UNUSED_PAR(me);
Q_UNUSED_PAR(e);
return Q_RET_IGNORED; // the top state ignores all events
//! @class QMsm
//! @extends QAsm
State machine implementation strategy requiring support
of a code generating tool and generally NOT suitable
for manual coding
//! @protected @memberof QMsm
//! @protected @memberof QMsm
static struct QAsmVtable const vtable = { // QAsm virtual table
&QMsm_init_,
&QMsm_dispatch_,
&QMsm_isIn_
#ifdef Q_SPY
,&QMsm_getStateHandler_
#endif
};
// do not call the QAsm_ctor() here
me->super.vptr = &vtable;
me->super.state.obj = &l_msm_top_s; // the current state (top)
me->super.temp.fun = initial; // the initial tran. handler
//! @private @memberof QMsm
//! @private @memberof QMsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(200, (me->vptr != (struct QAsmVtable *)0)
&& (me->temp.fun != Q_STATE_CAST(0))
&& (me->state.obj == &l_msm_top_s));
QF_CRIT_EXIT();
// execute the top-most initial tran.
QState r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
QF_CRIT_ENTRY();
// the top-most initial tran. must be taken
Q_ASSERT_INCRIT(210, r == Q_RET_TRAN_INIT);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(me->state.obj->stateHandler); // source state
QS_FUN_PRE(me->temp.tatbl->target->stateHandler); // target state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
// set state to the last tran. target
me->state.obj = me->temp.tatbl->target;
// drill down into the state hierarchy with initial transitions...
int_fast8_t lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
do {
// execute the tran. table
r = QMsm_execTatbl_(me, me->temp.tatbl, qsId);
--lbound;
} while ((r >= Q_RET_TRAN_INIT) && (lbound > 0));
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(290, lbound > 0);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_INIT_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(me->state.obj->stateHandler); // the new current state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
#ifndef Q_UNSAFE
me->temp.uint = ~me->state.uint;
#endif
//! @private @memberof QMsm
//! @private @memberof QMsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QMState const *s = me->state.obj; // store the current state
QMState const *t = s;
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(300,
(e != (QEvt *)0)
&& (s != (QMState *)0)
&& (me->state.uint == (uintptr_t)(~me->temp.uint)));
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(301, QEvt_verify_(e));
#endif
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_DISPATCH, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s->stateHandler); // the current state handler
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
// scan the state hierarchy up to the top state...
QState r;
int_fast8_t lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
do {
r = (*t->stateHandler)(me, e); // call state handler function
// event handled? (the most frequent case)
if (r >= Q_RET_HANDLED) {
break; // done scanning the state hierarchy
}
// event unhandled and passed to the superstate?
else if (r == Q_RET_SUPER) {
t = t->superstate; // advance to the superstate
}
else { // event unhandled due to a guard
QF_CRIT_ENTRY();
// event must be unhandled due to a guard evaluating to 'false'
Q_ASSERT_INCRIT(310, r == Q_RET_UNHANDLED);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_UNHANDLED, qsId)
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t->stateHandler); // the current state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
t = t->superstate; // advance to the superstate
}
--lbound;
} while ((t != (QMState *)0) && (lbound > 0));
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(320, lbound > 0);
QF_CRIT_EXIT();
if (r >= Q_RET_TRAN) { // any kind of tran. taken?
QF_CRIT_ENTRY();
// the tran. source state must not be NULL
Q_ASSERT_INCRIT(330, t != (QMState *)0);
QF_CRIT_EXIT();
#ifdef Q_SPY
QMState const * const ts = t; // tran. source for QS tracing
#endif // Q_SPY
struct QMTranActTable const *tatbl; // for saving tran. table
if (r == Q_RET_TRAN_HIST) { // was it tran. to history?
QMState const * const hist = me->state.obj; // save history
me->state.obj = s; // restore the original state
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_TRAN_HIST, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t->stateHandler); // source state handler
QS_FUN_PRE(hist->stateHandler); // target state handler
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
// save the tran-action table before it gets clobbered
tatbl = me->temp.tatbl;
QMsm_exitToTranSource_(me, s, t, qsId);
(void)QMsm_execTatbl_(me, tatbl, qsId);
r = QMsm_enterHistory_(me, hist, qsId);
s = me->state.obj;
t = s; // set target to the current state
}
lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
while ((r >= Q_RET_TRAN) && (lbound > 0)) {
// save the tran-action table before it gets clobbered
tatbl = me->temp.tatbl;
me->temp.obj = (QMState *)0; // clear
QMsm_exitToTranSource_(me, s, t, qsId);
r = QMsm_execTatbl_(me, tatbl, qsId);
s = me->state.obj;
t = s; // set target to the current state
--lbound;
}
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(360, lbound > 0);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(ts->stateHandler); // the tran. source
QS_FUN_PRE(s->stateHandler); // the new active state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
}
#ifdef Q_SPY
// was the event handled?
else if (r == Q_RET_HANDLED) {
QF_CRIT_ENTRY();
// internal tran. source can't be NULL
Q_ASSERT_INCRIT(380, t != (QMState *)0);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_INTERN_TRAN, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(t->stateHandler); // the source state
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
}
// event bubbled to the 'top' state?
else if (t == (QMState *)0) {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_IGNORED, qsId)
QS_TIME_PRE(); // time stamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s->stateHandler); // the current state
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
#endif // Q_SPY
else {
// empty
}
#ifndef Q_UNSAFE
me->temp.uint = ~me->state.uint;
#endif
//! @public @memberof QMsm
//! @public @memberof QMsm
return me->state.obj->stateHandler;
//! @private @memberof QMsm
//! @private @memberof QMsm
bool inState = false; // assume that this SM is not in 'state'
QMState const *s = me->state.obj;
int_fast8_t lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
for (; (s != (QMState *)0) && (lbound > 0); --lbound) {
if (s->stateHandler == state) { // match found?
inState = true;
break;
}
else {
s = s->superstate; // advance to the superstate
}
}
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(490, lbound > 0);
QF_CRIT_EXIT();
return inState;
const
//! @public @memberof QMsm
//! @public @memberof QMsm
return me->super.state.obj;
const
//! @public @memberof QMsm
//! @public @memberof QMsm
QMState const *child = me->super.state.obj;
bool isFound = false; // start with the child not found
QMState const *s;
int_fast8_t lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
for (s = me->super.state.obj;
(s != (QMState *)0) && (lbound > 0);
s = s->superstate)
{
if (s == parent) {
isFound = true; // child is found
break;
}
else {
child = s;
}
--lbound;
}
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(680, lbound > 0);
QF_CRIT_EXIT();
if (!isFound) { // still not found?
lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
for (s = me->super.temp.obj;
(s != (QMState *)0) && (lbound > 0);
s = s->superstate)
{
if (s == parent) {
isFound = true; // child is found
break;
}
else {
child = s;
}
--lbound;
}
}
QF_CRIT_ENTRY();
// NOTE: the following postcondition can only succeed when
// (lbound > 0), so no extra check is necessary.
Q_ENSURE_INCRIT(690, isFound);
QF_CRIT_EXIT();
return child; // return the child
//! @private @memberof QMsm
//! @private @memberof QMsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
// precondition:
// - the tran-action table pointer must not be NULL
Q_REQUIRE_INCRIT(700, tatbl != (struct QMTranActTable *)0);
QF_CRIT_EXIT();
QState r = Q_RET_NULL;
int_fast8_t lbound = QMSM_MAX_TRAN_LENGTH_; // fixed upper loop bound
QActionHandler const *a = &tatbl->act[0];
for (; (*a != Q_ACTION_CAST(0)) && (lbound > 0); ++a) {
r = (*(*a))(me); // call the action through the 'a' pointer
--lbound;
#ifdef Q_SPY
QS_CRIT_ENTRY();
QS_MEM_SYS();
if (r == Q_RET_ENTRY) {
QS_BEGIN_PRE(QS_QEP_STATE_ENTRY, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(me->temp.obj->stateHandler); // entered state
QS_END_PRE()
}
else if (r == Q_RET_EXIT) {
QS_BEGIN_PRE(QS_QEP_STATE_EXIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(me->temp.obj->stateHandler); // exited state
QS_END_PRE()
}
else if (r == Q_RET_TRAN_INIT) {
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(tatbl->target->stateHandler); // source
QS_FUN_PRE(me->temp.tatbl->target->stateHandler); // target
QS_END_PRE()
}
else {
// empty
}
QS_MEM_APP();
QS_CRIT_EXIT();
#endif // Q_SPY
}
QF_CRIT_ENTRY();
// NOTE: the following postcondition can only succeed when
// (lbound > 0), so no extra check is necessary.
Q_ENSURE_INCRIT(790, *a == Q_ACTION_CAST(0));
QF_CRIT_EXIT();
me->state.obj = (r >= Q_RET_TRAN)
? me->temp.tatbl->target
: tatbl->target;
return r;
//! @private @memberof QMsm
//! @private @memberof QMsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
// exit states from the current state to the tran. source state
QMState const *s = cs;
int_fast8_t lbound = QMSM_MAX_NEST_DEPTH_; // fixed upper loop bound
for (; (s != ts) && (lbound > 0); --lbound) {
// exit action provided in state 's'?
if (s->exitAction != Q_ACTION_CAST(0)) {
// execute the exit action
(void)(*s->exitAction)(me);
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_EXIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(s->stateHandler); // the exited state handler
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
s = s->superstate; // advance to the superstate
}
QF_CRIT_ENTRY();
Q_ENSURE_INCRIT(890, lbound > 0);
QF_CRIT_EXIT();
//! @private @memberof QMsm
//! @private @memberof QMsm
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
// record the entry path from current state to history
QMState const *epath[QMSM_MAX_ENTRY_DEPTH_];
QMState const *s = hist;
int_fast8_t i = 0; // tran. entry path index
while ((s != me->state.obj) && (i < (QMSM_MAX_ENTRY_DEPTH_ - 1))) {
if (s->entryAction != Q_ACTION_CAST(0)) {
epath[i] = s;
++i;
}
s = s->superstate;
}
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_ASSERT_INCRIT(910, s == me->state.obj);
QF_CRIT_EXIT();
// retrace the entry path in reverse (desired) order...
while (i > 0) {
--i;
(void)(*epath[i]->entryAction)(me); // run entry action in epath[i]
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_ENTRY, qsId)
QS_OBJ_PRE(me);
QS_FUN_PRE(epath[i]->stateHandler); // entered state handler
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
me->state.obj = hist; // set current state to the tran. target
// initial tran. present?
QState r;
if (hist->initAction != Q_ACTION_CAST(0)) {
r = (*hist->initAction)(me); // execute the tran. action
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
QS_OBJ_PRE(me); // this state machine object
QS_FUN_PRE(hist->stateHandler); // source
QS_FUN_PRE(me->temp.tatbl->target->stateHandler); // target
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
else {
r = Q_RET_NULL;
}
return r;
{ (QSignal)(sig_), 0x01U, 0x0EU }
((uint8_t)0)
do { \
Q_ASSERT(((QAsm *)(me_))->vptr); \
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), (qsId_)); \
} while (false)
do { \
Q_ASSERT(((QAsm *)(me_))->vptr); \
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), 0); \
} while (false)
\
(*((QAsm *)(me_))->vptr->dispatch)((QAsm *)(me_), (e_), (qsId_))
\
(*((QAsm *)(me_))->vptr->dispatch)((QAsm *)(me_), (e_), 0U)
\
(*((QAsm *)(me_))->vptr->isIn)((QAsm *)(me_), (state_))
((QAsm *)(ptr_))
((QHsm *)(ptr_))
((QMsm *)(ptr_))
((QSignal)0)
((QSignal)1)
((QSignal)2)
((QSignal)3)
((enum_t)4)
\
((Q_ASM_UPCAST(me))->temp.fun = Q_STATE_CAST(target_), \
(QState)Q_RET_TRAN)
\
((Q_ASM_UPCAST(me))->temp.fun = (hist_), \
(QState)Q_RET_TRAN_HIST)
\
((Q_ASM_UPCAST(me))->temp.fun = Q_STATE_CAST(super_), \
(QState)Q_RET_SUPER)
((QState)Q_RET_HANDLED)
((QState)Q_RET_UNHANDLED)
/
((QActionHandler)0)
((class_ const *)(e))
((QStateHandler)(handler_))
((QActionHandler)(action_))
((void)(par_))
(sizeof(array_) / sizeof((array_)[0U]))
((type_ *)(uint_))
\
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
(QState)Q_RET_ENTRY)
((QState)Q_RET_ENTRY)
\
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
(QState)Q_RET_EXIT)
((QState)Q_RET_EXIT)
\
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
(QState)Q_RET_EXIT)
((Q_ASM_UPCAST(me))->temp.tatbl \
= (struct QMTranActTable const *)(tatbl_), \
(QState)Q_RET_TRAN)
((Q_ASM_UPCAST(me))->temp.tatbl \
= (struct QMTranActTable const *)(tatbl_), \
(QState)Q_RET_TRAN_INIT)
\
((((Q_ASM_UPCAST(me))->state.obj = (history_)), \
((Q_ASM_UPCAST(me))->temp.tatbl = \
(struct QMTranActTable const *)(tatbl_))), \
(QState)Q_RET_TRAN_HIST)
((QState)Q_RET_HANDLED)
((QState)Q_RET_UNHANDLED)
((QState)Q_RET_SUPER)
((QMState *)0)
//! @class QF
{
//! @cond INTERNAL
uint8_t dummy;
//! @endcond
} QV;
const
static uint8_t const log2LUT[16] = {
0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
};
uint_fast8_t n = 0U;
QPSetBits tmp;
QPSetBits x = bitmask;
#if (QF_MAX_ACTIVE > 16U)
tmp = (x >> 16U);
if (tmp != 0U) {
n += 16U;
x = tmp;
}
#endif
#if (QF_MAX_ACTIVE > 8U)
tmp = (x >> 8U);
if (tmp != 0U) {
n += 8U;
x = tmp;
}
#endif
tmp = (x >> 4U);
if (tmp != 0U) {
n += 4U;
x = tmp;
}
return n + log2LUT[x];
//! @class QPSet
//! @private @memberof QPSet
//! @public @memberof QPSet
//! @public @memberof QPSet
me->bits[0] = 0U;
#if (QF_MAX_ACTIVE > 32)
me->bits[1] = 0U;
#endif
const
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
return (me->bits[0] == 0U);
#else
return (me->bits[0] == 0U) ? (me->bits[1] == 0U) : false;
#endif
const
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
return (me->bits[0] != 0U);
#else
return (me->bits[0] != 0U) ? true : (me->bits[1] != 0U);
#endif
const
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
return (me->bits[0] & ((QPSetBits)1U << (n - 1U))) != 0U;
#else
return (n <= 32U)
? ((me->bits[0] & ((QPSetBits)1U << (n - 1U))) != 0U)
: ((me->bits[1] & ((QPSetBits)1U << (n - 33U))) != 0U);
#endif
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
me->bits[0] = (me->bits[0] | ((QPSetBits)1U << (n - 1U)));
#else
if (n <= 32U) {
me->bits[0] = (me->bits[0] | ((QPSetBits)1U << (n - 1U)));
}
else {
me->bits[1] = (me->bits[1] | ((QPSetBits)1U << (n - 33U)));
}
#endif
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
me->bits[0] = (me->bits[0] & (QPSetBits)(~((QPSetBits)1U << (n - 1U))));
#else
if (n <= 32U) {
(me->bits[0] = (me->bits[0] & ~((QPSetBits)1U << (n - 1U))));
}
else {
(me->bits[1] = (me->bits[1] & ~((QPSetBits)1U << (n - 33U))));
}
#endif
const
//! @public @memberof QPSet
//! @public @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
return QF_LOG2(me->bits[0]);
#else
return (me->bits[1] != 0U)
? (QF_LOG2(me->bits[1]) + 32U)
: (QF_LOG2(me->bits[0]));
#endif
const
//! @private @memberof QPSet
//! @private @memberof QPSet
dis->bits[0] = ~me->bits[0];
#if (QF_MAX_ACTIVE > 32U)
dis->bits[1] = ~me->bits[1];
#endif
const
//! @private @memberof QPSet
//! @private @memberof QPSet
#if (QF_MAX_ACTIVE <= 32U)
return me->bits[0] == (QPSetBits)(~dis->bits[0]);
#else
return (me->bits[0] == (QPSetBits)(~dis->bits[0]))
&& (me->bits[1] == (QPSetBits)(~dis->bits[1]));
#endif
//! @struct QSubscrList
//! @private @memberof QSubscrList
//! @private @memberof QSubscrList
//! @class QActive
//! @extends QAsm
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @static @private @memberof QActive
//! @static @private @memberof QActive
//! @static @private @memberof QActive
//! @static @private @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
// clear the whole QActive object, so that the framework can start
// correctly even if the startup code fails to clear the uninitialized
// data (as is required by the C Standard).
QF_bzero_(me, sizeof(*me));
// NOTE: QActive inherits the abstract QAsm class, but it calls the
// constructor of the QHsm subclass. This is because QActive inherits
// the behavior from the QHsm subclass.
QHsm_ctor((QHsm *)(me), initial);
// NOTE: this vtable is identical as QHsm, but is provided
// for the QActive subclass to provide a UNIQUE vptr to distinguish
// subclasses of QActive (e.g., in the debugger).
static struct QAsmVtable const vtable = { // QActive virtual table
&QHsm_init_,
&QHsm_dispatch_,
&QHsm_isIn_
#ifdef Q_SPY
,&QHsm_getStateHandler_
#endif
};
me->super.vptr = &vtable; // hook vptr to QActive vtable
//! @public @memberof QActive
//! @public @memberof QActive
//! @public @memberof QActive
//! @public @memberof QActive
//! @protected @memberof QActive
//! @protected @memberof QActive
//! @private @memberof QActive
//! @private @memberof QActive
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
if (me->pthre == 0U) { // preemption-threshold not defined?
me->pthre = me->prio; // apply the default
}
#ifndef Q_UNSAFE
Q_REQUIRE_INCRIT(100, (0U < me->prio) && (me->prio <= QF_MAX_ACTIVE)
&& (QActive_registry_[me->prio] == (QActive *)0)
&& (me->prio <= me->pthre));
uint8_t prev_thre = me->pthre;
uint8_t next_thre = me->pthre;
uint_fast8_t p;
for (p = (uint_fast8_t)me->prio - 1U; p > 0U; --p) {
if (QActive_registry_[p] != (QActive *)0) {
prev_thre = QActive_registry_[p]->pthre;
break;
}
}
for (p = (uint_fast8_t)me->prio + 1U; p <= QF_MAX_ACTIVE; ++p) {
if (QActive_registry_[p] != (QActive *)0) {
next_thre = QActive_registry_[p]->pthre;
break;
}
}
Q_ASSERT_INCRIT(190, (prev_thre <= me->pthre)
&& (me->pthre <= next_thre));
me->prio_dis = (uint8_t)(~me->prio);
me->pthre_dis = (uint8_t)(~me->pthre);
#endif // Q_UNSAFE
// register the AO at the QF-prio.
QActive_registry_[me->prio] = me;
QF_MEM_APP();
QF_CRIT_EXIT();
//! @private @memberof QActive
//! @private @memberof QActive
uint_fast8_t const p = (uint_fast8_t)me->prio;
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(200, (0U < p) && (p <= QF_MAX_ACTIVE)
&& (QActive_registry_[p] == me));
QActive_registry_[p] = (QActive *)0; // free-up the prio. level
me->super.state.fun = Q_STATE_CAST(0); // invalidate the state
QF_MEM_APP();
QF_CRIT_EXIT();
//! @private @memberof QActive
//! @private @memberof QActive
#ifndef Q_SPY
Q_UNUSED_PAR(sender);
#endif
#ifdef Q_UTEST // test?
#if (Q_UTEST != 0) // testing QP-stub?
if (me->super.temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
return QActiveDummy_fakePost_(me, e, margin, sender);
}
#endif // (Q_UTEST != 0)
#endif // def Q_UTEST
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
QEQueueCtr tmp = me->eQueue.nFree; // get volatile into temporary
#ifndef Q_UNSAFE
QEQueueCtr dis = (QEQueueCtr)~me->eQueue.nFree_dis;
Q_INVARIANT_INCRIT(201, (QEvt_verify_(e)) && (tmp == dis));
#endif // ndef Q_UNSAFE
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_DEF(&QActive_post_)
QS_TEST_PROBE_ID(1,
tmp = 0U; // fake no free events
)
// required margin available?
bool status;
if (margin == QF_NO_MARGIN) {
if (tmp > 0U) { // free entries available in the queue?
status = true; // can post
}
else { // no free entries available
status = false; // cannot post
// The queue overflows, but QF_NO_MARGIN indicates that
// the "event delivery guarantee" is required.
Q_ERROR_INCRIT(210); // must be able to post the event
}
}
else if (tmp > (QEQueueCtr)margin) { // enough free entries?
status = true; // can post
}
else { // the # free entries below the requested margin
status = false; // cannot post, but don't assert
}
// is it a mutable event?
if (QEvt_getPoolNum_(e) != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
if (status) { // can post the event?
--tmp; // one free entry just used up
me->eQueue.nFree = tmp; // update the original
#ifndef Q_UNSAFE
me->eQueue.nFree_dis = (QEQueueCtr)~tmp; // update the DIS
if (me->eQueue.nMin > tmp) {
me->eQueue.nMin = tmp; // update minimum so far
}
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_ACTIVE_POST, me->prio)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(sender); // the sender object
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this active object (recipient)
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
#ifndef Q_UNSAFE
QS_EQC_PRE(me->eQueue.nMin); // min # free entries
#else
QS_EQC_PRE(0U); // min # free entries
#endif
QS_END_PRE()
#ifdef Q_UTEST
// callback to examine the posted event under the same conditions
// as producing the #QS_QF_ACTIVE_POST trace record, which are:
// the local filter for this AO ('me->prio') is set
if (QS_LOC_CHECK_(me->prio)) {
QF_MEM_APP();
QF_CRIT_EXIT();
QS_onTestPost(sender, me, e, status);
QF_CRIT_ENTRY();
QF_MEM_SYS();
}
#endif // def Q_UTEST
if (me->eQueue.frontEvt == (QEvt *)0) { // is the queue empty?
me->eQueue.frontEvt = e; // deliver event directly
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(211, me->eQueue.frontEvt_dis
== (uintptr_t)~Q_PTR2UINT_CAST_((QEvt *)0));
me->eQueue.frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(e);
#endif // ndef Q_UNSAFE
#ifdef QXK_H_
if (me->super.state.act == Q_ACTION_CAST(0)) { // eXtended?
QXTHREAD_EQUEUE_SIGNAL_(me); // signal eXtended Thread
}
else {
QACTIVE_EQUEUE_SIGNAL_(me); // signal the Active Object
}
#else
QACTIVE_EQUEUE_SIGNAL_(me); // signal the Active Object
#endif // def QXK_H_
}
else { // queue was not empty, insert event into the ring-buffer
tmp = me->eQueue.head; // get volatile into temporary
#ifndef Q_UNSAFE
dis = (QEQueueCtr)~me->eQueue.head_dis;
Q_INVARIANT_INCRIT(212, tmp == dis);
#endif // ndef Q_UNSAFE
me->eQueue.ring[tmp] = e; // insert e into buffer
if (tmp == 0U) { // need to wrap the head?
tmp = me->eQueue.end;
}
--tmp; // advance the head (counter-clockwise)
me->eQueue.head = tmp; // update the original
#ifndef Q_UNSAFE
me->eQueue.head_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
}
QF_MEM_APP();
QF_CRIT_EXIT();
}
else { // event cannot be posted
QS_BEGIN_PRE(QS_QF_ACTIVE_POST_ATTEMPT, me->prio)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(sender); // the sender object
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this active object (recipient)
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
QS_EQC_PRE(margin); // margin requested
QS_END_PRE()
#ifdef Q_UTEST
// callback to examine the posted event under the same conditions
// as producing the #QS_QF_ACTIVE_POST trace record, which are:
// the local filter for this AO ('me->prio') is set
if (QS_LOC_CHECK_(me->prio)) {
QF_MEM_APP();
QF_CRIT_EXIT();
QS_onTestPost(sender, me, e, status);
QF_CRIT_ENTRY();
QF_MEM_SYS();
}
#endif // def Q_USTEST
QF_MEM_APP();
QF_CRIT_EXIT();
#if (QF_MAX_EPOOL > 0U)
QF_gc(e); // recycle the event to avoid a leak
#endif // (QF_MAX_EPOOL > 0U)
}
return status;
//! @private @memberof QActive
//! @private @memberof QActive
#ifdef Q_UTEST // test?
#if (Q_UTEST != 0) // testing QP-stub?
if (me->super.temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
QActiveDummy_fakePostLIFO_(me, e);
return;
}
#endif // (Q_UTEST != 0)
#endif // def Q_UTEST
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// the posted event must be be valid (which includes not NULL)
Q_REQUIRE_INCRIT(300, e != (QEvt *)0);
QEQueueCtr tmp = me->eQueue.nFree; // get volatile into temporary
#ifndef Q_UNSAFE
QEQueueCtr dis = (QEQueueCtr)~me->eQueue.nFree_dis;
Q_INVARIANT_INCRIT(301, (QEvt_verify_(e)) && (tmp == dis));
#endif // ndef Q_UNSAFE
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_DEF(&QActive_postLIFO_)
QS_TEST_PROBE_ID(1,
tmp = 0U; // fake no free events
)
// The queue must NOT overflow for the LIFO posting policy.
Q_REQUIRE_INCRIT(310, tmp != 0U);
if (QEvt_getPoolNum_(e) != 0U) { // is it a mutable event?
QEvt_refCtr_inc_(e); // increment the reference counter
}
--tmp; // one free entry just used up
me->eQueue.nFree = tmp; // update the original
#ifndef Q_UNSAFE
me->eQueue.nFree_dis = (QEQueueCtr)~tmp;
if (me->eQueue.nMin > tmp) {
me->eQueue.nMin = tmp; // update minimum so far
}
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_ACTIVE_POST_LIFO, me->prio)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
#ifndef Q_UNSAFE
QS_EQC_PRE(me->eQueue.nMin); // min # free entries
#else
QS_EQC_PRE(0U); // min # free entries
#endif
QS_END_PRE()
#ifdef Q_UTEST
// callback to examine the posted event under the same conditions
// as producing the #QS_QF_ACTIVE_POST trace record, which are:
// the local filter for this AO ('me->prio') is set
if (QS_LOC_CHECK_(me->prio)) {
QF_MEM_APP();
QF_CRIT_EXIT();
QS_onTestPost((QActive *)0, me, e, true);
QF_CRIT_ENTRY();
QF_MEM_SYS();
}
#endif // def Q_UTEST
QEvt const * const frontEvt = me->eQueue.frontEvt;
me->eQueue.frontEvt = e; // deliver the event directly to the front
#ifndef Q_UNSAFE
me->eQueue.frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(e);
#endif // ndef Q_UNSAFE
if (frontEvt != (QEvt *)0) { // was the queue NOT empty?
tmp = me->eQueue.tail; // get volatile into temporary;
#ifndef Q_UNSAFE
dis = (QEQueueCtr)~me->eQueue.tail_dis;
Q_INVARIANT_INCRIT(311, tmp == dis);
#endif // ndef Q_UNSAFE
++tmp;
if (tmp == me->eQueue.end) { // need to wrap the tail?
tmp = 0U; // wrap around
}
me->eQueue.tail = tmp;
#ifndef Q_UNSAFE
me->eQueue.tail_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
me->eQueue.ring[tmp] = frontEvt;
}
else { // queue was empty
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
}
QF_MEM_APP();
QF_CRIT_EXIT();
//! @private @memberof QActive
//! @private @memberof QActive
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// wait for event to arrive directly (depends on QP port)
// NOTE: might use assertion-IDs 400-409
QACTIVE_EQUEUE_WAIT_(me);
// always remove event from the front
QEvt const * const e = me->eQueue.frontEvt;
QEQueueCtr tmp = me->eQueue.nFree; // get volatile into temporary
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(410, e != (QEvt *)0); // queue must NOT be empty
Q_INVARIANT_INCRIT(411, Q_PTR2UINT_CAST_(e)
== (uintptr_t)~me->eQueue.frontEvt_dis);
QEQueueCtr dis = (QEQueueCtr)~me->eQueue.nFree_dis;
Q_INVARIANT_INCRIT(412, tmp == dis);
#endif // ndef Q_UNSAFE
++tmp; // one more free event in the queue
me->eQueue.nFree = tmp; // update the # free
#ifndef Q_UNSAFE
me->eQueue.nFree_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
if (tmp <= me->eQueue.end) { // any events in the ring buffer?
QS_BEGIN_PRE(QS_QF_ACTIVE_GET, me->prio)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
QS_END_PRE()
// remove event from the tail
tmp = me->eQueue.tail; // get volatile into temporary
#ifndef Q_UNSAFE
dis = (QEQueueCtr)~me->eQueue.tail_dis;
Q_INVARIANT_INCRIT(420, tmp == dis);
#endif // ndef Q_UNSAFE
QEvt const * const frontEvt = me->eQueue.ring[tmp];
#ifndef Q_UNSAFE
Q_ASSERT_INCRIT(421, frontEvt != (QEvt *)0);
me->eQueue.frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(frontEvt);
#endif // ndef Q_UNSAFE
me->eQueue.frontEvt = frontEvt; // update the original
if (tmp == 0U) { // need to wrap the tail?
tmp = me->eQueue.end;
}
--tmp; // advance the tail (counter-clockwise)
me->eQueue.tail = tmp; // update the original
#ifndef Q_UNSAFE
me->eQueue.tail_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
}
else {
me->eQueue.frontEvt = (QEvt *)0; // queue becomes empty
#ifndef Q_UNSAFE
me->eQueue.frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_((QEvt *)0);
#endif // ndef Q_UNSAFE
// all entries in the queue must be free (+1 for fronEvt)
Q_ASSERT_INCRIT(440, tmp == (me->eQueue.end + 1U));
QS_BEGIN_PRE(QS_QF_ACTIVE_GET_LAST, me->prio)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_END_PRE()
}
QF_MEM_APP();
QF_CRIT_EXIT();
return e;
//! @static @public @memberof QActive
//! @static @public @memberof QActive
QActive_subscrList_ = subscrSto;
QActive_maxPubSignal_ = maxSignal;
// initialize the subscriber list
for (enum_t sig = 0; sig < maxSignal; ++sig) {
QPSet_setEmpty(&subscrSto[sig].set);
#ifndef Q_UNSAFE
QPSet_update_(&subscrSto[sig].set, &subscrSto[sig].set_dis);
#endif
}
//! @static @private @memberof QActive
//! @static @private @memberof QActive
#ifndef Q_SPY
Q_UNUSED_PAR(sender);
Q_UNUSED_PAR(qsId);
#endif
QSignal const sig = e->sig;
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(200, sig < (QSignal)QActive_maxPubSignal_);
Q_INVARIANT_INCRIT(202,
QPSet_verify_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis));
QS_BEGIN_PRE(QS_QF_PUBLISH, qsId)
QS_TIME_PRE(); // the timestamp
QS_OBJ_PRE(sender); // the sender object
QS_SIG_PRE(sig); // the signal of the event
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_END_PRE()
// is it a mutable event?
if (QEvt_getPoolNum_(e) != 0U) {
// NOTE: The reference counter of a mutable event is incremented to
// prevent premature recycling of the event while the multicasting
// is still in progress. At the end of the function, the garbage
// collector step (QF_gc()) decrements the reference counter and
// recycles the event if the counter drops to zero. This covers the
// case when the event was published without any subscribers.
QEvt_refCtr_inc_(e);
}
// make a local, modifiable copy of the subscriber set
QPSet subscrSet = QActive_subscrList_[sig].set;
QF_MEM_APP();
QF_CRIT_EXIT();
if (QPSet_notEmpty(&subscrSet)) { // any subscribers?
// highest-prio subscriber
uint_fast8_t p = QPSet_findMax(&subscrSet);
QF_CRIT_ENTRY();
QF_MEM_SYS();
QActive *a = QActive_registry_[p];
// the AO must be registered with the framework
Q_ASSERT_INCRIT(210, a != (QActive *)0);
QF_MEM_APP();
QF_CRIT_EXIT();
QF_SCHED_STAT_
QF_SCHED_LOCK_(p); // lock the scheduler up to AO's prio
uint_fast8_t lbound = QF_MAX_ACTIVE + 1U; // fixed upper loop bound
do { // loop over all subscribers
--lbound;
// QACTIVE_POST() asserts internally if the queue overflows
QACTIVE_POST(a, e, sender);
QPSet_remove(&subscrSet, p); // remove the handled subscriber
if (QPSet_notEmpty(&subscrSet)) { // still more subscribers?
p = QPSet_findMax(&subscrSet); // highest-prio subscriber
QF_CRIT_ENTRY();
QF_MEM_SYS();
a = QActive_registry_[p];
// the AO must be registered with the framework
Q_ASSERT_INCRIT(220, a != (QActive *)0);
QF_MEM_APP();
QF_CRIT_EXIT();
}
else {
p = 0U; // no more subscribers
}
} while ((p != 0U) && (lbound > 0U));
QF_CRIT_ENTRY();
// NOTE: the following postcondition can only succeed when
// (lbound > 0), so no extra check for lbound is necessary.
Q_ENSURE_INCRIT(290, p == 0U); // all subscribers processed
QF_CRIT_EXIT();
QF_SCHED_UNLOCK_(); // unlock the scheduler
}
// The following garbage collection step decrements the reference counter
// and recycles the event if the counter drops to zero. This covers both
// cases when the event was published with or without any subscribers.
#if (QF_MAX_EPOOL > 0U)
QF_gc(e); // recycle the event to avoid a leak
#endif
const
//! @protected @memberof QActive
//! @protected @memberof QActive
uint_fast8_t const p = (uint_fast8_t)me->prio;
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(300, (Q_USER_SIG <= sig)
&& (sig < QActive_maxPubSignal_)
&& (0U < p) && (p <= QF_MAX_ACTIVE)
&& (QActive_registry_[p] == me));
Q_INVARIANT_INCRIT(302,
QPSet_verify_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis));
QS_BEGIN_PRE(QS_QF_ACTIVE_SUBSCRIBE, p)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_END_PRE()
// insert the prio. into the subscriber set
QPSet_insert(&QActive_subscrList_[sig].set, p);
#ifndef Q_UNSAFE
QPSet_update_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis);
#endif
QF_MEM_APP();
QF_CRIT_EXIT();
const
//! @protected @memberof QActive
//! @protected @memberof QActive
uint_fast8_t const p = (uint_fast8_t)me->prio;
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(400, (Q_USER_SIG <= sig)
&& (sig < QActive_maxPubSignal_)
&& (0U < p) && (p <= QF_MAX_ACTIVE)
&& (QActive_registry_[p] == me));
Q_INVARIANT_INCRIT(402,
QPSet_verify_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis));
QS_BEGIN_PRE(QS_QF_ACTIVE_UNSUBSCRIBE, p)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_END_PRE()
// remove the prio. from the subscriber set
QPSet_remove(&QActive_subscrList_[sig].set, p);
#ifndef Q_UNSAFE
QPSet_update_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis);
#endif
QF_MEM_APP();
QF_CRIT_EXIT();
const
//! @protected @memberof QActive
//! @protected @memberof QActive
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
uint_fast8_t const p = (uint_fast8_t)me->prio;
Q_REQUIRE_INCRIT(500, (0U < p) && (p <= QF_MAX_ACTIVE)
&& (QActive_registry_[p] == me));
enum_t const maxPubSig = QActive_maxPubSignal_;
QF_MEM_APP();
QF_CRIT_EXIT();
for (enum_t sig = Q_USER_SIG; sig < maxPubSig; ++sig) {
QF_CRIT_ENTRY();
QF_MEM_SYS();
if (QPSet_hasElement(&QActive_subscrList_[sig].set, p)) {
QPSet_remove(&QActive_subscrList_[sig].set, p);
#ifndef Q_UNSAFE
QPSet_update_(&QActive_subscrList_[sig].set,
&QActive_subscrList_[sig].set_dis);
#endif
QS_BEGIN_PRE(QS_QF_ACTIVE_UNSUBSCRIBE, p)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(sig); // the signal of this event
QS_OBJ_PRE(me); // this active object
QS_END_PRE()
}
QF_MEM_APP();
QF_CRIT_EXIT();
QF_CRIT_EXIT_NOP(); // prevent merging critical sections
}
const
//! @protected @memberof QActive
//! @protected @memberof QActive
bool const status = QEQueue_post(eq, e, 0U, me->prio);
QS_CRIT_STAT
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_ACTIVE_DEFER, me->prio)
QS_TIME_PRE(); // time stamp
QS_OBJ_PRE(me); // this active object
QS_OBJ_PRE(eq); // the deferred queue
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
return status;
//! @protected @memberof QActive
//! @protected @memberof QActive
QEvt const * const e = QEQueue_get(eq, me->prio);
QF_CRIT_STAT
bool recalled;
if (e != (QEvt *)0) { // event available?
QACTIVE_POST_LIFO(me, e); // post it to the front of the AO's queue
QF_CRIT_ENTRY();
QF_MEM_SYS();
if (QEvt_getPoolNum_(e) != 0U) { // is it a mutable event?
// after posting to the AO's queue the event must be referenced
// at least twice: once in the deferred event queue (eq->get()
// did NOT decrement the reference counter) and once in the
// AO's event queue.
Q_ASSERT_INCRIT(210, e->refCtr_ >= 2U);
// we need to decrement the reference counter once, to account
// for removing the event from the deferred event queue.
QEvt_refCtr_dec_(e); // decrement the reference counter
}
QS_BEGIN_PRE(QS_QF_ACTIVE_RECALL, me->prio)
QS_TIME_PRE(); // time stamp
QS_OBJ_PRE(me); // this active object
QS_OBJ_PRE(eq); // the deferred queue
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_END_PRE()
QF_MEM_APP();
QF_CRIT_EXIT();
recalled = true;
}
else {
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_ACTIVE_RECALL_ATTEMPT, me->prio)
QS_TIME_PRE(); // time stamp
QS_OBJ_PRE(me); // this active object
QS_OBJ_PRE(eq); // the deferred queue
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
recalled = false;
}
return recalled;
const
//! @protected @memberof QActive
//! @protected @memberof QActive
uint_fast16_t n = 0U;
while (n < num) {
QEvt const * const e = QEQueue_get(eq, me->prio);
if (e != (QEvt *)0) {
++n; // count one more flushed event
#if (QF_MAX_EPOOL > 0U)
QF_gc(e); // garbage collect
#endif
}
else {
break;
}
}
return n;
//! @private @memberof QActive
//! @private @memberof QActive
//! @class QMActive
//! @extends QActive
//! @protected @memberof QMActive
//! @protected @memberof QMActive
// clear the whole QMActive object, so that the framework can start
// correctly even if the startup code fails to clear the uninitialized
// data (as is required by the C Standard).
QF_bzero_(me, sizeof(*me));
// NOTE: QActive inherits the QActvie class, but it calls the
// constructor of the QMsm subclass. This is because QMActive inherits
// the behavior from the QMsm subclass.
QMsm_ctor((QMsm *)(me), initial);
// NOTE: this vtable is identical as QMsm, but is provided
// for the QMActive subclass to provide a UNIQUE vptr to distinguish
// subclasses of QActive (e.g., in the debugger).
static struct QAsmVtable const vtable = { // QMActive virtual table
&QMsm_init_,
&QMsm_dispatch_,
&QMsm_isIn_
#ifdef Q_SPY
,&QMsm_getStateHandler_
#endif
};
me->super.super.vptr = &vtable; // hook vptr to QMActive vtable
//! @class QTimeEvt
//! @extends QEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @private @memberof QTimeEvt
//! @static @private @memberof QTimeEvt
//! @static @private @memberof QTimeEvt
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(300, (sig != 0)
&& (tickRate < QF_MAX_TICK_RATE));
QF_CRIT_EXIT();
QEvt_ctor(&me->super, sig);
me->next = (QTimeEvt *)0;
me->act = act;
me->ctr = 0U;
me->interval = 0U;
me->tickRate = (uint8_t)tickRate;
me->flags = 0U;
#ifndef Q_UNSAFE
me->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->next);
me->ctr_dis = (QTimeEvtCtr)~me->ctr;
#endif // ndef Q_UNSAFE
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// dynamic range checks
#if (QF_TIMEEVT_CTR_SIZE == 1U)
Q_REQUIRE_INCRIT(400, (nTicks < 0xFFU) && (interval < 0xFFU));
#elif (QF_TIMEEVT_CTR_SIZE == 2U)
Q_REQUIRE_INCRIT(400, (nTicks < 0xFFFFU) && (interval < 0xFFFFU));
#endif
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(401, QEvt_verify_(&me->super));
#endif
QTimeEvtCtr const ctr = me->ctr;
uint8_t const tickRate = me->tickRate;
#ifdef Q_SPY
uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
#endif
Q_REQUIRE_INCRIT(410,
(nTicks != 0U)
&& (ctr == 0U)
&& (me->act != (void *)0)
&& (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE));
#ifndef Q_UNSAFE
QTimeEvtCtr const dis = (QTimeEvtCtr)~me->ctr_dis;
Q_INVARIANT_INCRIT(411, ctr == dis);
#else
Q_UNUSED_PAR(ctr);
#endif // ndef Q_UNSAFE
me->ctr = (QTimeEvtCtr)nTicks;
me->interval = (QTimeEvtCtr)interval;
#ifndef Q_UNSAFE
me->ctr_dis = (QTimeEvtCtr)~nTicks;
#endif // ndef Q_UNSAFE
// is the time event unlinked?
// NOTE: For the duration of a single clock tick of the specified tick
// rate a time event can be disarmed and yet still linked into the list
// because un-linking is performed exclusively in QTimeEvt_tick_().
if ((me->flags & QTE_FLAG_IS_LINKED) == 0U) {
me->flags |= QTE_FLAG_IS_LINKED; // mark as linked
// The time event is initially inserted into the separate "freshly
// armed" link list based on QTimeEvt_timeEvtHead_[tickRate].act.
// Only later, inside the QTimeEvt_tick_() function, the "freshly
// armed" list is appended to the main list of armed time events
// based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
// to keep any changes to the main list exclusively inside the
// QTimeEvt_tick_().
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(420,
Q_PTR2UINT_CAST_(me->next) == (uintptr_t)~me->next_dis);
Q_INVARIANT_INCRIT(421,
Q_PTR2UINT_CAST_(QTimeEvt_timeEvtHead_[tickRate].act) ==
(uintptr_t)(~QTimeEvt_timeEvtHead_dis_[tickRate]));
#endif
me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
QTimeEvt_timeEvtHead_[tickRate].act = me;
#ifndef Q_UNSAFE
me->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->next);
QTimeEvt_timeEvtHead_dis_[tickRate] = (uintptr_t)~Q_PTR2UINT_CAST_(me);
#endif // ndef Q_UNSAFE
}
QS_BEGIN_PRE(QS_QF_TIMEEVT_ARM, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this time event object
QS_OBJ_PRE(me->act); // the active object
QS_TEC_PRE(nTicks); // the # ticks
QS_TEC_PRE(interval); // the interval
QS_U8_PRE(tickRate); // tick rate
QS_END_PRE()
QF_MEM_APP();
QF_CRIT_EXIT();
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
QTimeEvtCtr const ctr = me->ctr;
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(500, QEvt_verify_(&me->super));
QTimeEvtCtr const dis = (QTimeEvtCtr)~me->ctr_dis;
Q_INVARIANT_INCRIT(501, ctr == dis);
#endif // ndef Q_UNSAFE
#ifdef Q_SPY
uint_fast8_t const qsId = QACTIVE_CAST_(me->act)->prio;
#endif
// was the time event actually armed?
bool wasArmed;
if (ctr != 0U) {
wasArmed = true;
me->flags |= QTE_FLAG_WAS_DISARMED;
me->ctr = 0U; // schedule removal from the list
#ifndef Q_UNSAFE
me->ctr_dis = (QTimeEvtCtr)~0U;
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_TIMEEVT_DISARM, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this time event object
QS_OBJ_PRE(me->act); // the target AO
QS_TEC_PRE(ctr); // the # ticks
QS_TEC_PRE(me->interval); // the interval
QS_U8_PRE(me->tickRate); // tick rate
QS_END_PRE()
}
else { // the time event was already disarmed automatically
wasArmed = false;
me->flags &= (uint8_t)(~QTE_FLAG_WAS_DISARMED & 0xFFU);
QS_BEGIN_PRE(QS_QF_TIMEEVT_DISARM_ATTEMPT, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this time event object
QS_OBJ_PRE(me->act); // the target AO
QS_U8_PRE(me->tickRate); // tick rate
QS_END_PRE()
}
QF_MEM_APP();
QF_CRIT_EXIT();
return wasArmed;
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// dynamic range checks
#if (QF_TIMEEVT_CTR_SIZE == 1U)
Q_REQUIRE_INCRIT(600, nTicks < 0xFFU);
#elif (QF_TIMEEVT_CTR_SIZE == 2U)
Q_REQUIRE_INCRIT(600, nTicks < 0xFFFFU);
#endif
uint8_t const tickRate = me->tickRate;
QTimeEvtCtr const ctr = me->ctr;
Q_REQUIRE_INCRIT(600,
(nTicks != 0U)
&& (me->act != (void *)0)
&& (tickRate < QF_MAX_TICK_RATE));
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(601, QEvt_verify_(&me->super));
QTimeEvtCtr const dis = (QTimeEvtCtr)~me->ctr_dis;
Q_INVARIANT_INCRIT(602, ctr == dis);
#endif // ndef Q_UNSAFE
#ifdef Q_SPY
uint_fast8_t const qsId = ((QActive *)(me->act))->prio;
#endif
me->ctr = (QTimeEvtCtr)nTicks;
#ifndef Q_UNSAFE
me->ctr_dis = (QTimeEvtCtr)~nTicks;
#endif // ndef Q_UNSAFE
// was the time evt not running?
bool wasArmed;
if (ctr == 0U) {
wasArmed = false;
// NOTE: For the duration of a single clock tick of the specified
// tick rate a time event can be disarmed and yet still linked into
// the list, because unlinking is performed exclusively in the
// QTimeEvt_tick_() function.
// is the time event unlinked?
if ((me->flags & QTE_FLAG_IS_LINKED) == 0U) {
me->flags |= QTE_FLAG_IS_LINKED; // mark as linked
// The time event is initially inserted into the separate "freshly
// armed" link list based on QTimeEvt_timeEvtHead_[tickRate].act.
// Only later, inside the QTimeEvt_tick_() function, the "freshly
// armed" list is appended to the main list of armed time events
// based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
// to keep any changes to the main list exclusively inside
// QTimeEvt_tick_().
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(620,
Q_PTR2UINT_CAST_(me->next) == (uintptr_t)~me->next_dis);
Q_INVARIANT_INCRIT(621,
Q_PTR2UINT_CAST_(QTimeEvt_timeEvtHead_[tickRate].act) ==
(uintptr_t)(~QTimeEvt_timeEvtHead_dis_[tickRate]));
#endif
me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
QTimeEvt_timeEvtHead_[tickRate].act = me;
#ifndef Q_UNSAFE
me->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->next);
QTimeEvt_timeEvtHead_dis_[tickRate] =
(uintptr_t)~Q_PTR2UINT_CAST_(me);
#endif // ndef Q_UNSAFE
}
}
else { // the time event was armed
wasArmed = true;
}
QS_BEGIN_PRE(QS_QF_TIMEEVT_REARM, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this time event object
QS_OBJ_PRE(me->act); // the target AO
QS_TEC_PRE(nTicks); // the # ticks
QS_TEC_PRE(me->interval); // the interval
QS_2U8_PRE(tickRate, (wasArmed ? 1U : 0U));
QS_END_PRE()
QF_MEM_APP();
QF_CRIT_EXIT();
return wasArmed;
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
bool const wasDisarmed = (me->flags & QTE_FLAG_WAS_DISARMED) != 0U;
me->flags |= QTE_FLAG_WAS_DISARMED; // mark as disarmed
QF_MEM_APP();
QF_CRIT_EXIT();
return wasDisarmed;
const
//! @public @memberof QTimeEvt
//! @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
QTimeEvtCtr const ctr = me->ctr;
QF_CRIT_EXIT();
return ctr;
//! @static @private @memberof QTimeEvt
//! @static @private @memberof QTimeEvt
for (uint_fast8_t tickRate = 0U;
tickRate < Q_DIM(QTimeEvt_timeEvtHead_);
++tickRate)
{
QTimeEvt_ctorX(&QTimeEvt_timeEvtHead_[tickRate],
(QActive *)0, Q_USER_SIG, tickRate);
#ifndef Q_UNSAFE
QTimeEvt_timeEvtHead_dis_[tickRate] =
(uintptr_t)~Q_PTR2UINT_CAST_(QTimeEvt_timeEvtHead_[tickRate].act);
#endif
}
//! @static @private @memberof QTimeEvt
//! @static @private @memberof QTimeEvt
#ifndef Q_SPY
Q_UNUSED_PAR(sender);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(800, tickRate < Q_DIM(QTimeEvt_timeEvtHead_));
QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
QS_BEGIN_PRE(QS_QF_TICK, 0U)
++prev->ctr;
QS_TEC_PRE(prev->ctr); // tick ctr
QS_U8_PRE(tickRate); // tick rate
QS_END_PRE()
// scan the linked-list of time events at this rate...
uint_fast8_t lbound = 2U*QF_MAX_ACTIVE; // fixed upper loop bound
for (; lbound > 0U; --lbound) {
Q_ASSERT_INCRIT(810, prev != (QTimeEvt *)0); // sanity check
QTimeEvt *te = prev->next; // advance down the time evt. list
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(811,
Q_PTR2UINT_CAST_(te) == (uintptr_t)~prev->next_dis);
#endif // ndef Q_UNSAFE
if (te == (QTimeEvt *)0) { // end of the list?
// any new time events armed since the last QTimeEvt_tick_()?
if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(812,
Q_PTR2UINT_CAST_(QTimeEvt_timeEvtHead_[tickRate].act)
== (uintptr_t)~QTimeEvt_timeEvtHead_dis_[tickRate]);
#endif // ndef Q_UNSAFE
prev->next = (QTimeEvt*)QTimeEvt_timeEvtHead_[tickRate].act;
QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
#ifndef Q_UNSAFE
prev->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(prev->next);
QTimeEvt_timeEvtHead_dis_[tickRate] =
(uintptr_t)~Q_PTR2UINT_CAST_((void *)0);
#endif // ndef Q_UNSAFE
te = prev->next; // switch to the new list
}
else { // all currently armed time events are processed
break; // terminate the for-loop
}
}
// the time event 'te' must be valid
Q_ASSERT_INCRIT(820, te != (QTimeEvt *)0);
QTimeEvtCtr ctr = te->ctr;
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(821, QEvt_verify_(&te->super));
QTimeEvtCtr const dis = (QTimeEvtCtr)~te->ctr_dis;
Q_INVARIANT_INCRIT(822, ctr == dis);
#endif // ndef Q_UNSAFE
if (ctr == 0U) { // time event scheduled for removal?
prev->next = te->next;
#ifndef Q_UNSAFE
prev->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(te->next);
#endif // ndef Q_UNSAFE
// mark time event 'te' as NOT linked
te->flags &= (uint8_t)(~QTE_FLAG_IS_LINKED & 0xFFU);
// do NOT advance the prev pointer
QF_MEM_APP();
QF_CRIT_EXIT(); // exit crit. section to reduce latency
// NOTE: prevent merging critical sections
// In some QF ports the critical section exit takes effect only
// on the next machine instruction. If the next instruction is
// another entry to a critical section, the critical section
// might not be really exited, but rather the two adjacent
// critical sections would be MERGED. The QF_CRIT_EXIT_NOP()
// macro contains minimal code required to prevent such merging
// of critical sections in QF ports, in which it can occur.
QF_CRIT_EXIT_NOP();
}
else if (ctr == 1U) { // is time event about to expire?
QActive * const act = (QActive *)te->act;
if (te->interval != 0U) { // periodic time evt?
te->ctr = te->interval; // rearm the time event
#ifndef Q_UNSAFE
te->ctr_dis = (QTimeEvtCtr)~te->interval;
#endif // ndef Q_UNSAFE
prev = te; // advance to this time event
}
else { // one-shot time event: automatically disarm
te->ctr = 0U;
prev->next = te->next;
#ifndef Q_UNSAFE
te->ctr_dis = (QTimeEvtCtr)~0U;
prev->next_dis = (uintptr_t)~Q_PTR2UINT_CAST_(te->next);
#endif // ndef Q_UNSAFE
// mark time event 'te' as NOT linked
te->flags &= (uint8_t)(~QTE_FLAG_IS_LINKED & 0xFFU);
// do NOT advance the prev pointer
QS_BEGIN_PRE(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
QS_OBJ_PRE(te); // this time event object
QS_OBJ_PRE(act); // the target AO
QS_U8_PRE(tickRate); // tick rate
QS_END_PRE()
}
QS_BEGIN_PRE(QS_QF_TIMEEVT_POST, act->prio)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(te); // the time event object
QS_SIG_PRE(te->super.sig);// signal of this time event
QS_OBJ_PRE(act); // the target AO
QS_U8_PRE(tickRate); // tick rate
QS_END_PRE()
#ifdef QXK_H_
if ((enum_t)te->super.sig < Q_USER_SIG) {
QXThread_timeout_(act);
QF_MEM_APP();
QF_CRIT_EXIT();
}
else {
QF_MEM_APP();
QF_CRIT_EXIT(); // exit crit. section before posting
// QACTIVE_POST() asserts if the queue overflows
QACTIVE_POST(act, &te->super, sender);
}
#else
QF_MEM_APP();
QF_CRIT_EXIT(); // exit crit. section before posting
// QACTIVE_POST() asserts if the queue overflows
QACTIVE_POST(act, &te->super, sender);
#endif
}
else { // time event keeps timing out
--ctr; // decrement the tick counter
te->ctr = ctr; // update the original
#ifndef Q_UNSAFE
te->ctr_dis = (QTimeEvtCtr)~ctr;
#endif // ndef Q_UNSAFE
prev = te; // advance to this time event
QF_MEM_APP();
QF_CRIT_EXIT(); // exit crit. section to reduce latency
// prevent merging critical sections, see NOTE above
QF_CRIT_EXIT_NOP();
}
QF_CRIT_ENTRY(); // re-enter crit. section to continue the loop
QF_MEM_SYS();
}
Q_ENSURE_INCRIT(890, lbound > 0U);
QF_MEM_APP();
QF_CRIT_EXIT();
//! @static @private @memberof QTimeEvt
//! @static @private @memberof QTimeEvt
//! @static @public @memberof QTimeEvt
//! @static @public @memberof QTimeEvt
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(900, tickRate < QF_MAX_TICK_RATE);
QF_CRIT_EXIT();
bool inactive;
if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
inactive = false;
}
else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
inactive = false;
}
else {
inactive = true;
}
return inactive;
//! @class QTicker
//! @extends QActive
//! @public @memberof QTicker
//! @public @memberof QTicker
QActive_ctor(&me->super, Q_STATE_CAST(0)); // superclass' ctor
static struct QAsmVtable const vtable = { // QTicker virtual table
&QTicker_init_,
&QTicker_dispatch_,
&QHsm_isIn_
#ifdef Q_SPY
,&QHsm_getStateHandler_
#endif
};
me->super.super.vptr = &vtable; // hook the vptr
// reuse eQueue.head for tick-rate
me->super.eQueue.head = (QEQueueCtr)tickRate;
#ifndef Q_UNSAFE
me->super.eQueue.head_dis = (QEQueueCtr)~tickRate;
#endif // ndef Q_UNSAFE
//! @private @memberof QTicker
//! @private @memberof QTicker
Q_UNUSED_PAR(me);
Q_UNUSED_PAR(par);
Q_UNUSED_PAR(qsId);
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
QACTIVE_CAST_(me)->eQueue.tail = 0U;
#ifndef Q_UNSAFE
QACTIVE_CAST_(me)->eQueue.tail_dis = (QEQueueCtr)~0U;
#endif // ndef Q_UNSAFE
QF_MEM_APP();
QF_CRIT_EXIT();
//! @private @memberof QTicker
//! @private @memberof QTicker
Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qsId);
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// get volatile into temporaries
QEQueueCtr nTicks = QACTIVE_CAST_(me)->eQueue.tail;
QEQueueCtr const tickRate = QACTIVE_CAST_(me)->eQueue.head;
#ifndef Q_UNSAFE
Q_REQUIRE_INCRIT(700, nTicks > 0U);
QEQueueCtr dis = (QEQueueCtr)~QACTIVE_CAST_(me)->eQueue.tail_dis;
Q_INVARIANT_INCRIT(701, nTicks == dis);
dis = (QEQueueCtr)~QACTIVE_CAST_(me)->eQueue.head_dis;
Q_INVARIANT_INCRIT(702, tickRate == dis);
#endif // ndef Q_UNSAFE
QACTIVE_CAST_(me)->eQueue.tail = 0U; // clear # ticks
#ifndef Q_UNSAFE
QACTIVE_CAST_(me)->eQueue.tail_dis = (QEQueueCtr)~0U;
#endif // ndef Q_UNSAFE
QF_MEM_APP();
QF_CRIT_EXIT();
for (; nTicks > 0U; --nTicks) {
QTimeEvt_tick_((uint_fast8_t)tickRate, me);
}
//! @private @memberof QTicker
//! @private @memberof QTicker
#ifndef Q_SPY
Q_UNUSED_PAR(sender);
#endif
static QEvt const tickEvt = QEVT_INITIALIZER(0);
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
QEQueueCtr nTicks = me->eQueue.tail; // get volatile into temporary
if (me->eQueue.frontEvt == (QEvt *)0) { // no tick events?
#ifndef Q_UNSAFE
Q_REQUIRE_INCRIT(800, nTicks == 0U);
Q_REQUIRE_INCRIT(801, me->eQueue.nFree == 1U);
Q_INVARIANT_INCRIT(802, me->eQueue.frontEvt_dis
== (uintptr_t)~Q_PTR2UINT_CAST_((QEvt *)0));
QEQueueCtr dis = (QEQueueCtr)~me->eQueue.nFree_dis;
Q_INVARIANT_INCRIT(803, 1U == dis);
dis = (QEQueueCtr)~me->eQueue.tail_dis;
Q_INVARIANT_INCRIT(804, 0U == dis);
#endif // ndef Q_UNSAFE
me->eQueue.frontEvt = &tickEvt; // deliver event directly
me->eQueue.nFree = 0U;
#ifndef Q_UNSAFE
me->eQueue.frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(&tickEvt);
me->eQueue.nFree_dis = (QEQueueCtr)~0U;
#endif // ndef Q_UNSAFE
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
}
else {
#ifndef Q_UNSAFE
Q_REQUIRE_INCRIT(810, (nTicks > 0U) && (nTicks < 0xFFU));
Q_REQUIRE_INCRIT(811, me->eQueue.nFree == 0U);
Q_INVARIANT_INCRIT(812, me->eQueue.frontEvt_dis
== (uintptr_t)~Q_PTR2UINT_CAST_(&tickEvt));
QEQueueCtr dis = (QEQueueCtr)~me->eQueue.nFree_dis;
Q_INVARIANT_INCRIT(813, 0U == dis);
dis = (QEQueueCtr)~me->eQueue.tail_dis;
Q_INVARIANT_INCRIT(814, nTicks == dis);
#endif // ndef Q_UNSAFE
}
++nTicks; // account for one more tick event
me->eQueue.tail = nTicks; // update the original
#ifndef Q_UNSAFE
me->eQueue.tail_dis = (QEQueueCtr)~nTicks;
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_ACTIVE_POST, me->prio)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(sender); // the sender object
QS_SIG_PRE(0U); // the signal of the event
QS_OBJ_PRE(me); // this active object
QS_2U8_PRE(0U, 0U); // poolNum & refCtr
QS_EQC_PRE(0U); // # free entries
QS_EQC_PRE(0U); // min # free entries
QS_END_PRE()
QF_MEM_APP();
QF_CRIT_EXIT();
//! @class QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
//! @private @memberof QEQueue
// dummy static member to force generating 'struct QEQueue {...}'
//! @public @memberof QEQueue
//! @public @memberof QEQueue
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
#if (QF_EQUEUE_CTR_SIZE == 1U)
Q_REQUIRE_INCRIT(100, qLen < 0xFFU);
#endif
me->frontEvt = (QEvt *)0; // no events in the queue
me->ring = qSto; // the beginning of the ring buffer
me->end = (QEQueueCtr)qLen;
if (qLen > 0U) {
me->head = 0U;
me->tail = 0U;
}
me->nFree = (QEQueueCtr)(qLen + 1U); // +1 for frontEvt
#ifndef Q_UNSAFE
me->frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->frontEvt);
me->head_dis = (QEQueueCtr)~me->head;
me->tail_dis = (QEQueueCtr)~me->tail;
me->nFree_dis = (QEQueueCtr)~me->nFree;
me->nMin = me->nFree;
#endif
QF_MEM_APP();
QF_CRIT_EXIT();
//! @public @memberof QEQueue
//! @public @memberof QEQueue
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
QEQueueCtr tmp = me->nFree; // get volatile into temporary
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(201, QEvt_verify_(e));
QEQueueCtr dis = (QEQueueCtr)~me->nFree_dis;
Q_INVARIANT_INCRIT(202, tmp == dis);
#endif // ndef Q_UNSAFE
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_DEF(&QEQueue_post)
QS_TEST_PROBE_ID(1,
tmp = 0U; // fake no free events
)
// required margin available?
bool status;
if (((margin == QF_NO_MARGIN) && (tmp > 0U))
|| (tmp > (QEQueueCtr)margin))
{
// is it a mutable event?
if (QEvt_getPoolNum_(e) != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
--tmp; // one free entry just used up
me->nFree = tmp; // update the original
#ifndef Q_UNSAFE
me->nFree_dis = (QEQueueCtr)~tmp;
if (me->nMin > tmp) {
me->nMin = tmp; // update minimum so far
}
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_EQUEUE_POST, qsId)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_OBJ_PRE(me); // this queue object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
#ifndef Q_UNSAFE
QS_EQC_PRE(me->nMin); // min # free entries
#else
QS_EQC_PRE(0U); // min # free entries
#endif
QS_END_PRE()
if (me->frontEvt == (QEvt *)0) { // is the queue empty?
me->frontEvt = e; // deliver event directly
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(211, me->frontEvt_dis
== (uintptr_t)~Q_PTR2UINT_CAST_((QEvt *)0));
me->frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(e);
#endif // ndef Q_UNSAFE
}
else { // queue was not empty, insert event into the ring-buffer
tmp = me->head; // get volatile into temporary
#ifndef Q_UNSAFE
dis = (QEQueueCtr)~me->head_dis;
Q_INVARIANT_INCRIT(212, tmp == dis);
#endif // ndef Q_UNSAFE
me->ring[tmp] = e; // insert e into buffer
if (tmp == 0U) { // need to wrap the head?
tmp = me->end;
}
--tmp; // advance head (counter-clockwise)
me->head = tmp; // update the original
#ifndef Q_UNSAFE
me->head_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
}
status = true; // event posted successfully
}
else { // event cannot be posted
// dropping events must be acceptable
Q_ASSERT_INCRIT(210, margin != QF_NO_MARGIN);
QS_BEGIN_PRE(QS_QF_EQUEUE_POST_ATTEMPT, qsId)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this queue object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
QS_EQC_PRE(margin); // margin requested
QS_END_PRE()
status = false; // event not posted
}
QF_MEM_APP();
QF_CRIT_EXIT();
return status;
//! @public @memberof QEQueue
//! @public @memberof QEQueue
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(300, e != (QEvt *)0);
QEQueueCtr tmp = me->nFree; // get volatile into temporary
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(301, QEvt_verify_(e));
QEQueueCtr dis = (QEQueueCtr)~me->nFree_dis;
Q_INVARIANT_INCRIT(302, tmp == dis);
#endif // ndef Q_UNSAFE
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_DEF(&QEQueue_postLIFO)
QS_TEST_PROBE_ID(1,
tmp = 0U; // fake no free events
)
// must be able to LIFO-post the event
Q_REQUIRE_INCRIT(310, tmp != 0U);
if (QEvt_getPoolNum_(e) != 0U) { // is it a mutable event?
QEvt_refCtr_inc_(e); // increment the reference counter
}
--tmp; // one free entry just used up
me->nFree = tmp; // update the original
#ifndef Q_UNSAFE
me->nFree_dis = (QEQueueCtr)~tmp;
if (me->nMin > tmp) {
me->nMin = tmp; // update minimum so far
}
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_EQUEUE_POST_LIFO, qsId)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this queue object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
#ifndef Q_UNSAFE
QS_EQC_PRE(me->nMin); // min # free entries
#else
QS_EQC_PRE(0U); // min # free entries
#endif
QS_END_PRE()
QEvt const * const frontEvt = me->frontEvt;
me->frontEvt = e; // deliver the event directly to the front
#ifndef Q_UNSAFE
me->frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(e);
#endif // ndef Q_UNSAFE
if (frontEvt != (QEvt *)0) { // was the queue NOT empty?
tmp = me->tail; // get volatile into temporary;
#ifndef Q_UNSAFE
dis = (QEQueueCtr)~me->tail_dis;
Q_INVARIANT_INCRIT(311, tmp == dis);
#endif // ndef Q_UNSAFE
++tmp;
if (tmp == me->end) { // need to wrap the tail?
tmp = 0U; // wrap around
}
me->tail = tmp;
#ifndef Q_UNSAFE
me->tail_dis = (QEQueueCtr)~tmp;
#endif
me->ring[tmp] = frontEvt;
}
QF_MEM_APP();
QF_CRIT_EXIT();
//! @public @memberof QEQueue
//! @public @memberof QEQueue
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
QEvt const * const e = me->frontEvt; // always remove evt from the front
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(411, Q_PTR2UINT_CAST_(e)
== (uintptr_t)~me->frontEvt_dis);
#endif // ndef Q_UNSAFE
if (e != (QEvt *)0) { // was the queue not empty?
QEQueueCtr tmp = me->nFree; // get volatile into temporary
#ifndef Q_UNSAFE
QEQueueCtr const dis = (QEQueueCtr)~me->nFree_dis;
Q_INVARIANT_INCRIT(412, tmp == dis);
#endif // ndef Q_UNSAFE
++tmp; // one more free event in the queue
me->nFree = tmp; // update the # free
#ifndef Q_UNSAFE
me->nFree_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
// any events in the ring buffer?
if (tmp <= me->end) {
QS_BEGIN_PRE(QS_QF_EQUEUE_GET, qsId)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this queue object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_EQC_PRE(tmp); // # free entries
QS_END_PRE()
tmp = me->tail; // get volatile into temporary
QEvt const * const frontEvt = me->ring[tmp];
#ifndef Q_UNSAFE
Q_ASSERT_INCRIT(421, frontEvt != (QEvt *)0);
me->frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_(frontEvt);
#endif // ndef Q_UNSAFE
me->frontEvt = frontEvt; // update the original
if (tmp == 0U) { // need to wrap the tail?
tmp = me->end;
}
--tmp; // advance the tail (counter-clockwise)
me->tail = tmp; // update the original
#ifndef Q_UNSAFE
me->tail_dis = (QEQueueCtr)~tmp;
#endif // ndef Q_UNSAFE
}
else {
me->frontEvt = (QEvt *)0; // queue becomes empty
#ifndef Q_UNSAFE
me->frontEvt_dis = (uintptr_t)~Q_PTR2UINT_CAST_((QEvt *)0);
#endif // ndef Q_UNSAFE
// all entries in the queue must be free (+1 for frontEvt)
Q_INVARIANT_INCRIT(440, tmp == (me->end + 1U));
QS_BEGIN_PRE(QS_QF_EQUEUE_GET_LAST, qsId)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of this event
QS_OBJ_PRE(me); // this queue object
QS_2U8_PRE(QEvt_getPoolNum_(e), e->refCtr_);
QS_END_PRE()
}
}
QF_MEM_APP();
QF_CRIT_EXIT();
return e;
const
//! @public @memberof QEQueue
//! @public @memberof QEQueue
return me->nFree;
const
//! @public @memberof QEQueue
//! @public @memberof QEQueue
#ifndef Q_UNSAFE
return me->nMin;
#else
return 0U;
#endif
const
//! @public @memberof QEQueue
//! @public @memberof QEQueue
return me->frontEvt == (struct QEvt *)0;
//! @struct QFreeBlock
//! @private @memberof QFreeBlock
//! @private @memberof QFreeBlock
//! @class QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @private @memberof QMPool
//! @public @memberof QMPool
//! @public @memberof QMPool
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(100, poolSto != (void *)0);
Q_REQUIRE_INCRIT(101, poolSize >= (uint_fast32_t)sizeof(QFreeBlock));
Q_REQUIRE_INCRIT(102, (uint_fast16_t)(blockSize + sizeof(QFreeBlock))
> blockSize);
me->free_head = (QFreeBlock *)poolSto;
// find # free blocks in a memory block, NO DIVISION
me->blockSize = (QMPoolSize)(2U * sizeof(void *));
uint_fast16_t nblocks = 1U;
while (me->blockSize < (QMPoolSize)blockSize) {
me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
++nblocks;
}
// the pool buffer must fit at least one rounded-up block
Q_ASSERT_INCRIT(110, poolSize >= me->blockSize);
// start at the head of the free list
QFreeBlock *fb = me->free_head;
uint32_t nTot = 1U; // the last block already in the list
// chain all blocks together in a free-list...
for (uint_fast32_t size = poolSize - me->blockSize;
size >= (uint_fast32_t)me->blockSize;
size -= (uint_fast32_t)me->blockSize)
{
fb->next = &fb[nblocks]; // point next link to next block
#ifndef Q_UNSAFE
fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb->next));
#endif
fb = fb->next; // advance to the next block
++nTot; // one more free block in the pool
}
// dynamic range check
#if (QF_MPOOL_CTR_SIZE == 1U)
Q_ENSURE_INCRIT(190, nTot < 0xFFU);
#elif (QF_MPOOL_CTR_SIZE == 2U)
Q_ENSURE_INCRIT(190, nTot < 0xFFFFU);
#endif
fb->next = (QFreeBlock *)0; // the last link points to NULL
me->nTot = (QMPoolCtr)nTot;
me->nFree = me->nTot; // all blocks are free
me->start = (QFreeBlock *)poolSto; // the original start this pool buffer
me->end = fb; // the last block in this pool
#ifndef Q_UNSAFE
me->free_head_dis = (uintptr_t)~Q_PTR2UINT_CAST_(me->free_head);
me->nFree_dis = (QMPoolCtr)~me->nFree;
me->nMin = me->nTot; // the minimum # free blocks
fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb->next));
#endif
QF_MEM_APP();
QF_CRIT_EXIT();
//! @public @memberof QMPool
//! @public @memberof QMPool
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// get volatile into temporaries
QFreeBlock *fb = me->free_head;
QMPoolCtr nFree = me->nFree;
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(301, Q_PTR2UINT_CAST_(fb)
== (uintptr_t)~me->free_head_dis);
QMPoolCtr const dis = (QMPoolCtr)~me->nFree_dis;
Q_INVARIANT_INCRIT(302, nFree == dis);
#endif // ndef Q_UNSAFE
// have more free blocks than the requested margin?
if (nFree > (QMPoolCtr)margin) {
Q_ASSERT_INCRIT(310, fb != (QFreeBlock *)0);
QFreeBlock * const fb_next = fb->next; // fast temporary
#ifndef Q_UNSAFE
// the free block must have integrity (duplicate inverse storage)
Q_INVARIANT_INCRIT(311, Q_PTR2UINT_CAST_(fb_next)
== (uintptr_t)~fb->next_dis);
#endif // ndef Q_UNSAFE
--nFree; // one less free block
if (nFree == 0U) { // is the pool becoming empty?
// pool is becoming empty, so the next free block must be NULL
Q_ASSERT_INCRIT(320, fb_next == (QFreeBlock *)0);
me->nFree = 0U;
#ifndef Q_UNSAFE
me->nFree_dis = (QMPoolCtr)~0U;
me->nMin = 0U; // remember that the pool got empty
#endif // ndef Q_UNSAFE
}
else {
me->nFree = nFree; // update the original
#ifndef Q_UNSAFE
me->nFree_dis = (QMPoolCtr)~nFree;
// The pool is not empty, so the next free-block pointer
// must be in range.
Q_INVARIANT_INCRIT(330,
(me->start <= fb_next) && (fb_next <= me->end));
// is the # free blocks the new minimum so far?
if (me->nMin > nFree) {
me->nMin = nFree; // remember the minimum so far
}
#endif // ndef Q_UNSAFE
}
me->free_head = fb_next; // set the head to the next free block
#ifndef Q_UNSAFE
me->free_head_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb_next));
#endif // ndef Q_UNSAFE
QS_BEGIN_PRE(QS_QF_MPOOL_GET, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this memory pool
QS_MPC_PRE(nFree); // # of free blocks in the pool
#ifndef Q_UNSAFE
QS_MPC_PRE(me->nMin); // min # free blocks ever in the pool
#else
QS_MPC_PRE(0U); // min # free blocks (not available)
#endif // ndef Q_UNSAFE
QS_END_PRE()
}
else { // don't have enough free blocks at this point
fb = (QFreeBlock *)0;
QS_BEGIN_PRE(QS_QF_MPOOL_GET_ATTEMPT, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this memory pool
QS_MPC_PRE(nFree); // # of free blocks in the pool
QS_MPC_PRE(margin); // the requested margin
QS_END_PRE()
}
QF_MEM_APP();
QF_CRIT_EXIT();
return fb; // return the block or NULL pointer to the caller
//! @public @memberof QMPool
//! @public @memberof QMPool
#ifndef Q_SPY
Q_UNUSED_PAR(qsId);
#endif
QFreeBlock * const fb = (QFreeBlock *)block;
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// get volatile into temporaries
QFreeBlock * const free_head = me->free_head;
QMPoolCtr nFree = me->nFree;
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(401, Q_PTR2UINT_CAST_(free_head)
== (uintptr_t)~me->free_head_dis);
QMPoolCtr const dis = (QMPoolCtr)~me->nFree_dis;
Q_INVARIANT_INCRIT(402, nFree == dis);
Q_REQUIRE_INCRIT(410, nFree < me->nTot);
Q_REQUIRE_INCRIT(411, (me->start <= fb) && (fb <= me->end));
// the block must not be in the pool already
Q_REQUIRE_INCRIT(412, Q_PTR2UINT_CAST_(fb->next)
!= (uintptr_t)~fb->next_dis);
#endif // ndef Q_UNSAFE
++nFree; // one more free block in this pool
me->free_head = fb; // set as new head of the free list
me->nFree = nFree;
fb->next = free_head; // link into the list
#ifndef Q_UNSAFE
me->free_head_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(fb));
me->nFree_dis = (QMPoolCtr)~nFree;
fb->next_dis = (uintptr_t)(~Q_PTR2UINT_CAST_(free_head));
#endif
QS_BEGIN_PRE(QS_QF_MPOOL_PUT, qsId)
QS_TIME_PRE(); // timestamp
QS_OBJ_PRE(me); // this memory pool
QS_MPC_PRE(nFree); // the # free blocks in the pool
QS_END_PRE()
QF_MEM_APP();
QF_CRIT_EXIT();
//! @class QF_Attr
//! @private @memberof QF_Attr
//! @private @memberof QF_Attr
//! @private @memberof QF_Attr
//! @static @private @memberof QF
//! @static @private @memberof QF
//! @static @private @memberof QF
uint8_t *ptr = (uint8_t *)start;
for (uint_fast16_t n = len; n > 0U; --n) {
*ptr = 0U;
++ptr;
}
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(400, (prio <= QF_MAX_ACTIVE)
&& (QActive_registry_[prio] != (QActive *)0));
#ifndef Q_UNSAFE
uint_fast16_t const min =
(uint_fast16_t)QActive_registry_[prio]->eQueue.nMin;
#else
uint_fast16_t const min = 0U;
#endif
QF_CRIT_EXIT();
return min;
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
//! @static @public @memberof QF
uint_fast8_t const poolNum = QF_priv_.maxPool_;
// see precondition{qf_dyn,200} and precondition{qf_dyn,201}
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(200, poolNum < QF_MAX_EPOOL);
if (poolNum > 0U) {
Q_REQUIRE_INCRIT(201,
QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolNum - 1U]) < evtSize);
}
QF_priv_.maxPool_ = poolNum + 1U; // one more pool
QF_MEM_APP();
QF_CRIT_EXIT();
// perform the port-dependent initialization of the event-pool
QF_EPOOL_INIT_(QF_priv_.ePool_[poolNum], poolSto, poolSize, evtSize);
#ifdef Q_SPY
// generate the object-dictionary entry for the initialized pool
{
uint8_t obj_name[9] = "EvtPool?";
obj_name[7] = (uint8_t)((uint8_t)'0' + poolNum + 1U);
QS_obj_dict_pre_(&QF_priv_.ePool_[poolNum], (char const *)obj_name);
}
#endif // Q_SPY
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
uint_fast16_t const max_size =
QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[QF_priv_.maxPool_ - 1U]);
QF_MEM_APP();
QF_CRIT_EXIT();
return max_size;
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(400, (poolNum <= QF_MAX_EPOOL)
&& (0U < poolNum) && (poolNum <= QF_priv_.maxPool_));
#ifndef Q_UNSAFE
uint_fast16_t const min = (uint_fast16_t)QF_priv_.ePool_[poolNum - 1U].nMin;
#else
uint_fast16_t const min = 0U;
#endif
QF_MEM_APP();
QF_CRIT_EXIT();
return min;
//! @static @private @memberof QF
//! @static @private @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
// find the pool id that fits the requested event size...
uint_fast8_t poolNum = 0U; // zero-based poolNum initially
for (; poolNum < QF_priv_.maxPool_; ++poolNum) {
if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolNum])) {
break;
}
}
// precondition:
// - cannot run out of registered pools
Q_REQUIRE_INCRIT(300, poolNum < QF_priv_.maxPool_);
++poolNum; // convert to 1-based poolNum
QF_MEM_APP();
QF_CRIT_EXIT();
// get event e (port-dependent)...
QEvt *e;
#ifdef Q_SPY
QF_EPOOL_GET_(QF_priv_.ePool_[poolNum - 1U], e,
((margin != QF_NO_MARGIN) ? margin : 0U),
(uint_fast8_t)QS_EP_ID + poolNum);
#else
QF_EPOOL_GET_(QF_priv_.ePool_[poolNum - 1U], e,
((margin != QF_NO_MARGIN) ? margin : 0U), 0U);
#endif
if (e != (QEvt *)0) { // was e allocated correctly?
e->sig = (QSignal)sig; // set the signal
e->refCtr_ = 0U; // initialize the reference counter to 0
e->evtTag_ = (uint8_t)((poolNum << 4U) | 0x0FU);
QS_CRIT_ENTRY();
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_NEW,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_EVS_PRE(evtSize); // the size of the event
QS_SIG_PRE(sig); // the signal of the event
QS_END_PRE()
QS_MEM_APP();
QS_CRIT_EXIT();
}
else { // event was not allocated
QF_CRIT_ENTRY();
// This assertion means that the event allocation failed,
// and this failure cannot be tolerated. The most frequent
// reason is an event leak in the application.
Q_ASSERT_INCRIT(320, margin != QF_NO_MARGIN);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_NEW_ATTEMPT,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_EVS_PRE(evtSize); // the size of the event
QS_SIG_PRE(sig); // the signal of the event
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
}
// the returned event e is guaranteed to be valid (not NULL)
// if we can't tolerate failed allocation
return e;
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(400, e != (QEvt *)0);
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(401, QEvt_verify_(e));
#endif
uint_fast8_t const poolNum = QEvt_getPoolNum_(e);
if (poolNum != 0U) { // is it a pool event (mutable)?
QF_MEM_SYS();
if (e->refCtr_ > 1U) { // isn't this the last reference?
QS_BEGIN_PRE(QS_QF_GC_ATTEMPT,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(poolNum, e->refCtr_);
QS_END_PRE()
QEvt_refCtr_dec_(e); // decrement the ref counter
QF_MEM_APP();
QF_CRIT_EXIT();
}
else { // this is the last reference to this event, recycle it
QS_BEGIN_PRE(QS_QF_GC,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(poolNum, e->refCtr_);
QS_END_PRE()
// pool number must be in range
Q_ASSERT_INCRIT(410, (poolNum <= QF_priv_.maxPool_)
&& (poolNum <= QF_MAX_EPOOL));
QF_MEM_APP();
QF_CRIT_EXIT();
// NOTE: casting 'const' away is legit because it's a pool event
#ifdef Q_SPY
QF_EPOOL_PUT_(QF_priv_.ePool_[poolNum - 1U],
(QEvt *)e,
(uint_fast8_t)QS_EP_ID + poolNum);
#else
QF_EPOOL_PUT_(QF_priv_.ePool_[poolNum - 1U],
(QEvt *)e, 0U);
#endif
}
}
else {
QF_CRIT_EXIT();
}
//! @static @private @memberof QF
//! @static @private @memberof QF
#ifdef Q_UNSAFE
Q_UNUSED_PAR(evtRef);
#endif
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(500, e != (QEvt *)0);
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(501, QEvt_verify_(e));
#endif
uint_fast8_t const poolNum = QEvt_getPoolNum_(e);
Q_UNUSED_PAR(poolNum); // might be unused
Q_REQUIRE_INCRIT(510, (poolNum != 0U)
&& (evtRef == (void *)0));
QEvt_refCtr_inc_(e); // increments the ref counter
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_NEW_REF,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(poolNum, e->refCtr_);
QS_END_PRE()
QS_MEM_APP();
QF_CRIT_EXIT();
return e;
//! @static @private @memberof QF
//! @static @private @memberof QF
QF_CRIT_STAT
QF_CRIT_ENTRY();
QEvt const * const e = (QEvt const *)evtRef;
Q_REQUIRE_INCRIT(600, e != (QEvt *)0);
#ifndef Q_UNSAFE
Q_INVARIANT_INCRIT(601, QEvt_verify_(e));
#endif // ndef Q_UNSAFE
#ifdef Q_SPY
uint_fast8_t const poolNum = QEvt_getPoolNum_(e);
QS_MEM_SYS();
QS_BEGIN_PRE(QS_QF_DELETE_REF,
(uint_fast8_t)QS_EP_ID + poolNum)
QS_TIME_PRE(); // timestamp
QS_SIG_PRE(e->sig); // the signal of the event
QS_2U8_PRE(poolNum, e->refCtr_);
QS_END_PRE()
QS_MEM_APP();
#endif // def Q_SPY
QF_CRIT_EXIT();
#if (QF_MAX_EPOOL > 0U)
QF_gc(e); // recycle the referenced event
#endif
//! @static @public @memberof QF
//! @static @public @memberof QF
((uint_fast16_t)0xFFFFU)
((QPrioSpec)((prio_) | ((pthre_) << 8U)))
((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
QF_NO_MARGIN, (enum_t)(sig_)))
\
(evtT_##_init((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
QF_NO_MARGIN, (sig_)), __VA_ARGS__))
\
((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
(margin_), (enum_t)(sig_)))
\
(evtT_##_init((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
(margin_), (sig_)), __VA_ARGS__))
\
((evtRef_) = (evtT_ const *)QF_newRef_(e, (evtRef_)))
do { \
QF_deleteRef_((evtRef_)); \
(evtRef_) = (void *)0; \
} while (false)
\
((void)QActive_post_((me_), (e_), QF_NO_MARGIN, (sender_)))
\
((void)QActive_post_((me_), (e_), QF_NO_MARGIN, (void *)0))
\
(QActive_post_((me_), (e_), (margin_), (sender_)))
\
(QActive_post_((me_), (e_), (margin_), (void *)0))
\
(QActive_postLIFO_((me_), (e_)))
\
(QActive_publish_((e_), (void const *)(sender_), (sender_)->prio))
(QActive_publish_((e_), (void *)0, 0U))
(QTimeEvt_tick_((tickRate_), (sender_)))
(QTimeEvt_tick_((tickRate_), (void *)0))
QTIMEEVT_TICK_X(0U, (sender_))
(QTicker_trig_((ticker_), (sender_)))
(QTicker_trig_((ticker_), (void *)0))
((void)0)
QTIMEEVT_TICK_X((tickRate_), (sender_))
QTIMEEVT_TICK(sender_)
QACTIVE_PUBLISH((e_), (sender_))
((void)0)
((void)0)
QMPool
\
(QMPool_init(&(p_), (poolSto_), (poolSize_), (evtSize_)))
((uint_fast16_t)(p_).blockSize)
\
((e_) = (QEvt *)QMPool_get(&(p_), (m_), (qsId_)))
\
(QMPool_put(&(p_), (e_), (qsId_)))
//! @class QV
{
//! @cond INTERNAL
uint8_t dummy;
//! @endcond
} QV;
//! @class QV_Attr
//! @memberof QV_Attr
//! @memberof QV_Attr
//! @memberof QV_Attr
//! @memberof QV_Attr
//! @static @private @memberof QV
//! @static @public @memberof QV
//! @static @public @memberof QV
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_INVARIANT_INCRIT(102, QV_priv_.schedCeil
== (uint_fast8_t)(~QV_priv_.schedCeil_dis));
if (ceiling > QV_priv_.schedCeil) { // raising the scheduler ceiling?
QS_BEGIN_PRE(QS_SCHED_LOCK, 0U)
QS_TIME_PRE(); // timestamp
// the previous sched ceiling & new sched ceiling
QS_2U8_PRE((uint8_t)QV_priv_.schedCeil,
(uint8_t)ceiling);
QS_END_PRE()
QV_priv_.schedCeil = ceiling;
#ifndef Q_UNSAFE
QV_priv_.schedCeil_dis = (uint_fast8_t)(~ceiling);
#endif
}
QF_MEM_APP();
QF_CRIT_EXIT();
//! @static @public @memberof QV
//! @static @public @memberof QV
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_INVARIANT_INCRIT(202, QV_priv_.schedCeil
== (uint_fast8_t)(~QV_priv_.schedCeil_dis));
if (QV_priv_.schedCeil != 0U) { // actually enabling the scheduler?
QS_BEGIN_PRE(QS_SCHED_UNLOCK, 0U)
QS_TIME_PRE(); // timestamp
// current sched ceiling (old), previous sched ceiling (new)
QS_2U8_PRE((uint8_t)QV_priv_.schedCeil, 0U);
QS_END_PRE()
QV_priv_.schedCeil = 0U;
#ifndef Q_UNSAFE
QV_priv_.schedCeil_dis = (uint_fast8_t)(~0U);
#endif
}
QF_MEM_APP();
QF_CRIT_EXIT();
//! @static @public @memberof QV
//! @static @public @memberof QV
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_bzero_(&QF_priv_, sizeof(QF_priv_));
QF_bzero_(&QV_priv_, sizeof(QV_priv_));
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
#ifndef Q_UNSAFE
QPSet_update_(&QV_priv_.readySet, &QV_priv_.readySet_dis);
QV_priv_.schedCeil_dis = (uint_fast8_t)(~0U);
#endif
QTimeEvt_init(); // initialize QTimeEvts
#ifdef QV_INIT
QV_INIT(); // port-specific initialization of the QV kernel
#endif
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_onCleanup(); // application-specific cleanup callback
// nothing else to do for the QV kernel
//! @static @public @memberof QF
//! @static @public @memberof QF
#ifdef Q_SPY
// produce the QS_QF_RUN trace record
QF_INT_DISABLE();
QF_MEM_SYS();
QS_beginRec_((uint_fast8_t)QS_QF_RUN);
QS_endRec_();
QF_MEM_APP();
QF_INT_ENABLE();
#endif // Q_SPY
QF_onStartup(); // application-specific startup callback
QF_INT_DISABLE();
QF_MEM_SYS();
#ifdef QV_START
QV_START(); // port-specific startup of the QV kernel
#endif
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
uint_fast8_t pprev = 0U; // previously used prio.
#ifdef QF_ON_CONTEXT_SW
// officially switch to the idle cotext
QF_onContextSw((QActive *)0, (QActive *)0);
#endif // def QF_ON_CONTEXT_SW
#endif // def (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
for (;;) { // QV event loop...
// check internal integrity (duplicate inverse storage)
Q_INVARIANT_INCRIT(302, QPSet_verify_(&QV_priv_.readySet,
&QV_priv_.readySet_dis));
// check internal integrity (duplicate inverse storage)
Q_INVARIANT_INCRIT(303, QV_priv_.schedCeil
== (uint_fast8_t)(~QV_priv_.schedCeil_dis));
// find the maximum prio. AO ready to run
uint_fast8_t const p = (QPSet_notEmpty(&QV_priv_.readySet)
? QPSet_findMax(&QV_priv_.readySet)
: 0U);
if (p > QV_priv_.schedCeil) { // is it above the sched ceiling?
QActive * const a = QActive_registry_[p];
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
QS_BEGIN_PRE(QS_SCHED_NEXT, p)
QS_TIME_PRE(); // timestamp
QS_2U8_PRE((uint8_t)p,
(uint8_t)pprev);
QS_END_PRE()
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(((pprev != 0U)
? QActive_registry_[pprev]
: (QActive *)0), a);
#endif // QF_ON_CONTEXT_SW
pprev = p; // update previous prio.
#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
QF_MEM_APP();
QF_INT_ENABLE();
QEvt const * const e = QActive_get_(a);
// NOTE QActive_get_() performs QS_MEM_APP() before return
// dispatch event (virtual call)
(*a->super.vptr->dispatch)(&a->super, e, p);
#if (QF_MAX_EPOOL > 0U)
QF_gc(e);
#endif
QF_INT_DISABLE();
QF_MEM_SYS();
if (a->eQueue.frontEvt == (QEvt *)0) { // empty queue?
QPSet_remove(&QV_priv_.readySet, p);
#ifndef Q_UNSAFE
QPSet_update_(&QV_priv_.readySet, &QV_priv_.readySet_dis);
#endif
}
}
else { // no AO ready to run --> idle
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (pprev != 0U) {
QS_BEGIN_PRE(QS_SCHED_IDLE, pprev)
QS_TIME_PRE(); // timestamp
QS_U8_PRE((uint8_t)pprev); // previous prio
QS_END_PRE()
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QActive_registry_[pprev], (QActive *)0);
#endif // QF_ON_CONTEXT_SW
pprev = 0U; // update previous prio.
}
#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
QF_MEM_APP();
// QV_onIdle() must be called with interrupts DISABLED because
// the determination of the idle condition can change at any time
// by an interrupt posting events to a queue.
//
// NOTE: QV_onIdle() MUST enable interrupts internally, ideally
// atomically with putting the CPU into a power-saving mode.
QV_onIdle();
QF_INT_DISABLE(); // disable interrupts before looping back
QF_MEM_SYS();
}
}
#ifdef __GNUC__ // GNU compiler?
return 0;
#endif
//! QActive active object class customization for QV
//! @public @memberof QActive
//! @public @memberof QActive
Q_UNUSED_PAR(stkSto); // not needed in QV
Q_UNUSED_PAR(stkSize); // not needed in QV
QF_CRIT_STAT
QF_CRIT_ENTRY();
Q_REQUIRE_INCRIT(300, stkSto == (void *)0);
QF_CRIT_EXIT();
me->prio = (uint8_t)(prioSpec & 0xFFU); // QF-prio. of the AO
me->pthre = 0U; // not used
QActive_register_(me); // make QF aware of this active object
QEQueue_init(&me->eQueue, qSto, qLen); // init the built-in queue
// top-most initial tran. (virtual call)
(*me->super.vptr->init)(&me->super, par, me->prio);
QS_FLUSH(); // flush the trace buffer to the host
((void)0)
((void)0)
((void)0)
\
QPSet_insert(&QV_priv_.readySet, (uint_fast8_t)(me_)->prio); \
QPSet_update_(&QV_priv_.readySet, &QV_priv_.readySet_dis)
\
QPSet_insert(&QV_priv_.readySet, (uint_fast8_t)(me_)->prio)
//! @class QK
{
//! @cond INTERNAL
uint8_t dummy;
//! @endcond
} QK;
//! @class QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @memberof QK_Attr
//! @static @private @memberof QK
//! @static @public @memberof QK
//! @static @public @memberof QK
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(100, !QK_ISR_CONTEXT_());
Q_INVARIANT_INCRIT(102, QK_priv_.lockCeil
== (uint_fast8_t)(~QK_priv_.lockCeil_dis));
// first store the previous lock prio
QSchedStatus stat;
if (ceiling > QK_priv_.lockCeil) { // raising the lock ceiling?
QS_BEGIN_PRE(QS_SCHED_LOCK, QK_priv_.actPrio)
QS_TIME_PRE(); // timestamp
// the previous lock ceiling & new lock ceiling
QS_2U8_PRE((uint8_t)QK_priv_.lockCeil, (uint8_t)ceiling);
QS_END_PRE()
// previous status of the lock
stat = (QSchedStatus)QK_priv_.lockCeil;
// new status of the lock
QK_priv_.lockCeil = ceiling;
#ifndef Q_UNSAFE
QK_priv_.lockCeil_dis = (uint_fast8_t)(~ceiling);
#endif
}
else {
stat = 0xFFU; // scheduler not locked
}
QF_MEM_APP();
QF_CRIT_EXIT();
return stat; // return the status to be saved in a stack variable
//! @static @public @memberof QK
//! @static @public @memberof QK
// has the scheduler been actually locked by the last QK_schedLock()?
if (prevCeil != 0xFFU) {
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_INVARIANT_INCRIT(202, QK_priv_.lockCeil
== (uint_fast8_t)(~QK_priv_.lockCeil_dis));
Q_REQUIRE_INCRIT(210, (!QK_ISR_CONTEXT_())
&& (QK_priv_.lockCeil > prevCeil));
QS_BEGIN_PRE(QS_SCHED_UNLOCK, QK_priv_.actPrio)
QS_TIME_PRE(); // timestamp
// current lock ceiling (old), previous lock ceiling (new)
QS_2U8_PRE((uint8_t)QK_priv_.lockCeil, (uint8_t)prevCeil);
QS_END_PRE()
// restore the previous lock ceiling
QK_priv_.lockCeil = prevCeil;
#ifndef Q_UNSAFE
QK_priv_.lockCeil_dis = (uint_fast8_t)(~prevCeil);
#endif
// find if any AOs should be run after unlocking the scheduler
if (QK_sched_() != 0U) { // preemption needed?
QK_activate_(); // activate any unlocked AOs
}
QF_MEM_APP();
QF_CRIT_EXIT();
}
//! @static @public @memberof QK
//! @static @public @memberof QK
//! @static @private @memberof QK
//! @static @private @memberof QK
// NOTE: this function is entered with interrupts DISABLED
Q_INVARIANT_INCRIT(402, QPSet_verify_(&QK_priv_.readySet,
&QK_priv_.readySet_dis));
uint_fast8_t p;
if (QPSet_isEmpty(&QK_priv_.readySet)) {
p = 0U; // no activation needed
}
else {
// find the highest-prio AO with non-empty event queue
p = QPSet_findMax(&QK_priv_.readySet);
Q_INVARIANT_INCRIT(412,
QK_priv_.actThre == (uint_fast8_t)(~QK_priv_.actThre_dis));
// is the AO's prio. below the active preemption-threshold?
if (p <= QK_priv_.actThre) {
p = 0U; // no activation needed
}
else {
Q_INVARIANT_INCRIT(422, QK_priv_.lockCeil
== (uint_fast8_t)(~QK_priv_.lockCeil_dis));
// is the AO's prio. below the lock-ceiling?
if (p <= QK_priv_.lockCeil) {
p = 0U; // no activation needed
}
else {
Q_INVARIANT_INCRIT(432, QK_priv_.nextPrio
== (uint_fast8_t)(~QK_priv_.nextPrio_dis));
QK_priv_.nextPrio = p; // next AO to run
#ifndef Q_UNSAFE
QK_priv_.nextPrio_dis = (uint_fast8_t)(~QK_priv_.nextPrio);
#endif
}
}
}
return p;
//! @static @private @memberof QK
//! @static @private @memberof QK
// NOTE: this function is entered with interrupts DISABLED
uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio.
uint_fast8_t p = QK_priv_.nextPrio; // next prio to run
Q_INVARIANT_INCRIT(502,
(prio_in == (uint_fast8_t)(~QK_priv_.actPrio_dis))
&& (p == (uint_fast8_t)(~QK_priv_.nextPrio_dis)));
Q_REQUIRE_INCRIT(510, (prio_in <= QF_MAX_ACTIVE)
&& (0U < p) && (p <= QF_MAX_ACTIVE));
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
uint_fast8_t pprev = prio_in;
#endif // QF_ON_CONTEXT_SW || Q_SPY
QK_priv_.nextPrio = 0U; // clear for the next time
#ifndef Q_UNSAFE
QK_priv_.nextPrio_dis = (uint_fast8_t)(~0U);
#endif
uint_fast8_t pthre_in;
QActive *a;
if (prio_in == 0U) { // preempting the idle thread?
pthre_in = 0U;
}
else {
a = QActive_registry_[prio_in];
Q_ASSERT_INCRIT(510, a != (QActive *)0);
pthre_in = (uint_fast8_t)a->pthre;
Q_INVARIANT_INCRIT(511, pthre_in ==
(uint_fast8_t)(~(uint_fast8_t)a->pthre_dis & 0xFFU));
}
// loop until no more ready-to-run AOs of higher pthre than the initial
do {
a = QActive_registry_[p]; // obtain the pointer to the AO
Q_ASSERT_INCRIT(520, a != (QActive *)0); // the AO must be registered
uint_fast8_t const pthre = (uint_fast8_t)a->pthre;
Q_INVARIANT_INCRIT(522, pthre ==
(uint_fast8_t)(~(uint_fast8_t)a->pthre_dis & 0xFFU));
// set new active prio. and preemption-threshold
QK_priv_.actPrio = p;
QK_priv_.actThre = pthre;
#ifndef Q_UNSAFE
QK_priv_.actPrio_dis = (uint_fast8_t)(~p);
QK_priv_.actThre_dis = (uint_fast8_t)(~pthre);
#endif
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (p != pprev) { // changing threads?
QS_BEGIN_PRE(QS_SCHED_NEXT, p)
QS_TIME_PRE(); // timestamp
QS_2U8_PRE(p, // prio. of the scheduled AO
pprev); // previous prio.
QS_END_PRE()
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QActive_registry_[pprev], a);
#endif // QF_ON_CONTEXT_SW
pprev = p; // update previous prio.
}
#endif // QF_ON_CONTEXT_SW || Q_SPY
QF_MEM_APP();
QF_INT_ENABLE(); // unconditionally enable interrupts
QEvt const * const e = QActive_get_(a);
// NOTE QActive_get_() performs QF_MEM_APP() before return
// dispatch event (virtual call)
(*a->super.vptr->dispatch)(&a->super, e, p);
#if (QF_MAX_EPOOL > 0U)
QF_gc(e);
#endif
// determine the next highest-prio. AO ready to run...
QF_INT_DISABLE(); // unconditionally disable interrupts
QF_MEM_SYS();
// internal integrity check (duplicate inverse storage)
Q_INVARIANT_INCRIT(532, QPSet_verify_(&QK_priv_.readySet,
&QK_priv_.readySet_dis));
if (a->eQueue.frontEvt == (QEvt *)0) { // empty queue?
QPSet_remove(&QK_priv_.readySet, p);
#ifndef Q_UNSAFE
QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis);
#endif
}
if (QPSet_isEmpty(&QK_priv_.readySet)) {
p = 0U; // no activation needed
}
else {
// find new highest-prio AO ready to run...
p = QPSet_findMax(&QK_priv_.readySet);
// is the new prio. below the initial preemption-threshold?
if (p <= pthre_in) {
p = 0U; // no activation needed
}
else {
Q_INVARIANT_INCRIT(542, QK_priv_.lockCeil
== (uint_fast8_t)(~QK_priv_.lockCeil_dis));
// is the AO's prio. below the lock preemption-threshold?
if (p <= QK_priv_.lockCeil) {
p = 0U; // no activation needed
}
else {
Q_ASSERT_INCRIT(550, p <= QF_MAX_ACTIVE);
}
}
}
} while (p != 0U);
// restore the active prio. and preemption-threshold
QK_priv_.actPrio = prio_in;
QK_priv_.actThre = pthre_in;
#ifndef Q_UNSAFE
QK_priv_.actPrio_dis = (uint_fast8_t)(~QK_priv_.actPrio);
QK_priv_.actThre_dis = (uint_fast8_t)(~QK_priv_.actThre);
#endif
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (prio_in != 0U) { // resuming an active object?
a = QActive_registry_[prio_in]; // pointer to preempted AO
QS_BEGIN_PRE(QS_SCHED_NEXT, prio_in)
QS_TIME_PRE(); // timestamp
// prio. of the resumed AO, previous prio.
QS_2U8_PRE(prio_in, pprev);
QS_END_PRE()
}
else { // resuming prio.==0 --> idle
a = (QActive *)0; // QK idle loop
QS_BEGIN_PRE(QS_SCHED_IDLE, pprev)
QS_TIME_PRE(); // timestamp
QS_U8_PRE(pprev); // previous prio.
QS_END_PRE()
}
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QActive_registry_[pprev], a);
#endif // QF_ON_CONTEXT_SW
#endif // QF_ON_CONTEXT_SW || Q_SPY
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_bzero_(&QF_priv_, sizeof(QF_priv_));
QF_bzero_(&QK_priv_, sizeof(QK_priv_));
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
// setup the QK scheduler as initially locked and not running
QK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
#ifndef Q_UNSAFE
QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis);
QK_priv_.actPrio_dis = (uint_fast8_t)(~0U);
QK_priv_.nextPrio_dis = (uint_fast8_t)(~0U);
QK_priv_.actThre_dis = (uint_fast8_t)(~0U);
QK_priv_.lockCeil_dis = (uint_fast8_t)(~QK_priv_.lockCeil);
#endif
QTimeEvt_init(); // initialize QTimeEvts
#ifdef QK_INIT
QK_INIT(); // port-specific initialization of the QK kernel
#endif
//! @static @public @memberof QF
//! @static @public @memberof QF
QF_onCleanup(); // application-specific cleanup callback
// nothing else to do for the preemptive QK kernel
//! @static @public @memberof QF
//! @static @public @memberof QF
#ifdef Q_SPY
// produce the QS_QF_RUN trace record
QF_INT_DISABLE();
QF_MEM_SYS();
QS_beginRec_((uint_fast8_t)QS_QF_RUN);
QS_endRec_();
QF_MEM_APP();
QF_INT_ENABLE();
#endif // Q_SPY
QF_onStartup(); // application-specific startup callback
QF_INT_DISABLE();
QF_MEM_SYS();
#ifdef QK_START
QK_START(); // port-specific startup of the QK kernel
#endif
QK_priv_.lockCeil = 0U; // unlock the QK scheduler
#ifndef Q_UNSAFE
QK_priv_.lockCeil_dis = (uint_fast8_t)(~0U);
#endif
#ifdef QF_ON_CONTEXT_SW
// officially switch to the idle context
QF_onContextSw((QActive *)0, QActive_registry_[QK_priv_.nextPrio]);
#endif
// activate AOs to process events posted so far
if (QK_sched_() != 0U) {
QK_activate_();
}
QF_MEM_APP();
QF_INT_ENABLE();
for (;;) { // QK idle loop...
QK_onIdle(); // application-specific QK on-idle callback
}
#ifdef __GNUC__
return 0;
#endif
// QActive class customization for QK
//! @public @memberof QActive
//! @public @memberof QActive
Q_UNUSED_PAR(stkSto); // not needed in QK
Q_UNUSED_PAR(stkSize); // not needed in QK
QF_CRIT_STAT
QF_CRIT_ENTRY();
QF_MEM_SYS();
Q_REQUIRE_INCRIT(300, (!QK_ISR_CONTEXT_())
&& (stkSto == (void *)0));
QF_MEM_APP();
QF_CRIT_EXIT();
me->prio = (uint8_t)(prioSpec & 0xFFU); // QF-prio. of the AO
me->pthre = (uint8_t)(prioSpec >> 8U); // preemption-threshold
QActive_register_(me); // make QF aware of this active object
QEQueue_init(&me->eQueue, qSto, qLen); // init the built-in queue
// top-most initial tran. (virtual call)
(*me->super.vptr->init)(&me->super, par, me->prio);
QS_FLUSH(); // flush the trace buffer to the host
// See if this AO needs to be scheduled if QK is already running
QF_CRIT_ENTRY();
QF_MEM_SYS();
if (QK_sched_() != 0U) { // activation needed?
QK_activate_();
}
QF_MEM_APP();
QF_CRIT_EXIT();
QSchedStatus lockStat_;
do { \
if (QK_ISR_CONTEXT_()) { \
lockStat_ = 0xFFU; \
} else { \
lockStat_ = QK_schedLock((ceil_)); \
} \
} while (false)
do { \
if (lockStat_ != 0xFFU) { \
QK_schedUnlock(lockStat_); \
} \
} while (false)
((void)0)
do { \
QPSet_insert(&QK_priv_.readySet, (uint_fast8_t)(me_)->prio); \
QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis); \
if (!QK_ISR_CONTEXT_()) { \
if (QK_sched_() != 0U) { \
QK_activate_(); \
} \
} \
} while (false)
do { \
QPSet_insert(&QK_priv_.readySet, (uint_fast8_t)(me_)->prio); \
if (!QK_ISR_CONTEXT_()) { \
if (QK_sched_() != 0U) { \
QK_activate_(); \
} \
} \
} while (false)
#ifndef QSAFE_H_
#define QSAFE_H_
#ifdef __cplusplus
extern "C" {
#endif
// QF-FuSa enabled ===========================================================
#ifndef Q_UNSAFE
#ifndef QF_CRIT_STAT
#define QF_CRIT_STAT
#endif
#ifndef QF_CRIT_ENTRY
#define QF_CRIT_ENTRY() ((void)0)
#endif
#ifndef QF_CRIT_EXIT
#define QF_CRIT_EXIT() ((void)0)
#endif
$declare ${QP-FuSa::enabled}
// QF-FuSa disabled ==========================================================
#else
$declare ${QP-FuSa::disabled}
#endif
//============================================================================
$declare1 ${QP-FuSa}
#ifdef __cplusplus
}
#endif
#endif // QSAFE_H_
#ifndef QP_H_
#define QP_H_
//============================================================================
#define QP_VERSION_STR "8.0.0"
#define QP_VERSION 800U
#define QP_RELEASE 0x7055936FU
//============================================================================
//! @cond INTERNAL
#ifndef Q_SIGNAL_SIZE
#define Q_SIGNAL_SIZE 2U
#endif
#ifndef QF_MAX_ACTIVE
#define QF_MAX_ACTIVE 32U
#endif
#if (QF_MAX_ACTIVE > 64U)
#error QF_MAX_ACTIVE exceeds the maximum of 64U;
#endif
#ifndef QF_MAX_TICK_RATE
#define QF_MAX_TICK_RATE 1U
#endif
#if (QF_MAX_TICK_RATE > 15U)
#error QF_MAX_TICK_RATE exceeds the maximum of 15U;
#endif
#ifndef QF_MAX_EPOOL
#define QF_MAX_EPOOL 3U
#endif
#if (QF_MAX_EPOOL > 15U)
#error QF_MAX_EPOOL exceeds the maximum of 15U;
#endif
#ifndef QF_TIMEEVT_CTR_SIZE
#define QF_TIMEEVT_CTR_SIZE 4U
#endif
#if (QF_TIMEEVT_CTR_SIZE > 4U)
#error QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U;
#endif
#ifndef QF_EVENT_SIZ_SIZE
#define QF_EVENT_SIZ_SIZE 2U
#endif
#if (QF_EVENT_SIZ_SIZE > 4U)
#error QF_EVENT_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U;
#endif
//! @endcond
//============================================================================
$declare ${glob-types}
$declare ${QEP}
$declare ${QEP-macros}
$declare ${QF::types}
$declare ${QF::QActive}
$declare ${QF::QMActive}
$declare ${QF::QTimeEvt}
$declare ${QF::QTicker}
$declare ${QF::QF-base}
$declare ${QF::QF-dyn}
$declare ${QF-macros}
#endif // QP_H_
#ifndef QP_PKG_H_
#define QP_PKG_H_
$declare ${QF::QF-pkg}
// Bitmasks are for the QTimeEvt::flags attribute
#define QTE_FLAG_IS_LINKED (1U << 7U)
#define QTE_FLAG_WAS_DISARMED (1U << 6U)
//! @private @memberof QEvt
static inline void QEvt_refCtr_inc_(QEvt const *me) {
uint8_t rc = me->refCtr_ + 1U;
((QEvt *)me)->refCtr_ = rc; // cast away 'const'
#ifndef Q_UNSAFE
((QEvt *)me)->evtTag_ = (me->evtTag_ & 0xF0U) | ((~rc) & 0x0FU);
#endif // ndef Q_UNSAFE
}
//! @private @memberof QEvt
static inline void QEvt_refCtr_dec_(QEvt const *me) {
uint8_t rc = me->refCtr_ - 1U;
((QEvt *)me)->refCtr_ = rc; // cast away 'const'
#ifndef Q_UNSAFE
((QEvt *)me)->evtTag_ = (me->evtTag_ & 0xF0U) | ((~rc) & 0x0FU);
#endif // ndef Q_UNSAFE
}
#define QACTIVE_CAST_(ptr_) ((QActive *)(ptr_))
#define Q_PTR2UINT_CAST_(ptr_) ((uintptr_t)(ptr_))
#endif // QP_PKG_H_
#ifndef QEQUEUE_H_
#define QEQUEUE_H_
#ifndef QF_EQUEUE_CTR_SIZE
#define QF_EQUEUE_CTR_SIZE 1U
#endif
#if (QF_EQUEUE_CTR_SIZE == 1U)
typedef uint8_t QEQueueCtr;
#elif (QF_EQUEUE_CTR_SIZE == 2U)
typedef uint16_t QEQueueCtr;
#else
#error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U or 2U"
#endif
struct QEvt; // forward declartion
$declare ${QF::QEQueue}
#endif // QEQUEUE_H_
#ifndef QMPOOL_H_
#define QMPOOL_H_
#ifndef QF_MPOOL_SIZ_SIZE
#define QF_MPOOL_SIZ_SIZE 2U
#endif
#ifndef QF_MPOOL_CTR_SIZE
#define QF_MPOOL_CTR_SIZE 2U
#endif
#if (QF_MPOOL_SIZ_SIZE == 1U)
typedef uint8_t QMPoolSize;
#elif (QF_MPOOL_SIZ_SIZE == 2U)
typedef uint16_t QMPoolSize;
#elif (QF_MPOOL_SIZ_SIZE == 4U)
typedef uint32_t QMPoolSize;
#else
#error "QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U"
#endif
#if (QF_MPOOL_CTR_SIZE == 1U)
typedef uint8_t QMPoolCtr;
#elif (QF_MPOOL_CTR_SIZE == 2U)
typedef uint16_t QMPoolCtr;
#elif (QF_MPOOL_CTR_SIZE == 4U)
typedef uint32_t QMPoolCtr;
#else
#error "QF_MPOOL_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
#endif
#define QF_MPOOL_EL(evType_) struct { \
QFreeBlock sto_[((sizeof(evType_) - 1U) / (2U * sizeof(void *))) + 1U]; \
}
$declare ${QF::QFreeBlock}
$declare ${QF::QMPool}
#endif // QMPOOL_H_
#ifndef QV_H_
#define QV_H_
$declare ${QV::QV}
$declare ${QV::QV-base}
//============================================================================
// interface used only for internal implementation, but not in applications
#ifdef QP_IMPL
$declare ${QV-impl}
$declare ${QF_EPOOL-impl}
#endif // QP_IMPL
#endif // QV_H_
#ifndef QK_H_
#define QK_H_
$declare ${QK::QK}
$declare ${QK::QSchedStatus}
$declare ${QK::QK-base}
//============================================================================
// interface used only for internal implementation, but not in applications
#ifdef QP_IMPL
$declare ${QK-impl}
$declare ${QF_EPOOL-impl}
#endif // QP_IMPL
#endif // QK_H_
#ifndef QSTAMP_H_
#define QSTAMP_H_
extern char const Q_BUILD_DATE[12];
extern char const Q_BUILD_TIME[9];
#endif // QSTAMP_H_
#ifndef QPC_H_
#define QPC_H_
#include "qp_port.h" // QP port from the port directory
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // software tracing enabled?
#include "qs_port.h" // QS/C port from the port directory
#else
#include "qs_dummy.h" // QS/C dummy interface (inactive)
#endif
#ifndef QP_API_VERSION
#define QP_API_VERSION 0
#endif // #ifndef QP_API_VERSION
// QP API compatibility layer...
//============================================================================
#if (QP_API_VERSION < 800)
#define QM_SUPER_SUB(host_) error "submachines no longer supported"
#define QM_TRAN_EP(tatbl_) error "submachines no longer supported"
#define QM_TRAN_XP(xp_, tatbl_) error "submachines no longer supported"
#ifdef QEVT_DYN_CTOR
//! @deprecated #QEVT_DYN_CTOR, please use #QEVT_PAR_INIT
#define QEVT_PAR_INIT
#endif
//! @deprecated plain 'char' is no longer forbidden in MISRA-C:2023
typedef char char_t;
//! @deprecated Macro for starting an Active Object.
//! Use QActive::QActive_start() instead.
#define QACTIVE_START(me_, prioSpec_, qSto_, qLen_, stkSto_, stkSize_, par_) \
(QActive_start((QActive *)(me_), (prioSpec_), \
(qSto_), (qLen_), (stkSto_), (stkSize_), (par_)))
//! @deprecated Macro for starting an eXtended Thread.
//! Use QXThread::QXThread_start() instead.
#define QXTHREAD_START(me_, prioSpec_, qSto_, qLen_, stkSto_, stkSize_, par_) \
(QXThread_start((QXThread *)(me_), (prioSpec_), \
(qSto_), (qLen_), (stkSto_), (stkSize_), (par_)))
//! @deprecated Assertion failure handler.
//! Use Q_onError() instead.
#define Q_onAssert(module_, id_) Q_onError(module_, id_)
//! @deprecated #Q_NASSERT preprocessor switch to disable QP assertions
#ifdef Q_NASSERT
// #Q_UNSAFE now replaces the functionality of Q_NASSERT
#define Q_UNSAFE
//! @deprecated general purpose assertion with user-specified ID
//! number that **always** evaluates the `expr_` expression.
#define Q_ALLEGE_ID(id_, expr_) ((void)(expr_))
#elif defined Q_UNSAFE
//! @deprecated general purpose assertion with user-specified ID
//! number that **always** evaluates the `expr_` expression.
#define Q_ALLEGE_ID(id_, expr_) ((void)(expr_))
#else // QP FuSa Subsystem enabled
//! @deprecated general purpose assertion with user-specified ID
//! number that **always** evaluates the `expr_` expression.
//! @note
//! The use of this macro is no longer recommended.
#define Q_ALLEGE_ID(id_, expr_) if (!(expr_)) { \
QF_CRIT_STAT \
QF_CRIT_ENTRY(); \
Q_onError(&Q_this_module_[0], (id_)); \
QF_CRIT_EXIT(); \
} else ((void)0)
#endif
//! @deprecated general purpose assertion without ID number
//! that **always** evaluates the `expr_` expression.
//! Instead of ID number, this macro is based on the standard
//! `__LINE__` macro.
//!
//! @note The use of this macro is no longer recommended.
#define Q_ALLEGE(expr_) Q_ALLEGE_ID(__LINE__, (expr_))
//! Static (compile-time) assertion.
//! @deprecated
//! Use Q_ASSERT_STATIC() or better yet `_Static_assert()` instead.
#define Q_ASSERT_COMPILE(expr_) Q_ASSERT_STATIC(expr_)
//! @static @public @memberof QF
//! @deprecated
static inline void QF_psInit(
QSubscrList * const subscrSto,
enum_t const maxSignal)
{
QActive_psInit(subscrSto, maxSignal);
}
//! @deprecated instead use: QASM_INIT()
#define QHSM_INIT(me_, par_, qsId_) QASM_INIT((me_), (par_), (qsId_))
//! @deprecated instead use: QASM_DISPATCH()
#define QHSM_DISPATCH(me_, e_, qsId_) QASM_DISPATCH((me_), (e_), (qsId_))
//! @deprecated instead use: QASM_IS_IN()
#define QHsm_isIn(me_, state_) QASM_IS_IN((QAsm *)(me_), (state_))
#endif // QP_API_VERSION < 800
#endif // QPC_H_
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qep_hsm")
$define ${QEP::QP_versionStr[16]}
//============================================================================
//! @cond INTERNAL
$define ${QEP::QEvt::reserved_[4]}
// helper macro to handle reserved event in an QHsm
#define QHSM_RESERVED_EVT_(state_, sig_) \
((*(state_))(me, &QEvt_reserved_[(sig_)]))
// helper macro to trace state entry
#define QS_STATE_ENTRY_(state_, qsId_) \
QS_CRIT_ENTRY(); \
QS_MEM_SYS(); \
QS_BEGIN_PRE(QS_QEP_STATE_ENTRY, (qsId_)) \
QS_OBJ_PRE(me); \
QS_FUN_PRE(state_); \
QS_END_PRE() \
QS_MEM_APP(); \
QS_CRIT_EXIT()
// helper macro to trace state exit
#define QS_STATE_EXIT_(state_, qsId_) \
QS_CRIT_ENTRY(); \
QS_MEM_SYS(); \
QS_BEGIN_PRE(QS_QEP_STATE_EXIT, (qsId_)) \
QS_OBJ_PRE(me); \
QS_FUN_PRE(state_); \
QS_END_PRE() \
QS_MEM_APP(); \
QS_CRIT_EXIT()
//! @endcond
enum {
// maximum depth of state nesting in a QHsm (including the top level),
// must be >= 3
QHSM_MAX_NEST_DEPTH_ = 6
};
$define ${QEP::QHsm}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
//============================================================================
//! @cond INTERNAL
Q_DEFINE_THIS_MODULE("qep_msm")
// top-state object for QMsm-style state machines
static struct QMState const l_msm_top_s = {
(struct QMState *)0,
Q_STATE_CAST(0),
Q_ACTION_CAST(0),
Q_ACTION_CAST(0),
Q_ACTION_CAST(0)
};
//! @endcond
enum {
// maximum depth of state nesting in a QMsm (including the top level)
QMSM_MAX_NEST_DEPTH_ = 8,
// maximum length of transition-action array
QMSM_MAX_TRAN_LENGTH_ = 2*QMSM_MAX_NEST_DEPTH_,
// maximum depth of entry levels in a MSM for tran. to history
QMSM_MAX_ENTRY_DEPTH_ = 4
};
//============================================================================
$define ${QEP::QMsm}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
//Q_DEFINE_THIS_MODULE("qf_act")
$define ${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}
$define ${QF::QF-pkg}
$define ${QF::types::QF_LOG2}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_actq")
//============================================================================
$define ${QF::QActive::post_}
$define ${QF::QActive::postLIFO_}
$define ${QF::QActive::get_}
$define ${QF::QF-base::getQueueMin}
$define ${QF::QTicker}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_defer")
$define ${QF::QActive::defer}
$define ${QF::QActive::recall}
$define ${QF::QActive::flushDeferred}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
#if (QF_MAX_EPOOL > 0U) // mutable events configured?
Q_DEFINE_THIS_MODULE("qf_dyn")
$define ${QF::QF-dyn}
#endif // (QF_MAX_EPOOL > 0U) mutable events configured
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_mem")
$define ${QF::QMPool}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_qact")
$define ${QF::QActive::ctor}
$define ${QF::QActive::register_}
$define ${QF::QActive::unregister_}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
//Q_DEFINE_THIS_MODULE("qf_qmact")
$define ${QF::QMActive}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_qeq")
$define ${QF::QEQueue}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_ps")
$define ${QF::QActive::subscrList_}
$define ${QF::QActive::maxPubSignal_}
$define ${QF::QActive::psInit}
$define ${QF::QActive::publish_}
$define ${QF::QActive::subscribe}
$define ${QF::QActive::unsubscribe}
$define ${QF::QActive::unsubscribeAll}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
Q_DEFINE_THIS_MODULE("qf_time")
$define ${QF::QTimeEvt}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope internal interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QV_H_
#error "Source file included in a project NOT based on the QV kernel"
#endif // QV_H_
Q_DEFINE_THIS_MODULE("qv")
$define ${QV::QV-base}
$define ${QV::QF-cust}
$define ${QV::QActive}
#define QP_IMPL // this is QP implementation
#include "qp_port.h" // QP port
#include "qp_pkg.h" // QP package-scope internal interface
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
#ifdef Q_SPY // QS software tracing enabled?
#include "qs_port.h" // QS port
#include "qs_pkg.h" // QS facilities for pre-defined trace records
#else
#include "qs_dummy.h" // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QK_H_
#error "Source file included in a project NOT based on the QK kernel"
#endif // QK_H_
Q_DEFINE_THIS_MODULE("qk")
$define ${QK::QK-base}
$define ${QK::QF-cust}
$define ${QK::QActive}
#include "qstamp.h"
char const Q_BUILD_DATE[12] = __DATE__;
char const Q_BUILD_TIME[9] = __TIME__;