mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-14 06:43:19 +08:00
12082 lines
420 KiB
XML
12082 lines
420 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<model version="5.3.0" links="1">
|
|
<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 <state-machine.com>.
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
|
|
|
|
This software is dual-licensed under the terms of the open source GNU
|
|
General Public License version 3 (or any later version), or alternatively,
|
|
under the terms of one of the closed source Quantum Leaps commercial
|
|
licenses.
|
|
|
|
The terms of the open source GNU General Public License version 3
|
|
can be found at: <www.gnu.org/licenses/gpl-3.0>
|
|
|
|
The terms of the closed source Quantum Leaps commercial licenses
|
|
can be found at: <www.state-machine.com/licensing>
|
|
|
|
Redistributions in source code must retain this copyright notice.
|
|
Plagiarizing this software to sidestep the license obligations is illegal.
|
|
|
|
Contact information:
|
|
<www.state-machine.com/licensing>
|
|
<info@state-machine.com></documentation>
|
|
<!--${qpc}-->
|
|
<framework name="qpc" license="LICENSES/LicenseRef-QL-dual.qlc"/>
|
|
<!--${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="void" 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_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[8]}-->
|
|
<attribute name="QP_versionStr[8]" 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_MARKER}-->
|
|
<attribute name="QEVT_MARKER" type="" visibility="0x03" properties="0x00">
|
|
<code>0xE0U</code>
|
|
</attribute>
|
|
<!--${QEP::QEVT_DYNAMIC}-->
|
|
<attribute name="QEVT_DYNAMIC" type="" visibility="0x03" properties="0x00">
|
|
<code>0U</code>
|
|
</attribute>
|
|
<!--${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::refCtr_}-->
|
|
<attribute name="refCtr_" type="uint8_t volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @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::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="QEvt *" visibility="0x00" properties="0x02">
|
|
<documentation>//! @public @memberof QEvt
|
|
|
|
//! @public @memberof QEvt</documentation>
|
|
<!--${QEP::QEvt::ctor::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<code>if (sig != QEVT_DYNAMIC) {
|
|
me->sig = (QSignal)sig;
|
|
me->refCtr_ = 0U;
|
|
me->evtTag_ = QEVT_MARKER;
|
|
}
|
|
return me;</code>
|
|
</operation>
|
|
<!--${QEP::QEvt::verify_}-->
|
|
<operation name="verify_" type="bool" visibility="0x02" properties="0x02">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QEvt
|
|
|
|
//! @private @memberof QEvt</documentation>
|
|
<code>return (me != (QEvt const *)0)
|
|
&& ((me->evtTag_ & 0xF0U) == QEVT_MARKER);</code>
|
|
</operation>
|
|
<!--${QEP::QEvt::getPoolId_}-->
|
|
<operation name="getPoolId_" 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_ & 0x0FU;</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_SUPER_SUB, //!< event passed to submachine superstate
|
|
Q_RET_UNHANDLED, //!< event unhandled due to a 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 or submachine
|
|
Q_RET_TRAN_EP, //!< entry-point transition into a submachine
|
|
|
|
// transitions that additionally clobber me->state
|
|
Q_RET_TRAN_HIST, //!< transition to history of a given state
|
|
Q_RET_TRAN_XP //!< exit-point transition out of a submachine
|
|
};</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::QReservedSig}-->
|
|
<attribute name="QReservedSig" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! Reserved signals by the QHsm-style state machine implementation</documentation>
|
|
<code>{
|
|
Q_EMPTY_SIG, //!< signal to execute the default case
|
|
Q_ENTRY_SIG, //!< signal for coding entry actions
|
|
Q_EXIT_SIG, //!< signal for coding exit actions
|
|
Q_INIT_SIG, //!< signal for coding initial transitions
|
|
Q_USER_SIG //!< offset for the user signals (QP Application)
|
|
};</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 qs_id);
|
|
void (*dispatch)(QAsm * const me, QEvt const * const e,
|
|
uint_fast8_t const qs_id);
|
|
#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
|
|
|
|
Human-generated State Machine</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_
|
|
#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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>QF_CRIT_STAT
|
|
|
|
#ifdef Q_SPY
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
if ((QS_priv_.flags & 0x01U) == 0U) {
|
|
QS_priv_.flags |= 0x01U;
|
|
QS_FUN_DICTIONARY(&QHsm_top);
|
|
}
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
#else
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
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.
|
|
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);
|
|
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
|
|
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);
|
|
while (me->temp.fun != t) {
|
|
++ip;
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(220, ip < QHSM_MAX_NEST_DEPTH_);
|
|
QF_CRIT_EXIT();
|
|
path[ip] = me->temp.fun;
|
|
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
|
|
}
|
|
me->temp.fun = path[0];
|
|
|
|
// nested initial tran.; drill into the target hierarchy...
|
|
do {
|
|
// enter path[ip]
|
|
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
|
|
== Q_RET_HANDLED)
|
|
{
|
|
QS_STATE_ENTRY_(path[ip], qs_id);
|
|
}
|
|
--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, qs_id)
|
|
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);
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
|
|
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();
|
|
QS_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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QStateHandler s = me->state.fun;
|
|
QStateHandler t = s;
|
|
QF_CRIT_STAT
|
|
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(300, (s != Q_STATE_CAST(0))
|
|
&& (me->state.uint == (uintptr_t)(~me->temp.uint)));
|
|
Q_REQUIRE_INCRIT(302, QEvt_verify_(e));
|
|
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
|
|
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;
|
|
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, qs_id)
|
|
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
|
|
}
|
|
} while (r == Q_RET_SUPER);
|
|
|
|
if (r >= Q_RET_TRAN) { // regular tran. taken?
|
|
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...
|
|
for (; t != s; t = me->temp.fun) {
|
|
// exit from t
|
|
if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
|
|
QS_STATE_EXIT_(t, qs_id);
|
|
// find superstate of t
|
|
(void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
|
|
}
|
|
}
|
|
int_fast8_t ip = QHsm_tran_(me, path, qs_id); // take the tran.
|
|
|
|
#ifdef Q_SPY
|
|
if (r == Q_RET_TRAN_HIST) {
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
|
|
QS_OBJ_PRE_(me); // this state machine object
|
|
QS_FUN_PRE_(t); // the source of the tran.
|
|
QS_FUN_PRE_(path[0]); // the target of the tran. to history
|
|
QS_END_PRE_()
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
}
|
|
#endif // Q_SPY
|
|
|
|
// execute state entry actions in the desired order...
|
|
for (; ip >= 0; --ip) {
|
|
// enter path[ip]
|
|
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
|
|
== Q_RET_HANDLED)
|
|
{
|
|
QS_STATE_ENTRY_(path[ip], qs_id);
|
|
}
|
|
}
|
|
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, qs_id)
|
|
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);
|
|
|
|
while (me->temp.fun != t) {
|
|
++ip;
|
|
path[ip] = me->temp.fun;
|
|
// find superstate
|
|
(void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
|
|
}
|
|
me->temp.fun = path[0];
|
|
|
|
// entry path must not overflow
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(410, ip < QHSM_MAX_NEST_DEPTH_);
|
|
QF_CRIT_EXIT();
|
|
|
|
// retrace the entry path in reverse (correct) order...
|
|
do {
|
|
// enter path[ip]
|
|
if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
|
|
== Q_RET_HANDLED)
|
|
{
|
|
QS_STATE_ENTRY_(path[ip], qs_id);
|
|
}
|
|
--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, qs_id)
|
|
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, qs_id)
|
|
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, qs_id)
|
|
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="0x00">
|
|
<documentation>//! @public @memberof QHsm
|
|
|
|
//! @public @memberof QHsm</documentation>
|
|
<!--${QEP::QHsm::isIn::state}-->
|
|
<parameter name="state" type="QStateHandler const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(602, me->super.state.uint
|
|
== (uintptr_t)(~me->super.temp.uint));
|
|
QF_CRIT_EXIT();
|
|
|
|
bool inState = false; // assume that this HSM is not in 'state'
|
|
|
|
// scan the state hierarchy bottom-up
|
|
QState r;
|
|
do {
|
|
// do the states match?
|
|
if (me->super.temp.fun == state) {
|
|
inState = true; // 'true' means that match found
|
|
r = Q_RET_IGNORED; // cause breaking out of the loop
|
|
}
|
|
else {
|
|
r = QHSM_RESERVED_EVT_(me->super.temp.fun, Q_EMPTY_SIG);
|
|
}
|
|
} while (r != Q_RET_IGNORED); // QHsm_top() state not reached
|
|
|
|
#ifndef Q_UNSAFE
|
|
me->super.temp.uint = ~me->super.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;
|
|
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);
|
|
}
|
|
} while (r != Q_RET_IGNORED); // the top state not reached
|
|
|
|
#ifndef Q_UNSAFE
|
|
me->super.temp.uint = ~me->super.state.uint;
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(890, isFound);
|
|
QF_CRIT_EXIT();
|
|
|
|
return child; // return the 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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#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, qs_id);
|
|
}
|
|
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, qs_id);
|
|
}
|
|
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, qs_id);
|
|
}
|
|
}
|
|
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...
|
|
QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG);
|
|
while (r == Q_RET_SUPER) {
|
|
++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
|
|
|
|
// entry path must not overflow
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(510, ip < QHSM_MAX_NEST_DEPTH_);
|
|
QF_CRIT_EXIT();
|
|
--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);
|
|
}
|
|
}
|
|
|
|
// the LCA not found yet?
|
|
if (iq == 0) {
|
|
// entry path must not overflow
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(520, ip < QHSM_MAX_NEST_DEPTH_);
|
|
QF_CRIT_EXIT();
|
|
|
|
// exit source s
|
|
if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG)
|
|
== Q_RET_HANDLED)
|
|
{
|
|
QS_STATE_EXIT_(s, qs_id);
|
|
}
|
|
|
|
// (f) check the rest of source->super
|
|
// == target->super->super...
|
|
iq = ip;
|
|
r = Q_RET_IGNORED; // indicate that the LCA NOT found
|
|
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
|
|
do {
|
|
// exit from t
|
|
if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG)
|
|
== Q_RET_HANDLED)
|
|
{
|
|
QS_STATE_EXIT_(t, qs_id);
|
|
// 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);
|
|
} while (r != Q_RET_HANDLED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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
|
|
|
|
Machine-generated State Machine</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_
|
|
#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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#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, qs_id)
|
|
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...
|
|
do {
|
|
// execute the tran. table
|
|
r = QMsm_execTatbl_(me, me->temp.tatbl, qs_id);
|
|
} while (r >= Q_RET_TRAN_INIT);
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
|
|
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();
|
|
QS_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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#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, (s != (QMState *)0)
|
|
&& (me->state.uint == (uintptr_t)(~me->temp.uint)));
|
|
Q_REQUIRE_INCRIT(302, QEvt_verify_(e));
|
|
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
|
|
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;
|
|
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
|
|
}
|
|
// event unhandled and passed to a submachine superstate?
|
|
else if (r == Q_RET_SUPER_SUB) {
|
|
t = me->temp.obj; // current host state of the submachie
|
|
}
|
|
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, qs_id)
|
|
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
|
|
}
|
|
} while (t != (QMState *)0);
|
|
|
|
if (r >= Q_RET_TRAN) { // any kind of tran. taken?
|
|
#ifdef Q_SPY
|
|
QMState const * const ts = t; // tran. source for QS tracing
|
|
|
|
QF_CRIT_ENTRY();
|
|
// the tran. source state must not be NULL
|
|
Q_ASSERT_INCRIT(320, ts != (QMState *)0);
|
|
QF_CRIT_EXIT();
|
|
#endif // Q_SPY
|
|
|
|
do {
|
|
// save the tran-action table before it gets clobbered
|
|
struct QMTranActTable const * const tatbl = me->temp.tatbl;
|
|
union QAsmAttr tmp; // temporary to save intermediate values
|
|
|
|
// was TRAN, TRAN_INIT, or TRAN_EP taken?
|
|
if (r <= Q_RET_TRAN_EP) {
|
|
me->temp.obj = (QMState *)0; // clear
|
|
QMsm_exitToTranSource_(me, s, t, qs_id);
|
|
r = QMsm_execTatbl_(me, tatbl, qs_id);
|
|
s = me->state.obj;
|
|
}
|
|
// was a tran. segment to history taken?
|
|
else if (r == Q_RET_TRAN_HIST) {
|
|
tmp.obj = me->state.obj; // save history
|
|
me->state.obj = s; // restore the original state
|
|
QMsm_exitToTranSource_(me, s, t, qs_id);
|
|
(void)QMsm_execTatbl_(me, tatbl, qs_id);
|
|
r = QMsm_enterHistory_(me, tmp.obj, qs_id);
|
|
s = me->state.obj;
|
|
}
|
|
else {
|
|
QF_CRIT_ENTRY();
|
|
// must be tran. to exit point
|
|
Q_ASSERT_INCRIT(340, r == Q_RET_TRAN_XP);
|
|
QF_CRIT_EXIT();
|
|
|
|
tmp.act = me->state.act; // save XP action
|
|
me->state.obj = s; // restore the original state
|
|
r = (*tmp.act)(me); // execute the XP action
|
|
if (r == Q_RET_TRAN) { // XP -> TRAN ?
|
|
#ifdef Q_SPY
|
|
tmp.tatbl = me->temp.tatbl; // save me->temp
|
|
#endif // Q_SPY
|
|
QMsm_exitToTranSource_(me, s, t, qs_id);
|
|
// take the tran-to-XP segment inside submachine
|
|
(void)QMsm_execTatbl_(me, tatbl, qs_id);
|
|
s = me->state.obj;
|
|
#ifdef Q_SPY
|
|
me->temp.tatbl = tmp.tatbl; // restore me->temp
|
|
#endif // Q_SPY
|
|
}
|
|
else if (r == Q_RET_TRAN_HIST) { // XP -> HIST ?
|
|
tmp.obj = me->state.obj; // save the history
|
|
me->state.obj = s; // restore the original state
|
|
s = me->temp.obj; // save me->temp
|
|
QMsm_exitToTranSource_(me, me->state.obj, t, qs_id);
|
|
// take the tran-to-XP segment inside submachine
|
|
(void)QMsm_execTatbl_(me, tatbl, qs_id);
|
|
#ifdef Q_SPY
|
|
me->temp.obj = s; // restore me->temp
|
|
#endif // Q_SPY
|
|
s = me->state.obj;
|
|
me->state.obj = tmp.obj; // restore the history
|
|
}
|
|
else {
|
|
QF_CRIT_ENTRY();
|
|
// TRAN_XP must NOT be followed by any other tran type
|
|
Q_ASSERT_INCRIT(330, r < Q_RET_TRAN);
|
|
QF_CRIT_EXIT();
|
|
}
|
|
}
|
|
|
|
t = s; // set target to the current state
|
|
|
|
} while (r >= Q_RET_TRAN);
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
|
|
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();
|
|
QS_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(340, t != (QMState *)0);
|
|
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
|
|
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, qs_id)
|
|
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::isInState}-->
|
|
<operation name="isInState" type="bool" visibility="0x00" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @public @memberof QMsm
|
|
|
|
//! @public @memberof QMsm</documentation>
|
|
<!--${QEP::QMsm::isInState::stateObj}-->
|
|
<parameter name="stateObj" type="QMState const * const"/>
|
|
<code>bool inState = false; // assume that this SM is not in 'state'
|
|
|
|
for (QMState const *s = me->super.state.obj;
|
|
s != (QMState *)0;
|
|
s = s->superstate)
|
|
{
|
|
if (s == stateObj) {
|
|
inState = true; // match found, return 'true'
|
|
break;
|
|
}
|
|
}
|
|
return inState;</code>
|
|
</operation>
|
|
<!--${QEP::QMsm::stateObj}-->
|
|
<operation name="stateObj" type="QMState const *" visibility="0x00" properties="0x02">
|
|
<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;
|
|
|
|
for (s = me->super.state.obj; s != (QMState *)0; s = s->superstate) {
|
|
if (s == parent) {
|
|
isFound = true; // child is found
|
|
break;
|
|
}
|
|
else {
|
|
child = s;
|
|
}
|
|
}
|
|
if (!isFound) { // still not found?
|
|
for (s = me->super.temp.obj; s != (QMState *)0; s = s->superstate) {
|
|
if (s == parent) {
|
|
isFound = true; // child is found
|
|
break;
|
|
}
|
|
else {
|
|
child = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(890, 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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
// precondition:
|
|
// - the tran-action table pointer must not be NULL
|
|
Q_REQUIRE_INCRIT(400, tatbl != (struct QMTranActTable *)0);
|
|
QF_CRIT_EXIT();
|
|
|
|
QState r = Q_RET_NULL;
|
|
for (QActionHandler const *a = &tatbl->act[0];
|
|
*a != Q_ACTION_CAST(0);
|
|
++a)
|
|
{
|
|
r = (*(*a))(me); // call the action through the 'a' pointer
|
|
#ifdef Q_SPY
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
if (r == Q_RET_ENTRY) {
|
|
QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
|
|
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, qs_id)
|
|
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, qs_id)
|
|
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 if (r == Q_RET_TRAN_EP) {
|
|
QS_BEGIN_PRE_(QS_QEP_TRAN_EP, qs_id)
|
|
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 if (r == Q_RET_TRAN_XP) {
|
|
QS_BEGIN_PRE_(QS_QEP_TRAN_XP, qs_id)
|
|
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
|
|
}
|
|
|
|
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~::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
|
|
// exit states from the current state to the tran. source state
|
|
QMState const *s = cs;
|
|
while (s != ts) {
|
|
// 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, qs_id)
|
|
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
|
|
|
|
if (s == (QMState *)0) { // reached the top of a submachine?
|
|
s = me->temp.obj; // the superstate from QM_SM_EXIT()
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(510, s != (QMState *)0); // must be valid
|
|
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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QMState const *s = hist;
|
|
QMState const *ts = me->state.obj; // tran. source
|
|
QMState const *epath[QMSM_MAX_ENTRY_DEPTH_];
|
|
|
|
QF_CRIT_STAT
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
|
|
QS_OBJ_PRE_(me); // this state machine object
|
|
QS_FUN_PRE_(ts->stateHandler); // source state handler
|
|
QS_FUN_PRE_(hist->stateHandler); // target state handler
|
|
QS_END_PRE_()
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
|
|
int_fast8_t i = 0; // tran. entry path index
|
|
while (s != ts) {
|
|
if (s->entryAction != Q_ACTION_CAST(0)) {
|
|
QF_CRIT_ENTRY();
|
|
Q_ASSERT_INCRIT(620, i < QMSM_MAX_ENTRY_DEPTH_);
|
|
QF_CRIT_EXIT();
|
|
epath[i] = s;
|
|
++i;
|
|
}
|
|
s = s->superstate;
|
|
if (s == (QMState *)0) {
|
|
ts = s; // force exit from the for-loop
|
|
}
|
|
}
|
|
|
|
// 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, qs_id)
|
|
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
|
|
}
|
|
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_), 0U, QEVT_MARKER }</code>
|
|
</operation>
|
|
<!--${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::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>do { \
|
|
Q_ASSERT(((QAsm *)(me_))->vptr); \
|
|
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), (qs_id_)); \
|
|
} while (false)</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>do { \
|
|
Q_ASSERT(((QAsm *)(me_))->vptr); \
|
|
(*((QAsm *)(me_))->vptr->init)((QAsm *)(me_), (par_), 0); \
|
|
} while (false)</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::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>\
|
|
(*((QAsm *)(me_))->vptr->dispatch)((QAsm *)(me_), (e_), (qs_id_))</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::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_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_TRAN_EP}-->
|
|
<operation name="QM_TRAN_EP" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_TRAN_EP::tatbl_}-->
|
|
<parameter name="tatbl_" type="QMTranActionTable const *"/>
|
|
<code>((Q_ASM_UPCAST(me))->temp.tatbl \
|
|
= (struct QMTranActTable const *)(tatbl_), \
|
|
(QState)Q_RET_TRAN_EP)</code>
|
|
</operation>
|
|
<!--${QEP-macros::QM_TRAN_XP}-->
|
|
<operation name="QM_TRAN_XP" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_TRAN_XP::xp_}-->
|
|
<parameter name="xp_" type="QStateHandler"/>
|
|
<!--${QEP-macros::QM_TRAN_XP::tatbl_}-->
|
|
<parameter name="tatbl_" type="QMTranActionTable const *"/>
|
|
<code>\
|
|
((((Q_ASM_UPCAST(me))->state.act = (xp_)), \
|
|
((Q_ASM_UPCAST(me))->temp.tatbl = \
|
|
(struct QMTranActTable const *)(tatbl_))), \
|
|
(QState)Q_RET_TRAN_XP)</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_SUPER_SUB}-->
|
|
<operation name="QM_SUPER_SUB" type="" visibility="0x03" properties="0x00">
|
|
<!--${QEP-macros::QM_SUPER_SUB::host_}-->
|
|
<parameter name="host_" type="QStateHandler"/>
|
|
<code>\
|
|
((Q_ASM_UPCAST(me))->temp.obj = (host_), \
|
|
(QState)Q_RET_SUPER_SUB)</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::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::eQueue}-->
|
|
<attribute name="eQueue?def QACTIVE_EQUEUE_TYPE" type="QACTIVE_EQUEUE_TYPE" visibility="0x01" properties="0x00">
|
|
<documentation>//! @private @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>//! @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::thread}-->
|
|
<attribute name="thread?def QACTIVE_THREAD_TYPE" type="QACTIVE_THREAD_TYPE" visibility="0x01" properties="0x00">
|
|
<documentation>//! @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::prio}-->
|
|
<attribute name="prio" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @private @memberof QActive</documentation>
|
|
</attribute>
|
|
<!--${QF::QActive::pthre}-->
|
|
<attribute name="pthre" type="uint8_t" visibility="0x01" properties="0x00">
|
|
<documentation>//! @private @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</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_
|
|
#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="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<!--${QF::QActive::start_::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QF::QActive::start_::qSto}-->
|
|
<parameter name="qSto" type="QEvt const * * 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));
|
|
#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
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(102, QEvt_verify_(e));
|
|
|
|
QEQueueCtr nFree = me->eQueue.nFree; // get volatile into temporary
|
|
|
|
// test-probe#1 for faking queue overflow
|
|
QS_TEST_PROBE_DEF(&QActive_post_)
|
|
QS_TEST_PROBE_ID(1,
|
|
nFree = 0U;
|
|
)
|
|
|
|
bool status;
|
|
if (margin == QF_NO_MARGIN) {
|
|
if (nFree > 0U) {
|
|
status = true; // can post
|
|
}
|
|
else {
|
|
status = false; // cannot post
|
|
Q_ERROR_INCRIT(190); // must be able to post the event
|
|
}
|
|
}
|
|
else if (nFree > (QEQueueCtr)margin) {
|
|
status = true; // can post
|
|
}
|
|
else {
|
|
status = false; // cannot post, but don't assert
|
|
}
|
|
|
|
// is it a mutable event?
|
|
if (QEvt_getPoolId_(e) != 0U) {
|
|
QEvt_refCtr_inc_(e); // increment the reference counter
|
|
}
|
|
|
|
if (status) { // can post the event?
|
|
|
|
--nFree; // one free entry just used up
|
|
me->eQueue.nFree = nFree; // update the original
|
|
if (me->eQueue.nMin > nFree) {
|
|
me->eQueue.nMin = nFree; // increase minimum so far
|
|
}
|
|
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_EQC_PRE_(me->eQueue.nMin); // min # free entries
|
|
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)) {
|
|
QS_onTestPost(sender, me, e, status);
|
|
}
|
|
#endif
|
|
|
|
if (me->eQueue.frontEvt == (QEvt *)0) { // empty queue?
|
|
me->eQueue.frontEvt = e; // deliver event directly
|
|
|
|
#ifdef QXK_H_
|
|
if (me->super.state.act == Q_ACTION_CAST(0)) { // eXtended?
|
|
QXTHREAD_EQUEUE_SIGNAL_(me); // signal the event queue
|
|
}
|
|
else {
|
|
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
|
|
}
|
|
#else
|
|
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
|
|
#endif
|
|
}
|
|
// queue is not empty, insert event into the ring-buffer
|
|
else {
|
|
// insert event into the ring buffer (FIFO)
|
|
me->eQueue.ring[me->eQueue.head] = e;
|
|
|
|
if (me->eQueue.head == 0U) { // need to wrap head?
|
|
me->eQueue.head = me->eQueue.end; // wrap around
|
|
}
|
|
--me->eQueue.head; // advance the head (counter clockwise)
|
|
}
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
}
|
|
else { // cannot post the event
|
|
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # 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)) {
|
|
QS_onTestPost(sender, me, e, status);
|
|
}
|
|
#endif
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e); // recycle the event to avoid a leak
|
|
#endif
|
|
}
|
|
|
|
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
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(202, QEvt_verify_(e));
|
|
|
|
#ifdef QXK_H_
|
|
Q_REQUIRE_INCRIT(200, me->super.state.act != Q_ACTION_CAST(0));
|
|
#endif
|
|
|
|
QEQueueCtr nFree = me->eQueue.nFree; // get volatile into temporary
|
|
|
|
// test-probe#1 for faking queue overflow
|
|
QS_TEST_PROBE_DEF(&QActive_postLIFO_)
|
|
QS_TEST_PROBE_ID(1,
|
|
nFree = 0U;
|
|
)
|
|
|
|
Q_REQUIRE_INCRIT(201, nFree != 0U);
|
|
|
|
if (QEvt_getPoolId_(e) != 0U) { // is it a mutable event?
|
|
QEvt_refCtr_inc_(e); // increment the reference counter
|
|
}
|
|
|
|
--nFree; // one free entry just used up
|
|
me->eQueue.nFree = nFree; // update the original
|
|
if (me->eQueue.nMin > nFree) {
|
|
me->eQueue.nMin = nFree; // update minimum so far
|
|
}
|
|
|
|
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_getPoolId_(e), e->refCtr_);// poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_EQC_PRE_(me->eQueue.nMin); // min # free entries
|
|
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)) {
|
|
QS_onTestPost((QActive *)0, me, e, true);
|
|
}
|
|
#endif
|
|
|
|
QEvt const * const frontEvt = me->eQueue.frontEvt;
|
|
me->eQueue.frontEvt = e; // deliver the event directly to the front
|
|
|
|
if (frontEvt == (QEvt *)0) { // was the queue empty?
|
|
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
|
|
}
|
|
else { // queue was not empty, leave the event in the ring-buffer
|
|
++me->eQueue.tail;
|
|
if (me->eQueue.tail == me->eQueue.end) { // need to wrap the tail?
|
|
me->eQueue.tail = 0U; // wrap around
|
|
}
|
|
|
|
me->eQueue.ring[me->eQueue.tail] = frontEvt;
|
|
}
|
|
|
|
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();
|
|
|
|
QACTIVE_EQUEUE_WAIT_(me); // wait for event to arrive directly
|
|
|
|
// always remove event from the front
|
|
QEvt const * const e = me->eQueue.frontEvt;
|
|
QEQueueCtr const nFree = me->eQueue.nFree + 1U; // get volatile into tmp
|
|
me->eQueue.nFree = nFree; // update the # free
|
|
|
|
if (nFree <= me->eQueue.end) { // any events in the ring buffer?
|
|
// remove event from the tail
|
|
me->eQueue.frontEvt = me->eQueue.ring[me->eQueue.tail];
|
|
if (me->eQueue.tail == 0U) { // need to wrap the tail?
|
|
me->eQueue.tail = me->eQueue.end; // wrap around
|
|
}
|
|
--me->eQueue.tail;
|
|
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_END_PRE_()
|
|
}
|
|
else {
|
|
me->eQueue.frontEvt = (QEvt *)0; // queue becomes empty
|
|
|
|
// all entries in the queue must be free (+1 for fronEvt)
|
|
Q_ASSERT_INCRIT(310, nFree == (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_getPoolId_(e), e->refCtr_); // poolId & 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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(sender);
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QSignal const sig = e->sig;
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(200, sig < (QSignal)QActive_maxPubSignal_);
|
|
Q_REQUIRE_INCRIT(202,
|
|
QPSet_verify_(&QActive_subscrList_[sig].set,
|
|
&QActive_subscrList_[sig].set_dis));
|
|
|
|
QS_BEGIN_PRE_(QS_QF_PUBLISH, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_END_PRE_()
|
|
|
|
// is it a mutable event?
|
|
if (QEvt_getPoolId_(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
|
|
do { // loop over all subscribers
|
|
|
|
// 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);
|
|
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, ((enum_t)Q_USER_SIG <= sig)
|
|
&& (sig < QActive_maxPubSignal_)
|
|
&& (0U < p) && (p <= QF_MAX_ACTIVE)
|
|
&& (QActive_registry_[p] == me));
|
|
Q_REQUIRE_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, ((enum_t)Q_USER_SIG <= sig)
|
|
&& (sig < QActive_maxPubSignal_)
|
|
&& (0U < p) && (p <= QF_MAX_ACTIVE)
|
|
&& (QActive_registry_[p] == me));
|
|
Q_REQUIRE_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 = (enum_t)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_getPoolId_(e), e->refCtr_); // poolId & 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_getPoolId_(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_getPoolId_(e), e->refCtr_); // poolId & 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"/>
|
|
<code>uint_fast16_t n = 0U;
|
|
for (QEvt const *e = QEQueue_get(eq, me->prio);
|
|
e != (QEvt *)0;
|
|
e = QEQueue_get(eq, me->prio))
|
|
{
|
|
++n; // count the flushed event
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e); // garbage collect
|
|
#endif
|
|
}
|
|
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_
|
|
#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::act}-->
|
|
<attribute name="act" type="void * volatile" 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::interval}-->
|
|
<attribute name="interval" type="QTimeEvtCtr" 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::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>me->next = (QTimeEvt *)0;
|
|
me->act = act;
|
|
me->ctr = 0U;
|
|
me->interval = 0U;
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(300, (sig != 0)
|
|
&& (tickRate < QF_MAX_TICK_RATE));
|
|
QF_CRIT_EXIT();
|
|
|
|
// This default event constructor initializes the event
|
|
// as NOT allocated from any event-pool, which must be
|
|
// the case for Time Events.
|
|
(void)QEvt_ctor(&me->super, sig);
|
|
|
|
// The refCtr_ attribute is not used in time events, so it is
|
|
// reused to hold the tickRate as well as other information
|
|
me->super.refCtr_ = (uint8_t)tickRate;</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="QTimeEvtCtr const"/>
|
|
<!--${QF::QTimeEvt::armX::interval}-->
|
|
<parameter name="interval" type="QTimeEvtCtr const"/>
|
|
<code>uint_fast8_t const tickRate
|
|
= ((uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE);
|
|
QTimeEvtCtr const ctr = me->ctr;
|
|
#ifdef Q_SPY
|
|
uint_fast8_t const qs_id = ((QActive *)(me->act))->prio;
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(400, (me->act != (void *)0)
|
|
&& (ctr == 0U)
|
|
&& (nTicks != 0U)
|
|
&& (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
|
|
&& (me->super.sig >= (QSignal)Q_USER_SIG));
|
|
#ifdef Q_UNSAFE
|
|
Q_UNUSED_PAR(ctr);
|
|
#endif
|
|
|
|
me->ctr = nTicks;
|
|
me->interval = interval;
|
|
|
|
// 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->super.refCtr_ & QTE_IS_LINKED) == 0U) {
|
|
// mark as linked
|
|
me->super.refCtr_ |= QTE_IS_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_().
|
|
me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
|
|
QTimeEvt_timeEvtHead_[tickRate].act = me;
|
|
}
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_ARM, qs_id)
|
|
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>#ifdef Q_SPY
|
|
uint_fast8_t const qs_id = QACTIVE_CAST_(me->act)->prio;
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// is the time event actually armed?
|
|
bool wasArmed;
|
|
if (me->ctr != 0U) {
|
|
wasArmed = true;
|
|
me->super.refCtr_ |= QTE_WAS_DISARMED;
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this time event object
|
|
QS_OBJ_PRE_(me->act); // the target AO
|
|
QS_TEC_PRE_(me->ctr); // the # ticks
|
|
QS_TEC_PRE_(me->interval); // the interval
|
|
QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // tick rate
|
|
QS_END_PRE_()
|
|
|
|
me->ctr = 0U; // schedule removal from the list
|
|
}
|
|
else { // the time event was already disarmed automatically
|
|
wasArmed = false;
|
|
me->super.refCtr_ &= (uint8_t)(~QTE_WAS_DISARMED & 0xFFU);
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this time event object
|
|
QS_OBJ_PRE_(me->act); // the target AO
|
|
QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE); // 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="QTimeEvtCtr const"/>
|
|
<code>uint_fast8_t const tickRate
|
|
= (uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE;
|
|
#ifdef Q_SPY
|
|
uint_fast8_t const qs_id = ((QActive *)(me->act))->prio;
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(600, (me->act != (void *)0)
|
|
&& (tickRate < QF_MAX_TICK_RATE)
|
|
&& (nTicks != 0U)
|
|
&& (me->super.sig >= (QSignal)Q_USER_SIG));
|
|
|
|
// is the time evt not running?
|
|
bool wasArmed;
|
|
if (me->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->super.refCtr_ & QTE_IS_LINKED) == 0U) {
|
|
// mark as linked
|
|
me->super.refCtr_ |= QTE_IS_LINKED;
|
|
|
|
// The time event is initially inserted into the separate
|
|
// "freshly armed" 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_().
|
|
me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
|
|
QTimeEvt_timeEvtHead_[tickRate].act = me;
|
|
}
|
|
}
|
|
else { // the time event was armed
|
|
wasArmed = true;
|
|
}
|
|
me->ctr = nTicks; // re-load the tick counter (shift the phasing)
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_REARM, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this time event object
|
|
QS_OBJ_PRE_(me->act); // the target AO
|
|
QS_TEC_PRE_(me->ctr); // 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();
|
|
|
|
uint8_t const wasDisarmed = (me->super.refCtr_ & QTE_WAS_DISARMED);
|
|
me->super.refCtr_ |= QTE_WAS_DISARMED; // mark as disarmed
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return wasDisarmed != 0U;</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::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
|
|
|
|
QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
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...
|
|
for (;;) {
|
|
QTimeEvt *t = prev->next; // advance down the time evt. list
|
|
|
|
if (t == (QTimeEvt *)0) { // end of the list?
|
|
|
|
// any new time events armed since the last QTimeEvt_tick_()?
|
|
if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
|
|
|
|
// sanity check
|
|
Q_ASSERT_INCRIT(110, prev != (QTimeEvt *)0);
|
|
prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
|
|
QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
|
|
t = prev->next; // switch to the new list
|
|
}
|
|
else {
|
|
break; // all currently armed time evts. processed
|
|
}
|
|
}
|
|
|
|
if (t->ctr == 0U) { // time event scheduled for removal?
|
|
prev->next = t->next;
|
|
// mark time event 't' as NOT linked
|
|
t->super.refCtr_ &= (uint8_t)(~QTE_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 {
|
|
--t->ctr;
|
|
|
|
if (t->ctr == 0U) { // is time event about to expire?
|
|
QActive * const act = (QActive *)t->act;
|
|
|
|
if (t->interval != 0U) { // periodic time evt?
|
|
t->ctr = t->interval; // rearm the time event
|
|
prev = t; // advance to this time event
|
|
}
|
|
else { // one-shot time event: automatically disarm
|
|
prev->next = t->next;
|
|
|
|
// mark time event 't' as NOT linked
|
|
t->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
|
|
// do NOT advance the prev pointer
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
|
|
QS_OBJ_PRE_(t); // 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_(t); // the time event object
|
|
QS_SIG_PRE_(t->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 (t->super.sig < Q_USER_SIG) {
|
|
QXThread_timeout_(act);
|
|
}
|
|
else {
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT(); // exit crit. section before posting
|
|
|
|
// QACTIVE_POST() asserts if the queue overflows
|
|
QACTIVE_POST(act, &t->super, sender);
|
|
}
|
|
#else
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT(); // exit crit. section before posting
|
|
|
|
// QACTIVE_POST() asserts if the queue overflows
|
|
QACTIVE_POST(act, &t->super, sender);
|
|
#endif
|
|
}
|
|
else {
|
|
prev = t; // 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();
|
|
}
|
|
|
|
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>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(800, tickRate < QF_MAX_TICK_RATE);
|
|
QF_CRIT_EXIT();
|
|
|
|
bool inactive;
|
|
if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
|
|
inactive = false;
|
|
}
|
|
else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
|
|
inactive = false;
|
|
}
|
|
else {
|
|
inactive = true;
|
|
}
|
|
return inactive;</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_
|
|
#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;</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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>Q_UNUSED_PAR(me);
|
|
Q_UNUSED_PAR(par);
|
|
Q_UNUSED_PAR(qs_id);
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QACTIVE_CAST_(me)->eQueue.tail = 0U;
|
|
|
|
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_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>Q_UNUSED_PAR(e);
|
|
Q_UNUSED_PAR(qs_id);
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QEQueueCtr nTicks = QACTIVE_CAST_(me)->eQueue.tail; // save # of ticks
|
|
QACTIVE_CAST_(me)->eQueue.tail = 0U; // clear # ticks
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
for (; nTicks > 0U; --nTicks) {
|
|
QTimeEvt_tick_((uint_fast8_t)QACTIVE_CAST_(me)->eQueue.head, 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
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
if (me->eQueue.frontEvt == (QEvt *)0) {
|
|
|
|
static QEvt const tickEvt = QEVT_INITIALIZER(0);
|
|
me->eQueue.frontEvt = &tickEvt; // deliver event directly
|
|
--me->eQueue.nFree; // one less free event
|
|
|
|
QACTIVE_EQUEUE_SIGNAL_(me); // signal the event queue
|
|
}
|
|
|
|
++me->eQueue.tail; // account for one more tick event
|
|
|
|
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); // poolId & 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::nMin}-->
|
|
<attribute name="nMin" type="QEQueueCtr" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QEQueue</documentation>
|
|
</attribute>
|
|
<!--${QF::QEQueue::dummy}-->
|
|
<attribute name="dummy" type="QEQueue" visibility="0x00" properties="0x01">
|
|
<documentation>dummy static member to force generation of
|
|
'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>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
|
|
me->nMin = me->nFree;</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::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(200, e != (QEvt *)0);
|
|
|
|
QEQueueCtr nFree = me->nFree; // get volatile into temporary
|
|
|
|
// required margin available?
|
|
bool status;
|
|
if (((margin == QF_NO_MARGIN) && (nFree > 0U))
|
|
|| (nFree > (QEQueueCtr)margin))
|
|
{
|
|
// is it a mutable event?
|
|
if (QEvt_getPoolId_(e) != 0U) {
|
|
QEvt_refCtr_inc_(e); // increment the reference counter
|
|
}
|
|
|
|
--nFree; // one free entry just used up
|
|
me->nFree = nFree; // update the original
|
|
if (me->nMin > nFree) {
|
|
me->nMin = nFree; // update minimum so far
|
|
}
|
|
|
|
QS_BEGIN_PRE_(QS_QF_EQUEUE_POST, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_EQC_PRE_(me->nMin); // min # free entries
|
|
QS_END_PRE_()
|
|
|
|
if (me->frontEvt == (QEvt *)0) { // was the queue empty?
|
|
me->frontEvt = e; // deliver event directly
|
|
}
|
|
else { // queue was not empty, insert event into the ring-buffer
|
|
// insert event into the ring buffer (FIFO)...
|
|
me->ring[me->head] = e; // insert e into buffer
|
|
// need to wrap the head?
|
|
if (me->head == 0U) {
|
|
me->head = me->end; // wrap around
|
|
}
|
|
--me->head;
|
|
}
|
|
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, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # 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::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QEQueueCtr nFree = me->nFree; // get volatile into temporary
|
|
|
|
Q_REQUIRE_INCRIT(300, nFree != 0U);
|
|
|
|
if (QEvt_getPoolId_(e) != 0U) { // is it a mutable event?
|
|
QEvt_refCtr_inc_(e); // increment the reference counter
|
|
}
|
|
|
|
--nFree; // one free entry just used up
|
|
me->nFree = nFree; // update the original
|
|
if (me->nMin > nFree) {
|
|
me->nMin = nFree; // update minimum so far
|
|
}
|
|
|
|
QS_BEGIN_PRE_(QS_QF_EQUEUE_POST_LIFO, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_EQC_PRE_(me->nMin); // min # free entries
|
|
QS_END_PRE_()
|
|
|
|
QEvt const * const frontEvt = me->frontEvt; // read into temporary
|
|
me->frontEvt = e; // deliver event directly to the front of the queue
|
|
|
|
if (frontEvt != (QEvt *)0) { // was the queue not empty?
|
|
++me->tail;
|
|
if (me->tail == me->end) { // need to wrap the tail?
|
|
me->tail = 0U; // wrap around
|
|
}
|
|
me->ring[me->tail] = frontEvt; // save old front evt
|
|
}
|
|
|
|
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::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QEvt const * const e = me->frontEvt; // always remove evt from the front
|
|
|
|
if (e != (QEvt *)0) { // was the queue not empty?
|
|
// use a temporary variable to increment me->nFree
|
|
QEQueueCtr const nFree = me->nFree + 1U;
|
|
me->nFree = nFree; // update the # free
|
|
|
|
// any events in the ring buffer?
|
|
if (nFree <= me->end) {
|
|
me->frontEvt = me->ring[me->tail]; // get from tail
|
|
if (me->tail == 0U) { // need to wrap the tail?
|
|
me->tail = me->end; // wrap around
|
|
}
|
|
--me->tail;
|
|
|
|
QS_BEGIN_PRE_(QS_QF_EQUEUE_GET, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_END_PRE_()
|
|
}
|
|
else {
|
|
me->frontEvt = (QEvt *)0; // queue becomes empty
|
|
|
|
// all entries in the queue must be free (+1 for fronEvt)
|
|
Q_ASSERT_INCRIT(410, nFree == (me->end + 1U));
|
|
|
|
QS_BEGIN_PRE_(QS_QF_EQUEUE_GET_LAST, qs_id)
|
|
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_getPoolId_(e), e->refCtr_); // poolId & 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>return me->nMin;</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" 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)
|
|
&& (poolSize >= (uint_fast32_t)sizeof(QFreeBlock))
|
|
&& ((uint_fast16_t)(blockSize + sizeof(QFreeBlock)) > blockSize));
|
|
|
|
me->free_head = (QFreeBlock *)poolSto;
|
|
|
|
// find # free blocks in a memory block, NO DIVISION
|
|
me->blockSize = (QMPoolSize)sizeof(QFreeBlock);
|
|
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;
|
|
me->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_UINTPTR_CAST_(fb->next));
|
|
#endif
|
|
fb = fb->next; // advance to the next block
|
|
++me->nTot; // one more free block in the pool
|
|
}
|
|
|
|
fb->next = (QFreeBlock *)0; // the last link points to NULL
|
|
#ifndef Q_UNSAFE
|
|
fb->next_dis = (uintptr_t)(~Q_UINTPTR_CAST_(fb->next));
|
|
#endif
|
|
|
|
me->nFree = me->nTot; // all blocks are free
|
|
me->nMin = me->nTot; // the minimum # free blocks
|
|
me->start = poolSto; // the original start this pool buffer
|
|
me->end = fb; // the last block in this pool
|
|
|
|
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::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// have more free blocks than the requested margin?
|
|
QFreeBlock *fb;
|
|
if (me->nFree > (QMPoolCtr)margin) {
|
|
fb = me->free_head; // get a free block
|
|
|
|
// a free block must be valid
|
|
Q_ASSERT_INCRIT(300, fb != (QFreeBlock *)0);
|
|
|
|
QFreeBlock * const fb_next = fb->next; // fast temporary
|
|
|
|
// the free block must have integrity (duplicate inverse storage)
|
|
Q_ASSERT_INCRIT(302, Q_UINTPTR_CAST_(fb_next)
|
|
== (uintptr_t)~fb->next_dis);
|
|
|
|
--me->nFree; // one less free block
|
|
if (me->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->nMin = 0U; // remember that the pool got empty
|
|
}
|
|
else {
|
|
// invariant:
|
|
// The pool is not empty, so the next free-block pointer,
|
|
// so the next free block must be in range.
|
|
|
|
// NOTE: The next free block pointer can fall out of range
|
|
// when the client code writes past the memory block, thus
|
|
// corrupting the next block.
|
|
Q_ASSERT_INCRIT(330,
|
|
(me->start <= fb_next) && (fb_next <= me->end));
|
|
|
|
// is the # free blocks the new minimum so far?
|
|
if (me->nMin > me->nFree) {
|
|
me->nMin = me->nFree; // remember the new minimum
|
|
}
|
|
}
|
|
|
|
me->free_head = fb_next; // set the head to the next free block
|
|
|
|
QS_BEGIN_PRE_(QS_QF_MPOOL_GET, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this memory pool
|
|
QS_MPC_PRE_(me->nFree); // # of free blocks in the pool
|
|
QS_MPC_PRE_(me->nMin); // min # free blocks ever in the pool
|
|
QS_END_PRE_()
|
|
}
|
|
else { // don't have enough free blocks at this point
|
|
fb = (QFreeBlock *)0;
|
|
|
|
QS_BEGIN_PRE_(QS_QF_MPOOL_GET_ATTEMPT, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this memory pool
|
|
QS_MPC_PRE_(me->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::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>#ifndef Q_SPY
|
|
Q_UNUSED_PAR(qs_id);
|
|
#endif
|
|
|
|
QFreeBlock * const fb = (QFreeBlock *)block;
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(200, (me->nFree < me->nTot)
|
|
&& (me->start <= fb) && (fb <= me->end));
|
|
|
|
fb->next = me->free_head; // link into list
|
|
#ifndef Q_UNSAFE
|
|
fb->next_dis = (uintptr_t)(~Q_UINTPTR_CAST_(fb->next));
|
|
#endif
|
|
|
|
// set as new head of the free list
|
|
me->free_head = block;
|
|
|
|
++me->nFree; // one more free block in this pool
|
|
|
|
QS_BEGIN_PRE_(QS_QF_MPOOL_PUT, qs_id)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this memory pool
|
|
QS_MPC_PRE_(me->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));
|
|
uint_fast16_t const min =
|
|
(uint_fast16_t)QActive_registry_[prio]->eQueue.nMin;
|
|
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 poolId = 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, poolId < QF_MAX_EPOOL);
|
|
if (poolId > 0U) {
|
|
Q_REQUIRE_INCRIT(201,
|
|
QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolId - 1U]) < evtSize);
|
|
}
|
|
QF_priv_.maxPool_ = poolId + 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_[poolId], 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' + poolId + 1U);
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
QS_obj_dict_pre_(&QF_priv_.ePool_[poolId], (char const *)obj_name);
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
}
|
|
#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>return QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[QF_priv_.maxPool_ - 1U]);</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::poolId}-->
|
|
<parameter name="poolId" type="uint_fast8_t const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(400, (poolId <= QF_MAX_EPOOL)
|
|
&& (0U < poolId) && (poolId <= QF_priv_.maxPool_));
|
|
|
|
uint_fast16_t const min = (uint_fast16_t)QF_priv_.ePool_[poolId - 1U].nMin;
|
|
|
|
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 poolId = 0U; // zero-based poolId initially
|
|
for (; poolId < QF_priv_.maxPool_; ++poolId) {
|
|
if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_priv_.ePool_[poolId])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// precondition:
|
|
// - cannot run out of registered pools
|
|
Q_REQUIRE_INCRIT(300, poolId < QF_priv_.maxPool_);
|
|
|
|
++poolId; // convert to 1-based poolId
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
// get event e (port-dependent)...
|
|
QEvt *e;
|
|
#ifdef Q_SPY
|
|
QF_EPOOL_GET_(QF_priv_.ePool_[poolId - 1U], e,
|
|
((margin != QF_NO_MARGIN) ? margin : 0U),
|
|
(uint_fast8_t)QS_EP_ID + poolId);
|
|
#else
|
|
QF_EPOOL_GET_(QF_priv_.ePool_[poolId - 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)(QEVT_MARKER | poolId);
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QF_NEW,
|
|
(uint_fast8_t)QS_EP_ID + poolId)
|
|
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 + poolId)
|
|
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(402, QEvt_verify_(e));
|
|
|
|
uint_fast8_t const poolId = QEvt_getPoolId_(e);
|
|
|
|
if (poolId != 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 + poolId)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of the event
|
|
QS_2U8_PRE_(poolId, e->refCtr_); // poolId & 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 + poolId)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of the event
|
|
QS_2U8_PRE_(poolId, e->refCtr_); // poolId & refCtr
|
|
QS_END_PRE_()
|
|
|
|
// pool number must be in range
|
|
Q_ASSERT_INCRIT(410, (poolId <= QF_priv_.maxPool_)
|
|
&& (poolId <= 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_[poolId - 1U],
|
|
(QEvt *)e,
|
|
(uint_fast8_t)QS_EP_ID + poolId);
|
|
#else
|
|
QF_EPOOL_PUT_(QF_priv_.ePool_[poolId - 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(502, QEvt_verify_(e));
|
|
|
|
uint_fast8_t const poolId = QEvt_getPoolId_(e);
|
|
|
|
Q_REQUIRE_INCRIT(500, (poolId != 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 + poolId)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of the event
|
|
QS_2U8_PRE_(poolId, e->refCtr_); // poolId & 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>QEvt const * const e = evtRef;
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(602, QEvt_verify_(e));
|
|
|
|
#ifdef Q_SPY
|
|
uint_fast8_t const poolId = QEvt_getPoolId_(e);
|
|
#endif
|
|
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QF_DELETE_REF,
|
|
(uint_fast8_t)QS_EP_ID + poolId)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of the event
|
|
QS_2U8_PRE_(poolId, e->refCtr_); // poolId & refCtr
|
|
QS_END_PRE_()
|
|
QS_MEM_APP();
|
|
|
|
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_DYN_CTOR" 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_DYN_CTOR" 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_##_ctor((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_DYN_CTOR" 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_DYN_CTOR" 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_##_ctor((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_START}-->
|
|
<operation name="QACTIVE_START" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QF-macros::QACTIVE_START::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QF-macros::QACTIVE_START::prioSpec_}-->
|
|
<parameter name="prioSpec_" type="QPrioSpec"/>
|
|
<!--${QF-macros::QACTIVE_START::qSto_}-->
|
|
<parameter name="qSto_" type="QEvt const * *"/>
|
|
<!--${QF-macros::QACTIVE_START::qLen_}-->
|
|
<parameter name="qLen_" type="uint_fast16_t"/>
|
|
<!--${QF-macros::QACTIVE_START::stkSto_}-->
|
|
<parameter name="stkSto_" type="void *"/>
|
|
<!--${QF-macros::QACTIVE_START::stkSize_}-->
|
|
<parameter name="stkSize_" type="uint_fast16_t"/>
|
|
<!--${QF-macros::QACTIVE_START::par_}-->
|
|
<parameter name="par_" type="void const *"/>
|
|
<code>\
|
|
(QActive_start_((QActive *)(me_), (prioSpec_), \
|
|
(qSto_), (qLen_), (stkSto_), (stkSize_), (par_)))</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_::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>\
|
|
((e_) = (QEvt *)QMPool_get(&(p_), (m_), (qs_id_)))</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_::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint_fast8_t"/>
|
|
<code>\
|
|
(QMPool_put(&(p_), (e_), (qs_id_)))</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="0x00" properties="0x00">
|
|
<documentation>//! @memberof QV_Attr</documentation>
|
|
</attribute>
|
|
<!--${QV::QV-base::Attr::readySet_dis}-->
|
|
<attribute name="readySet_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x00" 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::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_(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
|
|
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
|
|
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QV_priv_.readySet, &QV_priv_.readySet_dis);
|
|
#endif
|
|
|
|
#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 cooperative 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)
|
|
uint8_t pprev = 0U; // previously used prio.
|
|
#endif
|
|
|
|
for (;;) { // QV event loop...
|
|
|
|
// check internal integrity (duplicate inverse storage)
|
|
Q_ASSERT_INCRIT(202, QPSet_verify_(&QV_priv_.readySet,
|
|
&QV_priv_.readySet_dis));
|
|
|
|
// find the maximum prio. AO ready to run
|
|
if (QPSet_notEmpty(&QV_priv_.readySet)) {
|
|
|
|
uint8_t const p = (uint8_t)QPSet_findMax(&QV_priv_.readySet);
|
|
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_(p, pprev); // scheduled prio & previous prio
|
|
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_(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 (all event
|
|
// queues empty) can change at any time by an interrupt posting
|
|
// events to a queue.
|
|
//
|
|
// NOTE: QV_onIdle() MUST enable interrupts internally,
|
|
// ideally at the same time as 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="QEvt const * * 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 = (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</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>\
|
|
Q_ASSERT_INCRIT(310, (me_)->eQueue.frontEvt != (QEvt *)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_fast16_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="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::readySet_dis}-->
|
|
<attribute name="readySet_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actPrio}-->
|
|
<attribute name="actPrio" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::nextPrio}-->
|
|
<attribute name="nextPrio" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::actThre}-->
|
|
<attribute name="actThre" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::lockCeil}-->
|
|
<attribute name="lockCeil" type="uint_fast8_t volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::lockHolder}-->
|
|
<attribute name="lockHolder" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QK::QK-base::Attr::intNest}-->
|
|
<attribute name="intNest" type="uint_fast8_t volatile" visibility="0x00" 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_());
|
|
|
|
// first store the previous lock prio
|
|
QSchedStatus stat;
|
|
if (ceiling > QK_priv_.lockCeil) { // raising the lock ceiling?
|
|
QS_BEGIN_PRE_(QS_SCHED_LOCK, 0U)
|
|
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_.lockHolder;
|
|
stat |= (QSchedStatus)QK_priv_.lockCeil << 8U;
|
|
|
|
// new status of the lock
|
|
QK_priv_.lockHolder = QK_priv_.actPrio;
|
|
QK_priv_.lockCeil = ceiling;
|
|
}
|
|
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::stat}-->
|
|
<parameter name="stat" type="QSchedStatus const"/>
|
|
<code>// has the scheduler been actually locked by the last QK_schedLock()?
|
|
if (stat != 0xFFU) {
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
uint_fast8_t const lockCeil = QK_priv_.lockCeil;
|
|
uint_fast8_t const prevCeil = (stat >> 8U);
|
|
Q_REQUIRE_INCRIT(200, (!QK_ISR_CONTEXT_())
|
|
&& (lockCeil > prevCeil));
|
|
|
|
QS_BEGIN_PRE_(QS_SCHED_UNLOCK, 0U)
|
|
QS_TIME_PRE_(); // timestamp
|
|
// current lock ceiling (old), previous lock ceiling (new)
|
|
QS_2U8_PRE_((uint8_t)lockCeil, (uint8_t)prevCeil);
|
|
QS_END_PRE_()
|
|
|
|
// restore the previous lock ceiling and lock holder
|
|
QK_priv_.lockCeil = prevCeil;
|
|
QK_priv_.lockHolder = (stat & 0xFFU);
|
|
|
|
// 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>Q_REQUIRE_INCRIT(400, 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);
|
|
|
|
// is the AO's prio. below the active preemption-threshold?
|
|
if (p <= QK_priv_.actThre) {
|
|
p = 0U; // no activation needed
|
|
}
|
|
// is the AO's prio. below the lock-ceiling?
|
|
else if (p <= QK_priv_.lockCeil) {
|
|
p = 0U; // no activation needed
|
|
}
|
|
else {
|
|
QK_priv_.nextPrio = p; // next AO to run
|
|
}
|
|
}
|
|
|
|
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>uint_fast8_t const prio_in = QK_priv_.actPrio; // save initial prio.
|
|
uint_fast8_t p = QK_priv_.nextPrio; // next prio to run
|
|
QK_priv_.nextPrio = 0U; // clear for the next time
|
|
|
|
Q_REQUIRE_INCRIT(500, (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
|
|
|
|
// loop until no more ready-to-run AOs of higher pthre than the initial
|
|
QActive *a;
|
|
do {
|
|
a = QActive_registry_[p]; // obtain the pointer to the AO
|
|
Q_ASSERT_INCRIT(505, a != (QActive *)0); // the AO must be registered
|
|
|
|
// set new active prio. and preemption-threshold
|
|
QK_priv_.actPrio = p;
|
|
QK_priv_.actThre = a->pthre;
|
|
|
|
#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(((pprev != 0U)
|
|
? QActive_registry_[pprev]
|
|
: (QActive *)0), a);
|
|
#endif // QF_ON_CONTEXT_SW
|
|
|
|
pprev = p; // update previous prio.
|
|
}
|
|
#endif // QF_ON_CONTEXT_SW || Q_SPY
|
|
|
|
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_ASSERT_INCRIT(502, 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 = (uint8_t)QPSet_findMax(&QK_priv_.readySet);
|
|
|
|
// is the new prio. below the initial preemption-threshold?
|
|
if (p <= QActive_registry_[prio_in]->pthre) {
|
|
p = 0U; // no activation needed
|
|
}
|
|
// is the AO's prio. below the lock preemption-threshold?
|
|
else if (p <= QK_priv_.lockCeil) {
|
|
p = 0U; // no activation needed
|
|
}
|
|
else {
|
|
Q_ASSERT_INCRIT(510, p <= QF_MAX_ACTIVE);
|
|
}
|
|
}
|
|
} while (p != 0U);
|
|
|
|
// restore the active prio. and preemption-threshold
|
|
QK_priv_.actPrio = prio_in;
|
|
QK_priv_.actThre = (uint_fast8_t)QActive_registry_[prio_in]->pthre;
|
|
|
|
#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_(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
|
|
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
|
|
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QK_priv_.readySet, &QK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
// setup the QK scheduler as initially locked and not running
|
|
QK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
|
|
|
|
// QK idle AO object (const in ROM)
|
|
static QActive const idle_ao = { (struct QAsmVtable const *)0 };
|
|
|
|
// register the idle AO object (cast 'const' away)
|
|
QActive_registry_[0] = QACTIVE_CAST_(&idle_ao);
|
|
|
|
#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();
|
|
|
|
QK_priv_.lockCeil = 0U; // unlock the QK scheduler
|
|
|
|
// activate AOs to process events posted so far
|
|
if (QK_sched_() != 0U) {
|
|
QK_activate_();
|
|
}
|
|
|
|
#ifdef QK_START
|
|
QK_START(); // port-specific startup of the QK kernel
|
|
#endif
|
|
|
|
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="QEvt const * * 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>\
|
|
Q_ASSERT_INCRIT(320, (me_)->eQueue.frontEvt != (QEvt *)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>
|
|
<!--${QXK}-->
|
|
<package name="QXK" stereotype="0x05">
|
|
<!--${QXK::QXK}-->
|
|
<attribute name="QXK" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<documentation>// @class QXK</documentation>
|
|
<code>{
|
|
//! @cond INTERNAL
|
|
uint8_t dummy;
|
|
//! @endcond
|
|
} QXK;</code>
|
|
</attribute>
|
|
<!--${QXK::QSchedStatus}-->
|
|
<attribute name="QSchedStatus" type="typedef uint_fast16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QXK::QXTHREAD_NO_TIMEOUT}-->
|
|
<attribute name="QXTHREAD_NO_TIMEOUT" type="QTimeEvtCtr" visibility="0x03" properties="0x00">
|
|
<code>((QTimeEvtCtr)0)</code>
|
|
</attribute>
|
|
<!--${QXK::QXK-base}-->
|
|
<package name="QXK-base" stereotype="0x02" namespace="QXK_">
|
|
<!--${QXK::QXK-base::Attr}-->
|
|
<class name="Attr">
|
|
<documentation>//! @class QXK_Attr</documentation>
|
|
<!--${QXK::QXK-base::Attr::curr}-->
|
|
<attribute name="curr" type="struct QActive * volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::next}-->
|
|
<attribute name="next" type="struct QActive * volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::prev}-->
|
|
<attribute name="prev" type="struct QActive * volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::actPrio}-->
|
|
<attribute name="actPrio" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::lockCeil}-->
|
|
<attribute name="lockCeil" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::lockHolder}-->
|
|
<attribute name="lockHolder" type="uint_fast8_t volatile" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::readySet}-->
|
|
<attribute name="readySet" type="QPSet" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::Attr::readySet_dis}-->
|
|
<attribute name="readySet_dis?ndef Q_UNSAFE" type="QPSet" visibility="0x00" properties="0x00">
|
|
<documentation>//! @memberof QXK_Attr</documentation>
|
|
</attribute>
|
|
</class>
|
|
<!--${QXK::QXK-base::priv_}-->
|
|
<attribute name="priv_" type="QXK_Attr" visibility="0x01" properties="0x00">
|
|
<documentation>//! @static @private @memberof QXK</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXK-base::onIdle}-->
|
|
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QXK
|
|
|
|
//! @static @public @memberof QXK</documentation>
|
|
</operation>
|
|
<!--${QXK::QXK-base::schedLock}-->
|
|
<operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QXK
|
|
|
|
//! @static @public @memberof QXK</documentation>
|
|
<!--${QXK::QXK-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, !QXK_ISR_CONTEXT_());
|
|
|
|
QSchedStatus stat; // saved lock status to be returned
|
|
|
|
// is the lock ceiling being raised?
|
|
if (ceiling > QXK_priv_.lockCeil) {
|
|
QS_BEGIN_PRE_(QS_SCHED_LOCK, 0U)
|
|
QS_TIME_PRE_(); // timestamp
|
|
// the previous lock ceiling & new lock ceiling
|
|
QS_2U8_PRE_((uint8_t)QXK_priv_.lockCeil, (uint8_t)ceiling);
|
|
QS_END_PRE_()
|
|
|
|
// previous status of the lock
|
|
stat = (QSchedStatus)QXK_priv_.lockHolder;
|
|
stat |= (QSchedStatus)QXK_priv_.lockCeil << 8U;
|
|
|
|
// new status of the lock
|
|
QXK_priv_.lockHolder = (QXK_priv_.curr != (QActive *)0)
|
|
? (uint_fast8_t)QXK_priv_.curr->prio
|
|
: 0U;
|
|
QXK_priv_.lockCeil = ceiling;
|
|
}
|
|
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>
|
|
<!--${QXK::QXK-base::schedUnlock}-->
|
|
<operation name="schedUnlock" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QXK
|
|
|
|
//! @static @public @memberof QXK</documentation>
|
|
<!--${QXK::QXK-base::schedUnlock::stat}-->
|
|
<parameter name="stat" type="QSchedStatus const"/>
|
|
<code>// has the scheduler been actually locked by the last QXK_schedLock()?
|
|
if (stat != 0xFFU) {
|
|
uint8_t const prevCeil = (uint8_t)(stat >> 8U);
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(200, !QXK_ISR_CONTEXT_());
|
|
Q_REQUIRE_INCRIT(201, QXK_priv_.lockCeil > prevCeil);
|
|
|
|
QS_BEGIN_PRE_(QS_SCHED_UNLOCK, 0U)
|
|
QS_TIME_PRE_(); // timestamp
|
|
// ceiling before unlocking & prio after unlocking
|
|
QS_2U8_PRE_((uint8_t)QXK_priv_.lockCeil, (uint8_t)prevCeil);
|
|
QS_END_PRE_()
|
|
|
|
// restore the previous lock ceiling and lock holder
|
|
QXK_priv_.lockCeil = prevCeil;
|
|
QXK_priv_.lockHolder = (stat & 0xFFU);
|
|
|
|
// find if any threads should be run after unlocking the scheduler
|
|
if (QXK_sched_() != 0U) { // activation needed?
|
|
QXK_activate_(); // synchronously activate basic-thred(s)
|
|
}
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
}</code>
|
|
</operation>
|
|
<!--${QXK::QXK-base::current}-->
|
|
<operation name="current" type="QActive *" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QXK
|
|
|
|
//! @static @public @memberof QXK</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(600, QXK_priv_.lockCeil <= QF_MAX_ACTIVE);
|
|
|
|
struct QActive *curr = QXK_priv_.curr;
|
|
if (curr == (QActive *)0) { // basic thread?
|
|
curr = QActive_registry_[QXK_priv_.actPrio];
|
|
}
|
|
|
|
Q_ASSERT_INCRIT(690, curr != (QActive *)0);
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return curr;</code>
|
|
</operation>
|
|
<!--${QXK::QXK-base::sched_}-->
|
|
<operation name="sched_" type="uint_fast8_t" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QXK
|
|
|
|
//! @static @private @memberof QXK</documentation>
|
|
<code>Q_REQUIRE_INCRIT(402, QPSet_verify_(&QXK_priv_.readySet,
|
|
&QXK_priv_.readySet_dis));
|
|
uint_fast8_t p;
|
|
if (QPSet_isEmpty(&QXK_priv_.readySet)) {
|
|
p = 0U; // no activation needed
|
|
}
|
|
else {
|
|
// find the highest-prio thread ready to run
|
|
p = QPSet_findMax(&QXK_priv_.readySet);
|
|
if (p <= QXK_priv_.lockCeil) {
|
|
// prio. of the thread holding the lock
|
|
p = (uint_fast8_t)QActive_registry_[QXK_priv_.lockHolder]->prio;
|
|
if (p != 0U) {
|
|
Q_ASSERT_INCRIT(410,
|
|
QPSet_hasElement(&QXK_priv_.readySet, p));
|
|
}
|
|
}
|
|
}
|
|
QActive const * const curr = QXK_priv_.curr;
|
|
QActive * const next = QActive_registry_[p];
|
|
|
|
// the next thread found must be registered in QF
|
|
Q_ASSERT_INCRIT(420, next != (QActive *)0);
|
|
|
|
// is the current thread a basic-thread?
|
|
if (curr == (QActive *)0) {
|
|
|
|
// is the new prio. above the active prio.?
|
|
if (p > QXK_priv_.actPrio) {
|
|
QXK_priv_.next = next; // set the next AO to activate
|
|
|
|
if (next->osObject != (void *)0) { // is next extended?
|
|
QXK_CONTEXT_SWITCH_();
|
|
p = 0U; // no activation needed
|
|
}
|
|
}
|
|
else { // below the pre-thre
|
|
QXK_priv_.next = (QActive *)0;
|
|
p = 0U; // no activation needed
|
|
}
|
|
}
|
|
else { // currently executing an extended-thread
|
|
// is the current thread different from the next?
|
|
if (curr != next) {
|
|
QXK_priv_.next = next;
|
|
QXK_CONTEXT_SWITCH_();
|
|
}
|
|
else { // current is the same as next
|
|
QXK_priv_.next = (QActive *)0; // no need to context-switch
|
|
}
|
|
p = 0U; // no activation needed
|
|
}
|
|
|
|
return p;</code>
|
|
</operation>
|
|
<!--${QXK::QXK-base::activate_}-->
|
|
<operation name="activate_" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QXK
|
|
|
|
//! @static @private @memberof QXK</documentation>
|
|
<code>uint_fast8_t const prio_in = QXK_priv_.actPrio;
|
|
QActive *next = QXK_priv_.next; // the next AO (basic-thread) to run
|
|
|
|
Q_REQUIRE_INCRIT(500, (next != (QActive *)0)
|
|
&& (prio_in <= QF_MAX_ACTIVE));
|
|
|
|
// QXK Context switch callback defined or QS tracing enabled?
|
|
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
|
|
QXK_contextSw_(next);
|
|
#endif // QF_ON_CONTEXT_SW || Q_SPY
|
|
|
|
QXK_priv_.next = (QActive *)0; // clear the next AO
|
|
QXK_priv_.curr = (QActive *)0; // current is basic-thread
|
|
|
|
// prio. of the next thread
|
|
uint_fast8_t p = (uint_fast8_t)next->prio;
|
|
|
|
// loop until no more ready-to-run AOs of higher prio than the initial
|
|
do {
|
|
QXK_priv_.actPrio = p; // next active prio
|
|
|
|
QF_INT_ENABLE(); // unconditionally enable interrupts
|
|
|
|
QEvt const * const e = QActive_get_(next);
|
|
// NOTE QActive_get_() performs QS_MEM_APP() before return
|
|
|
|
// dispatch event (virtual call)
|
|
(*next->super.vptr->dispatch)(&next->super, e, p);
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e);
|
|
#endif
|
|
|
|
QF_INT_DISABLE(); // unconditionally disable interrupts
|
|
QF_MEM_SYS();
|
|
|
|
// check internal integrity (duplicate inverse storage)
|
|
Q_ASSERT_INCRIT(502, QPSet_verify_(&QXK_priv_.readySet,
|
|
&QXK_priv_.readySet_dis));
|
|
|
|
if (next->eQueue.frontEvt == (QEvt *)0) { // empty queue?
|
|
QPSet_remove(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
}
|
|
|
|
if (QPSet_isEmpty(&QXK_priv_.readySet)) {
|
|
QXK_priv_.next = (QActive *)0;
|
|
next = QActive_registry_[0];
|
|
p = 0U; // no activation needed
|
|
}
|
|
else {
|
|
// find next highest-prio below the lock ceiling
|
|
p = (uint8_t)QPSet_findMax(&QXK_priv_.readySet);
|
|
if (p <= QXK_priv_.lockCeil) {
|
|
p = QXK_priv_.lockHolder; // thread holding lock
|
|
if (p != 0U) {
|
|
Q_ASSERT_INCRIT(510,
|
|
QPSet_hasElement(&QXK_priv_.readySet, p));
|
|
}
|
|
}
|
|
|
|
// set the next thread and ensure that it is registered
|
|
next = QActive_registry_[p];
|
|
Q_ASSERT_INCRIT(520, next != (QActive *)0);
|
|
|
|
// is next a basic thread?
|
|
if (next->osObject == (void *)0) {
|
|
// is the next prio. above the initial prio.?
|
|
if (p > QActive_registry_[prio_in]->prio) {
|
|
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
|
|
if (p != QXK_priv_.actPrio) { // changing threads?
|
|
QXK_contextSw_(next);
|
|
}
|
|
#endif // QF_ON_CONTEXT_SW || Q_SPY
|
|
QXK_priv_.next = next;
|
|
}
|
|
else {
|
|
QXK_priv_.next = (QActive *)0;
|
|
p = 0U; // no activation needed
|
|
}
|
|
}
|
|
else { // next is the extended-thread
|
|
QXK_priv_.next = next;
|
|
QXK_CONTEXT_SWITCH_();
|
|
p = 0U; // no activation needed
|
|
}
|
|
}
|
|
} while (p != 0U); // while activation needed
|
|
|
|
// restore the active prio.
|
|
QXK_priv_.actPrio = prio_in;
|
|
|
|
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
|
|
if (next->osObject == (void *)0) {
|
|
QXK_contextSw_((prio_in == 0U)
|
|
? (QActive *)0
|
|
: QActive_registry_[prio_in]);
|
|
}
|
|
#endif // QF_ON_CONTEXT_SW || Q_SPY</code>
|
|
</operation>
|
|
<!--${QXK::QXK-base::contextSw_}-->
|
|
<operation name="contextSw_" type="void" visibility="0x00" properties="0x00">
|
|
<specifiers>__attribute__(( used ))</specifiers>
|
|
<documentation>//! @static @public @memberof QXK
|
|
|
|
//! @static @public @memberof QXK</documentation>
|
|
<!--${QXK::QXK-base::contextSw_::next}-->
|
|
<parameter name="next" type="QActive * const"/>
|
|
<code>#ifdef Q_SPY
|
|
uint8_t const prev_prio = (QXK_priv_.prev != (QActive *)0)
|
|
? QXK_priv_.prev->prio
|
|
: 0U;
|
|
if (next != (QActive *)0) { // next is NOT idle?
|
|
QS_BEGIN_PRE_(QS_SCHED_NEXT, next->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_2U8_PRE_(next->prio, prev_prio);
|
|
QS_END_PRE_()
|
|
}
|
|
else { // going to idle
|
|
QS_BEGIN_PRE_(QS_SCHED_IDLE, prev_prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_U8_PRE_(prev_prio);
|
|
QS_END_PRE_()
|
|
}
|
|
#endif // Q_SPY
|
|
|
|
#ifdef QF_ON_CONTEXT_SW
|
|
QF_onContextSw(QXK_priv_.prev, next);
|
|
#endif // QF_ON_CONTEXT_SW
|
|
|
|
QXK_priv_.prev = next; // update the previous thread</code>
|
|
</operation>
|
|
<!--${QXK::QXK-base::threadExit_}-->
|
|
<operation name="threadExit_" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @private @memberof QXK
|
|
|
|
//! @static @private @memberof QXK</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
|
|
QXThread const * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
|
|
|
|
Q_REQUIRE_INCRIT(900, (!QXK_ISR_CONTEXT_())
|
|
&& (thr != (QXThread *)0)); // current thread must be extended
|
|
Q_REQUIRE_INCRIT(901,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)thr->super.prio);
|
|
|
|
uint_fast8_t const p = (uint_fast8_t)thr->super.prio;
|
|
|
|
QF_MEM_SYS();
|
|
QActive_registry_[p] = (QActive *)0;
|
|
QPSet_remove(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
(void)QXK_sched_(); // schedule other threads
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QXK::QF-cust}-->
|
|
<package name="QF-cust" stereotype="0x02" namespace="QF_">
|
|
<!--${QXK::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_(&QXK_priv_, sizeof(QXK_priv_));
|
|
QF_bzero_(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
|
|
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
|
|
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
// setup the QXK scheduler as initially locked and not running
|
|
QXK_priv_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
|
|
|
|
// QXK idle AO object (const in ROM)
|
|
static QActive const idle_ao = { (struct QAsmVtable const *)0 };
|
|
|
|
// register the idle AO object (cast 'const' away)
|
|
QActive_registry_[0] = QACTIVE_CAST_(&idle_ao);
|
|
QXK_priv_.prev = QActive_registry_[0];
|
|
|
|
#ifdef QXK_INIT
|
|
QXK_INIT(); // port-specific initialization of the QXK kernel
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QXK::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 dual-mode QXK kernel</code>
|
|
</operation>
|
|
<!--${QXK::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
|
|
QS_SIG_DICTIONARY(QXK_DELAY_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(QXK_TIMEOUT_SIG, (void *)0);
|
|
|
|
// 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();
|
|
|
|
QXK_priv_.lockCeil = 0U; // unlock the QXK scheduler
|
|
|
|
// activate AOs to process events posted so far
|
|
if (QXK_sched_() != 0U) {
|
|
QXK_activate_();
|
|
}
|
|
|
|
#ifdef QXK_START
|
|
QXK_START(); // port-specific startup of the QXK kernel
|
|
#endif
|
|
|
|
QF_MEM_APP();
|
|
QF_INT_ENABLE();
|
|
|
|
for (;;) { // QXK idle loop...
|
|
QXK_onIdle(); // application-specific QXK idle callback
|
|
}
|
|
|
|
#ifdef __GNUC__ // GNU compiler?
|
|
return 0;
|
|
#endif</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QXK::QActive}-->
|
|
<class name="QActive" superclass="QEP::QAsm">
|
|
<documentation>// QActive active object class customization for QK</documentation>
|
|
<!--${QXK::QActive::start_}-->
|
|
<operation name="start_" type="void" visibility="0x00" properties="0x04">
|
|
<documentation>//! @public @memberof QActive
|
|
|
|
//! @public @memberof QActive</documentation>
|
|
<!--${QXK::QActive::start_::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QXK::QActive::start_::qSto}-->
|
|
<parameter name="qSto" type="QEvt const * * const"/>
|
|
<!--${QXK::QActive::start_::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<!--${QXK::QActive::start_::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QXK::QActive::start_::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
<!--${QXK::QActive::start_::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(300, (!QXK_ISR_CONTEXT_())
|
|
&& ((prioSpec & 0xFF00U) == 0U));
|
|
QF_CRIT_EXIT();
|
|
|
|
me->prio = (uint8_t)(prioSpec & 0xFFU); // QF-prio. of the AO
|
|
me->pthre = 0U; // preemption-threshold NOT used
|
|
QActive_register_(me); // make QF aware of this active object
|
|
|
|
if (stkSto == (void *)0) { // starting basic thread (AO)?
|
|
|
|
QEQueue_init(&me->eQueue, qSto, qLen); // init the built-in queue
|
|
me->osObject = (void *)0; // no private stack for AO
|
|
|
|
// 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 QXK is already running
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
if (QXK_priv_.lockCeil <= QF_MAX_ACTIVE) { // scheduler running?
|
|
if (QXK_sched_() != 0U) { // activation needed?
|
|
QXK_activate_(); // synchronously activate basic-thred(s)
|
|
}
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
}
|
|
else { // starting QXThread
|
|
|
|
// is storage for the queue buffer provided?
|
|
if (qSto != (QEvt const **)0) {
|
|
QEQueue_init(&me->eQueue, qSto, qLen);
|
|
}
|
|
|
|
// extended thread constructor puts the thread handler in place of
|
|
// the top-most initial tran. 'me->super.temp.act'
|
|
QXThread_stackInit_(me, me->super.temp.thr, stkSto, stkSize);
|
|
|
|
// the new thread is not blocked on any object
|
|
me->super.temp.obj = (QMState *)0;
|
|
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// extended-thread becomes ready immediately
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)me->prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
// see if this thread needs to be scheduled in case QXK is running
|
|
if (QXK_priv_.lockCeil <= QF_MAX_ACTIVE) {
|
|
(void)QXK_sched_(); // schedule other threads
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
}</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QXK::QXThread}-->
|
|
<class name="QXThread" superclass="QF::QActive">
|
|
<documentation>//! @class QXThread
|
|
//! @extends QActive</documentation>
|
|
<!--${QXK::QXThread::timeEvt}-->
|
|
<attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXThread</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXThread::dummy}-->
|
|
<attribute name="dummy" type="QXThread const *" visibility="0x02" properties="0x01">
|
|
<documentation>//! @static @private @memberof QXThread
|
|
//! dummy static member to force QM to generate 'struct QXThread'</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXThread::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXThread
|
|
|
|
//! @public @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::ctor::handler}-->
|
|
<parameter name="handler" type="QXThreadHandler const"/>
|
|
<!--${QXK::QXThread::ctor::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<code>union QAsmAttr tmp;
|
|
tmp.thr = handler;
|
|
QActive_ctor(&me->super, tmp.fun); // superclass' ctor
|
|
|
|
me->super.super.state.act = Q_ACTION_CAST(0); // mark as extended thread
|
|
|
|
// instantiate the time-event member in the QXThread class
|
|
QTimeEvt_ctorX(&me->timeEvt, &me->super,
|
|
(enum_t)QXK_DELAY_SIG, tickRate);</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::delay}-->
|
|
<operation name="delay" type="bool" visibility="0x00" properties="0x01">
|
|
<documentation>//! @public @memberof QXThread
|
|
|
|
//! @public @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::delay::nTicks}-->
|
|
<parameter name="nTicks" type="QTimeEvtCtr const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QXThread * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
|
|
|
|
// precondition, this function:
|
|
// - must NOT be called from an ISR;
|
|
// - number of ticks cannot be zero
|
|
// - be called from an extended thread;
|
|
// - the thread must NOT be already blocked on any object.
|
|
Q_REQUIRE_INCRIT(800, (!QXK_ISR_CONTEXT_())
|
|
&& (nTicks != 0U)
|
|
&& (thr != (QXThread *)0)
|
|
&& (thr->super.super.temp.obj == (QMState *)0));
|
|
// - the thread must NOT be holding a scheduler lock.
|
|
Q_REQUIRE_INCRIT(801,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)thr->super.prio);
|
|
|
|
// remember the blocking object
|
|
thr->super.super.temp.obj = QXK_PTR_CAST_(QMState const*, &thr->timeEvt);
|
|
QXThread_teArm_(thr, (enum_t)QXK_DELAY_SIG, nTicks);
|
|
QXThread_block_(thr);
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
QF_CRIT_EXIT_NOP(); // BLOCK here
|
|
|
|
// after unblocking...
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// the blocking object must be the time event
|
|
Q_ASSERT_INCRIT(890, thr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState const*, &thr->timeEvt));
|
|
thr->super.super.temp.obj = (QMState *)0; // clear
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
// signal of zero means that the time event was posted without
|
|
// being canceled.
|
|
return thr->timeEvt.super.sig == 0U;</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::delayCancel}-->
|
|
<operation name="delayCancel" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXThread
|
|
|
|
//! @public @memberof QXThread</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
bool wasArmed;
|
|
if (me->super.super.temp.obj == QXK_PTR_CAST_(QMState*, &me->timeEvt)) {
|
|
wasArmed = QXThread_teDisarm_(me);
|
|
QXThread_unblock_(me);
|
|
}
|
|
else {
|
|
wasArmed = false;
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return wasArmed;</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::queueGet}-->
|
|
<operation name="queueGet" type="QEvt const *" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QXThread
|
|
|
|
//! @static @public @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::queueGet::nTicks}-->
|
|
<parameter name="nTicks" type="QTimeEvtCtr const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QXThread * const thr = QXTHREAD_CAST_(QXK_priv_.curr);
|
|
|
|
// precondition, this function:
|
|
// - must NOT be called from an ISR;
|
|
// - be called from an extended thread;
|
|
// - the thread must NOT be already blocked on any object.
|
|
Q_REQUIRE_INCRIT(500, (!QXK_ISR_CONTEXT_())
|
|
&& (thr != (QXThread *)0)
|
|
&& (thr->super.super.temp.obj == (QMState *)0));
|
|
// - the thread must NOT be holding a scheduler lock.
|
|
Q_REQUIRE_INCRIT(501,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)thr->super.prio);
|
|
|
|
// is the queue empty?
|
|
if (thr->super.eQueue.frontEvt == (QEvt *)0) {
|
|
|
|
// remember the blocking object (the thread's queue)
|
|
thr->super.super.temp.obj
|
|
= QXK_PTR_CAST_(QMState const*, &thr->super.eQueue);
|
|
|
|
QXThread_teArm_(thr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
|
|
QPSet_remove(&QXK_priv_.readySet, (uint_fast8_t)thr->super.prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
(void)QXK_sched_(); // schedule other threads
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
QF_CRIT_EXIT_NOP(); // BLOCK here
|
|
|
|
// after unblocking...
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// the blocking object must be this queue
|
|
Q_ASSERT_INCRIT(510, thr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState const*, &thr->super.eQueue));
|
|
thr->super.super.temp.obj = (QMState *)0; // clear
|
|
}
|
|
|
|
// is the queue not empty?
|
|
QEvt const *e;
|
|
if (thr->super.eQueue.frontEvt != (QEvt *)0) {
|
|
e = thr->super.eQueue.frontEvt; // remove from the front
|
|
QEQueueCtr const nFree= thr->super.eQueue.nFree + 1U;
|
|
thr->super.eQueue.nFree = nFree; // update the # free
|
|
|
|
// any events in the ring buffer?
|
|
if (nFree <= thr->super.eQueue.end) {
|
|
|
|
// remove event from the tail
|
|
thr->super.eQueue.frontEvt =
|
|
thr->super.eQueue.ring[thr->super.eQueue.tail];
|
|
if (thr->super.eQueue.tail == 0U) { // need to wrap?
|
|
thr->super.eQueue.tail = thr->super.eQueue.end; // wrap
|
|
}
|
|
--thr->super.eQueue.tail;
|
|
|
|
QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, thr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of this event
|
|
QS_OBJ_PRE_(&thr->super); // this active object
|
|
QS_2U8_PRE_(QEvt_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(nFree); // # free entries
|
|
QS_END_PRE_()
|
|
}
|
|
else {
|
|
thr->super.eQueue.frontEvt = (QEvt *)0; // empty queue
|
|
|
|
// all entries in the queue must be free (+1 for fronEvt)
|
|
Q_ASSERT_INCRIT(520, nFree == (thr->super.eQueue.end + 1U));
|
|
|
|
QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, thr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_SIG_PRE_(e->sig); // the signal of this event
|
|
QS_OBJ_PRE_(&thr->super); // this active object
|
|
QS_2U8_PRE_(QEvt_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_END_PRE_()
|
|
}
|
|
}
|
|
else { // the queue is still empty -- the timeout must have fired
|
|
e = (QEvt *)0;
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return e;</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::block_}-->
|
|
<operation name="block_" type="void" visibility="0x02" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<code>// NOTE: must be called IN a critical section
|
|
|
|
Q_REQUIRE_INCRIT(600,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)me->super.prio);
|
|
|
|
QPSet_remove(&QXK_priv_.readySet, (uint_fast8_t)me->super.prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
(void)QXK_sched_(); // schedule other threads</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::unblock_}-->
|
|
<operation name="unblock_" type="void" visibility="0x02" properties="0x00">
|
|
<specifiers>const</specifiers>
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<code>// NOTE: must be called IN a critical section
|
|
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)me->super.prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
if ((!QXK_ISR_CONTEXT_()) // not inside ISR?
|
|
&& (QActive_registry_[0] != (QActive *)0)) // kernel started?
|
|
{
|
|
(void)QXK_sched_(); // schedule other threads
|
|
}</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::timeout_}-->
|
|
<operation name="timeout_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::timeout_::act}-->
|
|
<parameter name="act" type="QActive * const"/>
|
|
<code>// NOTE: must be called IN a critical section
|
|
|
|
// the private time event is now disarmed and not in any queue,
|
|
// so it is safe to change its signal. The signal of 0 means
|
|
// that the time event has expired.
|
|
QXTHREAD_CAST_(act)->timeEvt.super.sig = 0U;
|
|
|
|
QXThread_unblock_(QXTHREAD_CAST_(act));</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::teArm_}-->
|
|
<operation name="teArm_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::teArm_::sig}-->
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<!--${QXK::QXThread::teArm_::nTicks}-->
|
|
<parameter name="nTicks" type="QTimeEvtCtr const"/>
|
|
<code>// NOTE: must be called IN a critical section
|
|
|
|
// precondition:
|
|
// - the time event must be unused
|
|
Q_REQUIRE_INCRIT(700, me->timeEvt.ctr == 0U);
|
|
|
|
me->timeEvt.super.sig = (QSignal)sig;
|
|
|
|
if (nTicks != QXTHREAD_NO_TIMEOUT) {
|
|
me->timeEvt.ctr = (QTimeEvtCtr)nTicks;
|
|
me->timeEvt.interval = 0U;
|
|
|
|
// 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 in the list,
|
|
// because un-linking is performed exclusively in QTimeEvt_tick_().
|
|
if ((me->timeEvt.super.refCtr_ & QTE_IS_LINKED) == 0U) {
|
|
uint_fast8_t const tickRate
|
|
= ((uint_fast8_t)me->timeEvt.super.refCtr_ & QTE_TICK_RATE);
|
|
Q_ASSERT_INCRIT(710, tickRate < QF_MAX_TICK_RATE);
|
|
|
|
// mark as linked
|
|
me->timeEvt.super.refCtr_ |= QTE_IS_LINKED;
|
|
|
|
// The time event is initially inserted into the separate
|
|
// "freshly armed" 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_().
|
|
me->timeEvt.next
|
|
= QXK_PTR_CAST_(QTimeEvt*, QTimeEvt_timeEvtHead_[tickRate].act);
|
|
QTimeEvt_timeEvtHead_[tickRate].act = &me->timeEvt;
|
|
}
|
|
}</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::teDisarm_}-->
|
|
<operation name="teDisarm_" type="bool" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<code>// NOTE: must be called IN a critical section
|
|
|
|
bool wasArmed;
|
|
// is the time evt running?
|
|
if (me->timeEvt.ctr != 0U) {
|
|
wasArmed = true;
|
|
me->timeEvt.ctr = 0U; // schedule removal from list
|
|
}
|
|
// the time event was already automatically disarmed
|
|
else {
|
|
wasArmed = false;
|
|
}
|
|
return wasArmed;</code>
|
|
</operation>
|
|
<!--${QXK::QXThread::stackInit_}-->
|
|
<operation name="stackInit_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @private @memberof QXThread
|
|
|
|
//! @private @memberof QXThread</documentation>
|
|
<!--${QXK::QXThread::stackInit_::me}-->
|
|
<parameter name="me" type="QActive * const"/>
|
|
<!--${QXK::QXThread::stackInit_::handler}-->
|
|
<parameter name="handler" type=" QXThreadHandler const"/>
|
|
<!--${QXK::QXThread::stackInit_::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QXK::QXThread::stackInit_::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
</operation>
|
|
</class>
|
|
<!--${QXK::QXSemaphore}-->
|
|
<class name="QXSemaphore">
|
|
<documentation>//! @class QXSemaphore</documentation>
|
|
<!--${QXK::QXSemaphore::waitSet}-->
|
|
<attribute name="waitSet" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXSemaphore</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXSemaphore::count}-->
|
|
<attribute name="count" type="uint8_t volatile" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXSemaphore</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXSemaphore::max_count}-->
|
|
<attribute name="max_count" type="uint8_t" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXSemaphore</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXSemaphore::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXSemaphore
|
|
|
|
//! @public @memberof QXSemaphore</documentation>
|
|
<!--${QXK::QXSemaphore::init::count}-->
|
|
<parameter name="count" type="uint_fast8_t const"/>
|
|
<!--${QXK::QXSemaphore::init::max_count}-->
|
|
<parameter name="max_count" type="uint_fast8_t const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(100, (count <= max_count)
|
|
&& (0U < max_count) && (max_count <= 0xFFU));
|
|
|
|
me->count = (uint8_t)count;
|
|
me->max_count = (uint8_t)max_count;
|
|
QPSet_setEmpty(&me->waitSet);
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();</code>
|
|
</operation>
|
|
<!--${QXK::QXSemaphore::wait}-->
|
|
<operation name="wait" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXSemaphore
|
|
|
|
//! @public @memberof QXSemaphore</documentation>
|
|
<!--${QXK::QXSemaphore::wait::nTicks}-->
|
|
<parameter name="nTicks" type="QTimeEvtCtr const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_priv_.curr);
|
|
|
|
// precondition, this function:
|
|
// - must NOT be called from an ISR;
|
|
// - the semaphore must be initialized
|
|
// - be called from an extended thread;
|
|
// - the thread must NOT be already blocked on any object.
|
|
Q_REQUIRE_INCRIT(200, (!QXK_ISR_CONTEXT_())
|
|
&& (me->max_count > 0U)
|
|
&& (curr != (QXThread *)0)
|
|
&& (curr->super.super.temp.obj == (QMState *)0));
|
|
// - the thread must NOT be holding a scheduler lock.
|
|
Q_REQUIRE_INCRIT(201,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)curr->super.prio);
|
|
|
|
bool taken = true; // assume that the semaphore will be signaled
|
|
if (me->count > 0U) {
|
|
--me->count; // semaphore taken: decrement the count
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_TAKE, curr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(curr->super.prio, me->count);
|
|
QS_END_PRE_()
|
|
}
|
|
else { // semaphore not available -- BLOCK the thread
|
|
uint_fast8_t const p = (uint_fast8_t)curr->super.prio;
|
|
// remove the curr prio from the ready set (will block)
|
|
// and insert to the waiting set on this semaphore
|
|
QPSet_remove(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
QPSet_insert(&me->waitSet, p);
|
|
|
|
// remember the blocking object (this semaphore)
|
|
curr->super.super.temp.obj = QXK_PTR_CAST_(QMState*, me);
|
|
QXThread_teArm_(curr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_BLOCK, curr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(curr->super.prio, me->count);
|
|
QS_END_PRE_()
|
|
|
|
// schedule the next thread if multitasking started
|
|
(void)QXK_sched_(); // schedule other threads
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
QF_CRIT_EXIT_NOP(); // BLOCK here !!!
|
|
|
|
QF_CRIT_ENTRY(); // AFTER unblocking...
|
|
QF_MEM_SYS();
|
|
|
|
// the blocking object must be this semaphore
|
|
Q_ASSERT_INCRIT(240, curr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState*, me));
|
|
|
|
// did the blocking time-out? (signal of zero means that it did)
|
|
if (curr->timeEvt.super.sig == 0U) {
|
|
if (QPSet_hasElement(&me->waitSet, p)) { // still waiting?
|
|
QPSet_remove(&me->waitSet, p); // remove unblocked thread
|
|
taken = false; // the semaphore was NOT taken
|
|
}
|
|
}
|
|
else { // blocking did NOT time out
|
|
// the thread must NOT be waiting on this semaphore
|
|
Q_ASSERT_INCRIT(250, !QPSet_hasElement(&me->waitSet, p));
|
|
}
|
|
curr->super.super.temp.obj = (QMState *)0; // clear blocking obj.
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return taken;</code>
|
|
</operation>
|
|
<!--${QXK::QXSemaphore::tryWait}-->
|
|
<operation name="tryWait" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXSemaphore
|
|
|
|
//! @public @memberof QXSemaphore</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// precondition:
|
|
// - the semaphore must be initialized
|
|
Q_REQUIRE_INCRIT(300, me->max_count > 0U);
|
|
|
|
#ifdef Q_SPY
|
|
QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_priv_.curr);
|
|
#endif // Q_SPY
|
|
|
|
bool taken;
|
|
// is the semaphore available?
|
|
if (me->count > 0U) {
|
|
--me->count;
|
|
taken = true;
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_TAKE, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(curr->prio, me->count);
|
|
QS_END_PRE_()
|
|
}
|
|
else { // the semaphore is NOT available (would block)
|
|
taken = false;
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_BLOCK_ATTEMPT, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(curr->prio, me->count);
|
|
QS_END_PRE_()
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return taken;</code>
|
|
</operation>
|
|
<!--${QXK::QXSemaphore::signal}-->
|
|
<operation name="signal" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXSemaphore
|
|
|
|
//! @public @memberof QXSemaphore</documentation>
|
|
<code>bool signaled = true; // assume that the semaphore will be signaled
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// precondition:
|
|
// - the semaphore must be initialized
|
|
Q_REQUIRE_INCRIT(400, me->max_count > 0U);
|
|
|
|
// any threads blocked on this semaphore?
|
|
if (QPSet_notEmpty(&me->waitSet)) {
|
|
// find the highest-prio. thread waiting on this semaphore
|
|
uint_fast8_t const p = QPSet_findMax(&me->waitSet);
|
|
QXThread * const thr =
|
|
QXK_PTR_CAST_(QXThread*, QActive_registry_[p]);
|
|
|
|
// assert that the tread:
|
|
// - must be registered in QF;
|
|
// - must be extended; and
|
|
// - must be blocked on this semaphore;
|
|
Q_ASSERT_INCRIT(410, (thr != (QXThread *)0)
|
|
&& (thr->super.osObject != (void *)0)
|
|
&& (thr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState*, me)));
|
|
|
|
// disarm the internal time event
|
|
(void)QXThread_teDisarm_(thr);
|
|
|
|
// make the thread ready to run and remove from the wait-list
|
|
QPSet_insert(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
QPSet_remove(&me->waitSet, p);
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_TAKE, thr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(thr->super.prio, me->count);
|
|
QS_END_PRE_()
|
|
|
|
if (!QXK_ISR_CONTEXT_()) { // not inside ISR?
|
|
(void)QXK_sched_(); // schedule other threads
|
|
}
|
|
}
|
|
else if (me->count < me->max_count) {
|
|
++me->count; // increment the semaphore count
|
|
|
|
QS_BEGIN_PRE_(QS_SEM_SIGNAL, 0U)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this semaphore
|
|
QS_2U8_PRE_(0U, me->count);
|
|
QS_END_PRE_()
|
|
}
|
|
else {
|
|
signaled = false; // semaphore NOT signaled
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return signaled;</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QXK::QXMutex}-->
|
|
<class name="QXMutex">
|
|
<documentation>//! @class QXMutex</documentation>
|
|
<!--${QXK::QXMutex::ao}-->
|
|
<attribute name="ao" type="QActive" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXMutex</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXMutex::waitSet}-->
|
|
<attribute name="waitSet" type="QPSet" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QXMutex</documentation>
|
|
</attribute>
|
|
<!--${QXK::QXMutex::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXMutex
|
|
|
|
//! @public @memberof QXMutex</documentation>
|
|
<!--${QXK::QXMutex::init::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
Q_REQUIRE_INCRIT(100, (prioSpec & 0xFF00U) == 0U);
|
|
|
|
me->ao.prio = (uint8_t)(prioSpec & 0xFFU); // QF-prio.
|
|
me->ao.pthre = 0U; // preemption-threshold (not used)
|
|
QActive * const ao = &me->ao;
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
QActive_register_(ao); // register this mutex as AO</code>
|
|
</operation>
|
|
<!--${QXK::QXMutex::lock}-->
|
|
<operation name="lock" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXMutex
|
|
|
|
//! @public @memberof QXMutex</documentation>
|
|
<!--${QXK::QXMutex::lock::nTicks}-->
|
|
<parameter name="nTicks" type="QTimeEvtCtr const"/>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_priv_.curr);
|
|
|
|
// precondition, this mutex operation must:
|
|
// - NOT be called from an ISR;
|
|
// - be called from an eXtended thread;
|
|
// - the mutex-prio. must be in range;
|
|
// - the thread must NOT be already blocked on any object.
|
|
Q_REQUIRE_INCRIT(200, (!QXK_ISR_CONTEXT_())
|
|
&& (curr != (QXThread *)0)
|
|
&& (me->ao.prio <= QF_MAX_ACTIVE)
|
|
&& (curr->super.super.temp.obj == (QMState *)0));
|
|
// also: the thread must NOT be holding a scheduler lock.
|
|
Q_REQUIRE_INCRIT(201,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)curr->super.prio);
|
|
|
|
// is the mutex available?
|
|
bool locked = true; // assume that the mutex will be locked
|
|
if (me->ao.eQueue.nFree == 0U) {
|
|
me->ao.eQueue.nFree = 1U; // mutex lock nesting
|
|
|
|
// also: the newly locked mutex must have no holder yet
|
|
Q_REQUIRE_INCRIT(203, me->ao.osObject == (void *)0);
|
|
|
|
// set the new mutex holder to the curr thread and
|
|
// save the thread's prio in the mutex
|
|
// NOTE: reuse the otherwise unused eQueue data member.
|
|
me->ao.osObject = curr;
|
|
me->ao.eQueue.head = (QEQueueCtr)curr->super.prio;
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_LOCK, curr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// the holder prio. must be lower than that of the mutex
|
|
// and the prio. slot must be occupied by this mutex
|
|
Q_ASSERT_INCRIT(210, (curr->super.prio < me->ao.prio)
|
|
&& (QActive_registry_[me->ao.prio] == &me->ao));
|
|
|
|
// remove the thread's original prio from the ready set
|
|
// and insert the mutex's prio into the ready set
|
|
QPSet_remove(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.eQueue.head);
|
|
QPSet_insert(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
// put the thread into the AO registry in place of the mutex
|
|
QActive_registry_[me->ao.prio] = &curr->super;
|
|
|
|
// set thread's prio to that of the mutex
|
|
curr->super.prio = me->ao.prio;
|
|
}
|
|
}
|
|
// is the mutex locked by this thread already (nested locking)?
|
|
else if (me->ao.osObject == &curr->super) {
|
|
|
|
// the nesting level beyond the arbitrary but high limit
|
|
// most likely means cyclic or recursive locking of a mutex.
|
|
Q_ASSERT_INCRIT(220, me->ao.eQueue.nFree < 0xFFU);
|
|
|
|
++me->ao.eQueue.nFree; // lock one more level
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_LOCK, curr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
}
|
|
else { // the mutex is already locked by a different thread
|
|
// the mutex holder must be valid
|
|
Q_ASSERT_INCRIT(230, me->ao.osObject != (void *)0);
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// the prio slot must be occupied by the thr. holding the mutex
|
|
Q_ASSERT_INCRIT(240, QActive_registry_[me->ao.prio]
|
|
== QACTIVE_CAST_(me->ao.osObject));
|
|
}
|
|
|
|
// remove the curr thread's prio from the ready set (will block)
|
|
// and insert it to the waiting set on this mutex
|
|
uint_fast8_t const p = (uint_fast8_t)curr->super.prio;
|
|
QPSet_remove(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
QPSet_insert(&me->waitSet, p);
|
|
|
|
// set the blocking object (this mutex)
|
|
curr->super.super.temp.obj = QXK_PTR_CAST_(QMState*, me);
|
|
QXThread_teArm_(curr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_BLOCK, curr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, // holder prio
|
|
curr->super.prio); // blocked thread prio
|
|
QS_END_PRE_()
|
|
|
|
// schedule the next thread if multitasking started
|
|
(void)QXK_sched_(); // schedule other threads
|
|
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
QF_CRIT_EXIT_NOP(); // BLOCK here !!!
|
|
|
|
// AFTER unblocking...
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
// the blocking object must be this mutex
|
|
Q_ASSERT_INCRIT(250, curr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState*, me));
|
|
|
|
// did the blocking time-out? (signal of zero means that it did)
|
|
if (curr->timeEvt.super.sig == 0U) {
|
|
if (QPSet_hasElement(&me->waitSet, p)) { // still waiting?
|
|
QPSet_remove(&me->waitSet, p); // remove unblocked thread
|
|
locked = false; // the mutex was NOT locked
|
|
}
|
|
}
|
|
else { // blocking did NOT time out
|
|
// the thread must NOT be waiting on this mutex
|
|
Q_ASSERT_INCRIT(260, !QPSet_hasElement(&me->waitSet, p));
|
|
}
|
|
curr->super.super.temp.obj = (QMState *)0; // clear blocking obj.
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return locked;</code>
|
|
</operation>
|
|
<!--${QXK::QXMutex::tryLock}-->
|
|
<operation name="tryLock" type="bool" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXMutex
|
|
|
|
//! @public @memberof QXMutex</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QActive *curr = QXK_priv_.curr;
|
|
if (curr == (QActive *)0) { // called from a basic thread?
|
|
curr = QActive_registry_[QXK_priv_.actPrio];
|
|
}
|
|
|
|
// precondition, this mutex must:
|
|
// - NOT be called from an ISR;
|
|
// - the calling thread must be valid;
|
|
// - the mutex-prio. must be in range
|
|
Q_REQUIRE_INCRIT(300, (!QXK_ISR_CONTEXT_())
|
|
&& (curr != (QActive *)0)
|
|
&& (me->ao.prio <= QF_MAX_ACTIVE));
|
|
// also: the thread must NOT be holding a scheduler lock.
|
|
Q_REQUIRE_INCRIT(301,
|
|
QXK_priv_.lockHolder != (uint_fast8_t)curr->prio);
|
|
|
|
// is the mutex available?
|
|
if (me->ao.eQueue.nFree == 0U) {
|
|
me->ao.eQueue.nFree = 1U; // mutex lock nesting
|
|
|
|
// also the newly locked mutex must have no holder yet
|
|
Q_REQUIRE_INCRIT(303, me->ao.osObject == (void *)0);
|
|
|
|
// set the new mutex holder to the curr thread and
|
|
// save the thread's prio in the mutex
|
|
// NOTE: reuse the otherwise unused eQueue data member.
|
|
me->ao.osObject = curr;
|
|
me->ao.eQueue.head = (QEQueueCtr)curr->prio;
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_LOCK, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// the holder prio. must be lower than that of the mutex
|
|
// and the prio. slot must be occupied by this mutex
|
|
Q_ASSERT_INCRIT(310, (curr->prio < me->ao.prio)
|
|
&& (QActive_registry_[me->ao.prio] == &me->ao));
|
|
|
|
// remove the thread's original prio from the ready set
|
|
// and insert the mutex's prio into the ready set
|
|
QPSet_remove(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.eQueue.head);
|
|
QPSet_insert(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.prio);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
// put the thread into the AO registry in place of the mutex
|
|
QActive_registry_[me->ao.prio] = curr;
|
|
|
|
// set thread's prio to that of the mutex
|
|
curr->prio = me->ao.prio;
|
|
}
|
|
}
|
|
// is the mutex locked by this thread already (nested locking)?
|
|
else if (me->ao.osObject == curr) {
|
|
// the nesting level must not exceed the specified limit
|
|
Q_ASSERT_INCRIT(320, me->ao.eQueue.nFree < 0xFFU);
|
|
|
|
++me->ao.eQueue.nFree; // lock one more level
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_LOCK, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
}
|
|
else { // the mutex is already locked by a different thread
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// the prio slot must be occupied by the thr. holding the mutex
|
|
Q_ASSERT_INCRIT(330, QActive_registry_[me->ao.prio]
|
|
== QACTIVE_CAST_(me->ao.osObject));
|
|
}
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_BLOCK_ATTEMPT, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, // holder prio
|
|
curr->prio); // trying thread prio
|
|
QS_END_PRE_()
|
|
|
|
curr = (QActive *)0; // means that mutex is NOT available
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
return curr != (QActive *)0;</code>
|
|
</operation>
|
|
<!--${QXK::QXMutex::unlock}-->
|
|
<operation name="unlock" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QXMutex
|
|
|
|
//! @public @memberof QXMutex</documentation>
|
|
<code>QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
QActive *curr = QXK_priv_.curr;
|
|
if (curr == (QActive *)0) { // called from a basic thread?
|
|
curr = QActive_registry_[QXK_priv_.actPrio];
|
|
}
|
|
|
|
Q_REQUIRE_INCRIT(400, (!QXK_ISR_CONTEXT_())
|
|
&& (curr != (QActive *)0));
|
|
Q_REQUIRE_INCRIT(401, me->ao.eQueue.nFree > 0U);
|
|
Q_REQUIRE_INCRIT(403, me->ao.osObject == curr);
|
|
|
|
// is this the last nesting level?
|
|
if (me->ao.eQueue.nFree == 1U) {
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// prio. must be in range
|
|
Q_ASSERT_INCRIT(410, me->ao.prio < QF_MAX_ACTIVE);
|
|
|
|
// restore the holding thread's prio from the mutex
|
|
curr->prio = (uint8_t)me->ao.eQueue.head;
|
|
|
|
// put the mutex back into the AO registry
|
|
QActive_registry_[me->ao.prio] = &me->ao;
|
|
|
|
// remove the mutex' prio from the ready set
|
|
// and insert the original thread's prio.
|
|
QPSet_remove(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.prio);
|
|
QPSet_insert(&QXK_priv_.readySet,
|
|
(uint_fast8_t)me->ao.eQueue.head);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
}
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_UNLOCK, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, // holder prio
|
|
0U); // nesting
|
|
QS_END_PRE_()
|
|
|
|
// are any other threads waiting on this mutex?
|
|
if (QPSet_notEmpty(&me->waitSet)) {
|
|
// find the highest-prio. thread waiting on this mutex
|
|
uint_fast8_t const p = QPSet_findMax(&me->waitSet);
|
|
|
|
// remove this thread from waiting on the mutex
|
|
// and insert it into the ready set.
|
|
QPSet_remove(&me->waitSet, p);
|
|
QPSet_insert(&QXK_priv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis);
|
|
#endif
|
|
|
|
QXThread * const thr =
|
|
QXK_PTR_CAST_(QXThread*, QActive_registry_[p]);
|
|
|
|
// the waiting thread must:
|
|
// - be registered in QF
|
|
// - have the prio. corresponding to the registration
|
|
// - be an extended thread
|
|
// - be blocked on this mutex
|
|
Q_ASSERT_INCRIT(420, (thr != (QXThread *)0)
|
|
&& (thr->super.prio == (uint8_t)p)
|
|
&& (thr->super.super.state.act == Q_ACTION_CAST(0))
|
|
&& (thr->super.super.temp.obj
|
|
== QXK_PTR_CAST_(QMState*, me)));
|
|
|
|
// disarm the internal time event
|
|
(void)QXThread_teDisarm_(thr);
|
|
|
|
// set the new mutex holder to the curr thread and
|
|
// save the thread's prio in the mutex
|
|
// NOTE: reuse the otherwise unused eQueue data member.
|
|
me->ao.osObject = thr;
|
|
me->ao.eQueue.head = (QEQueueCtr)thr->super.prio;
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_LOCK, thr->super.prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// the holder prio. must be lower than that of the mutex
|
|
Q_ASSERT_INCRIT(430, (me->ao.prio < QF_MAX_ACTIVE)
|
|
&& (thr->super.prio < me->ao.prio));
|
|
|
|
// put the thread into AO registry in place of the mutex
|
|
QActive_registry_[me->ao.prio] = &thr->super;
|
|
}
|
|
}
|
|
else { // no threads are waiting for this mutex
|
|
me->ao.eQueue.nFree = 0U; // free up the nesting count
|
|
|
|
// the mutex no longer held by any thread
|
|
me->ao.osObject = (void *)0;
|
|
me->ao.eQueue.head = 0U;
|
|
me->ao.eQueue.tail = 0U;
|
|
|
|
if (me->ao.prio != 0U) { // prio.-ceiling protocol used?
|
|
// put the mutex back at the original mutex slot
|
|
QActive_registry_[me->ao.prio] =
|
|
QXK_PTR_CAST_(QActive*, me);
|
|
}
|
|
}
|
|
|
|
// schedule the next thread if multitasking started
|
|
if (QXK_sched_() != 0U) { // activation needed?
|
|
QXK_activate_(); // synchronously activate basic-thred(s)
|
|
}
|
|
}
|
|
else { // releasing one level of nested mutex lock
|
|
--me->ao.eQueue.nFree; // unlock one level
|
|
|
|
QS_BEGIN_PRE_(QS_MTX_UNLOCK_ATTEMPT, curr->prio)
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_OBJ_PRE_(me); // this mutex
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.head); // holder prio
|
|
QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); // nesting
|
|
QS_END_PRE_()
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<!--${QXK-macros}-->
|
|
<package name="QXK-macros" stereotype="0x02">
|
|
<!--${QXK-macros::QXTHREAD_START}-->
|
|
<operation name="QXTHREAD_START" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QXK-macros::QXTHREAD_START::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QXK-macros::QXTHREAD_START::prioSpec_}-->
|
|
<parameter name="prioSpec_" type="QPrioSpec const"/>
|
|
<!--${QXK-macros::QXTHREAD_START::qSto_}-->
|
|
<parameter name="qSto_" type="QEvt const * *"/>
|
|
<!--${QXK-macros::QXTHREAD_START::qLen_}-->
|
|
<parameter name="qLen_" type="uint_fast16_t"/>
|
|
<!--${QXK-macros::QXTHREAD_START::stkSto_}-->
|
|
<parameter name="stkSto_" type="void *"/>
|
|
<!--${QXK-macros::QXTHREAD_START::stkSize_}-->
|
|
<parameter name="stkSize_" type="uint_fast16_t"/>
|
|
<!--${QXK-macros::QXTHREAD_START::par_}-->
|
|
<parameter name="par_" type="void const *"/>
|
|
<code>QACTIVE_START((me_), (prioSpec_), (qSto_), (qLen_), \
|
|
(stkSto_), (stkSize_), (par_))</code>
|
|
</operation>
|
|
<!--${QXK-macros::QXTHREAD_POST_X}-->
|
|
<operation name="QXTHREAD_POST_X" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QXK-macros::QXTHREAD_POST_X::me_}-->
|
|
<parameter name="me_" type="<QActive subclass *>"/>
|
|
<!--${QXK-macros::QXTHREAD_POST_X::e_}-->
|
|
<parameter name="e_" type="QEvt const *"/>
|
|
<!--${QXK-macros::QXTHREAD_POST_X::margin_}-->
|
|
<parameter name="margin_" type="uint16_t"/>
|
|
<!--${QXK-macros::QXTHREAD_POST_X::sender_}-->
|
|
<parameter name="sender_" type="<sender *>"/>
|
|
<code>\
|
|
QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_))</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QXK-impl}-->
|
|
<package name="QXK-impl" stereotype="0x02">
|
|
<!--${QXK-impl::QF_SCHED_STAT_}-->
|
|
<attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
|
|
<code>QSchedStatus lockStat_;</code>
|
|
</attribute>
|
|
<!--${QXK-impl::QF_SCHED_LOCK_}-->
|
|
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QF_SCHED_LOCK_::ceil_}-->
|
|
<parameter name="ceil_" type="uint_fast8_t"/>
|
|
<code>do { \
|
|
if (QXK_ISR_CONTEXT_()) { \
|
|
lockStat_ = 0xFFU; \
|
|
} else { \
|
|
lockStat_ = QXK_schedLock((ceil_)); \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QF_SCHED_UNLOCK_}-->
|
|
<operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
|
|
<code>do { \
|
|
if (lockStat_ != 0xFFU) { \
|
|
QXK_schedUnlock(lockStat_); \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_WAIT_}-->
|
|
<operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_W~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>\
|
|
Q_ASSERT_INCRIT(310, (me_)->eQueue.frontEvt != (QEvt *)0)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?ndef Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>do { \
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)(me_)->prio); \
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis); \
|
|
if (!QXK_ISR_CONTEXT_()) { \
|
|
if (QXK_sched_() != 0U) { \
|
|
QXK_activate_(); \
|
|
} \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
|
|
<operation name="QACTIVE_EQUEUE_SIGNAL_?def Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QACTIVE_EQUEUE_S~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>do { \
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)(me_)->prio); \
|
|
if (!QXK_ISR_CONTEXT_()) { \
|
|
if (QXK_sched_() != 0U) { \
|
|
QXK_activate_(); \
|
|
} \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QXTHREAD_EQUEUE_SIGNAL_}-->
|
|
<operation name="QXTHREAD_EQUEUE_SIGNAL_?ndef Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QXTHREAD_EQUEUE_~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>do { \
|
|
if (me->super.temp.obj == QXK_PTR_CAST_(QMState*, &me->eQueue)) { \
|
|
(void)QXThread_teDisarm_(QXTHREAD_CAST_(me)); \
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)me->prio); \
|
|
QPSet_update_(&QXK_priv_.readySet, &QXK_priv_.readySet_dis); \
|
|
if (!QXK_ISR_CONTEXT_()) { \
|
|
(void)QXK_sched_(); \
|
|
} \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QXTHREAD_EQUEUE_SIGNAL_}-->
|
|
<operation name="QXTHREAD_EQUEUE_SIGNAL_?def Q_UNSAFE" type="" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QXTHREAD_EQUEUE_~::me_}-->
|
|
<parameter name="me_" type="QActive *"/>
|
|
<code>do { \
|
|
if (me->super.temp.obj == QXK_PTR_CAST_(QMState*, &me->eQueue)) { \
|
|
(void)QXThread_teDisarm_(QXTHREAD_CAST_(me)); \
|
|
QPSet_insert(&QXK_priv_.readySet, (uint_fast8_t)me->prio); \
|
|
if (!QXK_ISR_CONTEXT_()) { \
|
|
(void)QXK_sched_(); \
|
|
} \
|
|
} \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QXK-impl::QXK_PTR_CAST_}-->
|
|
<operation name="QXK_PTR_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
|
|
<specifiers><type_></specifiers>
|
|
<!--${QXK-impl::QXK_PTR_CAST_::type_}-->
|
|
<parameter name="type_" type="<QXK obj>"/>
|
|
<!--${QXK-impl::QXK_PTR_CAST_::ptr_}-->
|
|
<parameter name="ptr_" type="QActive *"/>
|
|
<code>((type_)(ptr_))</code>
|
|
</operation>
|
|
<!--${QXK-impl::QXTHREAD_CAST_}-->
|
|
<operation name="QXTHREAD_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
|
|
<!--${QXK-impl::QXTHREAD_CAST_::ptr_}-->
|
|
<parameter name="ptr_" type="QActive *"/>
|
|
<code>((QXThread *)(ptr_))</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QS}-->
|
|
<package name="QS" stereotype="0x05">
|
|
<!--${QS::types}-->
|
|
<package name="types" stereotype="0x02">
|
|
<!--${QS::types::QS}-->
|
|
<attribute name="QS" type="typedef struct" visibility="0x04" properties="0x00">
|
|
<documentation>//! @class QS</documentation>
|
|
<code>{
|
|
//! @cond INTERNAL
|
|
uint8_t dummy;
|
|
//! @endcond
|
|
} QS;</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyPre}-->
|
|
<attribute name="QSpyPre" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! pre-defined QS record IDs</documentation>
|
|
<code>{
|
|
// [0] QS session (not maskable)
|
|
QS_EMPTY, //!< QS record for cleanly starting a session
|
|
|
|
// [1] SM records
|
|
QS_QEP_STATE_ENTRY, //!< a state was entered
|
|
QS_QEP_STATE_EXIT, //!< a state was exited
|
|
QS_QEP_STATE_INIT, //!< an initial transition was taken in a state
|
|
QS_QEP_INIT_TRAN, //!< the top-most initial transition was taken
|
|
QS_QEP_INTERN_TRAN, //!< an internal transition was taken
|
|
QS_QEP_TRAN, //!< a regular transition was taken
|
|
QS_QEP_IGNORED, //!< an event was ignored (silently discarded)
|
|
QS_QEP_DISPATCH, //!< an event was dispatched (begin of RTC step)
|
|
QS_QEP_UNHANDLED, //!< an event was un-handled due to a guard
|
|
|
|
// [10] Active Object (AO) records
|
|
QS_QF_ACTIVE_DEFER, //!< AO deferred an event
|
|
QS_QF_ACTIVE_RECALL, //!< AO recalled an event
|
|
QS_QF_ACTIVE_SUBSCRIBE, //!< an AO subscribed to an event
|
|
QS_QF_ACTIVE_UNSUBSCRIBE, //!< an AO unsubscribed to an event
|
|
QS_QF_ACTIVE_POST, //!< an event was posted (FIFO) directly to AO
|
|
QS_QF_ACTIVE_POST_LIFO, //!< an event was posted (LIFO) directly to AO
|
|
QS_QF_ACTIVE_GET, //!< AO got an event and its queue is not empty
|
|
QS_QF_ACTIVE_GET_LAST,//!< AO got an event and its queue is empty
|
|
QS_QF_ACTIVE_RECALL_ATTEMPT, //!< AO attempted to recall an event
|
|
|
|
// [19] Event Queue (EQ) records
|
|
QS_QF_EQUEUE_POST, //!< an event was posted (FIFO) to a raw queue
|
|
QS_QF_EQUEUE_POST_LIFO, //!< an event was posted (LIFO) to a raw queue
|
|
QS_QF_EQUEUE_GET, //!< get an event and queue still not empty
|
|
QS_QF_EQUEUE_GET_LAST,//!< get the last event from the queue
|
|
|
|
// [23] Framework (QF) records
|
|
QS_QF_NEW_ATTEMPT, //!< an attempt to allocate an event failed
|
|
|
|
// [24] Memory Pool (MP) records
|
|
QS_QF_MPOOL_GET, //!< a memory block was removed from memory pool
|
|
QS_QF_MPOOL_PUT, //!< a memory block was returned to memory pool
|
|
|
|
// [26] Additional Framework (QF) records
|
|
QS_QF_PUBLISH, //!< an event was published to active objects
|
|
QS_QF_NEW_REF, //!< new event reference was created
|
|
QS_QF_NEW, //!< new event was created
|
|
QS_QF_GC_ATTEMPT, //!< garbage collection attempt
|
|
QS_QF_GC, //!< garbage collection
|
|
QS_QF_TICK, //!< QTimeEvt tick was called
|
|
|
|
// [32] Time Event (TE) records
|
|
QS_QF_TIMEEVT_ARM, //!< a time event was armed
|
|
QS_QF_TIMEEVT_AUTO_DISARM, //!< a time event expired and was disarmed
|
|
QS_QF_TIMEEVT_DISARM_ATTEMPT,//!< attempt to disarm a disarmed QTimeEvt
|
|
QS_QF_TIMEEVT_DISARM, //!< true disarming of an armed time event
|
|
QS_QF_TIMEEVT_REARM, //!< rearming of a time event
|
|
QS_QF_TIMEEVT_POST, //!< a time event posted itself directly to an AO
|
|
|
|
// [38] Additional Framework (QF) records
|
|
QS_QF_DELETE_REF, //!< an event reference is about to be deleted
|
|
QS_QF_CRIT_ENTRY, //!< critical section was entered
|
|
QS_QF_CRIT_EXIT, //!< critical section was exited
|
|
QS_QF_ISR_ENTRY, //!< an ISR was entered
|
|
QS_QF_ISR_EXIT, //!< an ISR was exited
|
|
QS_QF_INT_DISABLE, //!< interrupts were disabled
|
|
QS_QF_INT_ENABLE, //!< interrupts were enabled
|
|
|
|
// [45] Additional Active Object (AO) records
|
|
QS_QF_ACTIVE_POST_ATTEMPT,//!< attempt to post an evt to AO failed
|
|
|
|
// [46] Additional Event Queue (EQ) records
|
|
QS_QF_EQUEUE_POST_ATTEMPT,//!< attempt to post evt to QEQueue failed
|
|
|
|
// [47] Additional Memory Pool (MP) records
|
|
QS_QF_MPOOL_GET_ATTEMPT, //!< attempt to get a memory block failed
|
|
|
|
// [48] Scheduler (SC) records
|
|
QS_SCHED_PREEMPT, //!< scheduler asynchronously preempted a task
|
|
QS_SCHED_RESTORE, //!< scheduler restored preempted task
|
|
QS_SCHED_LOCK, //!< scheduler was locked
|
|
QS_SCHED_UNLOCK, //!< scheduler was unlocked
|
|
QS_SCHED_NEXT, //!< scheduler started next task
|
|
QS_SCHED_IDLE, //!< scheduler restored the idle task
|
|
|
|
// [54] Miscellaneous QS records (not maskable)
|
|
QS_ENUM_DICT, //!< enumeration dictionary entry
|
|
|
|
// [55] Additional QEP records
|
|
QS_QEP_TRAN_HIST, //!< a tran to history was taken
|
|
QS_QEP_TRAN_EP, //!< a tran to entry point into a submachine
|
|
QS_QEP_TRAN_XP, //!< a tran to exit point out of a submachine
|
|
|
|
// [58] Miscellaneous QS records (not maskable)
|
|
QS_TEST_PAUSED, //!< test has been paused
|
|
QS_TEST_PROBE_GET, //!< reports that Test-Probe has been used
|
|
QS_SIG_DICT, //!< signal dictionary entry
|
|
QS_OBJ_DICT, //!< object dictionary entry
|
|
QS_FUN_DICT, //!< function dictionary entry
|
|
QS_USR_DICT, //!< user QS record dictionary entry
|
|
QS_TARGET_INFO, //!< reports the Target information
|
|
QS_TARGET_DONE, //!< reports completion of a user callback
|
|
QS_RX_STATUS, //!< reports QS data receive status
|
|
QS_QUERY_DATA, //!< reports the data from "current object" query
|
|
QS_PEEK_DATA, //!< reports the data from the PEEK query
|
|
QS_ASSERT_FAIL, //!< assertion failed in the code
|
|
QS_QF_RUN, //!< QF_run() was entered
|
|
|
|
// [71] Semaphore (SEM) records
|
|
QS_SEM_TAKE, //!< a semaphore was taken by a thread
|
|
QS_SEM_BLOCK, //!< a semaphore blocked a thread
|
|
QS_SEM_SIGNAL, //!< a semaphore was signaled
|
|
QS_SEM_BLOCK_ATTEMPT, //!< a semaphore blocked was attempted
|
|
|
|
// [75] Mutex (MTX) records
|
|
QS_MTX_LOCK, //!< a mutex was locked
|
|
QS_MTX_BLOCK, //!< a mutex blocked a thread
|
|
QS_MTX_UNLOCK, //!< a mutex was unlocked
|
|
QS_MTX_LOCK_ATTEMPT, //!< a mutex lock was attempted
|
|
QS_MTX_BLOCK_ATTEMPT, //!< a mutex blocking was attempted
|
|
QS_MTX_UNLOCK_ATTEMPT,//!< a mutex unlock was attempted
|
|
|
|
// [81]
|
|
QS_PRE_MAX //!< the # predefined signals
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyGroups}-->
|
|
<attribute name="QSpyGroups" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! QS-TX record groups for QS_GLB_FILTER()</documentation>
|
|
<code>{
|
|
QS_ALL_RECORDS = 0xF0,//!< all maskable QS records
|
|
QS_SM_RECORDS, //!< State Machine QS records
|
|
QS_AO_RECORDS, //!< Active Object QS records
|
|
QS_EQ_RECORDS, //!< Event Queues QS records
|
|
QS_MP_RECORDS, //!< Memory Pools QS records
|
|
QS_TE_RECORDS, //!< Time Events QS records
|
|
QS_QF_RECORDS, //!< QF QS records
|
|
QS_SC_RECORDS, //!< Scheduler QS records
|
|
QS_SEM_RECORDS, //!< Semaphore QS records
|
|
QS_MTX_RECORDS, //!< Mutex QS records
|
|
QS_U0_RECORDS, //!< User Group 100-104 records
|
|
QS_U1_RECORDS, //!< User Group 105-109 records
|
|
QS_U2_RECORDS, //!< User Group 110-114 records
|
|
QS_U3_RECORDS, //!< User Group 115-119 records
|
|
QS_U4_RECORDS, //!< User Group 120-124 records
|
|
QS_UA_RECORDS //!< All User records
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyUserOffsets}-->
|
|
<attribute name="QSpyUserOffsets" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! QS user record group offsets for QS_GLB_FILTER()</documentation>
|
|
<code>{
|
|
QS_USER = 100, //!< the first record available to QS users
|
|
QS_USER0 = QS_USER, //!< offset for User Group 0
|
|
QS_USER1 = (enum_t)QS_USER0 + 5, //!< offset for User Group 1
|
|
QS_USER2 = (enum_t)QS_USER1 + 5, //!< offset for User Group 2
|
|
QS_USER3 = (enum_t)QS_USER2 + 5, //!< offset for User Group 3
|
|
QS_USER4 = (enum_t)QS_USER3 + 5 //!< offset for User Group 4
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyIdOffsets}-->
|
|
<attribute name="QSpyIdOffsets" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! QS ID offsets for QS_LOC_FILTER()</documentation>
|
|
<code>{
|
|
QS_AO_ID = 0, //!< offset for AO priorities
|
|
QS_EP_ID = 64, //!< offset for event-pool IDs
|
|
QS_EQ_ID = 80, //!< offset for event-queue IDs
|
|
QS_AP_ID = 96 //!< offset for Application-specific IDs
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyIdGroups}-->
|
|
<attribute name="QSpyIdGroups" type="enum" visibility="0x04" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! QS ID groups for QS_LOC_FILTER()</documentation>
|
|
<code>{
|
|
QS_ALL_IDS = 0xF0, //!< all QS IDs
|
|
QS_AO_IDS = 0x80 + (enum_t)QS_AO_ID, //!< AO IDs (priorities)
|
|
QS_EP_IDS = 0x80 + (enum_t)QS_EP_ID, //!< event-pool IDs
|
|
QS_EQ_IDS = 0x80 + (enum_t)QS_EQ_ID, //!< event-queue IDs
|
|
QS_AP_IDS = 0x80 + (enum_t)QS_AP_ID //!< Application-specific IDs
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::types::QSpyId}-->
|
|
<attribute name="QSpyId" type="typedef struct { uint8_t prio; }" visibility="0x04" properties="0x00">
|
|
<documentation>//! @struct QSpyId</documentation>
|
|
</attribute>
|
|
<!--${QS::types::QSpyFunPtr}-->
|
|
<attribute name="QSpyFunPtr" type="typedef void (*" visibility="0x04" properties="0x01">
|
|
<documentation>//! @static @private @memberof QS</documentation>
|
|
<code>)(void);</code>
|
|
</attribute>
|
|
<!--${QS::types::QSCtr}-->
|
|
<attribute name="QSCtr? (QS_CTR_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSCtr}-->
|
|
<attribute name="QSCtr? (QS_CTR_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSTimeCtr}-->
|
|
<attribute name="QSTimeCtr? (QS_TIME_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSTimeCtr}-->
|
|
<attribute name="QSTimeCtr? (QS_TIME_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSFun}-->
|
|
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSFun}-->
|
|
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
|
|
<!--${QS::types::QSFun}-->
|
|
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 8U)" type="typedef uint64_t" visibility="0x04" properties="0x00"/>
|
|
</package>
|
|
<!--${QS::filters}-->
|
|
<package name="filters" stereotype="0x02" namespace="QS_">
|
|
<!--${QS::filters::Filter}-->
|
|
<class name="Filter">
|
|
<documentation>//! @struct QS_Filter</documentation>
|
|
<!--${QS::filters::Filter::glb[16]}-->
|
|
<attribute name="glb[16]" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<!--${QS::filters::Filter::loc[16]}-->
|
|
<attribute name="loc[16]" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
<!--${QS::filters::filt_}-->
|
|
<attribute name="filt_" type="QS_Filter" visibility="0x01" properties="0x01">
|
|
<documentation>//! @static @private @memberof QS</documentation>
|
|
</attribute>
|
|
</package>
|
|
<!--${QS::QS-TX}-->
|
|
<package name="QS-TX" stereotype="0x02" namespace="QS_">
|
|
<!--${QS::QS-TX::preType}-->
|
|
<attribute name="preType" type="enum" visibility="0x04" properties="0x01">
|
|
<documentation>//! Enumerates data elements for app-specific trace records</documentation>
|
|
<code>{
|
|
QS_I8_ENUM_T, //!< signed 8-bit integer or enum format
|
|
QS_U8_T, //!< unsigned 8-bit integer format
|
|
QS_I16_T, //!< signed 16-bit integer format
|
|
QS_U16_T, //!< unsigned 16-bit integer format
|
|
QS_I32_T, //!< signed 32-bit integer format
|
|
QS_U32_T, //!< unsigned 32-bit integer format
|
|
QS_F32_T, //!< 32-bit floating point format
|
|
QS_F64_T, //!< 64-bit floating point format
|
|
QS_STR_T, //!< zero-terminated ASCII string format
|
|
QS_MEM_T, //!< up to 255-bytes memory block format
|
|
QS_SIG_T, //!< event signal format
|
|
QS_OBJ_T, //!< object pointer format
|
|
QS_FUN_T, //!< function pointer format
|
|
QS_I64_T, //!< signed 64-bit integer format
|
|
QS_U64_T //!< unsigned 64-bit integer format
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::QS-TX::initBuf}-->
|
|
<operation name="initBuf" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-TX::initBuf::sto}-->
|
|
<parameter name="sto" type="uint8_t * const"/>
|
|
<!--${QS::QS-TX::initBuf::stoSize}-->
|
|
<parameter name="stoSize" type="uint_fast32_t const"/>
|
|
<code>QS_priv_.buf = &sto[0];
|
|
QS_priv_.end = (QSCtr)stoSize;
|
|
QS_priv_.head = 0U;
|
|
QS_priv_.tail = 0U;
|
|
QS_priv_.used = 0U;
|
|
QS_priv_.seq = 0U;
|
|
QS_priv_.chksum = 0U;
|
|
QS_priv_.critNest = 0U;
|
|
|
|
QS_glbFilter_(-(int_fast16_t)QS_ALL_RECORDS); // all global filters OFF
|
|
QS_locFilter_((int_fast16_t)QS_ALL_IDS); // all local filters ON
|
|
QS_priv_.locFilter_AP = (void *)0; // deprecated "AP-filter"
|
|
|
|
// produce an empty record to "flush" the QS trace buffer
|
|
QS_beginRec_((uint_fast8_t)QS_EMPTY);
|
|
QS_endRec_();
|
|
|
|
// produce the reset record to inform QSPY of a new session
|
|
QS_target_info_pre_(0xFFU);
|
|
|
|
// hold off flushing after successfull initialization (see QS_INIT())</code>
|
|
</operation>
|
|
<!--${QS::QS-TX::getByte}-->
|
|
<operation name="getByte" type="uint16_t" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<code>uint16_t ret;
|
|
if (QS_priv_.used == 0U) {
|
|
ret = QS_EOD; // set End-Of-Data
|
|
}
|
|
else {
|
|
uint8_t const * const buf = QS_priv_.buf; // put in a temporary
|
|
QSCtr tail = QS_priv_.tail; // put in a temporary (register)
|
|
ret = (uint16_t)buf[tail]; // set the byte to return
|
|
++tail; // advance the tail
|
|
if (tail == QS_priv_.end) { // tail wrap around?
|
|
tail = 0U;
|
|
}
|
|
QS_priv_.tail = tail; // update the tail
|
|
--QS_priv_.used; // one less byte used
|
|
}
|
|
return ret; // return the byte or EOD</code>
|
|
</operation>
|
|
<!--${QS::QS-TX::getBlock}-->
|
|
<operation name="getBlock" type="uint8_t const *" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-TX::getBlock::pNbytes}-->
|
|
<parameter name="pNbytes" type="uint16_t * const"/>
|
|
<code>QSCtr const used = QS_priv_.used; // put in a temporary (register)
|
|
uint8_t const *buf;
|
|
|
|
// any bytes used in the ring buffer?
|
|
if (used != 0U) {
|
|
QSCtr tail = QS_priv_.tail; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
QSCtr n = (QSCtr)(end - tail);
|
|
if (n > used) {
|
|
n = used;
|
|
}
|
|
if (n > (QSCtr)(*pNbytes)) {
|
|
n = (QSCtr)(*pNbytes);
|
|
}
|
|
*pNbytes = (uint16_t)n; // n-bytes available
|
|
buf = &QS_priv_.buf[tail]; // the bytes are at the tail
|
|
|
|
QS_priv_.used = (QSCtr)(used - n);
|
|
tail += n;
|
|
if (tail == end) {
|
|
tail = 0U;
|
|
}
|
|
QS_priv_.tail = tail;
|
|
}
|
|
else { // no bytes available
|
|
*pNbytes = 0U; // no bytes available right now
|
|
buf = (uint8_t *)0; // no bytes available right now
|
|
}
|
|
return buf;</code>
|
|
</operation>
|
|
<!--${QS::QS-TX::doOutput}-->
|
|
<operation name="doOutput" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QS-TX::onStartup}-->
|
|
<operation name="onStartup" type="uint8_t" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-TX::onStartup::arg}-->
|
|
<parameter name="arg" type="void const *"/>
|
|
</operation>
|
|
<!--${QS::QS-TX::onCleanup}-->
|
|
<operation name="onCleanup" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QS-TX::onFlush}-->
|
|
<operation name="onFlush" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QS-TX::onGetTime}-->
|
|
<operation name="onGetTime" type="QSTimeCtr" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
</package>
|
|
<!--${QS::QS-RX}-->
|
|
<package name="QS-RX" stereotype="0x02" namespace="QS_">
|
|
<!--${QS::QS-RX::QSpyObjKind}-->
|
|
<attribute name="QSpyObjKind" type="enum" visibility="0x04" properties="0x01">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! Kinds of objects used in QS-RX</documentation>
|
|
<code>{
|
|
SM_OBJ, //!< state machine object
|
|
AO_OBJ, //!< active object
|
|
MP_OBJ, //!< event pool object
|
|
EQ_OBJ, //!< raw queue object
|
|
TE_OBJ, //!< time event object
|
|
AP_OBJ, //!< generic Application-specific object
|
|
MAX_OBJ
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::QS-RX::OSpyObjComb}-->
|
|
<attribute name="OSpyObjComb" type="enum" visibility="0x04" properties="0x01">
|
|
<documentation>//! @static @public @memberof QS
|
|
//! Object combinations for QS-RX</documentation>
|
|
<code>{
|
|
SM_AO_OBJ = (enum_t)MAX_OBJ //!< combination of SM and AO
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::QS-RX::rxInitBuf}-->
|
|
<operation name="rxInitBuf" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-RX::rxInitBuf::sto}-->
|
|
<parameter name="sto" type="uint8_t * const"/>
|
|
<!--${QS::QS-RX::rxInitBuf::stoSize}-->
|
|
<parameter name="stoSize" type="uint16_t const"/>
|
|
<code>QS_rxPriv_.buf = &sto[0];
|
|
QS_rxPriv_.end = (QSCtr)stoSize;
|
|
QS_rxPriv_.head = 0U;
|
|
QS_rxPriv_.tail = 0U;
|
|
|
|
QS_rxPriv_.currObj[SM_OBJ] = (void *)0;
|
|
QS_rxPriv_.currObj[AO_OBJ] = (void *)0;
|
|
QS_rxPriv_.currObj[MP_OBJ] = (void *)0;
|
|
QS_rxPriv_.currObj[EQ_OBJ] = (void *)0;
|
|
QS_rxPriv_.currObj[TE_OBJ] = (void *)0;
|
|
QS_rxPriv_.currObj[AP_OBJ] = (void *)0;
|
|
|
|
QS_RX_TRAN_(WAIT4_SEQ);
|
|
l_rx.esc = 0U;
|
|
l_rx.seq = 0U;
|
|
l_rx.chksum = 0U;
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
|
|
QS_OBJ_PRE_(&QS_rxPriv_);
|
|
QS_STR_PRE_("QS_RX");
|
|
QS_endRec_();
|
|
// no QS_REC_DONE(), because QS is not running yet
|
|
|
|
#ifdef Q_UTEST
|
|
QS_tstPriv_.tpNum = 0U;
|
|
QS_tstPriv_.testTime = 0U;
|
|
#endif // Q_UTEST</code>
|
|
</operation>
|
|
<!--${QS::QS-RX::rxPut}-->
|
|
<operation name="rxPut" type="bool" visibility="0x00" properties="0x02">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-RX::rxPut::b}-->
|
|
<parameter name="b" type="uint8_t const"/>
|
|
<code>// NOTE: does not need critical section
|
|
// But requires system-level memory access (QF_MEM_SYS()).
|
|
|
|
QSCtr head = QS_rxPriv_.head + 1U;
|
|
if (head == QS_rxPriv_.end) {
|
|
head = 0U;
|
|
}
|
|
if (head != QS_rxPriv_.tail) { // buffer NOT full?
|
|
QS_rxPriv_.buf[QS_rxPriv_.head] = b;
|
|
QS_rxPriv_.head = head; // update the head to a *valid* index
|
|
return true; // byte placed in the buffer
|
|
}
|
|
else {
|
|
return false; // byte NOT placed in the buffer
|
|
}</code>
|
|
</operation>
|
|
<!--${QS::QS-RX::rxParse}-->
|
|
<operation name="rxParse" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<code>// NOTE: Must be called IN critical section.
|
|
// Also requires system-level memory access (QF_MEM_SYS()).
|
|
|
|
QSCtr tail = QS_rxPriv_.tail;
|
|
while (QS_rxPriv_.head != tail) { // QS-RX buffer NOT empty?
|
|
uint8_t b = QS_rxPriv_.buf[tail];
|
|
|
|
++tail;
|
|
if (tail == QS_rxPriv_.end) {
|
|
tail = 0U;
|
|
}
|
|
QS_rxPriv_.tail = tail; // update the tail to a *valid* index
|
|
|
|
if (l_rx.esc != 0U) { // escaped byte arrived?
|
|
l_rx.esc = 0U;
|
|
b ^= QS_ESC_XOR;
|
|
|
|
l_rx.chksum += b;
|
|
QS_rxParseData_(b);
|
|
}
|
|
else if (b == QS_ESC) {
|
|
l_rx.esc = 1U;
|
|
}
|
|
else if (b == QS_FRAME) {
|
|
// get ready for the next frame
|
|
b = l_rx.state; // save the current state in b
|
|
l_rx.esc = 0U;
|
|
QS_RX_TRAN_(WAIT4_SEQ);
|
|
|
|
if (l_rx.chksum == QS_GOOD_CHKSUM) {
|
|
l_rx.chksum = 0U;
|
|
QS_rxHandleGoodFrame_(b);
|
|
}
|
|
else { // bad checksum
|
|
l_rx.chksum = 0U;
|
|
QS_rxReportError_(0x41);
|
|
QS_rxHandleBadFrame_(b);
|
|
}
|
|
}
|
|
else {
|
|
l_rx.chksum += b;
|
|
QS_rxParseData_(b);
|
|
}
|
|
}</code>
|
|
</operation>
|
|
<!--${QS::QS-RX::rxGetNfree}-->
|
|
<operation name="rxGetNfree" type="uint16_t" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<code>// NOTE: Must be called IN critical section.
|
|
// Also requires system-level memory access (QF_MEM_SYS()).
|
|
|
|
QSCtr const head = QS_rxPriv_.head;
|
|
uint16_t nFree;
|
|
if (head == QS_rxPriv_.tail) { // buffer empty?
|
|
nFree = (uint16_t)(QS_rxPriv_.end - 1U);
|
|
}
|
|
else if (head < QS_rxPriv_.tail) {
|
|
nFree = (uint16_t)(QS_rxPriv_.tail - (head + 1U));
|
|
}
|
|
else {
|
|
nFree = (uint16_t)((head + 1U) - QS_rxPriv_.tail);
|
|
nFree = (uint16_t)(QS_rxPriv_.end - nFree);
|
|
}
|
|
return nFree;</code>
|
|
</operation>
|
|
<!--${QS::QS-RX::doInput}-->
|
|
<operation name="doInput" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QS-RX::onReset}-->
|
|
<operation name="onReset" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QS-RX::onCommand}-->
|
|
<operation name="onCommand" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QS-RX::onCommand::cmdId}-->
|
|
<parameter name="cmdId" type="uint8_t"/>
|
|
<!--${QS::QS-RX::onCommand::param1}-->
|
|
<parameter name="param1" type="uint32_t"/>
|
|
<!--${QS::QS-RX::onCommand::param2}-->
|
|
<parameter name="param2" type="uint32_t"/>
|
|
<!--${QS::QS-RX::onCommand::param3}-->
|
|
<parameter name="param3" type="uint32_t"/>
|
|
</operation>
|
|
</package>
|
|
<!--${QS::QUTest}-->
|
|
<package name="QUTest" stereotype="0x02" namespace="QS_">
|
|
<!--${QS::QUTest::TProbe}-->
|
|
<attribute name="TProbe" type="struct" visibility="0x04" properties="0x00">
|
|
<documentation>// @struct TProbe</documentation>
|
|
<code>{
|
|
QSFun addr;
|
|
uint32_t data;
|
|
uint8_t idx;
|
|
};</code>
|
|
</attribute>
|
|
<!--${QS::QUTest::onTestSetup}-->
|
|
<operation name="onTestSetup" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QUTest::onTestTeardown}-->
|
|
<operation name="onTestTeardown" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
<!--${QS::QUTest::onTestEvt}-->
|
|
<operation name="onTestEvt" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QUTest::onTestEvt::e}-->
|
|
<parameter name="e" type="QEvt *"/>
|
|
</operation>
|
|
<!--${QS::QUTest::onTestPost}-->
|
|
<operation name="onTestPost" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
<!--${QS::QUTest::onTestPost::sender}-->
|
|
<parameter name="sender" type="void const *"/>
|
|
<!--${QS::QUTest::onTestPost::recipient}-->
|
|
<parameter name="recipient" type="QActive *"/>
|
|
<!--${QS::QUTest::onTestPost::e}-->
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<!--${QS::QUTest::onTestPost::status}-->
|
|
<parameter name="status" type="bool"/>
|
|
</operation>
|
|
<!--${QS::QUTest::onTestLoop}-->
|
|
<operation name="onTestLoop" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @static @public @memberof QS
|
|
|
|
//! @static @public @memberof QS</documentation>
|
|
</operation>
|
|
</package>
|
|
<!--${QS::QUTest-stub}-->
|
|
<package name="QUTest-stub" stereotype="0x05">
|
|
<!--${QS::QUTest-stub::QF}-->
|
|
<package name="QF" stereotype="0x02" namespace="QF_">
|
|
<!--${QS::QUTest-stub::QF::init}-->
|
|
<operation name="init" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! QF_init() stub for QUTest</documentation>
|
|
<code>// Clear the internal QF variables, 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_(&QF_priv_, sizeof(QF_priv_));
|
|
QF_bzero_(&QS_tstPriv_, sizeof(QS_tstPriv_));
|
|
QF_bzero_(&QActive_registry_[0], sizeof(QActive_registry_));
|
|
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QS_tstPriv_.readySet, &QS_tstPriv_.readySet_dis);
|
|
#endif</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QF::stop}-->
|
|
<operation name="stop" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! QF_stop() stub for QUTest</documentation>
|
|
<code>QS_onReset();</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QF::run}-->
|
|
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
|
|
<documentation>//! QF_run() stub for QUTest</documentation>
|
|
<code>QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
// function dictionaries for the standard API
|
|
QS_FUN_DICTIONARY(&QActive_post_);
|
|
QS_FUN_DICTIONARY(&QActive_postLIFO_);
|
|
QS_FUN_DICTIONARY(&QS_processTestEvts_);
|
|
|
|
// produce the QS_QF_RUN trace record
|
|
QS_BEGIN_PRE_(QS_QF_RUN, 0U)
|
|
QS_END_PRE_()
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
|
|
QS_processTestEvts_(); // process all events posted so far
|
|
QS_onTestLoop(); // run the test loop
|
|
QS_onCleanup(); // application cleanup
|
|
return 0; // return no error</code>
|
|
</operation>
|
|
</package>
|
|
<!--${QS::QUTest-stub::QActive}-->
|
|
<class name="QActive" superclass="QEP::QAsm">
|
|
<documentation>// QActive stub for QUTest</documentation>
|
|
<!--${QS::QUTest-stub::QActive::start_}-->
|
|
<operation name="start_" type="void" visibility="0x02" properties="0x00">
|
|
<documentation>//! @private @memberof QActive
|
|
|
|
//! @private @memberof QActive</documentation>
|
|
<!--${QS::QUTest-stub::QActive::start_::prioSpec}-->
|
|
<parameter name="prioSpec" type="QPrioSpec const"/>
|
|
<!--${QS::QUTest-stub::QActive::start_::qSto}-->
|
|
<parameter name="qSto" type="QEvt const * * const"/>
|
|
<!--${QS::QUTest-stub::QActive::start_::qLen}-->
|
|
<parameter name="qLen" type="uint_fast16_t const"/>
|
|
<!--${QS::QUTest-stub::QActive::start_::stkSto}-->
|
|
<parameter name="stkSto" type="void * const"/>
|
|
<!--${QS::QUTest-stub::QActive::start_::stkSize}-->
|
|
<parameter name="stkSize" type="uint_fast16_t const"/>
|
|
<!--${QS::QUTest-stub::QActive::start_::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<code>Q_UNUSED_PAR(stkSto);
|
|
Q_UNUSED_PAR(stkSize);
|
|
|
|
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);
|
|
|
|
// top-most initial tran. (virtual call)
|
|
(*me->super.vptr->init)(&me->super, par, me->prio);</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QActive::stop}-->
|
|
<operation name="stop?def QACTIVE_CAN_STOP" type="void" visibility="0x01" properties="0x00">
|
|
<documentation>//! @protected @memberof QActive
|
|
|
|
//! @protected @memberof QActive</documentation>
|
|
<code>QActive_unsubscribeAll(me); // unsubscribe from all events
|
|
QActive_unregister_(me); // un-register this active object</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QS::QUTest-stub::QTimeEvt}-->
|
|
<class name="QTimeEvt" superclass="QEP::QEvt">
|
|
<documentation>// QTimeEvt stub for QUTest</documentation>
|
|
<!--${QS::QUTest-stub::QTimeEvt::tick1_}-->
|
|
<operation name="tick1_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QTimeEvt
|
|
|
|
//! @private @memberof QTimeEvt</documentation>
|
|
<!--${QS::QUTest-stub::QTimeEvt::tick1_::tickRate}-->
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<!--${QS::QUTest-stub::QTimeEvt::tick1_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<code>QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
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_()
|
|
|
|
// is current Time Event object provided?
|
|
QTimeEvt *t = (QTimeEvt *)QS_rxPriv_.currObj[TE_OBJ];
|
|
if (t != (QTimeEvt *)0) {
|
|
|
|
// the time event must be armed
|
|
Q_ASSERT_INCRIT(810, t->ctr != 0U);
|
|
|
|
QActive * const act = (QActive *)(t->act);
|
|
|
|
// the recipient AO must be provided
|
|
Q_ASSERT_INCRIT(820, act != (QActive *)0);
|
|
|
|
// periodic time evt?
|
|
if (t->interval != 0U) {
|
|
t->ctr = t->interval; // rearm the time event
|
|
}
|
|
else { // one-shot time event: automatically disarm
|
|
t->ctr = 0U; // auto-disarm
|
|
// mark time event 't' as NOT linked
|
|
t->super.refCtr_ &= (uint8_t)(~(uint8_t)QTE_IS_LINKED);
|
|
|
|
QS_BEGIN_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
|
|
QS_OBJ_PRE_(t); // 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_(t); // the time event object
|
|
QS_SIG_PRE_(t->super.sig); // signal of this time event
|
|
QS_OBJ_PRE_(act); // the target AO
|
|
QS_U8_PRE_(tickRate); // tick rate
|
|
QS_END_PRE_()
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT(); // exit critical section before posting
|
|
|
|
QACTIVE_POST(act, &t->super, sender); // asserts if queue overflows
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
}
|
|
|
|
// update the linked list of time events
|
|
for (;;) {
|
|
t = prev->next; // advance down the time evt. list
|
|
|
|
// end of the list?
|
|
if (t == (QTimeEvt *)0) {
|
|
|
|
// any new time events armed since the last QTimeEvt_tick_()?
|
|
if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
|
|
|
|
// sanity check
|
|
Q_ASSERT_INCRIT(830, prev != (QTimeEvt *)0);
|
|
prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
|
|
QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
|
|
t = prev->next; // switch to the new list
|
|
}
|
|
else {
|
|
break; // all currently armed time evts. processed
|
|
}
|
|
}
|
|
|
|
// time event scheduled for removal?
|
|
if (t->ctr == 0U) {
|
|
prev->next = t->next;
|
|
// mark time event 't' as NOT linked
|
|
t->super.refCtr_ &= (uint8_t)(~(uint8_t)QTE_IS_LINKED);
|
|
// do NOT advance the prev pointer
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT(); // exit crit. section to reduce latency
|
|
}
|
|
else {
|
|
prev = t; // advance to this time event
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT(); // exit crit. section to reduce latency
|
|
}
|
|
QS_CRIT_ENTRY(); // re-enter crit. section to continue
|
|
QS_MEM_SYS();
|
|
}
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QS::QUTest-stub::QHsmDummy}-->
|
|
<class name="QHsmDummy" superclass="QEP::QAsm">
|
|
<documentation>//! @class QHsmDummy
|
|
//! @extends QHsm</documentation>
|
|
<!--${QS::QUTest-stub::QHsmDummy::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QHsmDummy
|
|
|
|
//! @public @memberof QHsmDummy</documentation>
|
|
<code>static struct QAsmVtable const vtable = {
|
|
&QHsmDummy_init_,
|
|
&QHsmDummy_dispatch_
|
|
#ifdef Q_SPY
|
|
,&QHsm_getStateHandler_
|
|
#endif
|
|
};
|
|
me->super.vptr = &vtable; // hook the vptr</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QHsmDummy::init_}-->
|
|
<operation name="init_" type="void" visibility="0x00" properties="0x01">
|
|
<documentation>//! @private @memberof QHsmDummy
|
|
|
|
//! @private @memberof QHsmDummy</documentation>
|
|
<!--${QS::QUTest-stub::QHsmDummy::init_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QS::QUTest-stub::QHsmDummy::init_::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<!--${QS::QUTest-stub::QHsmDummy::init_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>Q_UNUSED_PAR(par);
|
|
|
|
#ifdef Q_SPY
|
|
if ((QS_priv_.flags & 0x01U) == 0U) {
|
|
QS_priv_.flags |= 0x01U;
|
|
QS_FUN_DICTIONARY(&QHsm_top);
|
|
}
|
|
#endif
|
|
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
|
|
QS_OBJ_PRE_(me); // this state machine object
|
|
QS_FUN_PRE_(me->state.fun); // the source state
|
|
QS_FUN_PRE_(me->temp.fun); // the target of the initial tran.
|
|
QS_END_PRE_()
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QHsmDummy::dispatch_}-->
|
|
<operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QHsmDummy
|
|
|
|
//! @private @memberof QHsmDummy</documentation>
|
|
<!--${QS::QUTest-stub::QHsmDummy::dispatch_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QS::QUTest-stub::QHsmDummy::dispatch_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QS::QUTest-stub::QHsmDummy::dispatch_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
|
|
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();</code>
|
|
</operation>
|
|
</class>
|
|
<!--${QS::QUTest-stub::QActiveDummy}-->
|
|
<class name="QActiveDummy" superclass="QF::QActive">
|
|
<documentation>//! @class QActiveDummy
|
|
//! @extends QActive</documentation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::ctor}-->
|
|
<operation name="ctor" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>//! @public @memberof QActiveDummy
|
|
|
|
//! @public @memberof QActiveDummy</documentation>
|
|
<code>// superclass' ctor
|
|
QActive_ctor(&me->super, Q_STATE_CAST(0));
|
|
|
|
static struct QAsmVtable const vtable = {
|
|
&QActiveDummy_init_,
|
|
&QActiveDummy_dispatch_
|
|
#ifdef Q_SPY
|
|
,&QHsm_getStateHandler_
|
|
#endif
|
|
};
|
|
me->super.super.vptr = &vtable; // hook the vptr</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::init_}-->
|
|
<operation name="init_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QActiveDummy
|
|
|
|
//! @private @memberof QActiveDummy</documentation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::init_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::init_::par}-->
|
|
<parameter name="par" type="void const * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::init_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>Q_UNUSED_PAR(qs_id);
|
|
|
|
QHsmDummy_init_(me, par, ((QActive const *)me)->prio);</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::dispatch_}-->
|
|
<operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QActiveDummy
|
|
|
|
//! @private @memberof QActiveDummy</documentation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::dispatch_::me}-->
|
|
<parameter name="me" type="QAsm * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::dispatch_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::dispatch_::qs_id}-->
|
|
<parameter name="qs_id" type="uint_fast8_t const"/>
|
|
<code>Q_UNUSED_PAR(qs_id);
|
|
|
|
QHsmDummy_dispatch_(me, e, ((QActive const *)me)->prio);</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePost_}-->
|
|
<operation name="fakePost_" type="bool" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QActiveDummy
|
|
|
|
//! @private @memberof QActiveDummy</documentation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePost_::me}-->
|
|
<parameter name="me" type="QActive * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePost_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePost_::margin}-->
|
|
<parameter name="margin" type="uint_fast16_t const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePost_::sender}-->
|
|
<parameter name="sender" type="void const * const"/>
|
|
<code>QS_TEST_PROBE_DEF(&QActive_post_)
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// test-probe#1 for faking queue overflow
|
|
bool status = true;
|
|
QS_TEST_PROBE_ID(1,
|
|
status = false;
|
|
if (margin == QF_NO_MARGIN) {
|
|
// fake assertion Mod=qf_actq,Loc=110
|
|
Q_onError("qf_actq", 110);
|
|
}
|
|
)
|
|
|
|
// is it a mutable event?
|
|
if (QEvt_getPoolId_(e) != 0U) {
|
|
QEvt_refCtr_inc_(e);
|
|
}
|
|
|
|
uint_fast8_t const rec = (status ? (uint_fast8_t)QS_QF_ACTIVE_POST
|
|
: (uint_fast8_t)QS_QF_ACTIVE_POST_ATTEMPT);
|
|
QS_BEGIN_PRE_(rec, 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
|
|
QS_2U8_PRE_(QEvt_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(0U); // # free entries
|
|
QS_EQC_PRE_(margin); // margin requested
|
|
QS_END_PRE_()
|
|
|
|
// 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)) {
|
|
QS_onTestPost(sender, me, e, status);
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
// recycle the event immediately, because it was not really posted
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e);
|
|
#endif
|
|
|
|
return status; // the event is "posted" correctly</code>
|
|
</operation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePostLIFO_}-->
|
|
<operation name="fakePostLIFO_" type="void" visibility="0x02" properties="0x01">
|
|
<documentation>//! @private @memberof QActiveDummy
|
|
|
|
//! @private @memberof QActiveDummy</documentation>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePostLIFO_::me}-->
|
|
<parameter name="me" type="QActive * const"/>
|
|
<!--${QS::QUTest-stub::QActiveDummy::fakePostLIFO_::e}-->
|
|
<parameter name="e" type="QEvt const * const"/>
|
|
<code>QS_TEST_PROBE_DEF(&QActive_postLIFO_)
|
|
|
|
QF_CRIT_STAT
|
|
QF_CRIT_ENTRY();
|
|
QF_MEM_SYS();
|
|
|
|
// test-probe#1 for faking queue overflow
|
|
QS_TEST_PROBE_ID(1,
|
|
// fake assertion Mod=qf_actq,Loc=210
|
|
Q_onError("qf_actq", 210);
|
|
)
|
|
|
|
// is it a mutable event?
|
|
if (QEvt_getPoolId_(e) != 0U) {
|
|
QEvt_refCtr_inc_(e);
|
|
}
|
|
|
|
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_getPoolId_(e), e->refCtr_); // poolId & refCtr
|
|
QS_EQC_PRE_(0U); // # free entries
|
|
QS_EQC_PRE_(0U); // min # free entries
|
|
QS_END_PRE_()
|
|
|
|
// 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)) {
|
|
QS_onTestPost((QActive *)0, me, e, true);
|
|
}
|
|
QF_MEM_APP();
|
|
QF_CRIT_EXIT();
|
|
|
|
// recycle the event immediately, because it was not really posted
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e);
|
|
#endif</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
</package>
|
|
<!--${QS-macros}-->
|
|
<package name="QS-macros" stereotype="0x02">
|
|
<!--${QS-macros::QS_INIT}-->
|
|
<operation name="QS_INIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_INIT::arg_}-->
|
|
<parameter name="arg_" type="void *"/>
|
|
<code>(QS_onStartup(arg_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_EXIT}-->
|
|
<operation name="QS_EXIT" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_onCleanup())</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OUTPUT}-->
|
|
<operation name="QS_OUTPUT" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_output())</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_RX_INPUT}-->
|
|
<operation name="QS_RX_INPUT" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_rx_input())</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_GLB_FILTER}-->
|
|
<operation name="QS_GLB_FILTER" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_GLB_FILTER::rec_}-->
|
|
<parameter name="rec_" type="uint8_t"/>
|
|
<code>(QS_glbFilter_((int_fast16_t)(rec_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_LOC_FILTER}-->
|
|
<operation name="QS_LOC_FILTER" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_LOC_FILTER::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>(QS_locFilter_((int_fast16_t)(qs_id_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_BEGIN_ID}-->
|
|
<operation name="QS_BEGIN_ID" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_BEGIN_ID::rec_}-->
|
|
<parameter name="rec_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_BEGIN_ID::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>\
|
|
if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
|
|
QS_CRIT_STAT \
|
|
QS_CRIT_ENTRY(); \
|
|
QS_MEM_SYS(); \
|
|
QS_beginRec_((uint_fast8_t)(rec_)); \
|
|
QS_TIME_PRE_(); {</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_END}-->
|
|
<operation name="QS_END" type="void" visibility="0x03" properties="0x00">
|
|
<code>} \
|
|
QS_endRec_(); \
|
|
QS_MEM_APP(); \
|
|
QS_CRIT_EXIT(); \
|
|
}</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_FLUSH}-->
|
|
<operation name="QS_FLUSH" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_onFlush())</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_BEGIN_INCRIT}-->
|
|
<operation name="QS_BEGIN_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_BEGIN_INCRIT::rec_}-->
|
|
<parameter name="rec_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_BEGIN_INCRIT::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>\
|
|
if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
|
|
QS_beginRec_((uint_fast8_t)(rec_)); \
|
|
QS_TIME_PRE_(); {</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_END_INCRIT}-->
|
|
<operation name="QS_END_INCRIT" type="void" visibility="0x03" properties="0x00">
|
|
<code>} \
|
|
QS_endRec_(); \
|
|
}</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_GLB_CHECK_}-->
|
|
<operation name="QS_GLB_CHECK_" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_GLB_CHECK_::rec_}-->
|
|
<parameter name="rec_" type="uint8_t"/>
|
|
<code>\
|
|
(((uint_fast8_t)QS_filt_.glb[(uint_fast8_t)(rec_) >> 3U] \
|
|
& ((uint_fast8_t)1U << ((uint_fast8_t)(rec_) & 7U))) != 0U)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_LOC_CHECK_}-->
|
|
<operation name="QS_LOC_CHECK_" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_LOC_CHECK_::qs_id_}-->
|
|
<parameter name="qs_id_" type="uint8_t"/>
|
|
<code>\
|
|
(((uint_fast8_t)QS_filt_.loc[(uint_fast8_t)(qs_id_) >> 3U] \
|
|
& ((uint_fast8_t)1U << ((uint_fast8_t)(qs_id_) & 7U))) != 0U)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_REC_DONE}-->
|
|
<operation name="QS_REC_DONE?ndef QS_REC_DONE" type="void" visibility="0x03" properties="0x00">
|
|
<code>((void)0)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_I8}-->
|
|
<operation name="QS_I8" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_I8::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_I8::data_}-->
|
|
<parameter name="data_" type="int8_t"/>
|
|
<code>\
|
|
(QS_u8_fmt_((uint8_t)(((width_) << 4U) & 0x7U) | (uint8_t)QS_I8_ENUM_T, \
|
|
(data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_U8}-->
|
|
<operation name="QS_U8" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_U8::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_U8::data_}-->
|
|
<parameter name="data_" type="std:u:int8_t"/>
|
|
<code>\
|
|
(QS_u8_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U8_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_I16}-->
|
|
<operation name="QS_I16" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_I16::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_I16::data_}-->
|
|
<parameter name="data_" type="int16_t"/>
|
|
<code>\
|
|
(QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I16_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_U16}-->
|
|
<operation name="QS_U16" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_U16::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_U16::data_}-->
|
|
<parameter name="data_" type="std:u:int16_t"/>
|
|
<code>\
|
|
(QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U16_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_I32}-->
|
|
<operation name="QS_I32" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_I32::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_I32::data_}-->
|
|
<parameter name="data_" type="int32_t"/>
|
|
<code>\
|
|
(QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I32_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_U32}-->
|
|
<operation name="QS_U32" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_U32::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_U32::data_}-->
|
|
<parameter name="data_" type="std:u:int32_t"/>
|
|
<code>\
|
|
(QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U32_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_I64}-->
|
|
<operation name="QS_I64" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_I64::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_I64::data_}-->
|
|
<parameter name="data_" type="int64_t"/>
|
|
<code>\
|
|
(QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I64_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_U64}-->
|
|
<operation name="QS_U64" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_U64::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_U64::data_}-->
|
|
<parameter name="data_" type="std:u:int64_t"/>
|
|
<code>\
|
|
(QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U64_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_F32}-->
|
|
<operation name="QS_F32" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_F32::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_F32::data_}-->
|
|
<parameter name="data_" type="float32_t"/>
|
|
<code>\
|
|
(QS_f32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F32_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_F64}-->
|
|
<operation name="QS_F64" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_F64::width_}-->
|
|
<parameter name="width_" type="uint8_t"/>
|
|
<!--${QS-macros::QS_F64::data_}-->
|
|
<parameter name="data_" type="float64_t"/>
|
|
<code>\
|
|
(QS_f64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F64_T, (data_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_STR}-->
|
|
<operation name="QS_STR" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_STR::str_}-->
|
|
<parameter name="str_" type="char const *"/>
|
|
<code>(QS_str_fmt_((str_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_MEM}-->
|
|
<operation name="QS_MEM" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_MEM::mem_}-->
|
|
<parameter name="mem_" type="void *"/>
|
|
<!--${QS-macros::QS_MEM::size_}-->
|
|
<parameter name="size_" type="std:u:int8_t"/>
|
|
<code>(QS_mem_fmt_((mem_), (size_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_ENUM}-->
|
|
<operation name="QS_ENUM" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_ENUM::group_}-->
|
|
<parameter name="group_" type="uint8_t const"/>
|
|
<!--${QS-macros::QS_ENUM::value_}-->
|
|
<parameter name="value_" type="enum_t const"/>
|
|
<code>\
|
|
(QS_u8_fmt_((uint8_t)(0x80U | ((group_) << 4U)) | (uint8_t)QS_I8_ENUM_T,\
|
|
(uint8_t)(value_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_TIME_PRE_}-->
|
|
<operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_u16_raw_(QS_onGetTime()))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_TIME_PRE_}-->
|
|
<operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
|
|
<code>(QS_u32_raw_(QS_onGetTime()))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OBJ}-->
|
|
<operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_OBJ::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>(QS_u16_fmt_(QS_OBJ_T, (uint16_t)(obj_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OBJ}-->
|
|
<operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_OBJ::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>(QS_u32_fmt_(QS_OBJ_T, (uint32_t)(obj_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OBJ}-->
|
|
<operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 8U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_OBJ::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>(QS_u64_fmt_(QS_OBJ_T, (uint64_t)(obj_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_FUN}-->
|
|
<operation name="QS_FUN? (QS_FUN_PTR_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_FUN::fun_}-->
|
|
<parameter name="fun_" type="QSpyFunPtr"/>
|
|
<code>(QS_u16_fmt_(QS_FUN_T, (uint16_t)(fun_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_FUN}-->
|
|
<operation name="QS_FUN? (QS_FUN_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_FUN::fun_}-->
|
|
<parameter name="fun_" type="QSpyFunPtr"/>
|
|
<code>(QS_u32_fmt_(QS_FUN_T, (uint32_t)(fun_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_FUN}-->
|
|
<operation name="QS_FUN? (QS_FUN_PTR_SIZE == 8U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_FUN::fun_}-->
|
|
<parameter name="fun_" type="QSpyFunPtr"/>
|
|
<code>(QS_u64_fmt_(QS_FUN_T, (uint64_t)(fun_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_SIG}-->
|
|
<operation name="QS_SIG? (Q_SIGNAL_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_SIG::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QS-macros::QS_SIG::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>\
|
|
QS_u8_fmt_(QS_SIG_T, (sig_)); \
|
|
QS_obj_raw_(obj_)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_SIG}-->
|
|
<operation name="QS_SIG? (Q_SIGNAL_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_SIG::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QS-macros::QS_SIG::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>\
|
|
QS_u16_fmt_(QS_SIG_T, (sig_)); \
|
|
QS_obj_raw_(obj_)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_SIG}-->
|
|
<operation name="QS_SIG? (Q_SIGNAL_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_SIG::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QS-macros::QS_SIG::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>\
|
|
QS_u32_fmt_(QS_SIG_T, (sig_)); \
|
|
QS_obj_raw_(obj_)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_SIG_DICTIONARY}-->
|
|
<operation name="QS_SIG_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_SIG_DICTIONAR~::sig_}-->
|
|
<parameter name="sig_" type="QSignal"/>
|
|
<!--${QS-macros::QS_SIG_DICTIONAR~::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>\
|
|
(QS_sig_dict_pre_((QSignal)(sig_), (obj_), #sig_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OBJ_DICTIONARY}-->
|
|
<operation name="QS_OBJ_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_OBJ_DICTIONAR~::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<code>\
|
|
(QS_obj_dict_pre_((obj_), #obj_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_OBJ_ARR_DICTIONARY}-->
|
|
<operation name="QS_OBJ_ARR_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_OBJ_ARR_DICTI~::obj_}-->
|
|
<parameter name="obj_" type="void const *"/>
|
|
<!--${QS-macros::QS_OBJ_ARR_DICTI~::idx_}-->
|
|
<parameter name="idx_" type="unsigned"/>
|
|
<code>\
|
|
(QS_obj_arr_dict_pre_((obj_), (idx_), #obj_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_FUN_DICTIONARY}-->
|
|
<operation name="QS_FUN_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_FUN_DICTIONAR~::fun_}-->
|
|
<parameter name="fun_" type="QSpyFunPtr"/>
|
|
<code>\
|
|
(QS_fun_dict_pre_((void (*)(void))(fun_), #fun_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_USR_DICTIONARY}-->
|
|
<operation name="QS_USR_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_USR_DICTIONAR~::rec_}-->
|
|
<parameter name="rec_" type="unit8_t"/>
|
|
<code>\
|
|
(QS_usr_dict_pre_((rec_), #rec_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_ENUM_DICTIONARY}-->
|
|
<operation name="QS_ENUM_DICTIONARY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_ENUM_DICTIONA~::value_}-->
|
|
<parameter name="value_" type="enum_t const"/>
|
|
<!--${QS-macros::QS_ENUM_DICTIONA~::group_}-->
|
|
<parameter name="group_" type="uint8_t const"/>
|
|
<code>\
|
|
(QS_enum_dict_pre_((value_), (group_), #value_))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_RX_PUT}-->
|
|
<operation name="QS_RX_PUT" type="bool" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_RX_PUT::b_}-->
|
|
<parameter name="b_" type="uint8_t const"/>
|
|
<code>(QS_rxPut((b_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_TR_CRIT_ENTRY}-->
|
|
<operation name="QS_TR_CRIT_ENTRY" type="void" visibility="0x03" properties="0x00"/>
|
|
<!--${QS-macros::QS_TR_CRIT_EXIT}-->
|
|
<operation name="QS_TR_CRIT_EXIT" type="void" visibility="0x03" properties="0x00"/>
|
|
<!--${QS-macros::QS_TR_ISR_ENTRY}-->
|
|
<operation name="QS_TR_ISR_ENTRY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_TR_ISR_ENTRY::isrnest}-->
|
|
<parameter name="isrnest" type="uint_fast8_t const"/>
|
|
<!--${QS-macros::QS_TR_ISR_ENTRY::prio}-->
|
|
<parameter name="prio" type="uint_fast8_t const"/>
|
|
<code>do { \
|
|
QS_BEGIN_PRE_(QS_QF_ISR_ENTRY, 0U) \
|
|
QS_TIME_PRE_(); \
|
|
QS_2u8_raw_(isrnest, prio); \
|
|
QS_END_PRE_() \
|
|
}</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_TR_ISR_EXIT}-->
|
|
<operation name="QS_TR_ISR_EXIT" type="void" visibility="0x00" properties="0x00">
|
|
<!--${QS-macros::QS_TR_ISR_EXIT::isrnest}-->
|
|
<parameter name="isrnest" type="uint_fast8_t"/>
|
|
<!--${QS-macros::QS_TR_ISR_EXIT::prio}-->
|
|
<parameter name="prio" type="uint_fast8_t"/>
|
|
<code>do { \
|
|
QS_BEGIN_PRE_(QS_QF_ISR_EXIT, 0U) \
|
|
QS_TIME_PRE_(); \
|
|
QS_2u8_raw_(isrnest, prio); \
|
|
QS_END_PRE_() \
|
|
} while (false)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_ONLY}-->
|
|
<operation name="QS_ONLY" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_ONLY::code_}-->
|
|
<parameter name="code_" type="<code>"/>
|
|
<code>(code_)</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_ASSERTION}-->
|
|
<operation name="QS_ASSERTION" type="void" visibility="0x03" properties="0x00">
|
|
<!--${QS-macros::QS_ASSERTION::module_}-->
|
|
<parameter name="module_" type="char const *"/>
|
|
<!--${QS-macros::QS_ASSERTION::id_}-->
|
|
<parameter name="id_" type="int_t"/>
|
|
<!--${QS-macros::QS_ASSERTION::delay_}-->
|
|
<parameter name="delay_" type="unsigned"/>
|
|
<code>\
|
|
(QS_assertion_pre_((module_), (id_), (delay_)))</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_EOD}-->
|
|
<attribute name="QS_EOD" type="uint16_t" visibility="0x03" properties="0x00">
|
|
<code>((uint16_t)0xFFFFU)</code>
|
|
</attribute>
|
|
<!--${QS-macros::QS_CMD}-->
|
|
<attribute name="QS_CMD" type="uint8_t" visibility="0x03" properties="0x00">
|
|
<code>((uint8_t)7U)</code>
|
|
</attribute>
|
|
<!--${QS-macros::QS_HEX_FMT}-->
|
|
<attribute name="QS_HEX_FMT" type="uint8_t" visibility="0x03" properties="0x00">
|
|
<code>((uint8_t)0x0FU)</code>
|
|
</attribute>
|
|
<!--${QS-macros::QS_CRIT_STAT}-->
|
|
<attribute name="QS_CRIT_STAT?ndef QS_CRIT_STAT" type="" visibility="0x03" properties="0x00">
|
|
<code>QF_CRIT_STAT</code>
|
|
</attribute>
|
|
<!--${QS-macros::QS_CRIT_ENTRY}-->
|
|
<operation name="QS_CRIT_ENTRY?ndef QS_CRIT_ENTRY" type="void" visibility="0x03" properties="0x00">
|
|
<code>QF_CRIT_ENTRY()</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_CRIT_EXIT}-->
|
|
<operation name="QS_CRIT_EXIT?ndef QS_CRIT_EXIT" type="void" visibility="0x03" properties="0x00">
|
|
<code>QF_CRIT_EXIT()</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_MEM_SYS}-->
|
|
<operation name="QS_MEM_SYS?ndef QS_MEM_SYS" type="void" visibility="0x03" properties="0x00">
|
|
<code>QF_MEM_SYS()</code>
|
|
</operation>
|
|
<!--${QS-macros::QS_MEM_APP}-->
|
|
<operation name="QS_MEM_APP?ndef QS_MEM_APP" type="void" visibility="0x03" properties="0x00">
|
|
<code>QF_MEM_APP()</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 730U
|
|
#define QP_VERSION_STR "7.3.0"
|
|
|
|
//! Encrypted current QP release (7.3.0) and date (2023-09-12)
|
|
#define QP_RELEASE 0x765D9D25U
|
|
|
|
//============================================================================
|
|
//! @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::refCtr_ attribute (inherited from ::QEvt).
|
|
// In ::QTimeEvt this attribute is NOT used for reference counting.
|
|
#define QTE_IS_LINKED (1U << 7U)
|
|
#define QTE_WAS_DISARMED (1U << 6U)
|
|
#define QTE_TICK_RATE 0x0FU
|
|
|
|
//! @private @memberof QEvt
|
|
static inline void QEvt_refCtr_inc_(QEvt const *me) {
|
|
++((QEvt *)me)->refCtr_;
|
|
}
|
|
|
|
//! @private @memberof QEvt
|
|
static inline void QEvt_refCtr_dec_(QEvt const *me) {
|
|
--((QEvt *)me)->refCtr_;
|
|
}
|
|
|
|
#define QACTIVE_CAST_(ptr_) ((QActive *)(ptr_))
|
|
#define Q_UINTPTR_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;
|
|
#elif (QF_EQUEUE_CTR_SIZE == 4U)
|
|
typedef uint32_t QEQueueCtr;
|
|
#else
|
|
#error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
|
|
#endif
|
|
|
|
struct QEvt; // forward declaration
|
|
|
|
$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) \
|
|
/ sizeof(QFreeBlock)) + 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::qxk.h}-->
|
|
<file name="qxk.h">
|
|
<text>#ifndef QXK_H_
|
|
#define QXK_H_
|
|
|
|
$declare ${QXK::QXK}
|
|
|
|
$declare ${QXK::QSchedStatus}
|
|
|
|
$declare ${QXK::QXTHREAD_NO_TIMEOUT}
|
|
|
|
$declare ${QXK::QXK-base}
|
|
|
|
$declare ${QXK::QXThread}
|
|
|
|
$declare ${QXK::QXSemaphore}
|
|
|
|
$declare ${QXK::QXMutex}
|
|
|
|
$declare ${QXK-macros}
|
|
|
|
//============================================================================
|
|
// interface used only for internal implementation, but not in applications
|
|
#ifdef QP_IMPL
|
|
|
|
$declare ${QXK-impl}
|
|
|
|
$declare ${QF_EPOOL-impl}
|
|
|
|
enum QXK_TimeoutSigs {
|
|
QXK_DELAY_SIG = 1,
|
|
QXK_TIMEOUT_SIG
|
|
};
|
|
|
|
#endif // QP_IMPL
|
|
|
|
#endif // QXK_H_</text>
|
|
</file>
|
|
<!--${include::qs.h}-->
|
|
<file name="qs.h">
|
|
<text>#ifndef QS_H_
|
|
#define QS_H_
|
|
|
|
#ifndef Q_SPY
|
|
#error "Q_SPY must be defined to include qs.h"
|
|
#endif
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
#ifndef QS_CTR_SIZE
|
|
#define QS_CTR_SIZE 2U
|
|
#endif
|
|
|
|
#ifndef QS_TIME_SIZE
|
|
#define QS_TIME_SIZE 4U
|
|
#endif
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
$declare ${QS::types}
|
|
$declare ${QS::filters}
|
|
$declare ${QS-macros}
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
typedef struct {
|
|
void const * locFilter_AP; //!< @deprecated
|
|
uint8_t * buf;
|
|
QSCtr end;
|
|
QSCtr volatile head;
|
|
QSCtr volatile tail;
|
|
QSCtr volatile used;
|
|
uint8_t volatile seq;
|
|
uint8_t volatile chksum;
|
|
uint8_t volatile critNest;
|
|
uint8_t flags;
|
|
} QS_Attr;
|
|
|
|
extern QS_Attr QS_priv_;
|
|
|
|
void QS_glbFilter_(int_fast16_t const filter);
|
|
void QS_locFilter_(int_fast16_t const filter);
|
|
|
|
void QS_beginRec_(uint_fast8_t const rec);
|
|
void QS_endRec_(void);
|
|
|
|
void QS_u8_raw_(uint8_t const d);
|
|
void QS_2u8_raw_(
|
|
uint8_t const d1,
|
|
uint8_t const d2);
|
|
void QS_u16_raw_(uint16_t const d);
|
|
void QS_u32_raw_(uint32_t const d);
|
|
void QS_u64_raw_(uint64_t const d);
|
|
void QS_obj_raw_(void const * const obj);
|
|
void QS_str_raw_(char const * const str);
|
|
|
|
void QS_u8_fmt_(
|
|
uint8_t const format,
|
|
uint8_t const d);
|
|
void QS_u16_fmt_(
|
|
uint8_t const format,
|
|
uint16_t const d);
|
|
void QS_u32_fmt_(
|
|
uint8_t const format,
|
|
uint32_t const d);
|
|
void QS_u64_fmt_(
|
|
uint8_t const format,
|
|
uint64_t const d);
|
|
void QS_f32_fmt_(
|
|
uint8_t const format,
|
|
float32_t const f);
|
|
void QS_f64_fmt_(
|
|
uint8_t const format,
|
|
float64_t const d);
|
|
void QS_str_fmt_(char const * const str);
|
|
void QS_mem_fmt_(
|
|
uint8_t const * const blk,
|
|
uint8_t const size);
|
|
|
|
void QS_sig_dict_pre_(
|
|
QSignal const sig,
|
|
void const * const obj,
|
|
char const * const name);
|
|
void QS_obj_dict_pre_(
|
|
void const * const obj,
|
|
char const * const name);
|
|
void QS_obj_arr_dict_pre_(
|
|
void const * const obj,
|
|
uint_fast16_t const idx,
|
|
char const * const name);
|
|
void QS_fun_dict_pre_(
|
|
QSpyFunPtr const fun,
|
|
char const * const name);
|
|
void QS_usr_dict_pre_(
|
|
enum_t const rec,
|
|
char const * const name);
|
|
void QS_enum_dict_pre_(
|
|
enum_t const value,
|
|
uint8_t const group,
|
|
char const * const name);
|
|
|
|
void QS_assertion_pre_(
|
|
char const * const module,
|
|
int_t const id,
|
|
uint32_t const delay);
|
|
|
|
void QS_target_info_pre_(uint8_t const isReset);
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
$declare ${QS::QS-TX}
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
typedef struct {
|
|
void * currObj[8];
|
|
uint8_t * buf;
|
|
QSCtr end;
|
|
QSCtr volatile head;
|
|
QSCtr volatile tail;
|
|
#ifdef Q_UTEST
|
|
bool inTestLoop;
|
|
#endif
|
|
} QS_RxAttr;
|
|
|
|
//! @static @private @memberof QS
|
|
extern QS_RxAttr QS_rxPriv_;
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
$declare ${QS::QS-RX}
|
|
|
|
//============================================================================
|
|
#ifdef Q_UTEST
|
|
|
|
$declare ${QS::QUTest}
|
|
|
|
#define QUTEST_ON_POST 124
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
typedef struct {
|
|
struct QS_TProbe tpBuf[16];
|
|
uint8_t tpNum;
|
|
QSTimeCtr testTime;
|
|
QPSet readySet;
|
|
QPSet readySet_dis;
|
|
uint_fast8_t intLock;
|
|
} QSTestAttr;
|
|
|
|
extern QSTestAttr QS_tstPriv_;
|
|
|
|
void QS_test_pause_(void);
|
|
uint32_t QS_getTestProbe_(QSpyFunPtr const api);
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
// QP-stub for QUTest
|
|
// NOTE: The QP-stub is needed for unit testing QP applications,
|
|
// but might NOT be needed for testing QP itself.
|
|
#if (Q_UTEST != 0)
|
|
|
|
$declare ${QS::QUTest-stub::QHsmDummy}
|
|
$declare ${QS::QUTest-stub::QActiveDummy}
|
|
|
|
#endif // Q_UTEST != 0
|
|
|
|
#define QS_TEST_PROBE_DEF(fun_) \
|
|
uint32_t const qs_tp_ = QS_getTestProbe_((void (*)(void))(fun_));
|
|
|
|
#define QS_TEST_PROBE(code_) \
|
|
if (qs_tp_ != 0U) { code_ }
|
|
|
|
#define QS_TEST_PROBE_ID(id_, code_) \
|
|
if (qs_tp_ == (uint32_t)(id_)) { code_ }
|
|
|
|
#define QS_TEST_PAUSE() (QS_test_pause_())
|
|
|
|
#else // Q_UTEST not defined
|
|
|
|
// dummy definitions when not building for QUTEST
|
|
#define QS_TEST_PROBE_DEF(fun_)
|
|
#define QS_TEST_PROBE(code_)
|
|
#define QS_TEST_PROBE_ID(id_, code_)
|
|
#define QS_TEST_PAUSE() ((void)0)
|
|
|
|
#endif // Q_UTEST
|
|
|
|
#endif // QS_H_</text>
|
|
</file>
|
|
<!--${include::qs_dummy.h}-->
|
|
<file name="qs_dummy.h">
|
|
<text>#ifndef QS_DUMMY_H_
|
|
#define QS_DUMMY_H_
|
|
|
|
#ifdef Q_SPY
|
|
#error "Q_SPY must NOT be defined to include qs_dummy.h"
|
|
#endif
|
|
|
|
#ifdef Q_UTEST
|
|
#error "Q_UTEST must NOT be defined to include qs_dummy.h"
|
|
#endif
|
|
|
|
#define QS_INIT(arg_) ((uint8_t)1U)
|
|
#define QS_EXIT() ((void)0)
|
|
#define QS_DUMP() ((void)0)
|
|
#define QS_GLB_FILTER(rec_) ((void)0)
|
|
#define QS_LOC_FILTER(qs_id_) ((void)0)
|
|
|
|
#define QS_GET_BYTE(pByte_) ((uint16_t)0xFFFFU)
|
|
#define QS_GET_BLOCK(pSize_) ((uint8_t *)0)
|
|
|
|
#define QS_BEGIN_ID(rec_, qs_id_) if (false) {
|
|
#define QS_END() }
|
|
#define QS_BEGIN_INCRIT(rec_, qs_id_) if (false) {
|
|
#define QS_END_INCRIT() }
|
|
|
|
#define QS_I8(width_, data_) ((void)0)
|
|
#define QS_U8(width_, data_) ((void)0)
|
|
#define QS_I16(width_, data_) ((void)0)
|
|
#define QS_U16(width_, data_) ((void)0)
|
|
#define QS_I32(width_, data_) ((void)0)
|
|
#define QS_U32(width_, data_) ((void)0)
|
|
#define QS_F32(width_, data_) ((void)0)
|
|
#define QS_F64(width_, data_) ((void)0)
|
|
#define QS_I64(width_, data_) ((void)0)
|
|
#define QS_U64(width_, data_) ((void)0)
|
|
#define QS_ENUM(group_, value_) ((void)0)
|
|
#define QS_STR(str_) ((void)0)
|
|
#define QS_MEM(mem_, size_) ((void)0)
|
|
#define QS_SIG(sig_, obj_) ((void)0)
|
|
#define QS_OBJ(obj_) ((void)0)
|
|
#define QS_FUN(fun_) ((void)0)
|
|
|
|
#define QS_SIG_DICTIONARY(sig_, obj_) ((void)0)
|
|
#define QS_OBJ_DICTIONARY(obj_) ((void)0)
|
|
#define QS_OBJ_ARR_DICTIONARY(obj_, idx_) ((void)0)
|
|
#define QS_FUN_DICTIONARY(fun_) ((void)0)
|
|
#define QS_USR_DICTIONARY(rec_) ((void)0)
|
|
#define QS_ENUM_DICTIONARY(value_, group_) ((void)0)
|
|
#define QS_ASSERTION(module_, loc_, delay_) ((void)0)
|
|
#define QS_FLUSH() ((void)0)
|
|
|
|
#define QS_TEST_PROBE_DEF(fun_)
|
|
#define QS_TEST_PROBE(code_)
|
|
#define QS_TEST_PROBE_ID(id_, code_)
|
|
#define QS_TEST_PAUSE() ((void)0)
|
|
|
|
#define QS_OUTPUT() ((void)0)
|
|
#define QS_RX_INPUT() ((void)0)
|
|
#define QS_ONLY(code_) ((void)0)
|
|
|
|
//============================================================================
|
|
// interface used only for internal implementation, but not in applications
|
|
#ifdef QP_IMPL
|
|
// predefined QS trace records
|
|
#define QS_BEGIN_PRE_(rec_, qs_id_) if (false) {
|
|
#define QS_END_PRE_() }
|
|
#define QS_U8_PRE_(data_) ((void)0)
|
|
#define QS_2U8_PRE_(data1_, data2_) ((void)0)
|
|
#define QS_U16_PRE_(data_) ((void)0)
|
|
#define QS_U32_PRE_(data_) ((void)0)
|
|
#define QS_TIME_PRE_() ((void)0)
|
|
#define QS_SIG_PRE_(sig_) ((void)0)
|
|
#define QS_EVS_PRE_(size_) ((void)0)
|
|
#define QS_OBJ_PRE_(obj_) ((void)0)
|
|
#define QS_FUN_PRE_(fun_) ((void)0)
|
|
#define QS_EQC_PRE_(ctr_) ((void)0)
|
|
#define QS_MPC_PRE_(ctr_) ((void)0)
|
|
#define QS_MPS_PRE_(size_) ((void)0)
|
|
#define QS_TEC_PRE_(ctr_) ((void)0)
|
|
|
|
#define QS_CRIT_STAT
|
|
#define QS_CRIT_ENTRY() ((void)0)
|
|
#define QS_CRIT_EXIT() ((void)0)
|
|
|
|
#define QS_MEM_SYS() ((void)0)
|
|
#define QS_MEM_APP() ((void)0)
|
|
|
|
#define QS_TR_CRIT_ENTRY() ((void)0)
|
|
#define QS_TR_CRIT_EXIT() ((void)0)
|
|
#define QS_TR_ISR_ENTRY(isrnest_, prio_) ((void)0)
|
|
#define QS_TR_ISR_EXIT(isrnest_, prio_) ((void)0)
|
|
#endif // QP_IMPL
|
|
|
|
#endif // QS_DUMMY_H_</text>
|
|
</file>
|
|
<!--${include::qs_pkg.h}-->
|
|
<file name="qs_pkg.h">
|
|
<text>#ifndef QS_PKG_H_
|
|
#define QS_PKG_H_
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
//! QS received record types (RX channel)
|
|
enum QSpyRxRecords {
|
|
QS_RX_INFO, //!< query Target info (ver, config, tstamp)
|
|
QS_RX_COMMAND, //!< execute a user-defined command in the Target
|
|
QS_RX_RESET, //!< reset the Target
|
|
QS_RX_TICK, //!< call system clock tick in the Target
|
|
QS_RX_PEEK, //!< peek Target memory
|
|
QS_RX_POKE, //!< poke Target memory
|
|
QS_RX_FILL, //!< fill Target memory
|
|
QS_RX_TEST_SETUP, //!< test setup
|
|
QS_RX_TEST_TEARDOWN, //!< test teardown
|
|
QS_RX_TEST_PROBE, //!< set a Test-Probe in the Target
|
|
QS_RX_GLB_FILTER, //!< set global filters in the Target
|
|
QS_RX_LOC_FILTER, //!< set local filters in the Target
|
|
QS_RX_AO_FILTER, //!< set local AO filter in the Target
|
|
QS_RX_CURR_OBJ, //!< set the "current-object" in the Target
|
|
QS_RX_TEST_CONTINUE, //!< continue a test after QS_TEST_PAUSE()
|
|
QS_RX_QUERY_CURR, //!< query the "current object" in the Target
|
|
QS_RX_EVENT //!< inject an event to the Target
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
#define QS_FRAME 0x7EU
|
|
#define QS_ESC 0x7DU
|
|
#define QS_ESC_XOR 0x20U
|
|
#define QS_GOOD_CHKSUM 0xFFU
|
|
|
|
//----------------------------------------------------------------------------
|
|
#define QS_BEGIN_PRE_(rec_, qs_id_) \
|
|
if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
|
|
QS_beginRec_((uint_fast8_t)(rec_));
|
|
#define QS_END_PRE_() QS_endRec_(); }
|
|
|
|
#define QS_U8_PRE_(data_) (QS_u8_raw_((uint8_t)(data_)))
|
|
#define QS_2U8_PRE_(data1_, data2_) \
|
|
(QS_2u8_raw_((uint8_t)(data1_), (uint8_t)(data2_)))
|
|
#define QS_U16_PRE_(data_) (QS_u16_raw_((uint16_t)(data_)))
|
|
#define QS_U32_PRE_(data_) (QS_u32_raw_((uint32_t)(data_)))
|
|
#define QS_STR_PRE_(msg_) (QS_str_raw_((msg_)))
|
|
#define QS_OBJ_PRE_(obj_) (QS_obj_raw_(obj_))
|
|
|
|
#if (!defined Q_SIGNAL_SIZE || (Q_SIGNAL_SIZE == 1U))
|
|
#define QS_SIG_PRE_(sig_) (QS_u8_raw_((uint8_t)sig_))
|
|
#elif (Q_SIGNAL_SIZE == 2U)
|
|
#define QS_SIG_PRE_(sig_) (QS_u16_raw_((uint16_t)sig_))
|
|
#elif (Q_SIGNAL_SIZE == 4U)
|
|
#define QS_SIG_PRE_(sig_) (QS_u32_raw_((uint32_t)sig_))
|
|
#endif
|
|
|
|
#if (!defined QS_FUN_PTR_SIZE || (QS_FUN_PTR_SIZE == 2U))
|
|
#define QS_FUN_PRE_(fun_) (QS_u16_raw_((uint16_t)(fun_)))
|
|
#elif (QS_FUN_PTR_SIZE == 4U)
|
|
#define QS_FUN_PRE_(fun_) (QS_u32_raw_((uint32_t)(fun_)))
|
|
#elif (QS_FUN_PTR_SIZE == 8U)
|
|
#define QS_FUN_PRE_(fun_) (QS_u64_raw_((uint64_t)(fun_)))
|
|
#else
|
|
#define QS_FUN_PRE_(fun_) (QS_u32_raw_((uint32_t)(fun_)))
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
#if (!defined QF_EQUEUE_CTR_SIZE || (QF_EQUEUE_CTR_SIZE == 1U))
|
|
#define QS_EQC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
|
|
#elif (QF_EQUEUE_CTR_SIZE == 2U)
|
|
#define QS_EQC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
|
|
#elif (QF_EQUEUE_CTR_SIZE == 4U)
|
|
#define QS_EQC_PRE_(ctr_) QS_u32_raw_((uint32_t)(ctr_))
|
|
#endif
|
|
|
|
#if (!defined QF_EVENT_SIZ_SIZE || (QF_EVENT_SIZ_SIZE == 1U))
|
|
#define QS_EVS_PRE_(size_) QS_u8_raw_((uint8_t)(size_))
|
|
#elif (QF_EVENT_SIZ_SIZE == 2U)
|
|
#define QS_EVS_PRE_(size_) QS_u16_raw_((uint16_t)(size_))
|
|
#elif (QF_EVENT_SIZ_SIZE == 4U)
|
|
#define QS_EVS_PRE_(size_) QS_u32_raw_((uint32_t)(size_))
|
|
#endif
|
|
|
|
#if (!defined QF_MPOOL_SIZ_SIZE || (QF_MPOOL_SIZ_SIZE == 1U))
|
|
#define QS_MPS_PRE_(size_) QS_u8_raw_((uint8_t)(size_))
|
|
#elif (QF_MPOOL_SIZ_SIZE == 2U)
|
|
#define QS_MPS_PRE_(size_) QS_u16_raw_((uint16_t)(size_))
|
|
#elif (QF_MPOOL_SIZ_SIZE == 4U)
|
|
#define QS_MPS_PRE_(size_) QS_u32_raw_((uint32_t)(size_))
|
|
#endif
|
|
|
|
#if (!defined QF_MPOOL_CTR_SIZE || (QF_MPOOL_CTR_SIZE == 1U))
|
|
#define QS_MPC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
|
|
#elif (QF_MPOOL_CTR_SIZE == 2U)
|
|
#define QS_MPC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
|
|
#elif (QF_MPOOL_CTR_SIZE == 4U)
|
|
#define QS_MPC_PRE_(ctr_) QS_u32_raw_((uint16_t)(ctr_))
|
|
#endif
|
|
|
|
#if (!defined QF_TIMEEVT_CTR_SIZE || (QF_TIMEEVT_CTR_SIZE == 1U))
|
|
#define QS_TEC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
|
|
#elif (QF_TIMEEVT_CTR_SIZE == 2U)
|
|
#define QS_TEC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
|
|
#elif (QF_TIMEEVT_CTR_SIZE == 4U)
|
|
#define QS_TEC_PRE_(ctr_) QS_u32_raw_((uint32_t)(ctr_))
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
#define QS_INSERT_BYTE_(b_) \
|
|
buf[head] = (b_); \
|
|
++head; \
|
|
if (head == end) { \
|
|
head = 0U; \
|
|
}
|
|
|
|
#define QS_INSERT_ESC_BYTE_(b_) \
|
|
chksum = (uint8_t)(chksum + (b_)); \
|
|
if (((b_) != QS_FRAME) && ((b_) != QS_ESC)) { \
|
|
QS_INSERT_BYTE_(b_) \
|
|
} \
|
|
else { \
|
|
QS_INSERT_BYTE_(QS_ESC) \
|
|
QS_INSERT_BYTE_((uint8_t)((b_) ^ QS_ESC_XOR))\
|
|
++QS_priv_.used; \
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
#if (defined Q_UTEST) && (Q_UTEST != 0)
|
|
void QS_processTestEvts_(void);
|
|
#endif // Q_UTEST != 0
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
#endif // QS_PKG_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_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
//============================================================================
|
|
#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 (inactive) interface
|
|
#endif
|
|
|
|
//============================================================================
|
|
#ifndef QP_API_VERSION
|
|
|
|
#define QP_API_VERSION 0
|
|
|
|
#endif // #ifndef QP_API_VERSION
|
|
|
|
//============================================================================
|
|
// QP API compatibility layer...
|
|
|
|
#if (QP_API_VERSION < 730)
|
|
|
|
//! @deprecated plain 'char' is no longer forbidden in MISRA-C:2023
|
|
typedef char char_t;
|
|
|
|
//! @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_))
|
|
|
|
#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_, qs_id_) QASM_INIT((me_), (par_), (qs_id_))
|
|
|
|
//! @deprecated instead use: QASM_DISPATCH()
|
|
#define QHSM_DISPATCH(me_, e_, qs_id_) QASM_DISPATCH((me_), (e_), (qs_id_))
|
|
|
|
//============================================================================
|
|
#if (QP_API_VERSION < 691)
|
|
|
|
//! @deprecated enable the QS global filter
|
|
#define QS_FILTER_ON(rec_) QS_GLB_FILTER((rec_))
|
|
|
|
//! @deprecated disable the QS global filter
|
|
#define QS_FILTER_OFF(rec_) QS_GLB_FILTER(-(rec_))
|
|
|
|
//! @deprecated enable the QS local filter for SM (state machine) object
|
|
#define QS_FILTER_SM_OBJ(obj_) ((void)0)
|
|
|
|
//! @deprecated enable the QS local filter for AO (active objects)
|
|
#define QS_FILTER_AO_OBJ(obj_) ((void)0)
|
|
|
|
//! @deprecated enable the QS local filter for MP (memory pool) object
|
|
#define QS_FILTER_MP_OBJ(obj_) ((void)0)
|
|
|
|
//! @deprecated enable the QS local filter for EQ (event queue) object
|
|
#define QS_FILTER_EQ_OBJ(obj_) ((void)0)
|
|
|
|
//! @deprecated enable the QS local filter for TE (time event) object
|
|
#define QS_FILTER_TE_OBJ(obj_) ((void)0)
|
|
|
|
#ifdef Q_SPY
|
|
|
|
//! @deprecated local Filter for a generic application object `obj_`.
|
|
#define QS_FILTER_AP_OBJ(obj_) (QS_filt_.loc_AP = (obj_))
|
|
|
|
//! @deprecated begin of a user QS record, instead use QS_BEGIN_ID()
|
|
#define QS_BEGIN(rec_, obj_) \
|
|
if (((QS_filt_.glb[(uint_fast8_t)(rec_) >> 3U] \
|
|
& (1U << ((uint_fast8_t)(rec_) & 7U))) != 0U) \
|
|
&& ((QS_priv_.locFilter_AP == (void *)0) \
|
|
|| (QS_priv_.locFilter_AP == (obj_)))) \
|
|
{ \
|
|
QS_CRIT_STAT \
|
|
QS_CRIT_ENTRY(); \
|
|
QS_beginRec_((uint_fast8_t)(rec_)); \
|
|
QS_TIME_PRE_(); {
|
|
|
|
//! @deprecated Output formatted uint32_t to the QS record
|
|
#define QS_U32_HEX(width_, data_) \
|
|
(QS_u32_fmt_((uint8_t)(((width_) << 4)) | QS_HEX_FMT, (data_)))
|
|
|
|
#else
|
|
|
|
#define QS_FILTER_AP_OBJ(obj_) ((void)0)
|
|
#define QS_BEGIN(rec_, obj_) if (false) {
|
|
#define QS_U32_HEX(width_, data_) ((void)0)
|
|
|
|
#endif
|
|
|
|
//============================================================================
|
|
#if (QP_API_VERSION < 660)
|
|
|
|
//! @deprecated casting to QXThreadHandler
|
|
//! instead use: the new signature of QXThreadHandler and don't cast
|
|
#define Q_XTHREAD_CAST(handler_) ((QXThreadHandler)(handler_))
|
|
|
|
//============================================================================
|
|
#if (QP_API_VERSION < 580)
|
|
|
|
//! @deprecated instead use: QASM_INIT()
|
|
#define QMSM_INIT(me_, par_, qs_id_) QASM_INIT((me_), (par_), (qs_id_))
|
|
|
|
//! @deprecated instead use: QASM_DISPATCH()
|
|
#define QMSM_DISPATCH(me_, e_, qs_id_) QASM_DISPATCH((me_), (e_), (qs_id_))
|
|
|
|
#endif // QP_API_VERSION < 580
|
|
#endif // QP_API_VERSION < 660
|
|
#endif // QP_API_VERSION < 691
|
|
#endif // QP_API_VERSION < 700
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#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 "qp_pkg.h" // QP package-scope interface
|
|
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
|
|
#ifdef Q_SPY // QS software tracing enabled?
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS facilities for pre-defined trace records
|
|
#else
|
|
#include "qs_dummy.h" // disable the QS software tracing
|
|
#endif // Q_SPY
|
|
|
|
Q_DEFINE_THIS_MODULE("qep_hsm")
|
|
|
|
$define ${QEP::QP_versionStr[8]}
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
$define ${QEP::QEvt::reserved_[4]}
|
|
|
|
enum {
|
|
// maximum depth of state nesting in a HSM (including the top level),
|
|
// must be >= 3
|
|
QHSM_MAX_NEST_DEPTH_ = 6
|
|
};
|
|
|
|
// 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_, qs_id_) \
|
|
QS_CRIT_ENTRY(); \
|
|
QS_MEM_SYS(); \
|
|
QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, (qs_id_)) \
|
|
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_, qs_id_) \
|
|
QS_CRIT_ENTRY(); \
|
|
QS_MEM_SYS(); \
|
|
QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, (qs_id_)) \
|
|
QS_OBJ_PRE_(me); \
|
|
QS_FUN_PRE_(state_); \
|
|
QS_END_PRE_() \
|
|
QS_MEM_APP(); \
|
|
QS_CRIT_EXIT()
|
|
|
|
//! @endcond
|
|
|
|
$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 "qp_pkg.h" // QP package-scope interface
|
|
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
|
|
#ifdef Q_SPY // QS software tracing enabled?
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS facilities for pre-defined trace records
|
|
#else
|
|
#include "qs_dummy.h" // disable the QS software tracing
|
|
#endif // Q_SPY
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
Q_DEFINE_THIS_MODULE("qep_msm")
|
|
|
|
// top-state object for QMsm-style state machines
|
|
static struct QMState const l_msm_top_s = {
|
|
(struct QMState *)0,
|
|
Q_STATE_CAST(0),
|
|
Q_ACTION_CAST(0),
|
|
Q_ACTION_CAST(0),
|
|
Q_ACTION_CAST(0)
|
|
};
|
|
|
|
enum {
|
|
// maximum depth of entry levels in a MSM for tran. to history.
|
|
QMSM_MAX_ENTRY_DEPTH_ = 4
|
|
};
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
$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::qxk}-->
|
|
<directory name="qxk">
|
|
<!--${src::qxk::qxk.c}-->
|
|
<file name="qxk.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
|
|
|
|
// protection against including this source file in a wrong project
|
|
#ifndef QXK_H_
|
|
#error "Source file included in a project NOT based on the QXK kernel"
|
|
#endif // QXK_H_
|
|
|
|
Q_DEFINE_THIS_MODULE("qxk")
|
|
|
|
$define ${QXK::QXK-base}
|
|
|
|
$define ${QXK::QF-cust}
|
|
|
|
$define ${QXK::QActive}</text>
|
|
</file>
|
|
<!--${src::qxk::qxk_mutex.c}-->
|
|
<file name="qxk_mutex.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
|
|
|
|
// protection against including this source file in a wrong project
|
|
#ifndef QXK_H_
|
|
#error "Source file included in a project NOT based on the QXK kernel"
|
|
#endif // QXK_H_
|
|
|
|
Q_DEFINE_THIS_MODULE("qxk_mutex")
|
|
|
|
$define ${QXK::QXMutex}</text>
|
|
</file>
|
|
<!--${src::qxk::qxk_sema.c}-->
|
|
<file name="qxk_sema.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
|
|
|
|
// protection against including this source file in a wrong project
|
|
#ifndef QXK_H_
|
|
#error "Source file included in a project NOT based on the QXK kernel"
|
|
#endif // QXK_H_
|
|
|
|
Q_DEFINE_THIS_MODULE("qxk_sema")
|
|
|
|
$define ${QXK::QXSemaphore}</text>
|
|
</file>
|
|
<!--${src::qxk::qxk_xthr.c}-->
|
|
<file name="qxk_xthr.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
|
|
|
|
// protection against including this source file in a wrong project
|
|
#ifndef QXK_H_
|
|
#error "Source file included in a project NOT based on the QXK kernel"
|
|
#endif // QXK_H_
|
|
|
|
Q_DEFINE_THIS_MODULE("qxk_xthr")
|
|
|
|
$define ${QXK::QXThread}</text>
|
|
</file>
|
|
</directory>
|
|
<!--${src::qs}-->
|
|
<directory name="qs">
|
|
<!--${src::qs::qs.c}-->
|
|
<file name="qs.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS package-scope interface
|
|
#include "qstamp.h" // QP time-stamp
|
|
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
|
|
|
|
Q_DEFINE_THIS_MODULE("qs")
|
|
|
|
// ensure that the predefined records don't overlap the
|
|
// user records (application-specific).
|
|
Q_ASSERT_STATIC((enum_t)QS_PRE_MAX <= (enum_t)QS_USER);
|
|
|
|
$define ${QS::QS-TX}
|
|
|
|
#ifndef QF_MEM_ISOLATE
|
|
$define ${QS::filters}
|
|
#endif
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
//! @static @private @memberof QS
|
|
QS_Attr QS_priv_;
|
|
|
|
//............................................................................
|
|
void QS_glbFilter_(int_fast16_t const filter) {
|
|
bool const isRemove = (filter < 0);
|
|
uint8_t const rec = isRemove ? (uint8_t)(-filter) : (uint8_t)filter;
|
|
switch (rec) {
|
|
case (uint8_t)QS_ALL_RECORDS: {
|
|
uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
|
|
|
|
// set all global filters (partially unrolled loop)
|
|
for (uint_fast8_t i = 0U;
|
|
i < Q_DIM(QS_filt_.glb);
|
|
i += 4U)
|
|
{
|
|
QS_filt_.glb[i ] = tmp;
|
|
QS_filt_.glb[i + 1U] = tmp;
|
|
QS_filt_.glb[i + 2U] = tmp;
|
|
QS_filt_.glb[i + 3U] = tmp;
|
|
}
|
|
if (isRemove) {
|
|
// leave the "not maskable" filters enabled,
|
|
// see qs.h, Miscellaneous QS records (not maskable)
|
|
QS_filt_.glb[0] = 0x01U;
|
|
QS_filt_.glb[6] = 0x40U;
|
|
QS_filt_.glb[7] = 0xFCU;
|
|
QS_filt_.glb[8] = 0x7FU;
|
|
}
|
|
else {
|
|
// never turn the last 3 records on (0x7D, 0x7E, 0x7F)
|
|
QS_filt_.glb[15] = 0x1FU;
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)QS_SM_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[0] &= (uint8_t)(~0xFEU & 0xFFU);
|
|
QS_filt_.glb[1] &= (uint8_t)(~0x03U & 0xFFU);
|
|
QS_filt_.glb[6] &= (uint8_t)(~0x80U & 0xFFU);
|
|
QS_filt_.glb[7] &= (uint8_t)(~0x03U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[0] |= 0xFEU;
|
|
QS_filt_.glb[1] |= 0x03U;
|
|
QS_filt_.glb[6] |= 0x80U;
|
|
QS_filt_.glb[7] |= 0x03U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_AO_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[1] &= (uint8_t)(~0xFCU & 0xFFU);
|
|
QS_filt_.glb[2] &= (uint8_t)(~0x07U & 0xFFU);
|
|
QS_filt_.glb[5] &= (uint8_t)(~0x20U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[1] |= 0xFCU;
|
|
QS_filt_.glb[2] |= 0x07U;
|
|
QS_filt_.glb[5] |= 0x20U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_EQ_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[2] &= (uint8_t)(~0x78U & 0xFFU);
|
|
QS_filt_.glb[5] &= (uint8_t)(~0x40U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[2] |= 0x78U;
|
|
QS_filt_.glb[5] |= 0x40U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_MP_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[3] &= (uint8_t)(~0x03U & 0xFFU);
|
|
QS_filt_.glb[5] &= (uint8_t)(~0x80U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[3] |= 0x03U;
|
|
QS_filt_.glb[5] |= 0x80U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_QF_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[2] &= (uint8_t)(~0x80U & 0xFFU);
|
|
QS_filt_.glb[3] &= (uint8_t)(~0xFCU & 0xFFU);
|
|
QS_filt_.glb[4] &= (uint8_t)(~0xC0U & 0xFFU);
|
|
QS_filt_.glb[5] &= (uint8_t)(~0x1FU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[2] |= 0x80U;
|
|
QS_filt_.glb[3] |= 0xFCU;
|
|
QS_filt_.glb[4] |= 0xC0U;
|
|
QS_filt_.glb[5] |= 0x1FU;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_TE_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[4] &= (uint8_t)(~0x3FU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[4] |= 0x3FU;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_SC_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[6] &= (uint8_t)(~0x3FU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[6] |= 0x3FU;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_SEM_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[8] &= (uint8_t)(~0x80U & 0xFFU);
|
|
QS_filt_.glb[9] &= (uint8_t)(~0x07U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[8] |= 0x80U;
|
|
QS_filt_.glb[9] |= 0x07U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_MTX_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[9] &= (uint8_t)(~0xF8U & 0xFFU);
|
|
QS_filt_.glb[10] &= (uint8_t)(~0x01U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[9] |= 0xF8U;
|
|
QS_filt_.glb[10] |= 0x01U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_U0_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[12] &= (uint8_t)(~0xF0U & 0xFFU);
|
|
QS_filt_.glb[13] &= (uint8_t)(~0x01U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[12] |= 0xF0U;
|
|
QS_filt_.glb[13] |= 0x01U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_U1_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[13] &= (uint8_t)(~0x3EU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[13] |= 0x3EU;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_U2_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[13] &= (uint8_t)(~0xC0U & 0xFFU);
|
|
QS_filt_.glb[14] &= (uint8_t)(~0x07U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[13] |= 0xC0U;
|
|
QS_filt_.glb[14] |= 0x07U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_U3_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[14] &= (uint8_t)(~0xF8U & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[14] |= 0xF8U;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_U4_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[15] &= (uint8_t)(~0x1FU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[15] |= 0x1FU;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_UA_RECORDS:
|
|
if (isRemove) {
|
|
QS_filt_.glb[12] &= (uint8_t)(~0xF0U & 0xFFU);
|
|
QS_filt_.glb[13] = 0U;
|
|
QS_filt_.glb[14] = 0U;
|
|
QS_filt_.glb[15] &= (uint8_t)(~0x1FU & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[12] |= 0xF0U;
|
|
QS_filt_.glb[13] |= 0xFFU;
|
|
QS_filt_.glb[14] |= 0xFFU;
|
|
QS_filt_.glb[15] |= 0x1FU;
|
|
}
|
|
break;
|
|
default: {
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
// QS rec number must be below 0x7D, so no need for escaping
|
|
Q_ASSERT_INCRIT(210, rec < 0x7DU);
|
|
QS_CRIT_EXIT();
|
|
|
|
if (isRemove) {
|
|
QS_filt_.glb[rec >> 3U]
|
|
&= (uint8_t)(~(1U << (rec & 7U)) & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.glb[rec >> 3U]
|
|
|= (1U << (rec & 7U));
|
|
// never turn the last 3 records on (0x7D, 0x7E, 0x7F)
|
|
QS_filt_.glb[15] &= 0x1FU;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_locFilter_(int_fast16_t const filter) {
|
|
bool const isRemove = (filter < 0);
|
|
uint8_t const qs_id = isRemove ? (uint8_t)(-filter) : (uint8_t)filter;
|
|
uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
|
|
uint_fast8_t i;
|
|
switch (qs_id) {
|
|
case (uint8_t)QS_ALL_IDS:
|
|
// set all local filters (partially unrolled loop)
|
|
for (i = 0U; i < Q_DIM(QS_filt_.loc); i += 4U) {
|
|
QS_filt_.loc[i ] = tmp;
|
|
QS_filt_.loc[i + 1U] = tmp;
|
|
QS_filt_.loc[i + 2U] = tmp;
|
|
QS_filt_.loc[i + 3U] = tmp;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_AO_IDS:
|
|
for (i = 0U; i < 8U; i += 4U) {
|
|
QS_filt_.loc[i ] = tmp;
|
|
QS_filt_.loc[i + 1U] = tmp;
|
|
QS_filt_.loc[i + 2U] = tmp;
|
|
QS_filt_.loc[i + 3U] = tmp;
|
|
}
|
|
break;
|
|
case (uint8_t)QS_EP_IDS:
|
|
i = 8U;
|
|
QS_filt_.loc[i ] = tmp;
|
|
QS_filt_.loc[i + 1U] = tmp;
|
|
break;
|
|
case (uint8_t)QS_AP_IDS:
|
|
i = 12U;
|
|
QS_filt_.loc[i ] = tmp;
|
|
QS_filt_.loc[i + 1U] = tmp;
|
|
QS_filt_.loc[i + 2U] = tmp;
|
|
QS_filt_.loc[i + 3U] = tmp;
|
|
break;
|
|
default: {
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
// qs_id must be in range
|
|
Q_ASSERT_INCRIT(310, qs_id < 0x7FU);
|
|
QS_CRIT_EXIT();
|
|
if (isRemove) {
|
|
QS_filt_.loc[qs_id >> 3U]
|
|
&= (uint8_t)(~(1U << (qs_id & 7U)) & 0xFFU);
|
|
}
|
|
else {
|
|
QS_filt_.loc[qs_id >> 3U]
|
|
|= (1U << (qs_id & 7U));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
QS_filt_.loc[0] |= 0x01U; // leave QS_ID == 0 always on
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_beginRec_(uint_fast8_t const rec) {
|
|
uint8_t const b = (uint8_t)(QS_priv_.seq + 1U);
|
|
uint8_t chksum = 0U; // reset the checksum
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
|
|
QS_priv_.seq = b; // store the incremented sequence num
|
|
QS_priv_.used += 2U; // 2 bytes about to be added
|
|
|
|
QS_INSERT_ESC_BYTE_(b)
|
|
|
|
chksum = (uint8_t)(chksum + rec); // update checksum
|
|
QS_INSERT_BYTE_((uint8_t)rec) // rec byte does not need escaping
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_endRec_(void) {
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head;
|
|
QSCtr const end = QS_priv_.end;
|
|
uint8_t b = QS_priv_.chksum;
|
|
b ^= 0xFFU; // invert the bits in the checksum
|
|
|
|
QS_priv_.used += 2U; // 2 bytes about to be added
|
|
|
|
if ((b != QS_FRAME) && (b != QS_ESC)) {
|
|
QS_INSERT_BYTE_(b)
|
|
}
|
|
else {
|
|
QS_INSERT_BYTE_(QS_ESC)
|
|
QS_INSERT_BYTE_(b ^ QS_ESC_XOR)
|
|
++QS_priv_.used; // account for the ESC byte
|
|
}
|
|
|
|
QS_INSERT_BYTE_(QS_FRAME) // do not escape this QS_FRAME
|
|
|
|
QS_priv_.head = head; // save the head
|
|
|
|
// overrun over the old data?
|
|
if (QS_priv_.used > end) {
|
|
QS_priv_.used = end; // the whole buffer is used
|
|
QS_priv_.tail = head; // shift the tail to the old data
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u8_raw_(uint8_t const d) {
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
|
|
QS_priv_.used += 1U; // 1 byte about to be added
|
|
QS_INSERT_ESC_BYTE_(d)
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_2u8_raw_(
|
|
uint8_t const d1,
|
|
uint8_t const d2)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
|
|
QS_priv_.used += 2U; // 2 bytes are about to be added
|
|
QS_INSERT_ESC_BYTE_(d1)
|
|
QS_INSERT_ESC_BYTE_(d2)
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u16_raw_(uint16_t const d) {
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
uint16_t x = d;
|
|
|
|
QS_priv_.used += 2U; // 2 bytes are about to be added
|
|
|
|
QS_INSERT_ESC_BYTE_((uint8_t)x)
|
|
x >>= 8U;
|
|
QS_INSERT_ESC_BYTE_((uint8_t)x)
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u32_raw_(uint32_t const d) {
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
uint32_t x = d;
|
|
|
|
QS_priv_.used += 4U; // 4 bytes are about to be added
|
|
for (uint_fast8_t i = 4U; i != 0U; --i) {
|
|
QS_INSERT_ESC_BYTE_((uint8_t)x)
|
|
x >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_obj_raw_(void const * const obj) {
|
|
#if (QS_OBJ_PTR_SIZE == 1U)
|
|
QS_u8_raw_((uint8_t)obj);
|
|
#elif (QS_OBJ_PTR_SIZE == 2U)
|
|
QS_u16_raw_((uint16_t)obj);
|
|
#elif (QS_OBJ_PTR_SIZE == 4U)
|
|
QS_u32_raw_((uint32_t)obj);
|
|
#elif (QS_OBJ_PTR_SIZE == 8U)
|
|
QS_u64_raw_((uint64_t)obj);
|
|
#else
|
|
QS_u32_raw_((uint32_t)obj);
|
|
#endif
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_str_raw_(char const * const str) {
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
QSCtr used = QS_priv_.used; // put in a temporary (register)
|
|
|
|
for (char const *s = str; *s != '\0'; ++s) {
|
|
chksum += (uint8_t)*s; // update checksum
|
|
QS_INSERT_BYTE_((uint8_t)*s) // ASCII char doesn't need escaping
|
|
++used;
|
|
}
|
|
QS_INSERT_BYTE_((uint8_t)'\0') // zero-terminate the string
|
|
++used;
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
QS_priv_.used = used; // save # of used buffer space
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u8_fmt_(
|
|
uint8_t const format,
|
|
uint8_t const d)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
|
|
QS_priv_.used += 2U; // 2 bytes about to be added
|
|
|
|
QS_INSERT_ESC_BYTE_(format)
|
|
QS_INSERT_ESC_BYTE_(d)
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u16_fmt_(
|
|
uint8_t const format,
|
|
uint16_t const d)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
uint8_t b = (uint8_t)d;
|
|
|
|
QS_priv_.used += 3U; // 3 bytes about to be added
|
|
|
|
QS_INSERT_ESC_BYTE_(format)
|
|
QS_INSERT_ESC_BYTE_(b)
|
|
b = (uint8_t)(d >> 8U);
|
|
QS_INSERT_ESC_BYTE_(b)
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_u32_fmt_(
|
|
uint8_t const format,
|
|
uint32_t const d)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
uint32_t x = d;
|
|
|
|
QS_priv_.used += 5U; // 5 bytes about to be added
|
|
QS_INSERT_ESC_BYTE_(format) // insert the format byte
|
|
|
|
// insert 4 bytes...
|
|
for (uint_fast8_t i = 4U; i != 0U; --i) {
|
|
QS_INSERT_ESC_BYTE_((uint8_t)x)
|
|
x >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_str_fmt_(char const * const str) {
|
|
uint8_t chksum = QS_priv_.chksum;
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
QSCtr used = QS_priv_.used; // put in a temporary (register)
|
|
|
|
used += 2U; // account for the format byte and the terminating-0
|
|
QS_INSERT_BYTE_((uint8_t)QS_STR_T)
|
|
chksum += (uint8_t)QS_STR_T;
|
|
|
|
for (char const *s = str; *s != '\0'; ++s) {
|
|
QS_INSERT_BYTE_((uint8_t)*s) // ASCII char doesn't need escaping
|
|
chksum += (uint8_t)*s; // update checksum
|
|
++used;
|
|
}
|
|
QS_INSERT_BYTE_(0U) // zero-terminate the string
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
QS_priv_.used = used; // save # of used buffer space
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_mem_fmt_(
|
|
uint8_t const * const blk,
|
|
uint8_t const size)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum;
|
|
uint8_t * const buf = QS_priv_.buf; // put in a temporary (register)
|
|
QSCtr head = QS_priv_.head; // put in a temporary (register)
|
|
QSCtr const end = QS_priv_.end; // put in a temporary (register)
|
|
uint8_t const *pb = blk;
|
|
|
|
QS_priv_.used += ((QSCtr)size + 2U); // size+2 bytes to be added
|
|
|
|
QS_INSERT_BYTE_((uint8_t)QS_MEM_T)
|
|
chksum += (uint8_t)QS_MEM_T;
|
|
|
|
QS_INSERT_ESC_BYTE_(size)
|
|
// output the 'size' # bytes
|
|
for (uint8_t len = size; len > 0U; --len) {
|
|
QS_INSERT_ESC_BYTE_(*pb)
|
|
++pb;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_sig_dict_pre_(
|
|
QSignal const sig,
|
|
void const * const obj,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_SIG_DICT);
|
|
QS_SIG_PRE_(sig);
|
|
QS_OBJ_PRE_(obj);
|
|
QS_STR_PRE_((*name == '&') ? &name[1] : name);
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_obj_dict_pre_(
|
|
void const * const obj,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
|
|
QS_OBJ_PRE_(obj);
|
|
QS_STR_PRE_((*name == '&') ? &name[1] : name);
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_obj_arr_dict_pre_(
|
|
void const * const obj,
|
|
uint_fast16_t const idx,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
Q_REQUIRE_INCRIT(400, idx < 1000U);
|
|
QS_CRIT_EXIT();
|
|
|
|
// format idx into a char buffer as "xxx\0"
|
|
uint8_t idx_str[4];
|
|
uint_fast16_t tmp = idx;
|
|
uint8_t i;
|
|
idx_str[3] = 0U; // zero-terminate
|
|
idx_str[2] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
|
|
tmp /= 10U;
|
|
idx_str[1] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
|
|
if (idx_str[1] == (uint8_t)'0') {
|
|
i = 2U;
|
|
}
|
|
else {
|
|
tmp /= 10U;
|
|
idx_str[0] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
|
|
if (idx_str[0] == (uint8_t)'0') {
|
|
i = 1U;
|
|
}
|
|
else {
|
|
i = 0U;
|
|
}
|
|
}
|
|
|
|
uint8_t j = ((*name == '&') ? 1U : 0U);
|
|
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
|
|
QS_OBJ_PRE_(obj);
|
|
for (; name[j] != '\0'; ++j) {
|
|
QS_U8_PRE_(name[j]);
|
|
if (name[j] == '[') {
|
|
++j;
|
|
break;
|
|
}
|
|
}
|
|
for (; idx_str[i] != 0U; ++i) {
|
|
QS_U8_PRE_(idx_str[i]);
|
|
}
|
|
// skip chars until ']'
|
|
for (; name[j] != '\0'; ++j) {
|
|
if (name[j] == ']') {
|
|
break;
|
|
}
|
|
}
|
|
for (; name[j] != '\0'; ++j) {
|
|
QS_U8_PRE_(name[j]);
|
|
}
|
|
QS_U8_PRE_(0U); // zero-terminate
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_fun_dict_pre_(
|
|
QSpyFunPtr const fun,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_FUN_DICT);
|
|
QS_FUN_PRE_(fun);
|
|
QS_STR_PRE_((*name == '&') ? &name[1] : name);
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_usr_dict_pre_(
|
|
enum_t const rec,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_USR_DICT);
|
|
QS_U8_PRE_(rec);
|
|
QS_STR_PRE_(name);
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_enum_dict_pre_(
|
|
enum_t const value,
|
|
uint8_t const group,
|
|
char const * const name)
|
|
{
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_ENUM_DICT);
|
|
QS_2U8_PRE_(value, group);
|
|
QS_STR_PRE_(name);
|
|
QS_endRec_();
|
|
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
QS_onFlush();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_assertion_pre_(
|
|
char const * const module,
|
|
int_t const id,
|
|
uint32_t const delay)
|
|
{
|
|
// NOTE: called in a critical section
|
|
|
|
QS_beginRec_((uint_fast8_t)QS_ASSERT_FAIL);
|
|
QS_TIME_PRE_();
|
|
QS_U16_PRE_(id);
|
|
QS_STR_PRE_((module != (char *)0) ? module : "?");
|
|
QS_endRec_();
|
|
QS_onFlush();
|
|
|
|
for (uint32_t volatile delay_ctr = delay;
|
|
delay_ctr > 0U; --delay_ctr)
|
|
{}
|
|
QS_onCleanup();
|
|
}
|
|
|
|
//............................................................................
|
|
void QS_target_info_pre_(uint8_t const isReset) {
|
|
// NOTE: called in a critical section
|
|
|
|
static uint8_t const ZERO = (uint8_t)'0';
|
|
static uint8_t const * const TIME = (uint8_t const *)&Q_BUILD_TIME[0];
|
|
static uint8_t const * const DATE = (uint8_t const *)&Q_BUILD_DATE[0];
|
|
static union {
|
|
uint16_t u16;
|
|
uint8_t u8[2];
|
|
} endian_test;
|
|
|
|
endian_test.u16 = 0x0102U;
|
|
QS_beginRec_((uint_fast8_t)QS_TARGET_INFO);
|
|
QS_U8_PRE_(isReset);
|
|
QS_U16_PRE_(((endian_test.u8[0] == 0x01U) // big endian?
|
|
? (0x8000U | QP_VERSION)
|
|
: QP_VERSION)); // target endianness + version number
|
|
|
|
// send the object sizes...
|
|
QS_U8_PRE_(Q_SIGNAL_SIZE | (QF_EVENT_SIZ_SIZE << 4U));
|
|
|
|
#ifdef QF_EQUEUE_CTR_SIZE
|
|
QS_U8_PRE_(QF_EQUEUE_CTR_SIZE | (QF_TIMEEVT_CTR_SIZE << 4U));
|
|
#else
|
|
QS_U8_PRE_(QF_TIMEEVT_CTR_SIZE << 4U);
|
|
#endif // QF_EQUEUE_CTR_SIZE
|
|
|
|
#ifdef QF_MPOOL_CTR_SIZE
|
|
QS_U8_PRE_(QF_MPOOL_SIZ_SIZE | (QF_MPOOL_CTR_SIZE << 4U));
|
|
#else
|
|
QS_U8_PRE_(0U);
|
|
#endif // QF_MPOOL_CTR_SIZE
|
|
|
|
QS_U8_PRE_(QS_OBJ_PTR_SIZE | (QS_FUN_PTR_SIZE << 4U));
|
|
QS_U8_PRE_(QS_TIME_SIZE);
|
|
|
|
// send the limits...
|
|
QS_U8_PRE_(QF_MAX_ACTIVE);
|
|
QS_U8_PRE_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE << 4U));
|
|
|
|
// send the build time in three bytes (sec, min, hour)...
|
|
QS_U8_PRE_((10U * (uint8_t)(TIME[6] - ZERO))
|
|
+ (uint8_t)(TIME[7] - ZERO));
|
|
QS_U8_PRE_((10U * (uint8_t)(TIME[3] - ZERO))
|
|
+ (uint8_t)(TIME[4] - ZERO));
|
|
if (Q_BUILD_TIME[0] == ' ') {
|
|
QS_U8_PRE_(TIME[1] - ZERO);
|
|
}
|
|
else {
|
|
QS_U8_PRE_((10U * (uint8_t)(TIME[0] - ZERO))
|
|
+ (uint8_t)(TIME[1] - ZERO));
|
|
}
|
|
|
|
// send the build date in three bytes (day, month, year) ...
|
|
if (Q_BUILD_DATE[4] == ' ') {
|
|
QS_U8_PRE_(DATE[5] - ZERO);
|
|
}
|
|
else {
|
|
QS_U8_PRE_((10U * (uint8_t)(DATE[4] - ZERO))
|
|
+ (uint8_t)(DATE[5] - ZERO));
|
|
}
|
|
// convert the 3-letter month to a number 1-12 ...
|
|
uint8_t b;
|
|
switch ((int_t)DATE[0] + (int_t)DATE[1] + (int_t)DATE[2]) {
|
|
case (int_t)'J' + (int_t)'a' + (int_t)'n':
|
|
b = 1U;
|
|
break;
|
|
case (int_t)'F' + (int_t)'e' + (int_t)'b':
|
|
b = 2U;
|
|
break;
|
|
case (int_t)'M' + (int_t)'a' + (int_t)'r':
|
|
b = 3U;
|
|
break;
|
|
case (int_t)'A' + (int_t)'p' + (int_t)'r':
|
|
b = 4U;
|
|
break;
|
|
case (int_t)'M' + (int_t)'a' + (int_t)'y':
|
|
b = 5U;
|
|
break;
|
|
case (int_t)'J' + (int_t)'u' + (int_t)'n':
|
|
b = 6U;
|
|
break;
|
|
case (int_t)'J' + (int_t)'u' + (int_t)'l':
|
|
b = 7U;
|
|
break;
|
|
case (int_t)'A' + (int_t)'u' + (int_t)'g':
|
|
b = 8U;
|
|
break;
|
|
case (int_t)'S' + (int_t)'e' + (int_t)'p':
|
|
b = 9U;
|
|
break;
|
|
case (int_t)'O' + (int_t)'c' + (int_t)'t':
|
|
b = 10U;
|
|
break;
|
|
case (int_t)'N' + (int_t)'o' + (int_t)'v':
|
|
b = 11U;
|
|
break;
|
|
case (int_t)'D' + (int_t)'e' + (int_t)'c':
|
|
b = 12U;
|
|
break;
|
|
default:
|
|
b = 0U;
|
|
break;
|
|
}
|
|
QS_U8_PRE_(b); // store the month
|
|
QS_U8_PRE_((10U * (uint8_t)(DATE[9] - ZERO))
|
|
+ (uint8_t)(DATE[10] - ZERO));
|
|
QS_endRec_();
|
|
}
|
|
|
|
//! @endcond</text>
|
|
</file>
|
|
<!--${src::qs::qs_64bit.c}-->
|
|
<file name="qs_64bit.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS package-scope internal interface
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
//! @static @private @memberof QS
|
|
void QS_u64_raw_(uint64_t const d) {
|
|
uint8_t chksum = QS_priv_.chksum;
|
|
uint8_t * const buf = QS_priv_.buf;
|
|
QSCtr head = QS_priv_.head;
|
|
QSCtr const end = QS_priv_.end;
|
|
|
|
QS_priv_.used += 8U; // 8 bytes are about to be added
|
|
uint64_t u64 = d;
|
|
for (uint_fast8_t i = 8U; i != 0U; --i) {
|
|
uint8_t const b = (uint8_t)u64;
|
|
QS_INSERT_ESC_BYTE_(b)
|
|
u64 >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//! @static @private @memberof QS
|
|
void QS_u64_fmt_(
|
|
uint8_t const format,
|
|
uint64_t const d)
|
|
{
|
|
uint8_t chksum = QS_priv_.chksum;
|
|
uint8_t * const buf = QS_priv_.buf;
|
|
QSCtr head = QS_priv_.head;
|
|
QSCtr const end = QS_priv_.end;
|
|
|
|
QS_priv_.used += 9U; // 9 bytes are about to be added
|
|
QS_INSERT_ESC_BYTE_(format) // insert the format byte
|
|
|
|
// output 8 bytes of data...
|
|
uint64_t u64 = d;
|
|
for (uint_fast8_t i = 8U; i != 0U; --i) {
|
|
uint8_t const b = (uint8_t)u64;
|
|
QS_INSERT_ESC_BYTE_(b)
|
|
u64 >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//! @endcond</text>
|
|
</file>
|
|
<!--${src::qs::qs_fp.c}-->
|
|
<file name="qs_fp.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS package-scope internal interface
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
//! @static @private @memberof QS
|
|
void QS_f32_fmt_(
|
|
uint8_t const format,
|
|
float32_t const f)
|
|
{
|
|
union F32Rep {
|
|
float32_t f;
|
|
uint32_t u;
|
|
} fu32; // the internal binary representation
|
|
uint8_t chksum = QS_priv_.chksum; // put in a temporary (register)
|
|
uint8_t * const buf = QS_priv_.buf;
|
|
QSCtr head = QS_priv_.head;
|
|
QSCtr const end = QS_priv_.end;
|
|
uint_fast8_t i;
|
|
|
|
fu32.f = f; // assign the binary representation
|
|
|
|
QS_priv_.used += 5U; // 5 bytes about to be added
|
|
QS_INSERT_ESC_BYTE_(format) // insert the format byte
|
|
|
|
// insert 4 bytes...
|
|
for (i = 4U; i != 0U; --i) {
|
|
QS_INSERT_ESC_BYTE_((uint8_t)fu32.u)
|
|
fu32.u >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//! @static @private @memberof QS
|
|
void QS_f64_fmt_(
|
|
uint8_t const format,
|
|
float64_t const d)
|
|
{
|
|
union F64Rep {
|
|
float64_t d;
|
|
uint32_t u[2];
|
|
} fu64; // the internal binary representation
|
|
uint8_t chksum = QS_priv_.chksum;
|
|
uint8_t * const buf = QS_priv_.buf;
|
|
QSCtr head = QS_priv_.head;
|
|
QSCtr const end = QS_priv_.end;
|
|
uint32_t i;
|
|
|
|
// static constant untion to detect endianness of the machine
|
|
static union U32Rep {
|
|
uint32_t u32;
|
|
uint8_t u8;
|
|
} const endian = { 1U };
|
|
|
|
fu64.d = d; // assign the binary representation
|
|
|
|
// is this a big-endian machine?
|
|
if (endian.u8 == 0U) {
|
|
// swap fu64.u[0] <-> fu64.u[1]...
|
|
i = fu64.u[0];
|
|
fu64.u[0] = fu64.u[1];
|
|
fu64.u[1] = i;
|
|
}
|
|
|
|
QS_priv_.used += 9U; // 9 bytes about to be added
|
|
QS_INSERT_ESC_BYTE_(format) // insert the format byte
|
|
|
|
// output 4 bytes from fu64.u[0]...
|
|
for (i = 4U; i != 0U; --i) {
|
|
QS_INSERT_ESC_BYTE_((uint8_t)fu64.u[0])
|
|
fu64.u[0] >>= 8U;
|
|
}
|
|
|
|
// output 4 bytes from fu64.u[1]...
|
|
for (i = 4U; i != 0U; --i) {
|
|
QS_INSERT_ESC_BYTE_((uint8_t)fu64.u[1])
|
|
fu64.u[1] >>= 8U;
|
|
}
|
|
|
|
QS_priv_.head = head; // save the head
|
|
QS_priv_.chksum = chksum; // save the checksum
|
|
}
|
|
|
|
//! @endcond</text>
|
|
</file>
|
|
<!--${src::qs::qs_rx.c}-->
|
|
<file name="qs_rx.c">
|
|
<text>#define QP_IMPL // this is QP implementation
|
|
#include "qs_port.h" // QS port
|
|
#include "qs_pkg.h" // QS package-scope interface
|
|
#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
Q_DEFINE_THIS_MODULE("qs_rx")
|
|
|
|
#if (QS_OBJ_PTR_SIZE == 1U)
|
|
typedef uint8_t QSObj;
|
|
#elif (QS_OBJ_PTR_SIZE == 2U)
|
|
typedef uint16_t QSObj;
|
|
#elif (QS_OBJ_PTR_SIZE == 4U)
|
|
typedef uint32_t QSObj;
|
|
#elif (QS_OBJ_PTR_SIZE == 8U)
|
|
typedef uint64_t QSObj;
|
|
#endif
|
|
|
|
typedef struct {
|
|
uint32_t param1;
|
|
uint32_t param2;
|
|
uint32_t param3;
|
|
uint8_t idx;
|
|
uint8_t cmdId;
|
|
} CmdVar;
|
|
|
|
typedef struct {
|
|
uint_fast8_t rate;
|
|
} TickVar;
|
|
|
|
typedef struct {
|
|
uint16_t offs;
|
|
uint8_t size;
|
|
uint8_t num;
|
|
uint8_t idx;
|
|
} PeekVar;
|
|
|
|
typedef struct {
|
|
uint32_t data;
|
|
uint16_t offs;
|
|
uint8_t size;
|
|
uint8_t num;
|
|
uint8_t idx;
|
|
uint8_t fill;
|
|
} PokeVar;
|
|
|
|
typedef struct {
|
|
uint8_t data[16];
|
|
uint8_t idx;
|
|
int8_t recId; // global/local
|
|
} FltVar;
|
|
|
|
typedef struct {
|
|
QSObj addr;
|
|
uint8_t idx;
|
|
uint8_t kind; // see qs.h, enum QSpyObjKind
|
|
int8_t recId;
|
|
} ObjVar;
|
|
|
|
typedef struct {
|
|
QEvt *e;
|
|
uint8_t *p;
|
|
QSignal sig;
|
|
uint16_t len;
|
|
uint8_t prio;
|
|
uint8_t idx;
|
|
} EvtVar;
|
|
|
|
//! extended-state variables for the current state
|
|
//!
|
|
//! @trace
|
|
//! - @tr{DVR-QS-MC4-R19_02}
|
|
static struct {
|
|
union Variant {
|
|
CmdVar cmd;
|
|
TickVar tick;
|
|
PeekVar peek;
|
|
PokeVar poke;
|
|
FltVar flt;
|
|
ObjVar obj;
|
|
EvtVar evt;
|
|
#ifdef Q_UTEST
|
|
struct QS_TProbe tp;
|
|
#endif // Q_UTEST
|
|
} var;
|
|
uint8_t state;
|
|
uint8_t esc;
|
|
uint8_t seq;
|
|
uint8_t chksum;
|
|
} l_rx;
|
|
|
|
enum {
|
|
ERROR_STATE,
|
|
WAIT4_SEQ,
|
|
WAIT4_REC,
|
|
WAIT4_INFO_FRAME,
|
|
WAIT4_CMD_ID,
|
|
WAIT4_CMD_PARAM1,
|
|
WAIT4_CMD_PARAM2,
|
|
WAIT4_CMD_PARAM3,
|
|
WAIT4_CMD_FRAME,
|
|
WAIT4_RESET_FRAME,
|
|
WAIT4_TICK_RATE,
|
|
WAIT4_TICK_FRAME,
|
|
WAIT4_PEEK_OFFS,
|
|
WAIT4_PEEK_SIZE,
|
|
WAIT4_PEEK_NUM,
|
|
WAIT4_PEEK_FRAME,
|
|
WAIT4_POKE_OFFS,
|
|
WAIT4_POKE_SIZE,
|
|
WAIT4_POKE_NUM,
|
|
WAIT4_POKE_DATA,
|
|
WAIT4_POKE_FRAME,
|
|
WAIT4_FILL_DATA,
|
|
WAIT4_FILL_FRAME,
|
|
WAIT4_FILTER_LEN,
|
|
WAIT4_FILTER_DATA,
|
|
WAIT4_FILTER_FRAME,
|
|
WAIT4_OBJ_KIND,
|
|
WAIT4_OBJ_ADDR,
|
|
WAIT4_OBJ_FRAME,
|
|
WAIT4_QUERY_KIND,
|
|
WAIT4_QUERY_FRAME,
|
|
WAIT4_EVT_PRIO,
|
|
WAIT4_EVT_SIG,
|
|
WAIT4_EVT_LEN,
|
|
WAIT4_EVT_PAR,
|
|
WAIT4_EVT_FRAME
|
|
|
|
#ifdef Q_UTEST
|
|
,
|
|
WAIT4_TEST_SETUP_FRAME,
|
|
WAIT4_TEST_TEARDOWN_FRAME,
|
|
WAIT4_TEST_PROBE_DATA,
|
|
WAIT4_TEST_PROBE_ADDR,
|
|
WAIT4_TEST_PROBE_FRAME,
|
|
WAIT4_TEST_CONTINUE_FRAME
|
|
#endif // Q_UTEST
|
|
};
|
|
|
|
// static helper functions...
|
|
static void QS_rxParseData_(uint8_t const b);
|
|
static void QS_rxHandleGoodFrame_(uint8_t const state);
|
|
static void QS_rxHandleBadFrame_(uint8_t const state);
|
|
static void QS_rxReportAck_(int8_t const recId);
|
|
static void QS_rxReportError_(int8_t const code);
|
|
static void QS_rxReportDone_(int8_t const recId);
|
|
static void QS_queryCurrObj(uint8_t const obj_kind);
|
|
static void QS_rxPoke_(void);
|
|
|
|
//! Internal QS-RX macro to encapsulate tran. in the QS-RX FSM
|
|
#define QS_RX_TRAN_(target_) (l_rx.state = (uint8_t)(target_))
|
|
|
|
QS_RxAttr QS_rxPriv_;
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
$define ${QS::QS-RX}
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
static void QS_rxParseData_(uint8_t const b) {
|
|
switch (l_rx.state) {
|
|
case (uint8_t)WAIT4_SEQ: {
|
|
++l_rx.seq;
|
|
if (l_rx.seq != b) {
|
|
QS_rxReportError_(0x42);
|
|
l_rx.seq = b; // update the sequence
|
|
}
|
|
QS_RX_TRAN_(WAIT4_REC);
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_REC: {
|
|
switch (b) {
|
|
case (uint8_t)QS_RX_INFO:
|
|
QS_RX_TRAN_(WAIT4_INFO_FRAME);
|
|
break;
|
|
case (uint8_t)QS_RX_COMMAND:
|
|
QS_RX_TRAN_(WAIT4_CMD_ID);
|
|
break;
|
|
case (uint8_t)QS_RX_RESET:
|
|
QS_RX_TRAN_(WAIT4_RESET_FRAME);
|
|
break;
|
|
case (uint8_t)QS_RX_TICK:
|
|
QS_RX_TRAN_(WAIT4_TICK_RATE);
|
|
break;
|
|
case (uint8_t)QS_RX_PEEK:
|
|
if (QS_rxPriv_.currObj[AP_OBJ] != (void *)0) {
|
|
l_rx.var.peek.offs = 0U;
|
|
l_rx.var.peek.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_PEEK_OFFS);
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_PEEK);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
case (uint8_t)QS_RX_POKE: // intentionally fall-through
|
|
case (uint8_t)QS_RX_FILL:
|
|
l_rx.var.poke.fill =
|
|
((b == (uint8_t)QS_RX_FILL) ? 1U : 0U);
|
|
if (QS_rxPriv_.currObj[AP_OBJ] != (void *)0) {
|
|
l_rx.var.poke.offs = 0U;
|
|
l_rx.var.poke.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_POKE_OFFS);
|
|
}
|
|
else {
|
|
QS_rxReportError_((l_rx.var.poke.fill != 0U)
|
|
? (int8_t)QS_RX_FILL
|
|
: (int8_t)QS_RX_POKE);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
case (uint8_t)QS_RX_GLB_FILTER: // intentionally fall-through
|
|
case (uint8_t)QS_RX_LOC_FILTER:
|
|
l_rx.var.flt.recId = (int8_t)b;
|
|
QS_RX_TRAN_(WAIT4_FILTER_LEN);
|
|
break;
|
|
case (uint8_t)QS_RX_AO_FILTER: // intentionally fall-through
|
|
case (uint8_t)QS_RX_CURR_OBJ:
|
|
l_rx.var.obj.recId = (int8_t)b;
|
|
QS_RX_TRAN_(WAIT4_OBJ_KIND);
|
|
break;
|
|
case (uint8_t)QS_RX_QUERY_CURR:
|
|
l_rx.var.obj.recId = (int8_t)QS_RX_QUERY_CURR;
|
|
QS_RX_TRAN_(WAIT4_QUERY_KIND);
|
|
break;
|
|
case (uint8_t)QS_RX_EVENT:
|
|
QS_RX_TRAN_(WAIT4_EVT_PRIO);
|
|
break;
|
|
|
|
#ifdef Q_UTEST
|
|
case (uint8_t)QS_RX_TEST_SETUP:
|
|
QS_RX_TRAN_(WAIT4_TEST_SETUP_FRAME);
|
|
break;
|
|
case (uint8_t)QS_RX_TEST_TEARDOWN:
|
|
QS_RX_TRAN_(WAIT4_TEST_TEARDOWN_FRAME);
|
|
break;
|
|
case (uint8_t)QS_RX_TEST_CONTINUE:
|
|
QS_RX_TRAN_(WAIT4_TEST_CONTINUE_FRAME);
|
|
break;
|
|
case (uint8_t)QS_RX_TEST_PROBE:
|
|
if (QS_tstPriv_.tpNum
|
|
< (uint8_t)(sizeof(QS_tstPriv_.tpBuf)
|
|
/ sizeof(QS_tstPriv_.tpBuf[0])))
|
|
{
|
|
l_rx.var.tp.data = 0U;
|
|
l_rx.var.tp.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_TEST_PROBE_DATA);
|
|
}
|
|
else { // the # Test-Probes exceeded
|
|
QS_rxReportError_((int8_t)QS_RX_TEST_PROBE);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
#endif // Q_UTEST
|
|
|
|
default:
|
|
QS_rxReportError_(0x43);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_INFO_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_CMD_ID: {
|
|
l_rx.var.cmd.cmdId = b;
|
|
l_rx.var.cmd.idx = 0U;
|
|
l_rx.var.cmd.param1 = 0U;
|
|
l_rx.var.cmd.param2 = 0U;
|
|
l_rx.var.cmd.param3 = 0U;
|
|
QS_RX_TRAN_(WAIT4_CMD_PARAM1);
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_CMD_PARAM1: {
|
|
l_rx.var.cmd.param1 |= ((uint32_t)b << l_rx.var.cmd.idx);
|
|
l_rx.var.cmd.idx += 8U;
|
|
if (l_rx.var.cmd.idx == (8U * 4U)) {
|
|
l_rx.var.cmd.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_CMD_PARAM2);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_CMD_PARAM2: {
|
|
l_rx.var.cmd.param2 |= ((uint32_t)b << l_rx.var.cmd.idx);
|
|
l_rx.var.cmd.idx += 8U;
|
|
if (l_rx.var.cmd.idx == (8U * 4U)) {
|
|
l_rx.var.cmd.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_CMD_PARAM3);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_CMD_PARAM3: {
|
|
l_rx.var.cmd.param3 |= ((uint32_t)b << l_rx.var.cmd.idx);
|
|
l_rx.var.cmd.idx += 8U;
|
|
if (l_rx.var.cmd.idx == (8U * 4U)) {
|
|
l_rx.var.cmd.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_CMD_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_CMD_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_RESET_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TICK_RATE: {
|
|
l_rx.var.tick.rate = (uint_fast8_t)b;
|
|
QS_RX_TRAN_(WAIT4_TICK_FRAME);
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TICK_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_PEEK_OFFS: {
|
|
if (l_rx.var.peek.idx == 0U) {
|
|
l_rx.var.peek.offs = (uint16_t)b;
|
|
l_rx.var.peek.idx += 8U;
|
|
}
|
|
else {
|
|
l_rx.var.peek.offs |= (uint16_t)((uint16_t)b << 8U);
|
|
QS_RX_TRAN_(WAIT4_PEEK_SIZE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_PEEK_SIZE: {
|
|
if ((b == 1U) || (b == 2U) || (b == 4U)) {
|
|
l_rx.var.peek.size = b;
|
|
QS_RX_TRAN_(WAIT4_PEEK_NUM);
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_PEEK);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_PEEK_NUM: {
|
|
l_rx.var.peek.num = b;
|
|
QS_RX_TRAN_(WAIT4_PEEK_FRAME);
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_PEEK_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_POKE_OFFS: {
|
|
if (l_rx.var.poke.idx == 0U) {
|
|
l_rx.var.poke.offs = (uint16_t)b;
|
|
l_rx.var.poke.idx = 1U;
|
|
}
|
|
else {
|
|
l_rx.var.poke.offs |= (uint16_t)((uint16_t)b << 8U);
|
|
QS_RX_TRAN_(WAIT4_POKE_SIZE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_POKE_SIZE: {
|
|
if ((b == 1U) || (b == 2U) || (b == 4U)) {
|
|
l_rx.var.poke.size = b;
|
|
QS_RX_TRAN_(WAIT4_POKE_NUM);
|
|
}
|
|
else {
|
|
QS_rxReportError_((l_rx.var.poke.fill != 0U)
|
|
? (int8_t)QS_RX_FILL
|
|
: (int8_t)QS_RX_POKE);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_POKE_NUM: {
|
|
if (b > 0U) {
|
|
l_rx.var.poke.num = b;
|
|
l_rx.var.poke.data = 0U;
|
|
l_rx.var.poke.idx = 0U;
|
|
QS_RX_TRAN_((l_rx.var.poke.fill != 0U)
|
|
? WAIT4_FILL_DATA
|
|
: WAIT4_POKE_DATA);
|
|
}
|
|
else {
|
|
QS_rxReportError_((l_rx.var.poke.fill != 0U)
|
|
? (int8_t)QS_RX_FILL
|
|
: (int8_t)QS_RX_POKE);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_FILL_DATA: {
|
|
l_rx.var.poke.data |= ((uint32_t)b << l_rx.var.poke.idx);
|
|
l_rx.var.poke.idx += 8U;
|
|
if ((uint8_t)(l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
|
|
QS_RX_TRAN_(WAIT4_FILL_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_POKE_DATA: {
|
|
l_rx.var.poke.data |= ((uint32_t)b << l_rx.var.poke.idx);
|
|
l_rx.var.poke.idx += 8U;
|
|
if ((uint8_t)(l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
|
|
QS_rxPoke_();
|
|
--l_rx.var.poke.num;
|
|
if (l_rx.var.poke.num == 0U) {
|
|
QS_RX_TRAN_(WAIT4_POKE_FRAME);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_FILL_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case WAIT4_POKE_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_FILTER_LEN: {
|
|
if (b == sizeof(l_rx.var.flt.data)) {
|
|
l_rx.var.flt.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_FILTER_DATA);
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.flt.recId);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_FILTER_DATA: {
|
|
l_rx.var.flt.data[l_rx.var.flt.idx] = b;
|
|
++l_rx.var.flt.idx;
|
|
if (l_rx.var.flt.idx == sizeof(l_rx.var.flt.data)) {
|
|
QS_RX_TRAN_(WAIT4_FILTER_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_FILTER_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_OBJ_KIND: {
|
|
if (b <= (uint8_t)SM_AO_OBJ) {
|
|
l_rx.var.obj.kind = b;
|
|
l_rx.var.obj.addr = 0U;
|
|
l_rx.var.obj.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_OBJ_ADDR);
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.obj.recId);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_OBJ_ADDR: {
|
|
l_rx.var.obj.addr |= ((QSObj)b << l_rx.var.obj.idx);
|
|
l_rx.var.obj.idx += 8U;
|
|
if (l_rx.var.obj.idx == (uint8_t)(8U * QS_OBJ_PTR_SIZE)) {
|
|
QS_RX_TRAN_(WAIT4_OBJ_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_OBJ_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_QUERY_KIND: {
|
|
if (b < (uint8_t)MAX_OBJ) {
|
|
l_rx.var.obj.kind = b;
|
|
QS_RX_TRAN_(WAIT4_QUERY_FRAME);
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.obj.recId);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_QUERY_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_EVT_PRIO: {
|
|
l_rx.var.evt.prio = b;
|
|
l_rx.var.evt.sig = 0U;
|
|
l_rx.var.evt.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_EVT_SIG);
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_EVT_SIG: {
|
|
l_rx.var.evt.sig |= (QSignal)((uint32_t)b << l_rx.var.evt.idx);
|
|
l_rx.var.evt.idx += 8U;
|
|
if (l_rx.var.evt.idx == (uint8_t)(8U * Q_SIGNAL_SIZE)) {
|
|
l_rx.var.evt.len = 0U;
|
|
l_rx.var.evt.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_EVT_LEN);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_EVT_LEN: {
|
|
l_rx.var.evt.len |= (uint16_t)((uint32_t)b << l_rx.var.evt.idx);
|
|
l_rx.var.evt.idx += 8U;
|
|
if (l_rx.var.evt.idx == (8U * 2U)) {
|
|
if ((l_rx.var.evt.len + sizeof(QEvt)) <=
|
|
QF_poolGetMaxBlockSize())
|
|
{
|
|
// report Ack before generating any other QS records
|
|
QS_rxReportAck_((int8_t)QS_RX_EVENT);
|
|
|
|
l_rx.var.evt.e = QF_newX_(
|
|
((uint_fast16_t)l_rx.var.evt.len + sizeof(QEvt)),
|
|
0U, // margin
|
|
(enum_t)l_rx.var.evt.sig);
|
|
if (l_rx.var.evt.e != (QEvt *)0) { // evt allocated?
|
|
l_rx.var.evt.p = (uint8_t *)l_rx.var.evt.e;
|
|
l_rx.var.evt.p = &l_rx.var.evt.p[sizeof(QEvt)];
|
|
if (l_rx.var.evt.len > 0U) {
|
|
QS_RX_TRAN_(WAIT4_EVT_PAR);
|
|
}
|
|
else {
|
|
QS_RX_TRAN_(WAIT4_EVT_FRAME);
|
|
}
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_EVENT);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_EVENT);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_EVT_PAR: { // event parameters
|
|
*l_rx.var.evt.p = b;
|
|
++l_rx.var.evt.p;
|
|
--l_rx.var.evt.len;
|
|
if (l_rx.var.evt.len == 0U) {
|
|
QS_RX_TRAN_(WAIT4_EVT_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_EVT_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
|
|
#ifdef Q_UTEST
|
|
case (uint8_t)WAIT4_TEST_SETUP_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TEST_TEARDOWN_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TEST_CONTINUE_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TEST_PROBE_DATA: {
|
|
l_rx.var.tp.data |= ((uint32_t)b << l_rx.var.tp.idx);
|
|
l_rx.var.tp.idx += 8U;
|
|
if (l_rx.var.tp.idx == (uint8_t)(8U * sizeof(uint32_t))) {
|
|
l_rx.var.tp.addr = 0U;
|
|
l_rx.var.tp.idx = 0U;
|
|
QS_RX_TRAN_(WAIT4_TEST_PROBE_ADDR);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TEST_PROBE_ADDR: {
|
|
l_rx.var.tp.addr |= ((QSFun)b << l_rx.var.tp.idx);
|
|
l_rx.var.tp.idx += 8U;
|
|
if (l_rx.var.tp.idx == (uint8_t)(8U * QS_FUN_PTR_SIZE)) {
|
|
QS_RX_TRAN_(WAIT4_TEST_PROBE_FRAME);
|
|
}
|
|
break;
|
|
}
|
|
case (uint8_t)WAIT4_TEST_PROBE_FRAME: {
|
|
// keep ignoring the data until a frame is collected
|
|
break;
|
|
}
|
|
#endif // Q_UTEST
|
|
|
|
case (uint8_t)ERROR_STATE: {
|
|
// keep ignoring the data until a good frame is collected
|
|
break;
|
|
}
|
|
default: { // unexpected or unimplemented state
|
|
QS_rxReportError_(0x45);
|
|
QS_RX_TRAN_(ERROR_STATE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxHandleGoodFrame_(uint8_t const state) {
|
|
uint8_t i;
|
|
uint8_t *ptr;
|
|
|
|
switch (state) {
|
|
case WAIT4_INFO_FRAME: {
|
|
// no need to report Ack or Done
|
|
QS_target_info_pre_(0U); // send only Target info
|
|
break;
|
|
}
|
|
case WAIT4_RESET_FRAME: {
|
|
// no need to report Ack or Done, because Target resets
|
|
QS_onReset(); // reset the Target
|
|
break;
|
|
}
|
|
case WAIT4_CMD_PARAM1: // intentionally fall-through
|
|
case WAIT4_CMD_PARAM2: // intentionally fall-through
|
|
case WAIT4_CMD_PARAM3: // intentionally fall-through
|
|
case WAIT4_CMD_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_COMMAND);
|
|
QS_onCommand(l_rx.var.cmd.cmdId, l_rx.var.cmd.param1,
|
|
l_rx.var.cmd.param2, l_rx.var.cmd.param3);
|
|
#ifdef Q_UTEST
|
|
#if Q_UTEST != 0
|
|
QS_processTestEvts_(); // process all events produced
|
|
#endif // Q_UTEST != 0
|
|
#endif // Q_UTEST
|
|
QS_rxReportDone_((int8_t)QS_RX_COMMAND);
|
|
break;
|
|
}
|
|
case WAIT4_TICK_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_TICK);
|
|
#ifdef Q_UTEST
|
|
QTimeEvt_tick1_((uint_fast8_t)l_rx.var.tick.rate, &QS_rxPriv_);
|
|
#if Q_UTEST != 0
|
|
QS_processTestEvts_(); // process all events produced
|
|
#endif // Q_UTEST != 0
|
|
#else
|
|
QTimeEvt_tick_((uint_fast8_t)l_rx.var.tick.rate, &QS_rxPriv_);
|
|
#endif // Q_UTEST
|
|
QS_rxReportDone_((int8_t)QS_RX_TICK);
|
|
break;
|
|
}
|
|
case WAIT4_PEEK_FRAME: {
|
|
// no need to report Ack or Done
|
|
QS_beginRec_((uint_fast8_t)QS_PEEK_DATA);
|
|
ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
|
|
ptr = &ptr[l_rx.var.peek.offs];
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_U16_PRE_(l_rx.var.peek.offs); // data offset
|
|
QS_U8_PRE_(l_rx.var.peek.size); // data size
|
|
QS_U8_PRE_(l_rx.var.peek.num); // # data items
|
|
for (i = 0U; i < l_rx.var.peek.num; ++i) {
|
|
switch (l_rx.var.peek.size) {
|
|
case 1:
|
|
QS_U8_PRE_(ptr[i]);
|
|
break;
|
|
case 2:
|
|
QS_U16_PRE_(((uint16_t *)ptr)[i]);
|
|
break;
|
|
case 4:
|
|
QS_U32_PRE_(((uint32_t *)ptr)[i]);
|
|
break;
|
|
default:
|
|
// intentionally empty
|
|
break;
|
|
}
|
|
}
|
|
QS_endRec_();
|
|
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
break;
|
|
}
|
|
case WAIT4_POKE_DATA: {
|
|
// received less than expected poke data items
|
|
QS_rxReportError_((int8_t)QS_RX_POKE);
|
|
break;
|
|
}
|
|
case WAIT4_POKE_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_POKE);
|
|
// no need to report done
|
|
break;
|
|
}
|
|
case WAIT4_FILL_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_FILL);
|
|
ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
|
|
ptr = &ptr[l_rx.var.poke.offs];
|
|
for (i = 0U; i < l_rx.var.poke.num; ++i) {
|
|
switch (l_rx.var.poke.size) {
|
|
case 1:
|
|
ptr[i] = (uint8_t)l_rx.var.poke.data;
|
|
break;
|
|
case 2:
|
|
((uint16_t *)ptr)[i]
|
|
= (uint16_t)l_rx.var.poke.data;
|
|
break;
|
|
case 4:
|
|
((uint32_t *)ptr)[i] = l_rx.var.poke.data;
|
|
break;
|
|
default:
|
|
// intentionally empty
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WAIT4_FILTER_FRAME: {
|
|
QS_rxReportAck_(l_rx.var.flt.recId);
|
|
|
|
// apply the received filters
|
|
if (l_rx.var.flt.recId == (int8_t)QS_RX_GLB_FILTER) {
|
|
for (i = 0U; i < Q_DIM(QS_filt_.glb); ++i) {
|
|
QS_filt_.glb[i] = l_rx.var.flt.data[i];
|
|
}
|
|
// leave the "not maskable" filters enabled,
|
|
// see qs.h, Miscellaneous QS records (not maskable)
|
|
QS_filt_.glb[0] |= 0x01U;
|
|
QS_filt_.glb[7] |= 0xFCU;
|
|
QS_filt_.glb[8] |= 0x7FU;
|
|
|
|
// never enable the last 3 records (0x7D, 0x7E, 0x7F)
|
|
QS_filt_.glb[15] &= 0x1FU;
|
|
}
|
|
else if (l_rx.var.flt.recId == (int8_t)QS_RX_LOC_FILTER) {
|
|
for (i = 0U; i < Q_DIM(QS_filt_.loc); ++i) {
|
|
QS_filt_.loc[i] = l_rx.var.flt.data[i];
|
|
}
|
|
// leave QS_ID == 0 always on
|
|
QS_filt_.loc[0] |= 0x01U;
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.flt.recId);
|
|
}
|
|
// no need to report Done
|
|
break;
|
|
}
|
|
case WAIT4_OBJ_FRAME: {
|
|
i = l_rx.var.obj.kind;
|
|
if (i < (uint8_t)MAX_OBJ) {
|
|
if (l_rx.var.obj.recId == (int8_t)QS_RX_CURR_OBJ) {
|
|
QS_rxPriv_.currObj[i] = (void *)l_rx.var.obj.addr;
|
|
QS_rxReportAck_((int8_t)QS_RX_CURR_OBJ);
|
|
}
|
|
else if (l_rx.var.obj.recId == (int8_t)QS_RX_AO_FILTER) {
|
|
if (l_rx.var.obj.addr != 0U) {
|
|
int_fast16_t const filter =
|
|
(int_fast16_t)((QActive *)l_rx.var.obj.addr)->prio;
|
|
QS_locFilter_((i == 0U)
|
|
? filter
|
|
:-filter);
|
|
QS_rxReportAck_((int8_t)QS_RX_AO_FILTER);
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_AO_FILTER);
|
|
}
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.obj.recId);
|
|
}
|
|
}
|
|
// both SM and AO
|
|
else if (i == (uint8_t)SM_AO_OBJ) {
|
|
if (l_rx.var.obj.recId == (int8_t)QS_RX_CURR_OBJ) {
|
|
QS_rxPriv_.currObj[SM_OBJ] = (void *)l_rx.var.obj.addr;
|
|
QS_rxPriv_.currObj[AO_OBJ] = (void *)l_rx.var.obj.addr;
|
|
}
|
|
QS_rxReportAck_(l_rx.var.obj.recId);
|
|
}
|
|
else {
|
|
QS_rxReportError_(l_rx.var.obj.recId);
|
|
}
|
|
break;
|
|
}
|
|
case WAIT4_QUERY_FRAME: {
|
|
QS_queryCurrObj(l_rx.var.obj.kind);
|
|
break;
|
|
}
|
|
case WAIT4_EVT_FRAME: {
|
|
// NOTE: Ack was already reported in the WAIT4_EVT_LEN state
|
|
#ifdef Q_UTEST
|
|
QS_onTestEvt(l_rx.var.evt.e); // adjust the event, if needed
|
|
#endif // Q_UTEST
|
|
i = 0U; // use 'i' as status, 0 == success,no-recycle
|
|
|
|
if (l_rx.var.evt.prio == 0U) { // publish
|
|
QActive_publish_(l_rx.var.evt.e, &QS_rxPriv_, 0U);
|
|
}
|
|
else if (l_rx.var.evt.prio < QF_MAX_ACTIVE) {
|
|
if (!QACTIVE_POST_X(QActive_registry_[l_rx.var.evt.prio],
|
|
l_rx.var.evt.e,
|
|
0U, // margin
|
|
&QS_rxPriv_))
|
|
{
|
|
// failed QACTIVE_POST() recycles the event
|
|
i = 0x80U; // failure status, no recycle
|
|
}
|
|
}
|
|
else if (l_rx.var.evt.prio == 255U) { // special prio
|
|
// dispatch to the current SM object
|
|
if (QS_rxPriv_.currObj[SM_OBJ] != (void *)0) {
|
|
// increment the ref-ctr to simulate the situation
|
|
// when the event is just retreived from a queue.
|
|
// This is expected for the following QF_gc() call.
|
|
++l_rx.var.evt.e->refCtr_;
|
|
|
|
QAsm * const sm = (QAsm *)QS_rxPriv_.currObj[SM_OBJ];
|
|
(*sm->vptr->dispatch)(sm, l_rx.var.evt.e, 0U);
|
|
i = 0x01U; // success status, recycle needed
|
|
}
|
|
else {
|
|
i = 0x81U; // failure status, recycle needed
|
|
}
|
|
}
|
|
else if (l_rx.var.evt.prio == 254U) { // special prio
|
|
// init the current SM object"
|
|
if (QS_rxPriv_.currObj[SM_OBJ] != (void *)0) {
|
|
// increment the ref-ctr to simulate the situation
|
|
// when the event is just retreived from a queue.
|
|
// This is expected for the following QF_gc() call.
|
|
++l_rx.var.evt.e->refCtr_;
|
|
|
|
QAsm * const sm = (QAsm *)QS_rxPriv_.currObj[SM_OBJ];
|
|
(*sm->vptr->init)(sm, l_rx.var.evt.e, 0U);
|
|
i = 0x01U; // success status, recycle needed
|
|
}
|
|
else {
|
|
i = 0x81U; // failure status, recycle needed
|
|
}
|
|
}
|
|
else if (l_rx.var.evt.prio == 253U) { // special prio
|
|
// post to the current AO
|
|
if (QS_rxPriv_.currObj[AO_OBJ] != (void *)0) {
|
|
if (!QACTIVE_POST_X(
|
|
(QActive *)QS_rxPriv_.currObj[AO_OBJ],
|
|
l_rx.var.evt.e,
|
|
0U, // margin
|
|
&QS_rxPriv_))
|
|
{
|
|
// failed QACTIVE_POST() recycles the event
|
|
i = 0x80U; // failure status, no recycle
|
|
}
|
|
}
|
|
else {
|
|
i = 0x81U; // failure status, recycle needed
|
|
}
|
|
}
|
|
else {
|
|
i = 0x81U; // failure status, recycle needed
|
|
}
|
|
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
if ((i & 0x01U) != 0U) { // recycle needed?
|
|
QF_gc(l_rx.var.evt.e);
|
|
}
|
|
#endif
|
|
if ((i & 0x80U) != 0U) { // failure?
|
|
QS_rxReportError_((int8_t)QS_RX_EVENT);
|
|
}
|
|
else {
|
|
#ifdef Q_UTEST
|
|
#if Q_UTEST != 0
|
|
QS_processTestEvts_(); // process all events produced
|
|
#endif // Q_UTEST != 0
|
|
#endif // Q_UTEST
|
|
QS_rxReportDone_((int8_t)QS_RX_EVENT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef Q_UTEST
|
|
case WAIT4_TEST_SETUP_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_TEST_SETUP);
|
|
QS_tstPriv_.tpNum = 0U; // clear the Test-Probes
|
|
QS_tstPriv_.testTime = 0U; // clear the time tick
|
|
// don't clear current objects
|
|
QS_onTestSetup(); // application-specific test setup
|
|
// no need to report Done
|
|
break;
|
|
}
|
|
case WAIT4_TEST_TEARDOWN_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_TEST_TEARDOWN);
|
|
QS_onTestTeardown(); // application-specific test teardown
|
|
// no need to report Done
|
|
break;
|
|
}
|
|
case WAIT4_TEST_CONTINUE_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_TEST_CONTINUE);
|
|
QS_rxPriv_.inTestLoop = false; // exit the QUTest loop
|
|
// no need to report Done
|
|
break;
|
|
}
|
|
case WAIT4_TEST_PROBE_FRAME: {
|
|
QS_rxReportAck_((int8_t)QS_RX_TEST_PROBE);
|
|
Q_ASSERT_INCRIT(815, QS_tstPriv_.tpNum
|
|
< (sizeof(QS_tstPriv_.tpBuf) / sizeof(QS_tstPriv_.tpBuf[0])));
|
|
QS_tstPriv_.tpBuf[QS_tstPriv_.tpNum] = l_rx.var.tp;
|
|
++QS_tstPriv_.tpNum;
|
|
// no need to report Done
|
|
break;
|
|
}
|
|
#endif // Q_UTEST
|
|
|
|
case ERROR_STATE: {
|
|
// keep ignoring all bytes until new frame
|
|
break;
|
|
}
|
|
default: {
|
|
QS_rxReportError_(0x47);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxHandleBadFrame_(uint8_t const state) {
|
|
QS_rxReportError_(0x50); // report error for all bad frames
|
|
switch (state) {
|
|
case WAIT4_EVT_FRAME: {
|
|
Q_ASSERT_INCRIT(910, l_rx.var.evt.e != (QEvt *)0);
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(l_rx.var.evt.e); // don't leak an allocated event
|
|
#endif
|
|
break;
|
|
}
|
|
default: {
|
|
// intentionally empty
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxReportAck_(int8_t const recId) {
|
|
QS_beginRec_((uint_fast8_t)QS_RX_STATUS);
|
|
QS_U8_PRE_(recId); // record ID
|
|
QS_endRec_();
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxReportError_(int8_t const code) {
|
|
QS_beginRec_((uint_fast8_t)QS_RX_STATUS);
|
|
QS_U8_PRE_(0x80U | (uint8_t)code); // error code
|
|
QS_endRec_();
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxReportDone_(int8_t const recId) {
|
|
QS_beginRec_((uint_fast8_t)QS_TARGET_DONE);
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_U8_PRE_(recId); // record ID
|
|
QS_endRec_();
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_queryCurrObj(uint8_t const obj_kind) {
|
|
if (QS_rxPriv_.currObj[obj_kind] != (void *)0) {
|
|
QS_beginRec_((uint_fast8_t)QS_QUERY_DATA);
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_U8_PRE_(obj_kind); // object kind
|
|
QS_OBJ_PRE_(QS_rxPriv_.currObj[obj_kind]);
|
|
switch (obj_kind) {
|
|
case (uint8_t)SM_OBJ: // intentionally fall through
|
|
case (uint8_t)AO_OBJ:
|
|
QS_FUN_PRE_((*((QAsm *)QS_rxPriv_.currObj[obj_kind])->vptr
|
|
->getStateHandler)(
|
|
((QAsm *)QS_rxPriv_.currObj[obj_kind])));
|
|
break;
|
|
case (uint8_t)MP_OBJ:
|
|
QS_MPC_PRE_(((QMPool *)QS_rxPriv_.currObj[obj_kind])
|
|
->nFree);
|
|
QS_MPC_PRE_(((QMPool *)QS_rxPriv_.currObj[obj_kind])
|
|
->nMin);
|
|
break;
|
|
case (uint8_t)EQ_OBJ:
|
|
QS_EQC_PRE_(((QEQueue *)QS_rxPriv_.currObj[obj_kind])
|
|
->nFree);
|
|
QS_EQC_PRE_(((QEQueue *)QS_rxPriv_.currObj[obj_kind])
|
|
->nMin);
|
|
break;
|
|
case (uint8_t)TE_OBJ:
|
|
QS_OBJ_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
|
|
->act);
|
|
QS_TEC_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
|
|
->ctr);
|
|
QS_TEC_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
|
|
->interval);
|
|
QS_SIG_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
|
|
->super.sig);
|
|
QS_U8_PRE_ (((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
|
|
->super.refCtr_);
|
|
break;
|
|
default:
|
|
// intentionally empty
|
|
break;
|
|
}
|
|
QS_endRec_();
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
}
|
|
else {
|
|
QS_rxReportError_((int8_t)QS_RX_QUERY_CURR);
|
|
}
|
|
}
|
|
|
|
//............................................................................
|
|
static void QS_rxPoke_(void) {
|
|
uint8_t *ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
|
|
ptr = &ptr[l_rx.var.poke.offs];
|
|
switch (l_rx.var.poke.size) {
|
|
case 1:
|
|
*ptr = (uint8_t)l_rx.var.poke.data;
|
|
break;
|
|
case 2:
|
|
*(uint16_t *)ptr = (uint16_t)l_rx.var.poke.data;
|
|
break;
|
|
case 4:
|
|
*(uint32_t *)ptr = l_rx.var.poke.data;
|
|
break;
|
|
default: {
|
|
Q_ERROR_INCRIT(900);
|
|
break;
|
|
}
|
|
}
|
|
|
|
l_rx.var.poke.data = 0U;
|
|
l_rx.var.poke.idx = 0U;
|
|
l_rx.var.poke.offs += (uint16_t)l_rx.var.poke.size;
|
|
}
|
|
|
|
//! @endcond</text>
|
|
</file>
|
|
<!--${src::qs::qutest.c}-->
|
|
<file name="qutest.c">
|
|
<text>// only build when Q_UTEST is defined
|
|
#ifdef Q_UTEST
|
|
|
|
#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
|
|
#include "qs_port.h" // include QS port
|
|
#include "qs_pkg.h" // QS facilities for pre-defined trace records
|
|
|
|
//============================================================================
|
|
// QUTest unit testing harness
|
|
$define ${QS::QUTest}
|
|
|
|
//============================================================================
|
|
//! @cond INTERNAL
|
|
|
|
QSTestAttr QS_tstPriv_;
|
|
|
|
//............................................................................
|
|
void QS_test_pause_(void) {
|
|
QS_beginRec_((uint_fast8_t)QS_TEST_PAUSED);
|
|
QS_endRec_();
|
|
QS_onTestLoop();
|
|
}
|
|
|
|
//............................................................................
|
|
uint32_t QS_getTestProbe_(QSpyFunPtr const api) {
|
|
uint32_t data = 0U;
|
|
for (uint_fast8_t i = 0U; i < QS_tstPriv_.tpNum; ++i) {
|
|
if (QS_tstPriv_.tpBuf[i].addr == (QSFun)api) {
|
|
data = QS_tstPriv_.tpBuf[i].data;
|
|
|
|
QS_CRIT_STAT
|
|
QS_CRIT_ENTRY();
|
|
QS_MEM_SYS();
|
|
QS_beginRec_((uint_fast8_t)QS_TEST_PROBE_GET);
|
|
QS_TIME_PRE_(); // timestamp
|
|
QS_FUN_PRE_(api); // the calling API
|
|
QS_U32_PRE_(data); // the Test-Probe data
|
|
QS_endRec_();
|
|
|
|
QS_REC_DONE(); // user callback (if defined)
|
|
|
|
--QS_tstPriv_.tpNum; // one less Test-Probe
|
|
// move all remaining entries in the buffer up by one
|
|
for (uint_fast8_t j = i; j < QS_tstPriv_.tpNum; ++j) {
|
|
QS_tstPriv_.tpBuf[j] = QS_tstPriv_.tpBuf[j + 1U];
|
|
}
|
|
QS_MEM_APP();
|
|
QS_CRIT_EXIT();
|
|
break; // we are done (Test-Probe retreived)
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
//............................................................................
|
|
QSTimeCtr QS_onGetTime(void) {
|
|
return (++QS_tstPriv_.testTime);
|
|
}
|
|
|
|
//............................................................................
|
|
Q_NORETURN Q_onError(
|
|
char const * const module,
|
|
int_t const id)
|
|
{
|
|
QS_beginRec_((uint_fast8_t)QS_ASSERT_FAIL);
|
|
QS_TIME_PRE_();
|
|
QS_U16_PRE_(id);
|
|
QS_STR_PRE_((module != (char *)0) ? module : "?");
|
|
QS_endRec_();
|
|
|
|
QS_onFlush(); // flush the assertion record to the host
|
|
QS_onCleanup(); // cleanup after the failure
|
|
QS_onReset(); // reset the target to prevent the code from continuing
|
|
for (;;) { // QS_onReset() should not return, but to ensure no-return
|
|
}
|
|
}
|
|
|
|
//! @endcond
|
|
//============================================================================
|
|
|
|
// QP-stub for QUTest
|
|
// NOTE: The QP-stub is needed for unit testing QP applications, but might
|
|
// NOT be needed for testing QP itself. In that case, the build process
|
|
// can define Q_UTEST=0 to exclude the QP-stub from the build.
|
|
#if (Q_UTEST != 0)
|
|
|
|
Q_DEFINE_THIS_MODULE("qutest")
|
|
|
|
//............................................................................
|
|
void QS_processTestEvts_(void) {
|
|
QS_TEST_PROBE_DEF(&QS_processTestEvts_)
|
|
|
|
// return immediately (do nothing) for Test Probe != 0
|
|
QS_TEST_PROBE(return;)
|
|
|
|
while (QPSet_notEmpty(&QS_tstPriv_.readySet)) {
|
|
uint_fast8_t const p = QPSet_findMax(&QS_tstPriv_.readySet);
|
|
QActive * const a = QActive_registry_[p];
|
|
|
|
QEvt const * const e = QActive_get_(a);
|
|
QASM_DISPATCH(a, e, a->prio);
|
|
#if (QF_MAX_EPOOL > 0U)
|
|
QF_gc(e);
|
|
#endif
|
|
if (a->eQueue.frontEvt == (QEvt *)0) { // empty queue?
|
|
QPSet_remove(&QS_tstPriv_.readySet, p);
|
|
#ifndef Q_UNSAFE
|
|
QPSet_update_(&QS_tstPriv_.readySet, &QS_tstPriv_.readySet_dis);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
$define ${QS::QUTest-stub}
|
|
|
|
#endif // Q_UTEST != 0
|
|
|
|
#endif // Q_UTEST</text>
|
|
</file>
|
|
<!--${src::qs::qstamp.c}-->
|
|
<file name="qstamp.c">
|
|
<text>#include "qstamp.h"
|
|
|
|
//! the calendar date of the last translation of the form: "Mmm dd yyyy"
|
|
char const Q_BUILD_DATE[12] = __DATE__;
|
|
|
|
//! the time of the last translation of the form: "hh:mm:ss"
|
|
char const Q_BUILD_TIME[9] = __TIME__;</text>
|
|
</file>
|
|
</directory>
|
|
</directory>
|
|
</model>
|