mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-14 06:43:19 +08:00
12c924a156
added missing <pthread.h> to ports/posix/qp_port.h changed ports to ARM-CM, BASEPRI critical section updated qp_config.h files updated examples fixed arm-cr ports, GNU compiler, ARM mode, QF_INT_ENABLE_ALL() macro
6896 lines
235 KiB
XML
6896 lines
235 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<model version="7.0.0" links="1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.state-machine.com/qm/qm7.xsd">
|
|
<documentation>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></documentation>
|
|
<!--${qpc}-->
|
|
<framework name="qpc">
|
|
<license name="LicenseRef-QL-dual">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</license>
|
|
</framework>
|
|
<!--${QP-FuSa}-->
|
|
<package name="QP-FuSa" stereotype="0x05">
|
|
<!--${QP-FuSa::enabled}-->
|
|
<package name="enabled" stereotype="0x05">
|
|
<!--${QP-FuSa::enabled::Q_DEFINE_THIS_MODULE}-->
|
|
<operation name="Q_DEFINE_THIS_MODULE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::enabled::Q_DEFINE_THIS_MO~::name_}-->
|
|
<parameter name="name_" type="char const *"/>
|
|
<code>\
|
|
static char const Q_this_module_[] = name_;</code>
|
|
</operation>
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_INCRIT}-->
|
|
<operation name="Q_ASSERT_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_INCRIT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code> \
|
|
((expr_) ? ((void)0) : Q_onError(&Q_this_module_[0], (id_)))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::enabled::Q_ERROR_INCRIT}-->
|
|
<operation name="Q_ERROR_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::enabled::Q_ERROR_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<code> \
|
|
(Q_onError(&Q_this_module_[0], (id_)))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_ID}-->
|
|
<operation name="Q_ASSERT_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::enabled::Q_ASSERT_ID::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>do { \
|
|
QF_CRIT_STAT \
|
|
QF_CRIT_ENTRY(); \
|
|
(expr_) ? ((void)0) : Q_onError(&Q_this_module_[0], (id_)); \
|
|
QF_CRIT_EXIT(); \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::enabled::Q_ERROR_ID}-->
|
|
<operation name="Q_ERROR_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::enabled::Q_ERROR_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<code>do { \
|
|
QF_CRIT_STAT \
|
|
QF_CRIT_ENTRY(); \
|
|
Q_onError(&Q_this_module_[0], (id_)); \
|
|
QF_CRIT_EXIT(); \
|
|
} while (false)</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QP-FuSa::disabled}-->
|
|
<package name="disabled" stereotype="0x05">
|
|
<!--${QP-FuSa::disabled::Q_DEFINE_THIS_MODULE}-->
|
|
<operation name="Q_DEFINE_THIS_MODULE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::disabled::Q_DEFINE_THIS_MO~::name_}-->
|
|
<parameter name="name_" type="char const *"/>
|
|
</operation>
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_INCRIT}-->
|
|
<operation name="Q_ASSERT_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_INCRIT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::disabled::Q_ERROR_INCRIT}-->
|
|
<operation name="Q_ERROR_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::disabled::Q_ERROR_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_ID}-->
|
|
<operation name="Q_ASSERT_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::disabled::Q_ASSERT_ID::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::disabled::Q_ERROR_ID}-->
|
|
<operation name="Q_ERROR_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::disabled::Q_ERROR_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QP-FuSa::Q_DEFINE_THIS_FILE}-->
|
|
<attribute name="Q_DEFINE_THIS_FILE" type="" visibility="0x03" properties="0x00">
|
|
<code>Q_DEFINE_THIS_MODULE(__FILE__)</code>
|
|
</attribute>
|
|
<!--${QP-FuSa::Q_ASSERT}-->
|
|
<operation name="Q_ASSERT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_ASSERT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_ID(__LINE__, (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_ERROR}-->
|
|
<operation name="Q_ERROR" type="void" visibility="0x03" properties="0x00">
|
|
<code>Q_ERROR_ID(__LINE__)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_REQUIRE_ID}-->
|
|
<operation name="Q_REQUIRE_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_REQUIRE_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_REQUIRE_ID::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_ID((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_REQUIRE}-->
|
|
<operation name="Q_REQUIRE" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_REQUIRE::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT(expr_)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_REQUIRE_INCRIT}-->
|
|
<operation name="Q_REQUIRE_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_REQUIRE_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_REQUIRE_INCRIT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_INCRIT((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_ENSURE_ID}-->
|
|
<operation name="Q_ENSURE_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_ENSURE_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_ENSURE_ID::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_ID((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_ENSURE}-->
|
|
<operation name="Q_ENSURE" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_ENSURE::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT(expr_)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_ENSURE_INCRIT}-->
|
|
<operation name="Q_ENSURE_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_ENSURE_INCRIT::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_ENSURE_INCRIT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_INCRIT((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_INVARIANT_ID}-->
|
|
<operation name="Q_INVARIANT_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_INVARIANT_ID::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_INVARIANT_ID::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_ID((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_INVARIANT}-->
|
|
<operation name="Q_INVARIANT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_INVARIANT::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT(expr_)</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_INVARIANT_INCRIT}-->
|
|
<operation name="Q_INVARIANT_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_INVARIANT_INCR~::id_}-->
|
|
<parameter name="id_" type="int"/>
|
|
<!--${QP-FuSa::Q_INVARIANT_INCR~::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>Q_ASSERT_INCRIT((id_), (expr_))</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_ASSERT_STATIC}-->
|
|
<operation name="Q_ASSERT_STATIC" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_ASSERT_STATIC::expr_}-->
|
|
<parameter name="expr_" type="bool"/>
|
|
<code>extern char Q_static_assert_[(expr_) ? 1 : -1]</code>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_NORETURN}-->
|
|
<attribute name="Q_NORETURN?ndef Q_NORETURN" type="void" visibility="0x03" properties="0x00">
|
|
<code>_Noreturn void</code>
|
|
</attribute>
|
|
<!--${QP-FuSa::int_t}-->
|
|
<attribute name="int_t?ndef QP_VERSION" type="typedef int" visibility="0x04" properties="0x00"/>
|
|
<!--${QP-FuSa::Q_onError}-->
|
|
<operation name="Q_onError" type="Q_NORETURN" visibility="0x00" properties="0x00">
|
|
<!--${QP-FuSa::Q_onError::module}-->
|
|
<parameter name="module" type="char const * const"/>
|
|
<!--${QP-FuSa::Q_onError::id}-->
|
|
<parameter name="id" type="int_t const"/>
|
|
</operation>
|
|
<!--${QP-FuSa::Q_DIM}-->
|
|
<operation name="Q_DIM?ndef QP_VERSION" type="unsigned" visibility="0x03" properties="0x00">
|
|
<!--${QP-FuSa::Q_DIM::array_}-->
|
|
<parameter name="array_" type="1-dimensional array"/>
|
|
<code>(sizeof(array_) / sizeof((array_)[0U]))</code>
|
|
</operation>
|
|
</package>
|
|
<!--${glob-types}-->
|
|
<package name="glob-types" stereotype="0x00">
|
|
<!--${glob-types::int_t}-->
|
|
<attribute name="int_t" type="typedef int" visibility="0x04" properties="0x00"/>
|
|
<!--${glob-types::enum_t}-->
|
|
<attribute name="enum_t" type="typedef int" visibility="0x04" properties="0x00"/>
|
|
<!--${glob-types::float32_t}-->
|
|
<attribute name="float32_t" type="typedef float" visibility="0x04" properties="0x00"/>
|
|
<!--${glob-types::float64_t}-->
|
|
<attribute name="float64_t" type="typedef double" visibility="0x04" properties="0x00"/>
|
|
</package>
|
|
<!--${QEP}-->
|
|
<package name="QEP" stereotype="0x05">
|
|
<!--${QEP::QP_versionStr[16]}-->
|
|
<attribute name="QP_versionStr[16]" type="char const" visibility="0x00" properties="0x00">
|
|
<documentation>//! the current QP version number string in ROM, based on #QP_VERSION_STR</documentation>
|
|
<code>= QP_VERSION_STR;</code>
|
|
</attribute>
|
|
<!--${QEP::QSignal}-->
|
|
<attribute name="QSignal? (Q_SIGNAL_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QEP::QSignal}-->
|
|
<attribute name="QSignal? (Q_SIGNAL_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QEP::QSignal}-->
|
|
<attribute name="QSignal? (Q_SIGNAL_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QEP::QEvt}-->
|
|
<class name="QEvt">
|
|
<documentation>//! @class QEvt</documentation>
|
|
<!--${QEP::QEvt::sig}-->
|
|
<attribute name="sig" type="QSignal" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QEvt</documentation>
|
|
</attribute>
|
|
<!--${QEP::QEvt::evtTag_}-->
|
|
<attribute name="evtTag_" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEvt</documentation>
|
|
</attribute>
|
|
<!--${QEP::QEvt::refCtr_}-->
|
|
<attribute name="refCtr_" type="uint8_t volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEvt</documentation>
|
|
</attribute>
|
|
<!--${QEP::QEvt::reserved_[4]}-->
|
|
<attribute name="reserved_[4]" type="QEvt const" visibility="0x02" properties="0x01">
|
|
<code>= {
|
|
QEVT_INITIALIZER(Q_EMPTY_SIG),
|
|
QEVT_INITIALIZER(Q_ENTRY_SIG),
|
|
QEVT_INITIALIZER(Q_EXIT_SIG),
|
|
QEVT_INITIALIZER(Q_INIT_SIG)
|
|
};</code>
|
|
</attribute>
|
|
<!--${QEP::QEvt::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QEvt
|
|
|
|
//! @public @memberof QEvt</documentation>
|
|
<!--${QEP::QEvt::ctor::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<code>me->sig = (QSignal)sig;
|
|
me->evtTag_ = 0x0FU;
|
|
me->refCtr_ = 0U;</code>
|
|
</operation>
|
|
<!--${QEP::QEvt::init}-->
|
|
<operation name="init" type="QEvt *" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QEvt
|
|
|
|
//! @public @memberof QEvt</documentation>
|
|
<!--${QEP::QEvt::init::dummy}-->
|
|
<parameter name="dummy" type="uint8_t"/>
|
|
<code>(void)dummy;
|
|
return me;</code>
|
|
</operation>
|
|
<!--${QEP::QEvt::verify_}-->
|
|
<operation name="verify_?ndef Q_UNSAFE" type="bool" visibility="0x02" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QEvt
|
|
|
|
//! @private @memberof QEvt</documentation>
|
|
<code>uint8_t rc = me->refCtr_;
|
|
return (rc <= 2U*QF_MAX_ACTIVE)
|
|
&& (((me->evtTag_ ^ rc) & 0x0FU) == 0x0FU);</code>
|
|
</operation>
|
|
<!--${QEP::QEvt::getPoolNum_}-->
|
|
<operation name="getPoolNum_" type="uint_fast8_t" visibility="0x02" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QEvt
|
|
|
|
//! @private @memberof QEvt</documentation>
|
|
<code>return (uint_fast8_t)(me->evtTag_ >> 4U);</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QEP::QStateRet}-->
|
|
<attribute name="QStateRet" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! All possible values returned from state/action handlers
|
|
//! @note
|
|
//! The order of enumeration matters for algorithmic correctness.</documentation>
|
|
<code>{
|
|
// 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
|
|
};</code>
|
|
</attribute>
|
|
<!--${QEP::QState}-->
|
|
<attribute name="QState" type="typedef enum QStateRet" visibility="0x04" properties="0x00"/>
|
|
<!--${QEP::QStateHandler}-->
|
|
<attribute name="QStateHandler" type="typedef QState (*" visibility="0x04" properties="0x00">
|
|
<code>)(void * const me, QEvt const * const e);</code>
|
|
</attribute>
|
|
<!--${QEP::QActionHandler}-->
|
|
<attribute name="QActionHandler" type="typedef QState (*" visibility="0x04" properties="0x00">
|
|
<code>)(void * const me);</code>
|
|
</attribute>
|
|
<!--${QEP::QXThread}-->
|
|
<attribute name="QXThread" type="struct" visibility="0x04" properties="0x00">
|
|
<documentation>// forward declaration</documentation>
|
|
</attribute>
|
|
<!--${QEP::QXThreadHandler}-->
|
|
<attribute name="QXThreadHandler" type="typedef void (*" visibility="0x04" properties="0x00">
|
|
<code>)(struct QXThread * const me);</code>
|
|
</attribute>
|
|
<!--${QEP::QMState}-->
|
|
<attribute name="QMState" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<code>{
|
|
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;</code>
|
|
</attribute>
|
|
<!--${QEP::QMTranActTable}-->
|
|
<attribute name="QMTranActTable" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<code>{
|
|
QMState const *target; //!< @private @memberof QMTranActTable
|
|
QActionHandler const act[1]; //!< @private @memberof QMTranActTable
|
|
} QMTranActTable;</code>
|
|
</attribute>
|
|
<!--${QEP::QAsmAttr}-->
|
|
<attribute name="QAsmAttr" type="union" visibility="0x04" properties="0x00">
|
|
<code>{
|
|
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
|
|
};</code>
|
|
</attribute>
|
|
<!--${QEP::QAsm}-->
|
|
<class name="QAsm">
|
|
<documentation>//! @class QAsm</documentation>
|
|
<!--${QEP::QAsm::vptr}-->
|
|
<attribute name="vptr" type="struct QAsmVtable const *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @protected @memberof QAsm</documentation>
|
|
</attribute>
|
|
<!--${QEP::QAsm::state}-->
|
|
<attribute name="state" type="union QAsmAttr" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QAsm</documentation>
|
|
</attribute>
|
|
<!--${QEP::QAsm::temp}-->
|
|
<attribute name="temp" type="union QAsmAttr" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QAsm</documentation>
|
|
</attribute>
|
|
<!--${QEP::QAsm::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QAsm
|
|
|
|
//! @protected @memberof QAsm</documentation>
|
|
<code>me->vptr = (QAsmVtable *)0;
|
|
me->state.fun = Q_STATE_CAST(0);
|
|
me->temp.fun = Q_STATE_CAST(0);</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QEP::QAsmVtable}-->
|
|
<attribute name="QAsmVtable" type="struct" visibility="0x04" properties="0x00">
|
|
<code>{
|
|
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
|
|
};</code>
|
|
</attribute>
|
|
<!--${QEP::QHsm}-->
|
|
<class name="QHsm" superclass="QEP::QAsm">
|
|
<documentation>//! @class QHsm
|
|
//! @extends QAsm
|
|
|
|
State machine implementation strategy suitable for
|
|
manual coding</documentation>
|
|
<!--${QEP::QHsm::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QHsm
|
|
|
|
//! @protected @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::ctor::initial}-->
|
|
<parameter name="initial" type="QStateHandler const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::init_}-->
|
|
<operation name="init_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QHsm
|
|
|
|
//! @private @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::init_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QHsm::init_::e}-->
|
|
<parameter name="e" type="void const * const"/>
|
|
<!--${QEP::QHsm::init_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::dispatch_}-->
|
|
<operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QHsm
|
|
|
|
//! @private @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::dispatch_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QHsm::dispatch_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QEP::QHsm::dispatch_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::getStateHandler_}-->
|
|
<operation name="getStateHandler_?def Q_SPY" type="QStateHandler" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QHsm
|
|
|
|
//! @private @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::getStateHandler_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<code>return me->state.fun;</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::isIn_}-->
|
|
<operation name="isIn_" type="bool" visibility="0x00" properties="0x01">
|
|
<documentation>//! @private @memberof QHsm
|
|
|
|
//! @private @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::isIn_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QHsm::isIn_::state}-->
|
|
<parameter name="state" type="QStateHandler const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::state}-->
|
|
<operation name="state" type="QStateHandler" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QHsm
|
|
|
|
//! @public @memberof QHsm</documentation>
|
|
<code>return me->super.state.fun;</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::childState}-->
|
|
<operation name="childState" type="QStateHandler" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QHsm
|
|
|
|
//! @public @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::childState::parent}-->
|
|
<parameter name="parent" type="QStateHandler const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::tran_}-->
|
|
<operation name="tran_" type="int_fast8_t" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QHsm
|
|
|
|
//! @private @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::tran_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QHsm::tran_::path}-->
|
|
<parameter name="path" type="QStateHandler * const"/>
|
|
<!--${QEP::QHsm::tran_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QEP::QHsm::top}-->
|
|
<operation name="top" type="QState" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QAsm
|
|
|
|
//! @protected @memberof QAsm</documentation>
|
|
<!--${QEP::QHsm::top::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<code>Q_UNUSED_PAR(me);
|
|
Q_UNUSED_PAR(e);
|
|
return Q_RET_IGNORED; // the top state ignores all events</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QEP::QMsm}-->
|
|
<class name="QMsm" superclass="QEP::QAsm">
|
|
<documentation>//! @class QMsm
|
|
//! @extends QAsm
|
|
|
|
State machine implementation strategy requiring support
|
|
of a code generating tool and generally NOT suitable
|
|
for manual coding</documentation>
|
|
<!--${QEP::QMsm::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QMsm
|
|
|
|
//! @protected @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::ctor::initial}-->
|
|
<parameter name="initial" type="QStateHandler const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::init_}-->
|
|
<operation name="init_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::init_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::init_::e}-->
|
|
<parameter name="e" type="void const * const"/>
|
|
<!--${QEP::QMsm::init_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::dispatch_}-->
|
|
<operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::dispatch_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::dispatch_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QEP::QMsm::dispatch_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::getStateHandler_}-->
|
|
<operation name="getStateHandler_?def Q_SPY" type="QStateHandler" visibility="0x00" properties="0x03">
|
|
<documentation>//! @public @memberof QMsm
|
|
|
|
//! @public @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::getStateHandler_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<code>return me->state.obj->stateHandler;</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::isIn_}-->
|
|
<operation name="isIn_" type="bool" visibility="0x00" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::isIn_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::isIn_::state}-->
|
|
<parameter name="state" type="QStateHandler const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::stateObj}-->
|
|
<operation name="stateObj" type="QMState const *" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QMsm
|
|
|
|
//! @public @memberof QMsm</documentation>
|
|
<code>return me->super.state.obj;</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::childStateObj}-->
|
|
<operation name="childStateObj" type="QMState const *" visibility="0x00" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QMsm
|
|
|
|
//! @public @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::childStateObj::parent}-->
|
|
<parameter name="parent" type="QMState const * const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::execTatbl_}-->
|
|
<operation name="execTatbl_" type="QState" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::execTatbl_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::execTatbl_::tatbl}-->
|
|
<parameter name="tatbl" type="QMTranActTable const * const"/>
|
|
<!--${QEP::QMsm::execTatbl_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::exitToTranSource_}-->
|
|
<operation name="exitToTranSource_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::exitToTranSource~::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::exitToTranSource~::cs}-->
|
|
<parameter name="cs" type="QMState const * const"/>
|
|
<!--${QEP::QMsm::exitToTranSource~::ts}-->
|
|
<parameter name="ts" type="QMState const * const"/>
|
|
<!--${QEP::QMsm::exitToTranSource~::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::enterHistory_}-->
|
|
<operation name="enterHistory_" type="QState" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QMsm
|
|
|
|
//! @private @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::enterHistory_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QEP::QMsm::enterHistory_::hist}-->
|
|
<parameter name="hist" type="QMState const *const"/>
|
|
<!--${QEP::QMsm::enterHistory_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<!--${QEP-macros}-->
|
|
<package name="QEP-macros" stereotype="0x02">
|
|
<!--${QEP-macros::QEVT_INITIALIZER}-->
|
|
<operation name="QEVT_INITIALIZER" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QEVT_INITIALIZER::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<code>{ (QSignal)(sig_), 0x01U, 0x0EU }</code>
|
|
</operation>
|
|
<!--${QEP-macros::QEVT_DYNAMIC}-->
|
|
<attribute name="QEVT_DYNAMIC" type="" visibility="0x03" properties="0x00">
|
|
<code>((uint8_t)0)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::QASM_INIT}-->
|
|
<operation name="QASM_INIT?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QASM_INIT::me_}-->
|
|
<parameter name="me_" type="<QAsm subclass*>"/>
|
|
<!--${QEP-macros::QASM_INIT::par_}-->
|
|
<parameter name="par_" type="void *"/>
|
|
<!--${QEP-macros::QASM_INIT::qsId_}-->
|
|
<parameter name="qsId_" type="uint8_t"/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), (qsId_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::QASM_INIT}-->
|
|
<operation name="QASM_INIT?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QASM_INIT::me_}-->
|
|
<parameter name="me_" type="<QAsm subclass*>"/>
|
|
<!--${QEP-macros::QASM_INIT::par_}-->
|
|
<parameter name="par_" type="void *"/>
|
|
<!--${QEP-macros::QASM_INIT::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), 0U)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QASM_DISPATCH}-->
|
|
<operation name="QASM_DISPATCH?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QASM_DISPATCH::me_}-->
|
|
<parameter name="me_" type="<QAsm subclass*>"/>
|
|
<!--${QEP-macros::QASM_DISPATCH::e_}-->
|
|
<parameter name="e_" type="QEvt *"/>
|
|
<!--${QEP-macros::QASM_DISPATCH::qsId_}-->
|
|
<parameter name="qsId_" type="uint8_t"/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->dispatch)((QAsm *)(me_), (e_), (qsId_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::QASM_DISPATCH}-->
|
|
<operation name="QASM_DISPATCH?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QASM_DISPATCH::me_}-->
|
|
<parameter name="me_" type="<QAsm subclass*>"/>
|
|
<!--${QEP-macros::QASM_DISPATCH::e_}-->
|
|
<parameter name="e_" type="QEvt *"/>
|
|
<!--${QEP-macros::QASM_DISPATCH::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->dispatch)((QAsm *)(me_), (e_), 0U)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QASM_IS_IN}-->
|
|
<operation name="QASM_IS_IN" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QASM_IS_IN::me_}-->
|
|
<parameter name="me_" type="<QAsm subclass*>"/>
|
|
<!--${QEP-macros::QASM_IS_IN::state_}-->
|
|
<parameter name="state_" type="QStateHandler"/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->isIn)((QAsm *)(me_), (state_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_ASM_UPCAST}-->
|
|
<operation name="Q_ASM_UPCAST" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_ASM_UPCAST::ptr_}-->
|
|
<parameter name="ptr_" type="<QAsm subclass*>"/>
|
|
<code>((QAsm *)(ptr_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_HSM_UPCAST}-->
|
|
<operation name="Q_HSM_UPCAST" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_HSM_UPCAST::ptr_}-->
|
|
<parameter name="ptr_" type="<QHsm subclass*>"/>
|
|
<code>((QHsm *)(ptr_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_MSM_UPCAST}-->
|
|
<operation name="Q_MSM_UPCAST" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_MSM_UPCAST::ptr_}-->
|
|
<parameter name="ptr_" type="<QMsm subclass*>"/>
|
|
<code>((QMsm *)(ptr_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_EMPTY_SIG}-->
|
|
<attribute name="Q_EMPTY_SIG" type="" visibility="0x03" properties="0x00">
|
|
<code>((QSignal)0)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_ENTRY_SIG}-->
|
|
<attribute name="Q_ENTRY_SIG" type="" visibility="0x03" properties="0x00">
|
|
<code>((QSignal)1)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_EXIT_SIG}-->
|
|
<attribute name="Q_EXIT_SIG" type="" visibility="0x03" properties="0x00">
|
|
<code>((QSignal)2)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_INIT_SIG}-->
|
|
<attribute name="Q_INIT_SIG" type="" visibility="0x03" properties="0x00">
|
|
<code>((QSignal)3)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_USER_SIG}-->
|
|
<attribute name="Q_USER_SIG" type="" visibility="0x03" properties="0x00">
|
|
<code>((enum_t)4)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_TRAN}-->
|
|
<operation name="Q_TRAN" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_TRAN::target_}-->
|
|
<parameter name="target_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.fun = Q_STATE_CAST(target_), \
|
|
(QState)Q_RET_TRAN)</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_TRAN_HIST}-->
|
|
<operation name="Q_TRAN_HIST" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_TRAN_HIST::hist_}-->
|
|
<parameter name="hist_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.fun = (hist_), \
|
|
(QState)Q_RET_TRAN_HIST)</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_SUPER}-->
|
|
<operation name="Q_SUPER" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_SUPER::super_}-->
|
|
<parameter name="super_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.fun = Q_STATE_CAST(super_), \
|
|
(QState)Q_RET_SUPER)</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_HANDLED}-->
|
|
<operation name="Q_HANDLED" type="" visibility="0x03" properties="0x00">
|
|
<code>((QState)Q_RET_HANDLED)</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_UNHANDLED}-->
|
|
<operation name="Q_UNHANDLED" type="" visibility="0x03" properties="0x00">
|
|
<code>((QState)Q_RET_UNHANDLED)</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_ACTION_NULL}-->
|
|
<attribute name="Q_ACTION_NULL" type="void" visibility="0x03" properties="0x00">
|
|
<documentation>/</documentation>
|
|
<code>((QActionHandler)0)</code>
|
|
</attribute>
|
|
<!--${QEP-macros::Q_EVT_CAST}-->
|
|
<operation name="Q_EVT_CAST" type="<QEvt subclass>*" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_EVT_CAST::class_}-->
|
|
<parameter name="class_" type="<QEvt subclass>"/>
|
|
<code>((class_ const *)(e))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_STATE_CAST}-->
|
|
<operation name="Q_STATE_CAST" type="QStateHandler" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_STATE_CAST::handler_}-->
|
|
<parameter name="handler_" type="<state handler>"/>
|
|
<code>((QStateHandler)(handler_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_ACTION_CAST}-->
|
|
<operation name="Q_ACTION_CAST" type="QActionHandler" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_ACTION_CAST::action_}-->
|
|
<parameter name="action_" type="<action handler>"/>
|
|
<code>((QActionHandler)(action_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_UNUSED_PAR}-->
|
|
<operation name="Q_UNUSED_PAR" type="<param type>" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_UNUSED_PAR::par_}-->
|
|
<parameter name="par_" type="<param type>"/>
|
|
<code>((void)(par_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_DIM}-->
|
|
<operation name="Q_DIM" type="unsigned" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_DIM::array_}-->
|
|
<parameter name="array_" type="1-dimensional array"/>
|
|
<code>(sizeof(array_) / sizeof((array_)[0U]))</code>
|
|
</operation>
|
|
<!--${QEP-macros::Q_UINT2PTR_CAST}-->
|
|
<operation name="Q_UINT2PTR_CAST" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::Q_UINT2PTR_CAST::type_}-->
|
|
<parameter name="type_" type=""/>
|
|
<!--${QEP-macros::Q_UINT2PTR_CAST::uint_}-->
|
|
<parameter name="uint_" type=""/>
|
|
<code>((type_ *)(uint_))</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_ENTRY}-->
|
|
<operation name="QM_ENTRY?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_ENTRY::state_}-->
|
|
<parameter name="state_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
|
|
(QState)Q_RET_ENTRY)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_ENTRY}-->
|
|
<operation name="QM_ENTRY?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_ENTRY::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>((QState)Q_RET_ENTRY)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_EXIT}-->
|
|
<operation name="QM_EXIT?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_EXIT::state_}-->
|
|
<parameter name="state_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
|
|
(QState)Q_RET_EXIT)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_EXIT}-->
|
|
<operation name="QM_EXIT?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_EXIT::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>((QState)Q_RET_EXIT)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_SM_EXIT}-->
|
|
<operation name="QM_SM_EXIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_SM_EXIT::state_}-->
|
|
<parameter name="state_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.obj = (state_), \
|
|
(QState)Q_RET_EXIT)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_TRAN}-->
|
|
<operation name="QM_TRAN" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_TRAN::tatbl_}-->
|
|
<parameter name="tatbl_" type="QMTranActionTable const *"/>
|
|
<code>((Q_ASM_UPCAST(me))->temp.tatbl \
|
|
= (struct QMTranActTable const *)(tatbl_), \
|
|
(QState)Q_RET_TRAN)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_TRAN_INIT}-->
|
|
<operation name="QM_TRAN_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_TRAN_INIT::tatbl_}-->
|
|
<parameter name="tatbl_" type="QMTranActionTable const *"/>
|
|
<code>((Q_ASM_UPCAST(me))->temp.tatbl \
|
|
= (struct QMTranActTable const *)(tatbl_), \
|
|
(QState)Q_RET_TRAN_INIT)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_TRAN_HIST}-->
|
|
<operation name="QM_TRAN_HIST" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_TRAN_HIST::history_}-->
|
|
<parameter name="history_" type="QStateHandler"/>
|
|
<!--${QEP-macros::QM_TRAN_HIST::tatbl_}-->
|
|
<parameter name="tatbl_" type="QMTranActionTable const *"/>
|
|
<code>\
|
|
((((Q_ASM_UPCAST(me))->state.obj = (history_)), \
|
|
((Q_ASM_UPCAST(me))->temp.tatbl = \
|
|
(struct QMTranActTable const *)(tatbl_))), \
|
|
(QState)Q_RET_TRAN_HIST)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_HANDLED}-->
|
|
<operation name="QM_HANDLED" type="" visibility="0x03" properties="0x00">
|
|
<code>((QState)Q_RET_HANDLED)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_UNHANDLED}-->
|
|
<operation name="QM_UNHANDLED" type="" visibility="0x03" properties="0x00">
|
|
<code>((QState)Q_RET_UNHANDLED)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_SUPER}-->
|
|
<operation name="QM_SUPER" type="" visibility="0x03" properties="0x00">
|
|
<code>((QState)Q_RET_SUPER)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_STATE_NULL}-->
|
|
<attribute name="QM_STATE_NULL" type="" visibility="0x03" properties="0x00">
|
|
<code>((QMState *)0)</code>
|
|
</attribute>
|
|
</package>
|
|
<!--${QF}-->
|
|
<package name="QF" stereotype="0x05">
|
|
<!--${QF::QF}-->
|
|
<attribute name="QF" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<documentation>//! @class QF</documentation>
|
|
<code>{
|
|
//! @cond INTERNAL
|
|
uint8_t dummy;
|
|
//! @endcond
|
|
} QV;</code>
|
|
</attribute>
|
|
<!--${QF::types}-->
|
|
<package name="types" stereotype="0x02">
|
|
<!--${QF::types::QPrioSpec}-->
|
|
<attribute name="QPrioSpec" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QTimeEvtCtr}-->
|
|
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QTimeEvtCtr}-->
|
|
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QTimeEvtCtr}-->
|
|
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QPSetBits}-->
|
|
<attribute name="QPSetBits? (QF_MAX_ACTIVE <= 8U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QPSetBits}-->
|
|
<attribute name="QPSetBits? (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QPSetBits}-->
|
|
<attribute name="QPSetBits? (16U < QF_MAX_ACTIVE)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QF_LOG2}-->
|
|
<operation name="QF_LOG2?ndef QF_LOG2" type="uint_fast8_t" visibility="0x00" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<!--${QF::types::QF_LOG2::bitmask}-->
|
|
<parameter name="bitmask" type="QPSetBits const"/>
|
|
<code>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];</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet}-->
|
|
<class name="QPSet">
|
|
<documentation>//! @class QPSet</documentation>
|
|
<!--${QF::types::QPSet::bits[((QF_MAX_ACTIVE + (8U*sizeo~}-->
|
|
<attribute name="bits[((QF_MAX_ACTIVE + (8U*sizeof(QPSetBits))) - 1U)/(8U*sizeof(QPSetBits))]" type="QPSetBits" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QPSet</documentation>
|
|
</attribute>
|
|
<!--${QF::types::QPSet::setEmpty}-->
|
|
<operation name="setEmpty" type="void" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<code>me->bits[0] = 0U;
|
|
#if (QF_MAX_ACTIVE > 32)
|
|
me->bits[1] = 0U;
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::isEmpty}-->
|
|
<operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<code>#if (QF_MAX_ACTIVE <= 32U)
|
|
return (me->bits[0] == 0U);
|
|
#else
|
|
return (me->bits[0] == 0U) ? (me->bits[1] == 0U) : false;
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::notEmpty}-->
|
|
<operation name="notEmpty" type="bool" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<code>#if (QF_MAX_ACTIVE <= 32U)
|
|
return (me->bits[0] != 0U);
|
|
#else
|
|
return (me->bits[0] != 0U) ? true : (me->bits[1] != 0U);
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::hasElement}-->
|
|
<operation name="hasElement" type="bool" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<!--${QF::types::QPSet::hasElement::n}-->
|
|
<parameter name="n" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::insert}-->
|
|
<operation name="insert" type="void" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<!--${QF::types::QPSet::insert::n}-->
|
|
<parameter name="n" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::remove}-->
|
|
<operation name="remove" type="void" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<!--${QF::types::QPSet::remove::n}-->
|
|
<parameter name="n" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::findMax}-->
|
|
<operation name="findMax" type="uint_fast8_t" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QPSet
|
|
|
|
//! @public @memberof QPSet</documentation>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::update_}-->
|
|
<operation name="update_?ndef Q_UNSAFE" type="void" visibility="0x02" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QPSet
|
|
|
|
//! @private @memberof QPSet</documentation>
|
|
<!--${QF::types::QPSet::update_::dis}-->
|
|
<parameter name="dis" type="QPSet * const"/>
|
|
<code>dis->bits[0] = ~me->bits[0];
|
|
#if (QF_MAX_ACTIVE > 32U)
|
|
dis->bits[1] = ~me->bits[1];
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QF::types::QPSet::verify_}-->
|
|
<operation name="verify_?ndef Q_UNSAFE" type="bool" visibility="0x02" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QPSet
|
|
|
|
//! @private @memberof QPSet</documentation>
|
|
<!--${QF::types::QPSet::verify_::dis}-->
|
|
<parameter name="dis" type="QPSet const * const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::types::QSubscrList}-->
|
|
<class name="QSubscrList">
|
|
<documentation>//! @struct QSubscrList</documentation>
|
|
<!--${QF::types::QSubscrList::set}-->
|
|
<attribute name="set" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QSubscrList</documentation>
|
|
</attribute>
|
|
<!--${QF::types::QSubscrList::set_dis}-->
|
|
<attribute name="set_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QSubscrList</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QF::types::QEvtPtr}-->
|
|
<attribute name="QEvtPtr" type="typedef QEvt const *" visibility="0x04" properties="0x00"/>
|
|
<!--${QF::types::QEQueue}-->
|
|
<attribute name="QEQueue" type="struct" visibility="0x04" properties="0x00"/>
|
|
</package>
|
|
<!--${QF::QActive}-->
|
|
<class name="QActive" superclass="QEP::QAsm">
|
|
<documentation>//! @class QActive
|
|
//! @extends QAsm</documentation>
|
|
<!--${QF::QActive::prio}-->
|
|
<attribute name="prio" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::pthre}-->
|
|
<attribute name="pthre" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::thread}-->
|
|
<attribute name="thread?def QACTIVE_THREAD_TYPE" type="QACTIVE_THREAD_TYPE" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::osObject}-->
|
|
<attribute name="osObject?def QACTIVE_OS_OBJ_TYPE" type="QACTIVE_OS_OBJ_TYPE" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::eQueue}-->
|
|
<attribute name="eQueue?def QACTIVE_EQUEUE_TYPE" type="QACTIVE_EQUEUE_TYPE" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::prio_dis}-->
|
|
<attribute name="prio_dis?ndef Q_UNSAFE" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::pthre_dis}-->
|
|
<attribute name="pthre_dis?ndef Q_UNSAFE" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}-->
|
|
<attribute name="registry_[QF_MAX_ACTIVE + 1U]" type="QActive *" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QActive
|
|
|
|
//! @static @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::subscrList_}-->
|
|
<attribute name="subscrList_" type="QSubscrList *" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::maxPubSignal_}-->
|
|
<attribute name="maxPubSignal_" type="enum_t" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::ctor::initial}-->
|
|
<parameter name="initial" type="QStateHandler const"/>
|
|
<code>// 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</code>
|
|
</operation>
|
|
<!--${QF::QActive::setAttr}-->
|
|
<operation name="setAttr" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QActive
|
|
|
|
//! @public @memberof QActive</documentation>
|
|
<!--${QF::QActive::setAttr::attr1}-->
|
|
<parameter name="attr1" type="uint32_t"/>
|
|
<!--${QF::QActive::setAttr::attr2}-->
|
|
<parameter name="attr2" type="void const *"/>
|
|
</operation>
|
|
<!--${QF::QActive::start}-->
|
|
<operation name="start" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QActive
|
|
|
|
//! @public @memberof QActive</documentation>
|
|
<!--${QF::QActive::start::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QF::QActive::start::qSto}-->
|
|
<parameter name="qSto" type="QEvtPtr * const"/>
|
|
<!--${QF::QActive::start::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<!--${QF::QActive::start::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QF::QActive::start::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
<!--${QF::QActive::start::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
</operation>
|
|
<!--${QF::QActive::stop}-->
|
|
<operation name="stop?def QACTIVE_CAN_STOP" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
</operation>
|
|
<!--${QF::QActive::register_}-->
|
|
<operation name="register_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QActive::unregister_}-->
|
|
<operation name="unregister_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QActive::post_}-->
|
|
<operation name="post_" type="bool" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<!--${QF::QActive::post_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QF::QActive::post_::margin}-->
|
|
<parameter name="margin" type="uint_fast16_t const"/>
|
|
<!--${QF::QActive::post_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QF::QActive::postLIFO_}-->
|
|
<operation name="postLIFO_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<!--${QF::QActive::postLIFO_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
<!--${QF::QActive::get_}-->
|
|
<operation name="get_" type="QEvt const *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QActive::psInit}-->
|
|
<operation name="psInit" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QActive
|
|
|
|
//! @static @public @memberof QActive</documentation>
|
|
<!--${QF::QActive::psInit::subscrSto}-->
|
|
<parameter name="subscrSto" type="QSubscrList * const"/>
|
|
<!--${QF::QActive::psInit::maxSignal}-->
|
|
<parameter name="maxSignal" type="enum_t const"/>
|
|
<code>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
|
|
}</code>
|
|
</operation>
|
|
<!--${QF::QActive::publish_}-->
|
|
<operation name="publish_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QActive
|
|
|
|
//! @static @private @memberof QActive</documentation>
|
|
<!--${QF::QActive::publish_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QF::QActive::publish_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<!--${QF::QActive::publish_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::QActive::subscribe}-->
|
|
<operation name="subscribe" type="void" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::subscribe::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QActive::unsubscribe}-->
|
|
<operation name="unsubscribe" type="void" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::unsubscribe::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QActive::unsubscribeAll}-->
|
|
<operation name="unsubscribeAll" type="void" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<code>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
|
|
}</code>
|
|
</operation>
|
|
<!--${QF::QActive::defer}-->
|
|
<operation name="defer" type="bool" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::defer::eq}-->
|
|
<parameter name="eq" type="struct QEQueue * const"/>
|
|
<!--${QF::QActive::defer::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QActive::recall}-->
|
|
<operation name="recall" type="bool" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::recall::eq}-->
|
|
<parameter name="eq" type="struct QEQueue * const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QActive::flushDeferred}-->
|
|
<operation name="flushDeferred" type="uint_fast16_t" visibility="0x01" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<!--${QF::QActive::flushDeferred::eq}-->
|
|
<parameter name="eq" type="struct QEQueue * const"/>
|
|
<!--${QF::QActive::flushDeferred::num}-->
|
|
<parameter name="num" type="uint_fast16_t const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QActive::evtLoop_}-->
|
|
<operation name="evtLoop_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QMActive}-->
|
|
<class name="QMActive" superclass="QF::QActive">
|
|
<documentation>//! @class QMActive
|
|
//! @extends QActive</documentation>
|
|
<!--${QF::QMActive::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QMActive
|
|
|
|
//! @protected @memberof QMActive</documentation>
|
|
<!--${QF::QMActive::ctor::initial}-->
|
|
<parameter name="initial" type="QStateHandler const"/>
|
|
<code>// 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</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QTimeEvt}-->
|
|
<class name="QTimeEvt" superclass="QEP::QEvt">
|
|
<documentation>//! @class QTimeEvt
|
|
//! @extends QEvt</documentation>
|
|
<!--${QF::QTimeEvt::next}-->
|
|
<attribute name="next" type="struct QTimeEvt * volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::next_dis}-->
|
|
<attribute name="next_dis?ndef Q_UNSAFE" type="uintptr_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::act}-->
|
|
<attribute name="act" type="void *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::ctr}-->
|
|
<attribute name="ctr" type="QTimeEvtCtr volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::ctr_dis}-->
|
|
<attribute name="ctr_dis?ndef Q_UNSAFE" type="QTimeEvtCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::interval}-->
|
|
<attribute name="interval" type="QTimeEvtCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::tickRate}-->
|
|
<attribute name="tickRate" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::flags}-->
|
|
<attribute name="flags" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::timeEvtHead_[QF_MAX_TICK_RATE]}-->
|
|
<attribute name="timeEvtHead_[QF_MAX_TICK_RATE]" type="QTimeEvt" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::timeEvtHead_dis_[QF_MAX_TICK_RAT~}-->
|
|
<attribute name="timeEvtHead_dis_[QF_MAX_TICK_RATE]?ndef Q_UNSAFE" type="uintptr_t" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QTimeEvt</documentation>
|
|
</attribute>
|
|
<!--${QF::QTimeEvt::ctorX}-->
|
|
<operation name="ctorX" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::ctorX::act}-->
|
|
<parameter name="act" type="QActive * const"/>
|
|
<!--${QF::QTimeEvt::ctorX::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<!--${QF::QTimeEvt::ctorX::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::armX}-->
|
|
<operation name="armX" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::armX::nTicks}-->
|
|
<parameter name="nTicks" type="uint32_t const"/>
|
|
<!--${QF::QTimeEvt::armX::interval}-->
|
|
<parameter name="interval" type="uint32_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::disarm}-->
|
|
<operation name="disarm" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::rearm}-->
|
|
<operation name="rearm" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::rearm::nTicks}-->
|
|
<parameter name="nTicks" type="uint32_t const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::wasDisarmed}-->
|
|
<operation name="wasDisarmed" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::currCtr}-->
|
|
<operation name="currCtr" type="QTimeEvtCtr" visibility="0x00" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QTimeEvt
|
|
|
|
//! @public @memberof QTimeEvt</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QTimeEvtCtr const ctr = me->ctr;
|
|
QF_CRIT_EXIT();
|
|
|
|
return ctr;</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QTimeEvt
|
|
|
|
//! @static @private @memberof QTimeEvt</documentation>
|
|
<code>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
|
|
}</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::tick_}-->
|
|
<operation name="tick_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QTimeEvt
|
|
|
|
//! @static @private @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::tick_::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<!--${QF::QTimeEvt::tick_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::tick1_}-->
|
|
<operation name="tick1_?def Q_UTEST" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QTimeEvt
|
|
|
|
//! @static @private @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::tick1_::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<!--${QF::QTimeEvt::tick1_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
</operation>
|
|
<!--${QF::QTimeEvt::noActive}-->
|
|
<operation name="noActive" type="bool" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QTimeEvt
|
|
|
|
//! @static @public @memberof QTimeEvt</documentation>
|
|
<!--${QF::QTimeEvt::noActive::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<code>// NOTE: this function must be called *inside* critical section
|
|
Q_REQUIRE_INCRIT(900, tickRate < QF_MAX_TICK_RATE);
|
|
|
|
bool inactive;
|
|
|
|
QF_MEM_SYS();
|
|
if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
|
|
inactive = false;
|
|
}
|
|
else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
|
|
inactive = false;
|
|
}
|
|
else {
|
|
inactive = true;
|
|
}
|
|
QF_MEM_APP();
|
|
|
|
return inactive;</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QTicker}-->
|
|
<class name="QTicker" superclass="QF::QActive">
|
|
<documentation>//! @class QTicker
|
|
//! @extends QActive</documentation>
|
|
<!--${QF::QTicker::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QTicker
|
|
|
|
//! @public @memberof QTicker</documentation>
|
|
<!--${QF::QTicker::ctor::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QF::QTicker::init_}-->
|
|
<operation name="init_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QTicker
|
|
|
|
//! @private @memberof QTicker</documentation>
|
|
<!--${QF::QTicker::init_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QF::QTicker::init_::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<!--${QF::QTicker::init_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QTicker::dispatch_}-->
|
|
<operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QTicker
|
|
|
|
//! @private @memberof QTicker</documentation>
|
|
<!--${QF::QTicker::dispatch_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QF::QTicker::dispatch_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QF::QTicker::dispatch_::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>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);
|
|
}</code>
|
|
</operation>
|
|
<!--${QF::QTicker::trig_}-->
|
|
<operation name="trig_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QTicker
|
|
|
|
//! @private @memberof QTicker</documentation>
|
|
<!--${QF::QTicker::trig_::me}-->
|
|
<parameter name="me" type="QActive * const"/>
|
|
<!--${QF::QTicker::trig_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QEQueue}-->
|
|
<class name="QEQueue">
|
|
<documentation>//! @class QEQueue</documentation>
|
|
<!--${QF::QEQueue::frontEvt}-->
|
|
<attribute name="frontEvt" type="struct QEvt const * volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::ring}-->
|
|
<attribute name="ring" type="struct QEvt const * *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::end}-->
|
|
<attribute name="end" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::head}-->
|
|
<attribute name="head" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::tail}-->
|
|
<attribute name="tail" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::nFree}-->
|
|
<attribute name="nFree" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::frontEvt_dis}-->
|
|
<attribute name="frontEvt_dis?ndef Q_UNSAFE" type="uintptr_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::head_dis}-->
|
|
<attribute name="head_dis?ndef Q_UNSAFE" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::tail_dis}-->
|
|
<attribute name="tail_dis?ndef Q_UNSAFE" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::nFree_dis}-->
|
|
<attribute name="nFree_dis?ndef Q_UNSAFE" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::nMin}-->
|
|
<attribute name="nMin?ndef Q_UNSAFE" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::dummy}-->
|
|
<attribute name="dummy" type="extern QEQueue *" visibility="0x04" properties="0x01">
|
|
<documentation>// dummy static member to force generating 'struct QEQueue {...}'</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<!--${QF::QEQueue::init::qSto}-->
|
|
<parameter name="qSto" type="struct QEvt const * * const"/>
|
|
<!--${QF::QEQueue::init::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::post}-->
|
|
<operation name="post" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<!--${QF::QEQueue::post::e}-->
|
|
<parameter name="e" type="struct QEvt const * const"/>
|
|
<!--${QF::QEQueue::post::margin}-->
|
|
<parameter name="margin" type="uint_fast16_t const"/>
|
|
<!--${QF::QEQueue::post::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::postLIFO}-->
|
|
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<!--${QF::QEQueue::postLIFO::e}-->
|
|
<parameter name="e" type="struct QEvt const * const"/>
|
|
<!--${QF::QEQueue::postLIFO::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::get}-->
|
|
<operation name="get" type="struct QEvt const *" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<!--${QF::QEQueue::get::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::getNFree}-->
|
|
<operation name="getNFree" type="QEQueueCtr" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<code>return me->nFree;</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::getNMin}-->
|
|
<operation name="getNMin" type="QEQueueCtr" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<code>#ifndef Q_UNSAFE
|
|
return me->nMin;
|
|
#else
|
|
return 0U;
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QF::QEQueue::isEmpty}-->
|
|
<operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QEQueue
|
|
|
|
//! @public @memberof QEQueue</documentation>
|
|
<code>return me->frontEvt == (struct QEvt *)0;</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QFreeBlock}-->
|
|
<class name="QFreeBlock">
|
|
<documentation>//! @struct QFreeBlock</documentation>
|
|
<!--${QF::QFreeBlock::next}-->
|
|
<attribute name="next" type="struct QFreeBlock *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QFreeBlock</documentation>
|
|
</attribute>
|
|
<!--${QF::QFreeBlock::next_dis}-->
|
|
<attribute name="next_dis?ndef Q_UNSAFE" type="uintptr_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QFreeBlock</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QF::QMPool}-->
|
|
<class name="QMPool">
|
|
<documentation>//! @class QMPool</documentation>
|
|
<!--${QF::QMPool::start}-->
|
|
<attribute name="start" type="QFreeBlock *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::end}-->
|
|
<attribute name="end" type="QFreeBlock *" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::free_head}-->
|
|
<attribute name="free_head" type="QFreeBlock * volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::blockSize}-->
|
|
<attribute name="blockSize" type="QMPoolSize" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::nTot}-->
|
|
<attribute name="nTot" type="QMPoolCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::nFree}-->
|
|
<attribute name="nFree" type="QMPoolCtr volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::nMin}-->
|
|
<attribute name="nMin?ndef Q_UNSAFE" type="QMPoolCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::free_head_dis}-->
|
|
<attribute name="free_head_dis?ndef Q_UNSAFE" type="uintptr_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::nFree_dis}-->
|
|
<attribute name="nFree_dis?ndef Q_UNSAFE" type="QMPoolCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QMPool</documentation>
|
|
</attribute>
|
|
<!--${QF::QMPool::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QMPool
|
|
|
|
//! @public @memberof QMPool</documentation>
|
|
<!--${QF::QMPool::init::poolSto}-->
|
|
<parameter name="poolSto" type="void * const"/>
|
|
<!--${QF::QMPool::init::poolSize}-->
|
|
<parameter name="poolSize" type="uint_fast32_t const"/>
|
|
<!--${QF::QMPool::init::blockSize}-->
|
|
<parameter name="blockSize" type="uint_fast16_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QF::QMPool::get}-->
|
|
<operation name="get" type="void *" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QMPool
|
|
|
|
//! @public @memberof QMPool</documentation>
|
|
<!--${QF::QMPool::get::margin}-->
|
|
<parameter name="margin" type="uint_fast16_t const"/>
|
|
<!--${QF::QMPool::get::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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</code>
|
|
</operation>
|
|
<!--${QF::QMPool::put}-->
|
|
<operation name="put" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QMPool
|
|
|
|
//! @public @memberof QMPool</documentation>
|
|
<!--${QF::QMPool::put::block}-->
|
|
<parameter name="block" type="void * const"/>
|
|
<!--${QF::QMPool::put::qsId}-->
|
|
<parameter name="qsId" type="uint_fast8_t const"/>
|
|
<code>#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();</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QF::QF-pkg}-->
|
|
<package name="QF-pkg" stereotype="0x02" namespace="QF_">
|
|
<!--${QF::QF-pkg::Attr}-->
|
|
<class name="Attr">
|
|
<documentation>//! @class QF_Attr</documentation>
|
|
<!--${QF::QF-pkg::Attr::ePool_[QF_MAX_EPOOL]}-->
|
|
<attribute name="ePool_[QF_MAX_EPOOL]? (QF_MAX_EPOOL > 0U)" type="QF_EPOOL_TYPE_" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QF_Attr</documentation>
|
|
</attribute>
|
|
<!--${QF::QF-pkg::Attr::maxPool_}-->
|
|
<attribute name="maxPool_? (QF_MAX_EPOOL > 0U)" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QF_Attr</documentation>
|
|
</attribute>
|
|
<!--${QF::QF-pkg::Attr::dummy}-->
|
|
<attribute name="dummy? (QF_MAX_EPOOL == 0U)" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QF_Attr</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QF::QF-pkg::priv_}-->
|
|
<attribute name="priv_" type="QF_Attr" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QF</documentation>
|
|
</attribute>
|
|
<!--${QF::QF-pkg::bzero_}-->
|
|
<operation name="bzero_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QF
|
|
|
|
//! @static @private @memberof QF</documentation>
|
|
<!--${QF::QF-pkg::bzero_::start}-->
|
|
<parameter name="start" type="void * const"/>
|
|
<!--${QF::QF-pkg::bzero_::len}-->
|
|
<parameter name="len" type="uint_fast16_t const"/>
|
|
<code>uint8_t *ptr = (uint8_t *)start;
|
|
for (uint_fast16_t n = len; n > 0U; --n) {
|
|
*ptr = 0U;
|
|
++ptr;
|
|
}</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QF::QF-base}-->
|
|
<package name="QF-base" stereotype="0x02" namespace="QF_">
|
|
<!--${QF::QF-base::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
</operation>
|
|
<!--${QF::QF-base::stop}-->
|
|
<operation name="stop" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
</operation>
|
|
<!--${QF::QF-base::run}-->
|
|
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
</operation>
|
|
<!--${QF::QF-base::getQueueMin}-->
|
|
<operation name="getQueueMin" type="uint_fast16_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-base::getQueueMin::prio}-->
|
|
<parameter name="prio" type="uint_fast8_t const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QF-base::onStartup}-->
|
|
<operation name="onStartup" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
</operation>
|
|
<!--${QF::QF-base::onCleanup}-->
|
|
<operation name="onCleanup" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
</operation>
|
|
<!--${QF::QF-base::onContextSw}-->
|
|
<operation name="onContextSw?def QF_ON_CONTEXT_SW" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-base::onContextSw::prev}-->
|
|
<parameter name="prev" type="QActive *"/>
|
|
<!--${QF::QF-base::onContextSw::next}-->
|
|
<parameter name="next" type="QActive *"/>
|
|
</operation>
|
|
</package>
|
|
<!--${QF::QF-dyn}-->
|
|
<package name="QF-dyn" stereotype="0x02" namespace="QF_">
|
|
<!--${QF::QF-dyn::poolInit}-->
|
|
<operation name="poolInit" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::poolInit::poolSto}-->
|
|
<parameter name="poolSto" type="void * const"/>
|
|
<!--${QF::QF-dyn::poolInit::poolSize}-->
|
|
<parameter name="poolSize" type="uint_fast32_t const"/>
|
|
<!--${QF::QF-dyn::poolInit::evtSize}-->
|
|
<parameter name="evtSize" type="uint_fast16_t const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::poolGetMaxBlockSize}-->
|
|
<operation name="poolGetMaxBlockSize" type="uint_fast16_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::getPoolMin}-->
|
|
<operation name="getPoolMin" type="uint_fast16_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::getPoolMin::poolNum}-->
|
|
<parameter name="poolNum" type="uint_fast8_t const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::newX_}-->
|
|
<operation name="newX_" type="QEvt *" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QF
|
|
|
|
//! @static @private @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::newX_::evtSize}-->
|
|
<parameter name="evtSize" type="uint_fast16_t const"/>
|
|
<!--${QF::QF-dyn::newX_::margin}-->
|
|
<parameter name="margin" type="uint_fast16_t const"/>
|
|
<!--${QF::QF-dyn::newX_::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<code>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;</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::gc}-->
|
|
<operation name="gc" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::gc::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<code>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();
|
|
}</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::newRef_}-->
|
|
<operation name="newRef_" type="QEvt const *" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QF
|
|
|
|
//! @static @private @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::newRef_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QF::QF-dyn::newRef_::evtRef}-->
|
|
<parameter name="evtRef" type="void const * const"/>
|
|
<code>#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;</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::deleteRef_}-->
|
|
<operation name="deleteRef_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @private @memberof QF
|
|
|
|
//! @static @private @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::deleteRef_::evtRef}-->
|
|
<parameter name="evtRef" type="void const * const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QF::QF-dyn::gcFromISR}-->
|
|
<operation name="gcFromISR" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<!--${QF::QF-dyn::gcFromISR::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
</operation>
|
|
</package>
|
|
</package>
|
|
<!--${QF-macros}-->
|
|
<package name="QF-macros" stereotype="0x02">
|
|
<!--${QF-macros::QF_NO_MARGIN}-->
|
|
<attribute name="QF_NO_MARGIN" type="uint_fast16_t" visibility="0x03" properties="0x00">
|
|
<code>((uint_fast16_t)0xFFFFU)</code>
|
|
</attribute>
|
|
<!--${QF-macros::Q_PRIO}-->
|
|
<operation name="Q_PRIO" type="QPrioSpec" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_PRIO::prio_}-->
|
|
<parameter name="prio_" type="uint8_t"/>
|
|
<!--${QF-macros::Q_PRIO::pthre_}-->
|
|
<parameter name="pthre_" type="uint8_t"/>
|
|
<code>((QPrioSpec)((prio_) | ((pthre_) << 8U)))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_NEW}-->
|
|
<operation name="Q_NEW?ndef QEVT_PAR_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_NEW::evtT_}-->
|
|
<parameter name="evtT_" type="<event class>"/>
|
|
<!--${QF-macros::Q_NEW::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<code>((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
QF_NO_MARGIN, (enum_t)(sig_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_NEW}-->
|
|
<operation name="Q_NEW?def QEVT_PAR_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_NEW::evtT_}-->
|
|
<parameter name="evtT_" type="<event class>"/>
|
|
<!--${QF-macros::Q_NEW::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QF-macros::Q_NEW::...}-->
|
|
<parameter name="..." type="__VA_ARGS__"/>
|
|
<code>\
|
|
(evtT_##_init((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
QF_NO_MARGIN, (sig_)), __VA_ARGS__))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_NEW_X}-->
|
|
<operation name="Q_NEW_X?ndef QEVT_PAR_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_NEW_X::evtT_}-->
|
|
<parameter name="evtT_" type="<event class>"/>
|
|
<!--${QF-macros::Q_NEW_X::margin_}-->
|
|
<parameter name="margin_" type="uint16_t"/>
|
|
<!--${QF-macros::Q_NEW_X::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<code>\
|
|
((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
(margin_), (enum_t)(sig_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_NEW_X}-->
|
|
<operation name="Q_NEW_X?def QEVT_PAR_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_NEW_X::evtT_}-->
|
|
<parameter name="evtT_" type="<event class>"/>
|
|
<!--${QF-macros::Q_NEW_X::margin_}-->
|
|
<parameter name="margin_" type="uint16_t"/>
|
|
<!--${QF-macros::Q_NEW_X::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QF-macros::Q_NEW_X::...}-->
|
|
<parameter name="..." type="__VA_ARGS__"/>
|
|
<code>\
|
|
(evtT_##_init((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
(margin_), (sig_)), __VA_ARGS__))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_NEW_REF}-->
|
|
<operation name="Q_NEW_REF" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_NEW_REF::evtRef_}-->
|
|
<parameter name="evtRef_" type="<event class>"/>
|
|
<!--${QF-macros::Q_NEW_REF::evtT_}-->
|
|
<parameter name="evtT_" type="<event class>"/>
|
|
<code>\
|
|
((evtRef_) = (evtT_ const *)QF_newRef_(e, (evtRef_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::Q_DELETE_REF}-->
|
|
<operation name="Q_DELETE_REF" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::Q_DELETE_REF::evtRef_}-->
|
|
<parameter name="evtRef_" type="<event class>"/>
|
|
<code>do { \
|
|
QF_deleteRef_((evtRef_)); \
|
|
(evtRef_) = (void *)0; \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_POST}-->
|
|
<operation name="QACTIVE_POST?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_POST::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_POST::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_POST::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>\
|
|
((void)QActive_post_((me_), (e_), QF_NO_MARGIN, (sender_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_POST}-->
|
|
<operation name="QACTIVE_POST?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_POST::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_POST::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_POST::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>\
|
|
((void)QActive_post_((me_), (e_), QF_NO_MARGIN, (void *)0))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_POST_X}-->
|
|
<operation name="QACTIVE_POST_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_POST_X::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::margin_}-->
|
|
<parameter name="margin_" type="uint16_t"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>\
|
|
(QActive_post_((me_), (e_), (margin_), (sender_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_POST_X}-->
|
|
<operation name="QACTIVE_POST_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_POST_X::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::margin_}-->
|
|
<parameter name="margin_" type="uint16_t"/>
|
|
<!--${QF-macros::QACTIVE_POST_X::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>\
|
|
(QActive_post_((me_), (e_), (margin_), (void *)0))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_POST_LIFO}-->
|
|
<operation name="QACTIVE_POST_LIFO" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_POST_LIF~::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_POST_LIF~::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<code>\
|
|
(QActive_postLIFO_((me_), (e_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_PUBLISH}-->
|
|
<operation name="QACTIVE_PUBLISH?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_PUBLISH::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_PUBLISH::sender_}-->
|
|
<parameter name="sender_" type="<void const *>"/>
|
|
<code>\
|
|
(QActive_publish_((e_), (void const *)(sender_), (sender_)->prio))</code>
|
|
</operation>
|
|
<!--${QF-macros::QACTIVE_PUBLISH}-->
|
|
<operation name="QACTIVE_PUBLISH?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_PUBLISH::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QACTIVE_PUBLISH::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>(QActive_publish_((e_), (void *)0, 0U))</code>
|
|
</operation>
|
|
<!--${QF-macros::QTIMEEVT_TICK_X}-->
|
|
<operation name="QTIMEEVT_TICK_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QTIMEEVT_TICK_X::tickRate_}-->
|
|
<parameter name="tickRate_" type="uint8_t"/>
|
|
<!--${QF-macros::QTIMEEVT_TICK_X::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>(QTimeEvt_tick_((tickRate_), (sender_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::QTIMEEVT_TICK_X}-->
|
|
<operation name="QTIMEEVT_TICK_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QTIMEEVT_TICK_X::tickRate_}-->
|
|
<parameter name="tickRate_" type="uint8_t"/>
|
|
<!--${QF-macros::QTIMEEVT_TICK_X::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>(QTimeEvt_tick_((tickRate_), (void *)0))</code>
|
|
</operation>
|
|
<!--${QF-macros::QTIMEEVT_TICK}-->
|
|
<operation name="QTIMEEVT_TICK" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QTIMEEVT_TICK::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>QTIMEEVT_TICK_X(0U, (sender_))</code>
|
|
</operation>
|
|
<!--${QF-macros::QTICKER_TRIG}-->
|
|
<operation name="QTICKER_TRIG?def Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QTICKER_TRIG::ticker_}-->
|
|
<parameter name="ticker_" type="QTicker * const"/>
|
|
<!--${QF-macros::QTICKER_TRIG::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>(QTicker_trig_((ticker_), (sender_)))</code>
|
|
</operation>
|
|
<!--${QF-macros::QTICKER_TRIG}-->
|
|
<operation name="QTICKER_TRIG?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QTICKER_TRIG::ticker_}-->
|
|
<parameter name="ticker_" type="QTicker * const"/>
|
|
<!--${QF-macros::QTICKER_TRIG::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>(QTicker_trig_((ticker_), (void *)0))</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_CRIT_EXIT_NOP}-->
|
|
<operation name="QF_CRIT_EXIT_NOP?ndef QF_CRIT_EXIT_NOP" type="void" visibility="0x03" properties="0x00">
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_TICK_X}-->
|
|
<operation name="QF_TICK_X" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QF_TICK_X::tickRate_}-->
|
|
<parameter name="tickRate_" type="uint8_t"/>
|
|
<!--${QF-macros::QF_TICK_X::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>QTIMEEVT_TICK_X((tickRate_), (sender_))</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_TICK}-->
|
|
<operation name="QF_TICK" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QF_TICK::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>QTIMEEVT_TICK(sender_)</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_PUBLISH}-->
|
|
<operation name="QF_PUBLISH" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QF_PUBLISH::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QF-macros::QF_PUBLISH::sender_}-->
|
|
<parameter name="sender_" type="<void const *>"/>
|
|
<code>QACTIVE_PUBLISH((e_), (sender_))</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_MEM_SYS}-->
|
|
<operation name="QF_MEM_SYS?ndef QF_MEM_SYS" type="void" visibility="0x03" properties="0x00">
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QF-macros::QF_MEM_APP}-->
|
|
<operation name="QF_MEM_APP?ndef QF_MEM_APP" type="void" visibility="0x03" properties="0x00">
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QF_EPOOL-impl}-->
|
|
<package name="QF_EPOOL-impl" stereotype="0x02">
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_TYPE_}-->
|
|
<attribute name="QF_EPOOL_TYPE_" type="" visibility="0x03" properties="0x00">
|
|
<code>QMPool</code>
|
|
</attribute>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_INIT_}-->
|
|
<operation name="QF_EPOOL_INIT_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_INIT_::p_}-->
|
|
<parameter name="p_" type="QMPool *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_INIT_::poolSto_}-->
|
|
<parameter name="poolSto_" type="void *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_INIT_::poolSize_}-->
|
|
<parameter name="poolSize_" type="uint_fast32_t"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_INIT_::evtSize_}-->
|
|
<parameter name="evtSize_" type="uint_fast16_t"/>
|
|
<code>\
|
|
(QMPool_init(&(p_), (poolSto_), (poolSize_), (evtSize_)))</code>
|
|
</operation>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_EVENT_SIZE_}-->
|
|
<operation name="QF_EPOOL_EVENT_SIZE_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_EVENT_S~::p_}-->
|
|
<parameter name="p_" type="QMPool const *"/>
|
|
<code>((uint_fast16_t)(p_).blockSize)</code>
|
|
</operation>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_GET_}-->
|
|
<operation name="QF_EPOOL_GET_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_GET_::p_}-->
|
|
<parameter name="p_" type="QMPool *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_GET_::e_}-->
|
|
<parameter name="e_" type="QEvt *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_GET_::m_}-->
|
|
<parameter name="m_" type="uint_fast16_t"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_GET_::qsId_}-->
|
|
<parameter name="qsId_" type="uint8_t"/>
|
|
<code>\
|
|
((e_) = (QEvt *)QMPool_get(&(p_), (m_), (qsId_)))</code>
|
|
</operation>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_PUT_}-->
|
|
<operation name="QF_EPOOL_PUT_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_PUT_::p_}-->
|
|
<parameter name="p_" type="QMPool *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_PUT_::e_}-->
|
|
<parameter name="e_" type="QEvt *"/>
|
|
<!--${QF_EPOOL-impl::QF_EPOOL_PUT_::qsId_}-->
|
|
<parameter name="qsId_" type="uint_fast8_t"/>
|
|
<code>\
|
|
(QMPool_put(&(p_), (e_), (qsId_)))</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QV}-->
|
|
<package name="QV" stereotype="0x05">
|
|
<!--${QV::QV}-->
|
|
<attribute name="QV" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<documentation>//! @class QV</documentation>
|
|
<code>{
|
|
//! @cond INTERNAL
|
|
uint8_t dummy;
|
|
//! @endcond
|
|
} QV;</code>
|
|
</attribute>
|
|
<!--${QV::QV-base}-->
|
|
<package name="QV-base" stereotype="0x02" namespace="QV_">
|
|
<!--${QV::QV-base::Attr}-->
|
|
<class name="Attr">
|
|
<documentation>//! @class QV_Attr</documentation>
|
|
<!--${QV::QV-base::Attr::readySet}-->
|
|
<attribute name="readySet" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QV_Attr</documentation>
|
|
</attribute>
|
|
<!--${QV::QV-base::Attr::schedCeil}-->
|
|
<attribute name="schedCeil" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QV_Attr</documentation>
|
|
</attribute>
|
|
<!--${QV::QV-base::Attr::readySet_dis}-->
|
|
<attribute name="readySet_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QV_Attr</documentation>
|
|
</attribute>
|
|
<!--${QV::QV-base::Attr::schedCeil_dis}-->
|
|
<attribute name="schedCeil_dis?ndef Q_UNSAFE" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QV_Attr</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QV::QV-base::priv_}-->
|
|
<attribute name="priv_" type="QV_Attr" visibility="0x01" properties="0x00">
|
|
<documentation>//! @static @private @memberof QV</documentation>
|
|
</attribute>
|
|
<!--${QV::QV-base::schedDisable}-->
|
|
<operation name="schedDisable" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QV
|
|
|
|
//! @static @public @memberof QV</documentation>
|
|
<!--${QV::QV-base::schedDisable::ceiling}-->
|
|
<parameter name="ceiling" type="uint_fast8_t const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QV::QV-base::schedEnable}-->
|
|
<operation name="schedEnable" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QV
|
|
|
|
//! @static @public @memberof QV</documentation>
|
|
<code>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();</code>
|
|
</operation>
|
|
<!--${QV::QV-base::onIdle}-->
|
|
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QV
|
|
|
|
//! @static @public @memberof QV</documentation>
|
|
</operation>
|
|
</package>
|
|
<!--${QV::QF-cust}-->
|
|
<package name="QF-cust" stereotype="0x02" namespace="QF_">
|
|
<!--${QV::QF-cust::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QV::QF-cust::stop}-->
|
|
<operation name="stop" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>QF_onCleanup(); // application-specific cleanup callback
|
|
// nothing else to do for the QV kernel</code>
|
|
</operation>
|
|
<!--${QV::QF-cust::run}-->
|
|
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>#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</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QV::QActive}-->
|
|
<class name="QActive" superclass="QEP::QAsm">
|
|
<documentation>//! QActive active object class customization for QV</documentation>
|
|
<!--${QV::QActive::start}-->
|
|
<operation name="start" type="void" visibility="0x00" properties="0x04">
|
|
<documentation>//! @public @memberof QActive
|
|
|
|
//! @public @memberof QActive</documentation>
|
|
<!--${QV::QActive::start::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QV::QActive::start::qSto}-->
|
|
<parameter name="qSto" type="QEvtPtr * const"/>
|
|
<!--${QV::QActive::start::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<!--${QV::QActive::start::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QV::QActive::start::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
<!--${QV::QActive::start::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<!--${QV-impl}-->
|
|
<package name="QV-impl" stereotype="0x02">
|
|
<!--${QV-impl::QF_SCHED_STAT_}-->
|
|
<attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00"/>
|
|
<!--${QV-impl::QF_SCHED_LOCK_}-->
|
|
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QV-impl::QF_SCHED_LOCK_::dummy}-->
|
|
<parameter name="dummy" type=""/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QV-impl::QF_SCHED_UNLOCK_}-->
|
|
<operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QV-impl::QACTIVE_EQUEUE_WAIT_}-->
|
|
<operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QV-impl::QACTIVE_EQUEUE_W~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QV-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?ndef Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QV-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>\
|
|
QPSet_insert(&QV_priv_.readySet, (uint_fast8_t)(me_)->prio); \
|
|
QPSet_update_(&QV_priv_.readySet, &QV_priv_.readySet_dis)</code>
|
|
</operation>
|
|
<!--${QV-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?def Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QV-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>\
|
|
QPSet_insert(&QV_priv_.readySet, (uint_fast8_t)(me_)->prio)</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QK}-->
|
|
<package name="QK" stereotype="0x05">
|
|
<!--${QK::QK}-->
|
|
<attribute name="QK" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<documentation>//! @class QK</documentation>
|
|
<code>{
|
|
//! @cond INTERNAL
|
|
uint8_t dummy;
|
|
//! @endcond
|
|
} QK;</code>
|
|
</attribute>
|
|
<!--${QK::QSchedStatus}-->
|
|
<attribute name="QSchedStatus" type="typedef uint_fast8_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QK::QK-base}-->
|
|
<package name="QK-base" stereotype="0x02" namespace="QK_">
|
|
<!--${QK::QK-base::Attr}-->
|
|
<class name="Attr">
|
|
<documentation>//! @class QK_Attr</documentation>
|
|
<!--${QK::QK-base::Attr::readySet}-->
|
|
<attribute name="readySet" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actPrio}-->
|
|
<attribute name="actPrio" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::nextPrio}-->
|
|
<attribute name="nextPrio" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actThre}-->
|
|
<attribute name="actThre" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::lockCeil}-->
|
|
<attribute name="lockCeil" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::intNest}-->
|
|
<attribute name="intNest" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::readySet_dis}-->
|
|
<attribute name="readySet_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actPrio_dis}-->
|
|
<attribute name="actPrio_dis?ndef Q_UNSAFE" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::nextPrio_dis}-->
|
|
<attribute name="nextPrio_dis?ndef Q_UNSAFE" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actThre_dis}-->
|
|
<attribute name="actThre_dis?ndef Q_UNSAFE" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::lockCeil_dis}-->
|
|
<attribute name="lockCeil_dis?ndef Q_UNSAFE" type="uint_fast8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QK::QK-base::priv_}-->
|
|
<attribute name="priv_" type="QK_Attr" visibility="0x01" properties="0x00">
|
|
<documentation>//! @static @private @memberof QK</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::schedLock}-->
|
|
<operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QK
|
|
|
|
//! @static @public @memberof QK</documentation>
|
|
<!--${QK::QK-base::schedLock::ceiling}-->
|
|
<parameter name="ceiling" type="uint_fast8_t const"/>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QK::QK-base::schedUnlock}-->
|
|
<operation name="schedUnlock" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QK
|
|
|
|
//! @static @public @memberof QK</documentation>
|
|
<!--${QK::QK-base::schedUnlock::prevCeil}-->
|
|
<parameter name="prevCeil" type="QSchedStatus const"/>
|
|
<code>// 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();
|
|
}</code>
|
|
</operation>
|
|
<!--${QK::QK-base::onIdle}-->
|
|
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QK
|
|
|
|
//! @static @public @memberof QK</documentation>
|
|
</operation>
|
|
<!--${QK::QK-base::sched_}-->
|
|
<operation name="sched_" type="uint_fast8_t" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QK
|
|
|
|
//! @static @private @memberof QK</documentation>
|
|
<code>// 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;</code>
|
|
</operation>
|
|
<!--${QK::QK-base::activate_}-->
|
|
<operation name="activate_" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QK
|
|
|
|
//! @static @private @memberof QK</documentation>
|
|
<code>// 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</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QK::QF-cust}-->
|
|
<package name="QF-cust" stereotype="0x02" namespace="QF_">
|
|
<!--${QK::QF-cust::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>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</code>
|
|
</operation>
|
|
<!--${QK::QF-cust::stop}-->
|
|
<operation name="stop" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>QF_onCleanup(); // application-specific cleanup callback
|
|
// nothing else to do for the preemptive QK kernel</code>
|
|
</operation>
|
|
<!--${QK::QF-cust::run}-->
|
|
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QF
|
|
|
|
//! @static @public @memberof QF</documentation>
|
|
<code>#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</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QK::QActive}-->
|
|
<class name="QActive" superclass="QEP::QAsm">
|
|
<documentation>// QActive class customization for QK</documentation>
|
|
<!--${QK::QActive::start}-->
|
|
<operation name="start" type="void" visibility="0x00" properties="0x04">
|
|
<documentation>//! @public @memberof QActive
|
|
|
|
//! @public @memberof QActive</documentation>
|
|
<!--${QK::QActive::start::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QK::QActive::start::qSto}-->
|
|
<parameter name="qSto" type="QEvtPtr * const"/>
|
|
<!--${QK::QActive::start::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<!--${QK::QActive::start::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QK::QActive::start::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
<!--${QK::QActive::start::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<code>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();</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<!--${QK-impl}-->
|
|
<package name="QK-impl" stereotype="0x02">
|
|
<!--${QK-impl::QF_SCHED_STAT_}-->
|
|
<attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
|
|
<code>QSchedStatus lockStat_;</code>
|
|
</attribute>
|
|
<!--${QK-impl::QF_SCHED_LOCK_}-->
|
|
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QK-impl::QF_SCHED_LOCK_::ceil_}-->
|
|
<parameter name="ceil_" type="uint_fast8_t"/>
|
|
<code>do { \
|
|
if (QK_ISR_CONTEXT_()) { \
|
|
lockStat_ = 0xFFU; \
|
|
} else { \
|
|
lockStat_ = QK_schedLock((ceil_)); \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QK-impl::QF_SCHED_UNLOCK_}-->
|
|
<operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
|
|
<code>do { \
|
|
if (lockStat_ != 0xFFU) { \
|
|
QK_schedUnlock(lockStat_); \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QK-impl::QACTIVE_EQUEUE_WAIT_}-->
|
|
<operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QK-impl::QACTIVE_EQUEUE_W~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?ndef Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QK-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>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)</code>
|
|
</operation>
|
|
<!--${QK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?def Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QK-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>do { \
|
|
QPSet_insert(&QK_priv_.readySet, (uint_fast8_t)(me_)->prio); \
|
|
if (!QK_ISR_CONTEXT_()) { \
|
|
if (QK_sched_() != 0U) { \
|
|
QK_activate_(); \
|
|
} \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
</package>
|
|
<!--${include}-->
|
|
<directory name="include">
|
|
<!--${include::qsafe.h}-->
|
|
<file name="qsafe.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qp.h}-->
|
|
<file name="qp.h">
|
|
<text>#ifndef QP_H_
|
|
#define QP_H_
|
|
|
|
//============================================================================
|
|
#define QP_VERSION_STR "8.0.1"
|
|
#define QP_VERSION 801U
|
|
#define QP_RELEASE 0x703931CEU
|
|
|
|
//============================================================================
|
|
//! @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_</text>
|
|
</file>
|
|
<!--${include::qp_pkg.h}-->
|
|
<file name="qp_pkg.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qequeue.h}-->
|
|
<file name="qequeue.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qmpool.h}-->
|
|
<file name="qmpool.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qv.h}-->
|
|
<file name="qv.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qk.h}-->
|
|
<file name="qk.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
<!--${include::qstamp.h}-->
|
|
<file name="qstamp.h">
|
|
<text>#ifndef QSTAMP_H_
|
|
#define QSTAMP_H_
|
|
|
|
extern char const Q_BUILD_DATE[12];
|
|
extern char const Q_BUILD_TIME[9];
|
|
|
|
#endif // QSTAMP_H_</text>
|
|
</file>
|
|
<!--${include::qpc.h}-->
|
|
<file name="qpc.h">
|
|
<text>#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_</text>
|
|
</file>
|
|
</directory>
|
|
<!--${src}-->
|
|
<directory name="src">
|
|
<!--${src::qf}-->
|
|
<directory name="qf">
|
|
<!--${src::qf::qep_hsm.c}-->
|
|
<file name="qep_hsm.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qp_port.h" // QP port
|
|
#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}</text>
|
|
</file>
|
|
<!--${src::qf::qep_msm.c}-->
|
|
<file name="qep_msm.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qp_port.h" // QP port
|
|
#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_act.c}-->
|
|
<file name="qf_act.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_actq.c}-->
|
|
<file name="qf_actq.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_defer.c}-->
|
|
<file name="qf_defer.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_dyn.c}-->
|
|
<file name="qf_dyn.c">
|
|
<text>#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</text>
|
|
</file>
|
|
<!--${src::qf::qf_mem.c}-->
|
|
<file name="qf_mem.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_qact.c}-->
|
|
<file name="qf_qact.c">
|
|
<text>#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_}</text>
|
|
</file>
|
|
<!--${src::qf::qf_qmact.c}-->
|
|
<file name="qf_qmact.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_qeq.c}-->
|
|
<file name="qf_qeq.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_ps.c}-->
|
|
<file name="qf_ps.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
<!--${src::qf::qf_time.c}-->
|
|
<file name="qf_time.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
</directory>
|
|
<!--${src::qv}-->
|
|
<directory name="qv">
|
|
<!--${src::qv::qv.c}-->
|
|
<file name="qv.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
</directory>
|
|
<!--${src::qk}-->
|
|
<directory name="qk">
|
|
<!--${src::qk::qk.c}-->
|
|
<file name="qk.c">
|
|
<text>#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}</text>
|
|
</file>
|
|
</directory>
|
|
<!--${src::qs}-->
|
|
<directory name="qs">
|
|
<!--${src::qs::qstamp.c}-->
|
|
<file name="qstamp.c">
|
|
<text>#include "qstamp.h"
|
|
|
|
char const Q_BUILD_DATE[12] = __DATE__;
|
|
char const Q_BUILD_TIME[9] = __TIME__;</text>
|
|
</file>
|
|
</directory>
|
|
</directory>
|
|
</model>
|