qpcpp/qpcpp.qm
MMS 8c5a806c8e 7.2.1
Fixed bug in QXK activator
2023-01-11 12:06:55 -05:00

15007 lines
584 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<model version="5.2.4" links="1">
<documentation>QP/C++ Real-Time Embedded Framework (RTEF)
The model is used to generate the whole QP/C++ source code.
Copyright (C) 2005 Quantum Leaps, LLC &lt;state-machine.com&gt;.
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: &lt;www.gnu.org/licenses/gpl-3.0&gt;
The terms of the closed source Quantum Leaps commercial licenses
can be found at: &lt;www.state-machine.com/licensing&gt;
Redistributions in source code must retain this copyright notice.
Plagiarizing this software to sidestep the license obligations is illegal.
Contact information:
&lt;www.state-machine.com/licensing&gt;
&lt;info@state-machine.com&gt;</documentation>
<!--${qpcpp}-->
<framework name="qpcpp" license="LICENSES/LicenseRef-QL-dual.qlc"/>
<!--${glob-types}-->
<package name="glob-types" stereotype="0x00">
<!--${glob-types::int_t}-->
<attribute name="int_t" type="using" visibility="0x04" properties="0x00">
<documentation>//! alias for line numbers in assertions and return from QF::run()</documentation>
<code> = int;</code>
</attribute>
<!--${glob-types::enum_t}-->
<attribute name="enum_t" type="using" visibility="0x04" properties="0x00">
<documentation>//! alias for enumerations used for event signals</documentation>
<code> = int;</code>
</attribute>
<!--${glob-types::float32_t}-->
<attribute name="float32_t" type="using" visibility="0x04" properties="0x00">
<documentation>//! alias for 32-bit IEEE 754 floating point numbers
//!
//! @note
//! QP does not use floating-point types anywhere in the internal
//! implementation, except in QS software tracing, where utilities for
//! output of floating-point numbers are provided for application-specific
//! trace records.</documentation>
<code> = float;</code>
</attribute>
<!--${glob-types::float64_t}-->
<attribute name="float64_t" type="using" visibility="0x04" properties="0x00">
<documentation>//! alias for 64-bit IEEE 754 floating point numbers
//!
//! @note
//! QP does not use floating-point types anywhere in the internal
//! implementation, except in QS software tracing, where utilities for
//! output of floating-point numbers are provided for application-specific
//! trace records.</documentation>
<code> = double;</code>
</attribute>
</package>
<!--${QEP-config}-->
<package name="QEP-config" stereotype="0x02">
<!--${QEP-config::Q_SIGNAL_SIZE}-->
<attribute name="Q_SIGNAL_SIZE?ndef Q_SIGNAL_SIZE" type="" visibility="0x03" properties="0x00">
<documentation>//! The size (in bytes) of the signal of an event. Valid values:
//! 1U, 2U, or 4U; default 2U
//!
//! @details
//! This macro can be defined in the QEP port file (qep_port.hpp) to
//! configure the QP::QSignal type. When the macro is not defined, the
//! default of 2 bytes is applied.</documentation>
<code>2U</code>
</attribute>
</package>
<!--${QEP-macros}-->
<package name="QEP-macros" stereotype="0x02">
<!--${QEP-macros::Q_STATE_DECL}-->
<operation name="Q_STATE_DECL" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a declaration of a state-handler, state-caller and
//! a state-object for a given state in a subclass of QP::QHsm.</documentation>
<!--${QEP-macros::Q_STATE_DECL::state_}-->
<parameter name="state_" type="&lt;state name&gt;"/>
<code>\
QP::QState state_ ## _h(QP::QEvt const * const e); \
static QP::QState state_(void * const me, QP::QEvt const * const e)</code>
</operation>
<!--${QEP-macros::Q_STATE_DEF}-->
<operation name="Q_STATE_DEF" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a declaration of a state-handler, state-caller and
//! a state-object for a given state in a subclass of QP::QHsm.</documentation>
<!--${QEP-macros::Q_STATE_DEF::subclass_}-->
<parameter name="subclass_" type="&lt;QHsm subclass&gt;"/>
<!--${QEP-macros::Q_STATE_DEF::state_}-->
<parameter name="state_" type="&lt;state name&gt;"/>
<code>\
QP::QState subclass_::state_(void * const me, QP::QEvt const * const e) { \
return static_cast&lt;subclass_ *&gt;(me)-&gt;state_ ## _h(e); } \
QP::QState subclass_::state_ ## _h(QP::QEvt const * const e)</code>
</operation>
<!--${QEP-macros::Q_HANDLED}-->
<operation name="Q_HANDLED" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to specify that the event was handled</documentation>
<code>(Q_RET_HANDLED)</code>
</operation>
<!--${QEP-macros::Q_UNHANDLED}-->
<operation name="Q_UNHANDLED" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to specify that the event was NOT handled
//! due to a guard condition evaluating to 'false'</documentation>
<code>(Q_RET_UNHANDLED)</code>
</operation>
<!--${QEP-macros::Q_EVT_CAST}-->
<operation name="Q_EVT_CAST" type="" visibility="0x03" properties="0x00">
<documentation>//! Perform downcast of an event onto a subclass of QEvt `class_`
//!
//! @details
//! This macro encapsulates the downcast of QEvt pointers, which violates
//! MISRA-C 2004 rule 11.4(advisory). This macro helps to localize this
//! deviation.</documentation>
<!--${QEP-macros::Q_EVT_CAST::subclass_}-->
<parameter name="subclass_" type="&lt;QEvt subclass&gt;"/>
<code>(static_cast&lt;subclass_ const *&gt;(e))</code>
</operation>
<!--${QEP-macros::Q_STATE_CAST}-->
<operation name="Q_STATE_CAST" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to perform casting to QStateHandler.
//!
//! @details
//! This macro encapsulates the cast of a specific state handler function
//! pointer to QStateHandler, which violates MISRA-C 2004 rule 11.4(advisory).
//! This macro helps to localize this deviation.</documentation>
<!--${QEP-macros::Q_STATE_CAST::handler_}-->
<parameter name="handler_" type="&lt;state handler&gt;"/>
<code>\
(reinterpret_cast&lt;QP::QStateHandler&gt;(handler_))</code>
</operation>
<!--${QEP-macros::Q_ACTION_CAST}-->
<operation name="Q_ACTION_CAST" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to perform casting to QActionHandler.
//!
//! @details
//! This macro encapsulates the cast of a specific action handler function
//! pointer to QActionHandler, which violates MISRA-C2004 rule 11.4(advisory).
//! This macro helps to localize this deviation.</documentation>
<!--${QEP-macros::Q_ACTION_CAST::act_}-->
<parameter name="act_" type="&lt;action handler&gt;"/>
<code>\
(reinterpret_cast&lt;QP::QActionHandler&gt;(act_))</code>
</operation>
<!--${QEP-macros::QM_STATE_DECL}-->
<operation name="QM_STATE_DECL" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a declaration of a state-handler, state-caller and
//! a state-object for a given state in a subclass of QP::QMsm.</documentation>
<!--${QEP-macros::QM_STATE_DECL::state_}-->
<parameter name="state_" type="&lt;state name&gt;"/>
<code>\
QP::QState state_ ## _h(QP::QEvt const * const e); \
static QP::QState state_(void * const me, QP::QEvt const * const e); \
static QP::QMState const state_ ## _s</code>
</operation>
<!--${QEP-macros::QM_SM_STATE_DECL}-->
<operation name="QM_SM_STATE_DECL" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a declaration of a state-handler, state-caller and
//! a state-object for a given *submachine* state in a subclass of QP::QMsm.</documentation>
<!--${QEP-macros::QM_SM_STATE_DECL::subm_}-->
<parameter name="subm_" type="&lt;submachine name&gt;"/>
<!--${QEP-macros::QM_SM_STATE_DECL::state_}-->
<parameter name="state_" type="&lt;state name&gt;"/>
<code>\
QP::QState state_ ## _h(QP::QEvt const * const e);\
static QP::QState state_(void * const me, QP::QEvt const * const e); \
static SM_ ## subm_ const state_ ## _s</code>
</operation>
<!--${QEP-macros::QM_ACTION_DECL}-->
<operation name="QM_ACTION_DECL" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a declaration of an action-handler and action-caller
//! in a subclass of QP::QMsm.</documentation>
<!--${QEP-macros::QM_ACTION_DECL::action_}-->
<parameter name="action_" type="&lt;predefined&gt;"/>
<code>\
QP::QState action_ ## _h(); \
static QP::QState action_(void * const me)</code>
</operation>
<!--${QEP-macros::QM_STATE_DEF}-->
<operation name="QM_STATE_DEF" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a definition of a state-caller and state-handler
//! for a given state in a subclass of QP::QMsm.</documentation>
<!--${QEP-macros::QM_STATE_DEF::subclass_}-->
<parameter name="subclass_" type="&lt;QMsm subclass&gt;"/>
<!--${QEP-macros::QM_STATE_DEF::state_}-->
<parameter name="state_" type="&lt;state name&gt;"/>
<code>\
QP::QState subclass_::state_(void * const me, QP::QEvt const * const e) { \
return static_cast&lt;subclass_ *&gt;(me)-&gt;state_ ## _h(e); } \
QP::QState subclass_::state_ ## _h(QP::QEvt const * const e)</code>
</operation>
<!--${QEP-macros::QM_ACTION_DEF}-->
<operation name="QM_ACTION_DEF" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro to generate a definition of an action-caller and action-handler
//! in a subclass of QP::QMsm.</documentation>
<!--${QEP-macros::QM_ACTION_DEF::subclass_}-->
<parameter name="subclass_" type="&lt;QMsm subclass&gt;"/>
<!--${QEP-macros::QM_ACTION_DEF::action_}-->
<parameter name="action_" type="&lt;predefined&gt;"/>
<code> \
QP::QState subclass_::action_(void * const me) { \
return static_cast&lt;subclass_ *&gt;(me)-&gt;action_ ## _h(); } \
QP::QState subclass_::action_ ## _h()</code>
</operation>
<!--${QEP-macros::QM_HANDLED}-->
<operation name="QM_HANDLED" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro for a QM action-handler when it handles the event.</documentation>
<code>(Q_RET_HANDLED)</code>
</operation>
<!--${QEP-macros::QM_UNHANDLED}-->
<operation name="QM_UNHANDLED" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro for a QM action-handler when it does not handle the event
//! due to a guard condition evaluating to false.</documentation>
<code>(Q_RET_HANDLED)</code>
</operation>
<!--${QEP-macros::QM_SUPER}-->
<operation name="QM_SUPER" type="" visibility="0x03" properties="0x00">
<documentation>//! Macro for a QM action-handler when it passes the event to the superstate</documentation>
<code>(Q_RET_SUPER)</code>
</operation>
<!--${QEP-macros::QM_STATE_NULL}-->
<attribute name="QM_STATE_NULL" type="&lt;action handler&gt;" visibility="0x03" properties="0x00">
<documentation>//! Macro to provide strictly-typed zero-state to use for submachines.
//! Applicable to suclasses of QP::QMsm.</documentation>
<code>(nullptr)</code>
</attribute>
<!--${QEP-macros::Q_ACTION_NULL}-->
<attribute name="Q_ACTION_NULL" type="&lt;action handler&gt;" visibility="0x03" properties="0x00">
<documentation>//! Macro to provide strictly-typed zero-action to terminate action lists
//! in the transition-action-tables in QP::QMsm.</documentation>
<code>(nullptr)</code>
</attribute>
<!--${QEP-macros::Q_UNUSED_PAR}-->
<operation name="Q_UNUSED_PAR" type="&lt;param type&gt;" visibility="0x03" properties="0x00">
<documentation>//! Helper macro to clearly mark unused parameters of functions.</documentation>
<!--${QEP-macros::Q_UNUSED_PAR::par_}-->
<parameter name="par_" type="&lt;param type&gt;"/>
<code>(static_cast&lt;void&gt;(par_))</code>
</operation>
<!--${QEP-macros::Q_DIM}-->
<operation name="Q_DIM" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Helper macro to calculate static dimension of a 1-dim `array_`
//!
//! @param[in] array_ 1-dimensional array
//!
//! @returns
//! the length of the array (number of elements it can hold)</documentation>
<!--${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">
<documentation>//! Perform cast from unsigned integer `uint_` to pointer of type `type_`
//!
//! @details
//! This macro encapsulates the cast to (type_ *), which QP ports or
//! application might use to access embedded hardware registers.
//! Such uses can trigger PC-Lint &quot;Note 923: cast from int to pointer&quot;
//! and this macro helps to encapsulate this deviation.</documentation>
<!--${QEP-macros::Q_UINT2PTR_CAST::type_}-->
<parameter name="type_" type=""/>
<!--${QEP-macros::Q_UINT2PTR_CAST::uint_}-->
<parameter name="uint_" type=""/>
<code>(reinterpret_cast&lt;type_ *&gt;(uint_))</code>
</operation>
<!--${QEP-macros::QEVT_INITIALIZER}-->
<operation name="QEVT_INITIALIZER" type="" visibility="0x03" properties="0x00">
<documentation>//! Initializer of static constant QEvt instances
//!
//! @details
//! This macro encapsulates the ugly casting of enumerated signals
//! to QSignal and constants for QEvt.poolID and QEvt.refCtr_.</documentation>
<!--${QEP-macros::QEVT_INITIALIZER::sig_}-->
<parameter name="sig_" type="QSignal"/>
<code>{ static_cast&lt;QP::QSignal&gt;(sig_), 0U, 0U }</code>
</operation>
</package>
<!--${QEP}-->
<package name="QEP" stereotype="0x05" namespace="QP::">
<!--${QEP::versionStr[]}-->
<attribute name="versionStr[]" type="constexpr char const" visibility="0x04" properties="0x01">
<documentation>//! the current QP version number string based on QP_VERSION_STR</documentation>
<code>{QP_VERSION_STR};</code>
</attribute>
<!--${QEP::QSignal}-->
<attribute name="QSignal? (Q_SIGNAL_SIZE == 2U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! QSignal represents the signal of an event
//!
//! @details
//! The relationship between an event and a signal is as follows. A signal
//! in UML is the specification of an asynchronous stimulus that triggers
//! reactions, and as such is an essential part of an event. (The signal
//! conveys the type of the occurrence--what happened?) However, an event
//! can also contain additional quantitative information about the
//! occurrence in form of event parameters.</documentation>
<code>= std::uint16_t;</code>
</attribute>
<!--${QEP::QSignal}-->
<attribute name="QSignal? (Q_SIGNAL_SIZE == 1U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint8_t;</code>
</attribute>
<!--${QEP::QSignal}-->
<attribute name="QSignal? (Q_SIGNAL_SIZE == 4U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint32_t;</code>
</attribute>
<!--${QEP::QEvt}-->
<class name="QEvt">
<documentation>//! Event class
//!
//! @details
//! QP::QEvt represents events without parameters and serves as the
//! base class for derivation of events with parameters.
//!
//! @note
//! When #Q_EVT_CTOR and #Q_EVT_VIRTUAL are NOT defined, the QP::QEvt is
//! a POD (Plain Old Data). Otherwise, it is a class with constructors
//! and virtual destructor.
//!
//! @usage
//! The following example illustrates how to add an event parameter by
//! inheriting from the QP::QEvt class.
//! @include qep_qevt.cpp</documentation>
<!--${QEP::QEvt::sig}-->
<attribute name="sig" type="QSignal" visibility="0x00" properties="0x00">
<documentation>//! signal of the event instance
//! @tr{RQP002}</documentation>
</attribute>
<!--${QEP::QEvt::poolId_}-->
<attribute name="poolId_" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! pool ID (0 for static, immutable event)
//! @tr{RQP003}</documentation>
</attribute>
<!--${QEP::QEvt::refCtr_}-->
<attribute name="refCtr_" type="std::uint8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! reference counter (only used for dynamic, mutable events)
//! @tr{RQP003}</documentation>
</attribute>
<!--${QEP::QEvt::QEvt}-->
<operation name="QEvt?def Q_EVT_CTOR" type="explicit" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! QP::QEvt constructor when the macro #Q_EVT_CTOR is defined</documentation>
<!--${QEP::QEvt::QEvt::s}-->
<parameter name="s" type="QSignal"/>
<code>: sig(s)
// poolId_/refCtr_ intentionally uninitialized</code>
</operation>
<!--${QEP::QEvt::QEvt}-->
<operation name="QEvt?def Q_EVT_CTOR" type="constexpr" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! QP::QEvt constructor (overload for static, immutable events)</documentation>
<!--${QEP::QEvt::QEvt::s}-->
<parameter name="s" type="QSignal"/>
<!--${QEP::QEvt::QEvt::/* dummy */}-->
<parameter name="/* dummy */" type="std::uint8_t"/>
<code>: sig(s),
poolId_(0U),
refCtr_(0U)</code>
</operation>
<!--${QEP::QEvt::~QEvt}-->
<operation name="~QEvt?def Q_EVT_VIRTUAL" type="" visibility="0x00" properties="0x06">
<specifiers>noexcept</specifiers>
<documentation>//! QP::QEvt virtual destructor when the macro #Q_EVT_VIRTUAL is defined</documentation>
<code>// empty</code>
</operation>
</class>
<!--${QEP::QState}-->
<attribute name="QState" type="using" visibility="0x04" properties="0x00">
<documentation>//! Type returned from state-handler functions</documentation>
<code>= std::uint_fast8_t;</code>
</attribute>
<!--${QEP::QStateHandler}-->
<attribute name="QStateHandler" type="using" visibility="0x04" properties="0x00">
<documentation>//! Pointer to state-handler function</documentation>
<code>= QState (*)(void * const me, QEvt const * const e);</code>
</attribute>
<!--${QEP::QActionHandler}-->
<attribute name="QActionHandler" type="using" visibility="0x04" properties="0x00">
<documentation>//! Pointer to an action-handler function</documentation>
<code>= QState (*)(void * const me);</code>
</attribute>
<!--${QEP::QXThread}-->
<attribute name="QXThread" type="class" visibility="0x04" properties="0x00">
<documentation>//! forward declaration</documentation>
</attribute>
<!--${QEP::QXThreadHandler}-->
<attribute name="QXThreadHandler" type="using" visibility="0x04" properties="0x00">
<documentation>//! Pointer to an extended thread-handler function</documentation>
<code>= void (*)(QXThread * const me);</code>
</attribute>
<!--${QEP::QMState}-->
<attribute name="QMState" type="struct" visibility="0x04" properties="0x00">
<documentation>//! State object for the QP::QMsm class (QM State Machine).
//!
//! @details
//! This class groups together the attributes of a QP::QMsm state, such as
//! the parent state (state nesting), the associated state handler function
//! and the exit action handler function. These attributes are used inside
//! the QP::QMsm::dispatch() and QP::QMsm::init() functions.
//!
//! @attention
//! The QP::QMState class is only intended for the QM code generator and
//! should not be used in hand-crafted code.</documentation>
<code>{
QMState const * superstate; //!&lt; superstate of this state
QStateHandler const stateHandler; //!&lt; state handler function
QActionHandler const entryAction; //!&lt; entry action handler function
QActionHandler const exitAction; //!&lt; exit action handler function
QActionHandler const initAction; //!&lt; init action handler function
};</code>
</attribute>
<!--${QEP::QMTranActTable}-->
<attribute name="QMTranActTable" type="struct" visibility="0x04" properties="0x00">
<documentation>//! Transition-Action Table for the QP::QMsm State Machine.</documentation>
<code>{
QMState const * target; //!&lt; target of the transition
QActionHandler const act[1]; //!&lt; array of actions
};</code>
</attribute>
<!--${QEP::QHsmAttr}-->
<attribute name="QHsmAttr" type="union" visibility="0x04" properties="0x00">
<documentation>//! Attribute of for the QP::QHsm class (Hierarchical State Machine)
//!
//! @details
//! This union represents possible values stored in the 'state' and 'temp'
//! attributes of the QP::QHsm class.</documentation>
<code>{
QStateHandler fun; //!&lt; pointer to a state handler function
QActionHandler act; //!&lt; pointer to an action-handler function
QXThreadHandler thr; //!&lt; pointer to an thread-handler function
QMState const *obj; //!&lt; pointer to QMState object
QMTranActTable const *tatbl; //!&lt; transition-action table
};</code>
</attribute>
<!--${QEP::Q_USER_SIG}-->
<attribute name="Q_USER_SIG" type="constexpr enum_t " visibility="0x04" properties="0x00">
<documentation>//! Type returned from state-handler functions</documentation>
<code>{4};</code>
</attribute>
<!--${QEP::QHsm}-->
<class name="QHsm">
<documentation>//! Hierarchical State Machine abstract base class (ABC)
//!
//! @details
//! QP::QHsm represents a Hierarchical State Machine (HSM) with full support
//! for hierarchical nesting of states, entry/exit actions, and initial
//! transitions in any composite state. QHsm inherits QP::QMsm without adding
//! new attributes, so it takes the same amount of RAM as QP::QMsm.&lt;br&gt;
//!
//! QP::QHsm is also the base class for the QP::QMsm state machine, which
//! provides better efficiency, but requires the use of the QM modeling tool
//! to generate code.
//!
//! @note
//! QP::QHsm is not intended to be instantiated directly, but rather serves as
//! the base class for derivation of state machines in the application code.
//!
//! @usage
//! The following example illustrates how to derive a state machine class
//! from QP::QHsm.
//! @include qep_qhsm.cpp</documentation>
<!--${QEP::QHsm::m_state}-->
<attribute name="m_state" type="QHsmAttr" visibility="0x02" properties="0x00">
<documentation>//! current active state (the state-variable)</documentation>
</attribute>
<!--${QEP::QHsm::m_temp}-->
<attribute name="m_temp" type="QHsmAttr" visibility="0x02" properties="0x00">
<documentation>//! temporary: transition chain, target state, etc.</documentation>
</attribute>
<!--${QEP::QHsm::MAX_NEST_DEPTH_}-->
<attribute name="MAX_NEST_DEPTH_" type="static constexpr std::int_fast8_t" visibility="0x04" properties="0x01">
<documentation>//! Maximum nesting depth of states in HSM</documentation>
<code>{6};</code>
</attribute>
<!--${QEP::QHsm::QMsm}-->
<attribute name="QMsm" type="friend class" visibility="0x02" properties="0x00">
<documentation>// friends...</documentation>
</attribute>
<!--${QEP::QHsm::QActive}-->
<attribute name="QActive" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QMActive}-->
<attribute name="QMActive" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QXThread}-->
<attribute name="QXThread" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QXMutex}-->
<attribute name="QXMutex" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QXSemaphore}-->
<attribute name="QXSemaphore" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QHsmDummy}-->
<attribute name="QHsmDummy?def Q_UTEST" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::QActiveDummy}-->
<attribute name="QActiveDummy?def Q_UTEST" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QEP::QHsm::ReservedSig}-->
<attribute name="ReservedSig" type="enum" visibility="0x04" properties="0x01">
<documentation>//! Reserved signals by the HSM-style state machine
//! implementation strategy.</documentation>
<code> : QSignal {
Q_EMPTY_SIG, //!&lt; signal to execute the default case
Q_ENTRY_SIG, //!&lt; signal for entry actions
Q_EXIT_SIG, //!&lt; signal for exit actions
Q_INIT_SIG //!&lt; signal for nested initial transitions
};</code>
</attribute>
<!--${QEP::QHsm::QStateRet}-->
<attribute name="QStateRet" type="enum" visibility="0x04" properties="0x01">
<documentation>//! All possible return values from state-handlers</documentation>
<code> : std::uint_fast8_t {
// unhandled and need to &quot;bubble up&quot;
Q_RET_SUPER, //!&lt; event passed to superstate to handle
Q_RET_SUPER_SUB, //!&lt; event passed to submachine superstate
Q_RET_UNHANDLED, //!&lt; event unhandled due to a guard
// handled and do not need to &quot;bubble up&quot;
Q_RET_HANDLED, //!&lt; event handled (internal transition)
Q_RET_IGNORED, //!&lt; event silently ignored (bubbled up to top)
// entry/exit
Q_RET_ENTRY, //!&lt; state entry action executed
Q_RET_EXIT, //!&lt; state exit action executed
// no side effects
Q_RET_NULL, //!&lt; return value without any effect
// transitions need to execute transition-action table in QP::QMsm
Q_RET_TRAN, //!&lt; regular transition
Q_RET_TRAN_INIT, //!&lt; initial transition in a state or submachine
Q_RET_TRAN_EP, //!&lt; entry-point transition into a submachine
// transitions that additionally clobber QHsm.m_state
Q_RET_TRAN_HIST, //!&lt; transition to history of a given state
Q_RET_TRAN_XP //!&lt; exit-point transition out of a submachine
};</code>
</attribute>
<!--${QEP::QHsm::QHsm}-->
<operation name="QHsm" type="explicit" visibility="0x01" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! protected constructor of QHsm</documentation>
<!--${QEP::QHsm::QHsm::initial}-->
<parameter name="initial" type="QStateHandler const"/>
<code>m_state.fun = Q_STATE_CAST(&amp;top);
m_temp.fun = initial;</code>
</operation>
<!--${QEP::QHsm::~QHsm}-->
<operation name="~QHsm?def Q_HSM_XTOR" type="" visibility="0x00" properties="0x06">
<specifiers>noexcept</specifiers>
<documentation>//! virtual destructor</documentation>
<code>// empty</code>
</operation>
<!--${QEP::QHsm::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x04">
<documentation>//! Executes the top-most initial transition in QP::QHsm
//!
//! @details
//! Executes the top-most initial transition in a HSM.
//!
//! @param[in] e pointer to an extra parameter (might be NULL)
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @note
//! Must be called exactly __once__ before the QP::QHsm::dispatch().
//!
//! @tr{RQP103} @tr{RQP120I} @tr{RQP120D}</documentation>
<!--${QEP::QHsm::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QEP::QHsm::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>#ifdef Q_SPY
if ((QS::priv_.flags &amp; 0x01U) == 0U) {
QS::priv_.flags |= 0x01U;
QS_FUN_DICTIONARY(&amp;QP::QHsm::top);
}
#else
Q_UNUSED_PAR(qs_id);
#endif
QStateHandler t = m_state.fun;
//! @pre ctor must have been executed and initial tran NOT taken
Q_REQUIRE_ID(200, (m_temp.fun != nullptr)
&amp;&amp; (t == Q_STATE_CAST(&amp;top)));
// execute the top-most initial transition
QState r = (*m_temp.fun)(this, Q_EVT_CAST(QEvt));
// the top-most initial transition must be taken
Q_ASSERT_ID(210, r == Q_RET_TRAN);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the source state
QS_FUN_PRE_(m_temp.fun); // the target of the initial transition
QS_END_PRE_()
// drill down into the state hierarchy with initial transitions...
do {
QStateHandler path[MAX_NEST_DEPTH_]; // tran entry path array
std::int_fast8_t ip = 0; // entry path index
path[0] = m_temp.fun;
static_cast&lt;void&gt;(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
while (m_temp.fun != t) {
++ip;
Q_ASSERT_ID(220, ip &lt; MAX_NEST_DEPTH_);
path[ip] = m_temp.fun;
static_cast&lt;void&gt;(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
}
m_temp.fun = path[0];
// retrace the entry path in reverse (desired) order...
do {
hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
--ip;
} while (ip &gt;= 0);
t = path[0]; // current state becomes the new source
r = hsm_reservedEvt_(this, t, Q_INIT_SIG); // execute initial tran.
#ifdef Q_SPY
if (r == Q_RET_TRAN) {
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the source state
QS_FUN_PRE_(m_temp.fun); // the target of the initial tran.
QS_END_PRE_()
}
#endif // Q_SPY
} while (r == Q_RET_TRAN);
QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the new active state
QS_END_PRE_()
m_state.fun = t; // change the current active state
m_temp.fun = t; // mark the configuration as stable</code>
</operation>
<!--${QEP::QHsm::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x06">
<documentation>//! overloaded init(qs_id)
//!
//! @details
//! Executes the top-most initial transition in a HSM (overloaded).
//!
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! QHsm::init() must be called exactly **once** before
//! QHsm::dispatch()</documentation>
<!--${QEP::QHsm::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>init(nullptr, qs_id);</code>
</operation>
<!--${QEP::QHsm::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x04">
<documentation>//! Dispatches an event to QP::QHsm
//!
//! @details
//! Dispatches an event for processing to a hierarchical state machine.
//! The event dispatching represents one run-to-completion (RTC) step.
//!
//! @param[in] e pointer to the event to be dispatched to the HSM
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! This state machine must be initialized by calling QP::QHsm::init()
//! exactly **once** before calling QP::QHsm::dispatch().
//!
//! @tr{RQP103}
//! @tr{RQP120A} @tr{RQP120B} @tr{RQP120C} @tr{RQP120D} @tr{RQP120E}</documentation>
<!--${QEP::QHsm::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QEP::QHsm::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>#ifndef Q_SPY
Q_UNUSED_PAR(qs_id);
#endif
QStateHandler t = m_state.fun;
QS_CRIT_STAT_
//! @pre the current state must be initialized and
//! the state configuration must be stable
Q_REQUIRE_ID(400, (t != nullptr)
&amp;&amp; (t == m_temp.fun));
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the current state
QS_END_PRE_()
QStateHandler s;
QState r;
// process the event hierarchically...
//! @tr{RQP120A}
do {
s = m_temp.fun;
r = (*s)(this, e); // invoke state handler s
if (r == Q_RET_UNHANDLED) { // unhandled due to a guard?
QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s); // the current state
QS_END_PRE_()
r = hsm_reservedEvt_(this, s, Q_EMPTY_SIG); // find superstate of s
}
} while (r == Q_RET_SUPER);
// regular transition taken?
//! @tr{RQP120E}
if (r &gt;= Q_RET_TRAN) {
QStateHandler path[MAX_NEST_DEPTH_];
path[0] = m_temp.fun; // save the target of the transition
path[1] = t;
path[2] = s;
// exit current state to transition source s...
//! @tr{RQP120C}
for (; t != s; t = m_temp.fun) {
// exit handled?
if (hsm_state_exit_(this, t, qs_id)) {
// find superstate of t
static_cast&lt;void&gt;(hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
}
}
std::int_fast8_t ip = hsm_tran(path, qs_id); // the HSM transition
#ifdef Q_SPY
if (r == Q_RET_TRAN_HIST) {
QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the source of the transition
QS_FUN_PRE_(path[0]); // the target of the tran. to history
QS_END_PRE_()
}
#endif // Q_SPY
// execute state entry actions in the desired order...
//! @tr{RQP120B}
for (; ip &gt;= 0; --ip) {
hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
}
t = path[0]; // stick the target into register
m_temp.fun = t; // update the next state
// drill into the target hierarchy...
//! @tr{RQP120I}
while (hsm_reservedEvt_(this, t, Q_INIT_SIG) == Q_RET_TRAN) {
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t); // the source (pseudo)state
QS_FUN_PRE_(m_temp.fun); // the target of the transition
QS_END_PRE_()
ip = 0;
path[0] = m_temp.fun;
// find superstate
static_cast&lt;void&gt;(hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
while (m_temp.fun != t) {
++ip;
path[ip] = m_temp.fun;
// find superstate
static_cast&lt;void&gt;(
hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG));
}
m_temp.fun = path[0];
// entry path must not overflow
Q_ASSERT_ID(410, ip &lt; MAX_NEST_DEPTH_);
// retrace the entry path in reverse (correct) order...
do {
hsm_state_entry_(this, path[ip], qs_id); // enter path[ip]
--ip;
} while (ip &gt;= 0);
t = path[0];
}
QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s); // the source of the transition
QS_FUN_PRE_(t); // the new active state
QS_END_PRE_()
}
#ifdef Q_SPY
else if (r == Q_RET_HANDLED) {
QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s); // the source state
QS_END_PRE_()
}
else {
QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.fun);// the current state
QS_END_PRE_()
}
#else
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
#endif // Q_SPY
m_state.fun = t; // change the current active state
m_temp.fun = t; // mark the configuration as stable</code>
</operation>
<!--${QEP::QHsm::top}-->
<operation name="top" type="QState" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! The top-state handler
//!
//! @details
//! The QHsm::top() state handler is the ultimate root of state
//! hierarchy in all HSMs derived from QP::QHsm.
//!
//! @param[in] me pointer to the HSM instance
//! @param[in] e pointer to the event to be dispatched to the HSM
//!
//! @returns
//! Always returns #Q_RET_IGNORED, which means that the top state ignores
//! all events.
//!
//! @note
//! The parameters to this state handler are not used. They are provided
//! for conformance with the state-handler function signature
//! QP::QStateHandler.
//!
//! @tr{RQP103} @tr{RQP120T}</documentation>
<!--${QEP::QHsm::top::me}-->
<parameter name="me" type="void * const"/>
<!--${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>
<!--${QEP::QHsm::state}-->
<operation name="state" type="QStateHandler" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Obtain the current state (state handler function)
//!
//! @note used in the QM code generation</documentation>
<code>return m_state.fun;</code>
</operation>
<!--${QEP::QHsm::getStateHandler}-->
<operation name="getStateHandler?def Q_SPY" type="QStateHandler" visibility="0x00" properties="0x06">
<specifiers>noexcept</specifiers>
<documentation>//! Get the current state handler of the QP::QHsm</documentation>
<code>return m_state.fun;</code>
</operation>
<!--${QEP::QHsm::isIn}-->
<operation name="isIn" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Tests if a given state is part of the current active state
//! configuration
//!
//! @details
//! Tests if a state machine derived from QHsm is-in a given state.
//!
//! @note
//! For a HSM, to &quot;be in a state&quot; means also to be in a superstate of
//! of the state.
//!
//! @param[in] s pointer to the state-handler function to be tested
//!
//! @returns
//! 'true' if the HSM is in the `state` and 'false' otherwise
//!
//! @tr{RQP103}
//! @tr{RQP120S}</documentation>
<!--${QEP::QHsm::isIn::s}-->
<parameter name="s" type="QStateHandler const"/>
<code>//! @pre state configuration must be stable
Q_REQUIRE_ID(600, m_temp.fun == m_state.fun);
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 (m_temp.fun == s) {
inState = true; // 'true' means that match found
r = Q_RET_IGNORED; // cause breaking out of the loop
}
else {
r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
}
} while (r != Q_RET_IGNORED); // QHsm::top() state not reached
m_temp.fun = m_state.fun; // restore the stable state configuration
return inState; // return the status</code>
</operation>
<!--${QEP::QHsm::childState}-->
<operation name="childState" type="QStateHandler" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Obtain the current active child state of a given parent
//!
//! @note used in the QM code generation</documentation>
<!--${QEP::QHsm::childState::parent}-->
<parameter name="parent" type="QStateHandler const"/>
<code>QStateHandler child = m_state.fun; // start with the current state
bool isFound = false; // start with the child not found
// establish stable state configuration
m_temp.fun = m_state.fun;
QState r;
do {
// is this the parent of the current child?
if (m_temp.fun == parent) {
isFound = true; // child is found
r = Q_RET_IGNORED; // cause breaking out of the loop
}
else {
child = m_temp.fun;
r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
}
} while (r != Q_RET_IGNORED); // QHsm::top() state not reached
m_temp.fun = m_state.fun; // establish stable state configuration
//! @post the child must be confirmed
Q_ENSURE_ID(810, isFound);
#ifdef Q_NASSERT
Q_UNUSED_PAR(isFound);
#endif
return child; // return the child</code>
</operation>
<!--${QEP::QHsm::tran}-->
<operation name="tran" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a state transition</documentation>
<!--${QEP::QHsm::tran::target}-->
<parameter name="target" type="QStateHandler const"/>
<code>m_temp.fun = target;
return Q_RET_TRAN;</code>
</operation>
<!--${QEP::QHsm::tran_hist}-->
<operation name="tran_hist" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a transition to history</documentation>
<!--${QEP::QHsm::tran_hist::hist}-->
<parameter name="hist" type="QStateHandler const"/>
<code>m_temp.fun = hist;
return Q_RET_TRAN_HIST;</code>
</operation>
<!--${QEP::QHsm::super}-->
<operation name="super" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify the superstate of a given state</documentation>
<!--${QEP::QHsm::super::superstate}-->
<parameter name="superstate" type="QStateHandler const"/>
<code>m_temp.fun = superstate;
return Q_RET_SUPER;</code>
</operation>
<!--${QEP::QHsm::qm_tran}-->
<operation name="qm_tran" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a regular state transition
//! in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_tran::tatbl}-->
<parameter name="tatbl" type="void const * const"/>
<code>m_temp.tatbl = static_cast&lt;QP::QMTranActTable const *&gt;(tatbl);
return Q_RET_TRAN;</code>
</operation>
<!--${QEP::QHsm::qm_tran_init}-->
<operation name="qm_tran_init" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify an initial state transition
//! in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_tran_init::tatbl}-->
<parameter name="tatbl" type="void const * const"/>
<code>m_temp.tatbl = static_cast&lt;QP::QMTranActTable const *&gt;(tatbl);
return Q_RET_TRAN_INIT;</code>
</operation>
<!--${QEP::QHsm::qm_tran_hist}-->
<operation name="qm_tran_hist" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specifiy a transition to history
//! in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_tran_hist::hist}-->
<parameter name="hist" type="QMState const * const"/>
<!--${QEP::QHsm::qm_tran_hist::tatbl}-->
<parameter name="tatbl" type="void const * const"/>
<code>m_state.obj = hist;
m_temp.tatbl = static_cast&lt;QP::QMTranActTable const *&gt;(tatbl);
return Q_RET_TRAN_HIST;</code>
</operation>
<!--${QEP::QHsm::qm_tran_ep}-->
<operation name="qm_tran_ep" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a transition to an entry point
//! to a submachine state in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_tran_ep::tatbl}-->
<parameter name="tatbl" type="void const * const"/>
<code>m_temp.tatbl = static_cast&lt;QP::QMTranActTable const *&gt;(tatbl);
return Q_RET_TRAN_EP;</code>
</operation>
<!--${QEP::QHsm::qm_tran_xp}-->
<operation name="qm_tran_xp" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a transition to an exit point
//! from a submachine state in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_tran_xp::xp}-->
<parameter name="xp" type="QActionHandler const"/>
<!--${QEP::QHsm::qm_tran_xp::tatbl}-->
<parameter name="tatbl" type="void const * const"/>
<code>m_state.act = xp;
m_temp.tatbl = static_cast&lt;QP::QMTranActTable const *&gt;(tatbl);
return Q_RET_TRAN_XP;</code>
</operation>
<!--${QEP::QHsm::qm_entry}-->
<operation name="qm_entry?def Q_SPY" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a state entry in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_entry::s}-->
<parameter name="s" type="QMState const * const"/>
<code>m_temp.obj = s;
return Q_RET_ENTRY;</code>
</operation>
<!--${QEP::QHsm::qm_entry}-->
<operation name="qm_entry?ndef Q_SPY" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a state entry in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_entry::s}-->
<parameter name="s" type="QMState const * const"/>
<code>static_cast&lt;void&gt;(s); // unused parameter
return Q_RET_ENTRY;</code>
</operation>
<!--${QEP::QHsm::qm_exit}-->
<operation name="qm_exit?def Q_SPY" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a state exit in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_exit::s}-->
<parameter name="s" type="QMState const * const"/>
<code>m_temp.obj = s;
return Q_RET_EXIT;</code>
</operation>
<!--${QEP::QHsm::qm_exit}-->
<operation name="qm_exit?ndef Q_SPY" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a state exit in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_exit::s}-->
<parameter name="s" type="QMState const * const"/>
<code>static_cast&lt;void&gt;(s); // unused parameter
return Q_RET_EXIT;</code>
</operation>
<!--${QEP::QHsm::qm_sm_exit}-->
<operation name="qm_sm_exit" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to specify a submachine exit in a QM state-handler</documentation>
<!--${QEP::QHsm::qm_sm_exit::s}-->
<parameter name="s" type="QMState const * const"/>
<code>m_temp.obj = s;
return Q_RET_EXIT;</code>
</operation>
<!--${QEP::QHsm::qm_super_sub}-->
<operation name="qm_super_sub" type="QState" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Helper function to call in a QM state-handler when it passes
//! the event to the host submachine state to handle an event.</documentation>
<!--${QEP::QHsm::qm_super_sub::s}-->
<parameter name="s" type="QMState const * const"/>
<code>m_temp.obj = s;
return Q_RET_SUPER_SUB;</code>
</operation>
<!--${QEP::QHsm::hsm_tran}-->
<operation name="hsm_tran" type="std::int_fast8_t" visibility="0x02" properties="0x00">
<documentation>//! @details
//! helper function to execute transition sequence in a hierarchical
//! state machine (HSM).
//!
//! @param[in,out] path array of pointers to state-handler functions
//! to execute the entry actions
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! the depth of the entry path stored in the `path` parameter.
//!
//! @tr{RQP103}
//! @tr{RQP120E} @tr{RQP120F}</documentation>
<!--${QEP::QHsm::hsm_tran::(&path)[MAX_NEST_DEPTH_]}-->
<parameter name="(&amp;path)[MAX_NEST_DEPTH_]" type="QStateHandler"/>
<!--${QEP::QHsm::hsm_tran::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>#ifndef Q_SPY
Q_UNUSED_PAR(qs_id);
#endif
std::int_fast8_t ip = -1; // transition entry path index
QStateHandler t = path[0];
QStateHandler const s = path[2];
// (a) check source==target (transition to self)
if (s == t) {
// exit the source
static_cast&lt;void&gt;(hsm_state_exit_(this, s, qs_id));
ip = 0; // enter the target
}
else {
// superstate of target
static_cast&lt;void&gt;(hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
t = m_temp.fun;
// (b) check source==target-&gt;super
if (s == t) {
ip = 0; // enter the target
}
else {
// superstate of src
static_cast&lt;void&gt;(hsm_reservedEvt_(this, s, Q_EMPTY_SIG));
// (c) check source-&gt;super==target-&gt;super
if (m_temp.fun == t) {
// exit the source
static_cast&lt;void&gt;(hsm_state_exit_(this, s, qs_id));
ip = 0; // enter the target
}
else {
// (d) check source-&gt;super==target
if (m_temp.fun == path[0]) {
// exit the source
static_cast&lt;void&gt;(hsm_state_exit_(this, s, qs_id));
}
else {
// (e) check rest of source==target-&gt;super-&gt;super..
// and store the entry path along the way
std::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 = m_temp.fun; // save source-&gt;super
// find target-&gt;super-&gt;super
QState r = hsm_reservedEvt_(this, path[1], Q_EMPTY_SIG);
while (r == Q_RET_SUPER) {
++ip;
path[ip] = m_temp.fun; // store the entry path
if (m_temp.fun == s) { // is it the source?
// indicate that the LCA was found
iq = 1;
// entry path must not overflow
Q_ASSERT_ID(510, ip &lt; MAX_NEST_DEPTH_);
--ip; // do not enter the source
r = Q_RET_HANDLED; // terminate the loop
}
// it is not the source, keep going up
else {
r = hsm_reservedEvt_(this, m_temp.fun, Q_EMPTY_SIG);
}
}
// the LCA not found yet?
if (iq == 0) {
// entry path must not overflow
Q_ASSERT_ID(520, ip &lt; MAX_NEST_DEPTH_);
// exit the source
static_cast&lt;void&gt;(hsm_state_exit_(this, s, qs_id));
// (f) check the rest of source-&gt;super
// == target-&gt;super-&gt;super...
//
iq = ip;
r = Q_RET_IGNORED; // indicate LCA NOT found
do {
// is this the LCA?
if (t == path[iq]) {
r = Q_RET_HANDLED; // indicate LCA found
ip = iq - 1; // do not enter LCA
iq = -1; // cause termination of the loop
}
else {
--iq; // try lower superstate of target
}
} while (iq &gt;= 0);
// LCA not found yet?
if (r != Q_RET_HANDLED) {
// (g) check each source-&gt;super-&gt;...
// for each target-&gt;super...
//
r = Q_RET_IGNORED; // keep looping
do {
// exit from t handled?
if (hsm_state_exit_(this, t, qs_id)) {
// find superstate of t
static_cast&lt;void&gt;(
hsm_reservedEvt_(this, t, Q_EMPTY_SIG));
}
t = m_temp.fun; // set to super of t
iq = ip;
do {
// is this LCA?
if (t == path[iq]) {
ip = iq - 1; // do not enter LCA
iq = -1; // break out of inner loop
r = Q_RET_HANDLED; // break outer loop
}
else {
--iq;
}
} while (iq &gt;= 0);
} while (r != Q_RET_HANDLED);
}
}
}
}
}
}
return ip;
</code>
</operation>
</class>
<!--${QEP::QMsm}-->
<class name="QMsm" superclass="QEP::QHsm">
<documentation>//! QM State Machine implementation strategy
//!
//! @details
//! QP::QMsm (QM State Machine) provides a more efficient state machine
//! implementation strategy than QHsm, but requires the use of the QM
//! modeling tool, but are the fastest and need the least run-time
//! support (the smallest event-processor taking up the least code space).
//!
//! @note
//! QP::QMsm is not intended to be instantiated directly, but rather serves as
//! the base class for derivation of state machines in the application code.
//!
//! @usage
//! The following example illustrates how to derive a state machine class
//! from QP::QMsm:
//! @include qep_qmsm.cpp</documentation>
<!--${QEP::QMsm::msm_top_s}-->
<attribute name="msm_top_s" type="QMState const" visibility="0x02" properties="0x01">
<documentation>//! the top state object for the QP::QMsm</documentation>
<code> = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr
};</code>
</attribute>
<!--${QEP::QMsm::QMActive}-->
<attribute name="QMActive" type="friend class" visibility="0x02" properties="0x00">
<documentation>// friends...</documentation>
</attribute>
<!--${QEP::QMsm::MAX_ENTRY_DEPTH_}-->
<attribute name="MAX_ENTRY_DEPTH_" type="static constexpr std::int_fast8_t" visibility="0x04" properties="0x01">
<documentation>//! maximum depth of implemented entry levels for transitions to history</documentation>
<code>{4};</code>
</attribute>
<!--${QEP::QMsm::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x04">
<specifiers>override</specifiers>
<documentation>//! Performs the second step of SM initialization by triggering
//! the top-most initial transition.
//!
//! @details
//! Executes the top-most initial transition in a MSM.
//!
//! @param[in] e pointer to an extra parameter (might be nullptr)
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! QMsm::init() must be called exactly **once** before QMsm::dispatch()</documentation>
<!--${QEP::QMsm::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QEP::QMsm::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>//! @pre the top-most initial transition must be initialized, and the
//! initial transition must not be taken yet.
Q_REQUIRE_ID(200, (m_temp.fun != nullptr)
&amp;&amp; (m_state.obj == &amp;msm_top_s));
// execute the top-most initial tran.
QState r = (*m_temp.fun)(this, Q_EVT_CAST(QEvt));
// initial tran. must be taken
Q_ASSERT_ID(210, r == Q_RET_TRAN_INIT);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.obj-&gt;stateHandler); // source handler
QS_FUN_PRE_(m_temp.tatbl-&gt;target-&gt;stateHandler); // target handler
QS_END_PRE_()
// set state to the last tran. target
m_state.obj = m_temp.tatbl-&gt;target;
// drill down into the state hierarchy with initial transitions...
do {
r = execTatbl_(m_temp.tatbl, qs_id); // execute the tran-action table
} while (r &gt;= Q_RET_TRAN_INIT);
QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.obj-&gt;stateHandler); // the new current state
QS_END_PRE_()
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined</code>
</operation>
<!--${QEP::QMsm::QMsm}-->
<operation name="QMsm" type="explicit" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Protected constructor
//! @details
//! Performs the first step of initialization by assigning the initial
//! pseudostate to the currently active state of the state machine.
//!
//! @param[in] initial the top-most initial transition for the MSM.
//!
//! @note
//! The constructor is protected to prevent direct instantiating of the
//! QP::QMsm objects. This class is intended for subclassing only.
//!
//! @sa
//! The QP::QMsm example illustrates how to use the QMsm constructor
//! in the constructor initializer list of the derived state machines.</documentation>
<!--${QEP::QMsm::QMsm::initial}-->
<parameter name="initial" type="QStateHandler const"/>
<code> : QHsm(initial)
m_state.obj = &amp;msm_top_s;
m_temp.fun = initial;</code>
</operation>
<!--${QEP::QMsm::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x06">
<specifiers>override</specifiers>
<documentation>//! overloaded init(qs_id)
//!
//! @details
//! Executes the top-most initial transition in a MSM (overloaded).
//!
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! QMsm::init() must be called exactly **once** before QMsm::dispatch()</documentation>
<!--${QEP::QMsm::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QMsm::init(nullptr, qs_id);</code>
</operation>
<!--${QEP::QMsm::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x04">
<specifiers>override</specifiers>
<documentation>//! Dispatches an event to a MSM
//!
//! @details
//! Dispatches an event for processing to a meta state machine (MSM).
//! The processing of an event represents one run-to-completion (RTC) step.
//!
//! @param[in] e pointer to the event to be dispatched to the MSM
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @note
//! Must be called after QMsm::init().</documentation>
<!--${QEP::QMsm::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QEP::QMsm::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QMState const *s = m_state.obj; // store the current state
//! @pre current state must be initialized
Q_REQUIRE_ID(300, s != nullptr);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s-&gt;stateHandler); // the current state handler
QS_END_PRE_()
// scan the state hierarchy up to the top state...
QMState const *t = s;
QState r;
do {
r = (*t-&gt;stateHandler)(this, e); // call state handler function
// event handled? (the most frequent case)
if (r &gt;= Q_RET_HANDLED) {
break; // done scanning the state hierarchy
}
// event unhandled and passed to the superstate?
else if (r == Q_RET_SUPER) {
t = t-&gt;superstate; // advance to the superstate
}
// event unhandled and passed to a submachine superstate?
else if (r == Q_RET_SUPER_SUB) {
t = m_temp.obj; // current host state of the submachie
}
// event unhandled due to a guard?
else if (r == Q_RET_UNHANDLED) {
QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t-&gt;stateHandler); // the current state
QS_END_PRE_()
t = t-&gt;superstate; // advance to the superstate
}
else {
// no other return value should be produced
Q_ERROR_ID(310);
}
} while (t != nullptr);
// any kind of transition taken?
if (r &gt;= Q_RET_TRAN) {
#ifdef Q_SPY
QMState const * const ts = t; // transition source for QS tracing
// the transition source state must not be nullptr
Q_ASSERT_ID(320, ts != nullptr);
#endif // Q_SPY
do {
// save the transition-action table before it gets clobbered
QMTranActTable const * const tatbl = m_temp.tatbl;
QHsmAttr tmp; // temporary to save intermediate values
// was TRAN, TRAN_INIT, or TRAN_EP taken?
if (r &lt;= Q_RET_TRAN_EP) {
m_temp.obj = nullptr; // clear
exitToTranSource_(s, t, qs_id);
r = execTatbl_(tatbl, qs_id);
s = m_state.obj;
}
// was a transition segment to history taken?
else if (r == Q_RET_TRAN_HIST) {
tmp.obj = m_state.obj; // save history
m_state.obj = s; // restore the original state
exitToTranSource_(s, t, qs_id);
static_cast&lt;void&gt;(execTatbl_(tatbl, qs_id));
r = enterHistory_(tmp.obj, qs_id);
s = m_state.obj;
}
// was a transition segment to an exit point taken?
else if (r == Q_RET_TRAN_XP) {
tmp.act = m_state.act; // save XP action
m_state.obj = s; // restore the original state
r = (*tmp.act)(this); // execute the XP action
if (r == Q_RET_TRAN) { // XP -&gt; TRAN ?
#ifdef Q_SPY
tmp.tatbl = m_temp.tatbl; // save m_temp
#endif // Q_SPY
exitToTranSource_(s, t, qs_id);
// take the tran-to-XP segment inside submachine
static_cast&lt;void&gt;(execTatbl_(tatbl, qs_id));
s = m_state.obj;
#ifdef Q_SPY
m_temp.tatbl = tmp.tatbl; // restore m_temp
#endif // Q_SPY
}
else if (r == Q_RET_TRAN_HIST) { // XP -&gt; HIST ?
tmp.obj = m_state.obj; // save the history
m_state.obj = s; // restore the original state
#ifdef Q_SPY
s = m_temp.obj; // save m_temp
#endif // Q_SPY
exitToTranSource_(m_state.obj, t, qs_id);
// take the tran-to-XP segment inside submachine
static_cast&lt;void&gt;(execTatbl_(tatbl, qs_id));
#ifdef Q_SPY
m_temp.obj = s; // restore me-&gt;temp
#endif // Q_SPY
s = m_state.obj;
m_state.obj = tmp.obj; // restore the history
}
else {
// TRAN_XP must NOT be followed by any other tran type
Q_ASSERT_ID(330, r &lt; Q_RET_TRAN);
}
}
else {
// no other return value should be produced
Q_ERROR_ID(340);
}
t = s; // set target to the current state
} while (r &gt;= Q_RET_TRAN);
QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(ts-&gt;stateHandler); // the transition source
QS_FUN_PRE_(s-&gt;stateHandler); // the new active state
QS_END_PRE_()
}
#ifdef Q_SPY
// was the event handled?
else if (r == Q_RET_HANDLED) {
// internal tran. source can't be nullptr
Q_ASSERT_ID(340, t != nullptr);
QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(t-&gt;stateHandler); // the source state
QS_END_PRE_()
}
// event bubbled to the 'top' state?
else if (t == nullptr) {
QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s-&gt;stateHandler); // the current state
QS_END_PRE_()
}
#endif // Q_SPY
else {
// empty
}
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined</code>
</operation>
<!--${QEP::QMsm::isInState}-->
<operation name="isInState" type="bool" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Tests if a given state is part of the active state configuration
//!
//! @details
//! Tests if a state machine derived from QMsm is-in a given state.
//!
//! @note
//! For a MSM, to &quot;be-in&quot; a state means also to &quot;be-in&quot; a superstate of
//! of the state.
//!
//! @param[in] st pointer to the QMState object that corresponds to the
//! tested state.
//! @returns
//! 'true' if the MSM is in the \c st and 'false' otherwise</documentation>
<!--${QEP::QMsm::isInState::st}-->
<parameter name="st" type="QMState const * const"/>
<code>bool inState = false; // assume that this MSM is not in 'state'
for (QMState const *s = m_state.obj;
s != nullptr;
s = s-&gt;superstate)
{
if (s == st) {
inState = true; // match found, return 'true'
break;
}
}
return inState;</code>
</operation>
<!--${QEP::QMsm::top}-->
<operation name="top" type="QStateHandler" visibility="0x02" properties="0x01">
<specifiers>noexcept = delete</specifiers>
<documentation>//! disallow inherited top() function in QP::QMsm and subclasses
//! @sa QMsm::msm_top_s</documentation>
<!--${QEP::QMsm::top::me}-->
<parameter name="me" type="void * const"/>
<!--${QEP::QMsm::top::e}-->
<parameter name="e" type="QEvt const * const"/>
</operation>
<!--${QEP::QMsm::stateObj}-->
<operation name="stateObj" type="QMState const *" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Return the current active state object (read only)</documentation>
<code>return m_state.obj;</code>
</operation>
<!--${QEP::QMsm::childStateObj}-->
<operation name="childStateObj" type="QMState const *" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Obtain the current active child state of a given parent (read only)
//!
//! @details
//! Finds the child state of the given `parent`, such that this child
//! state is an ancestor of the currently active state. The main purpose
//! of this function is to support **shallow history** transitions in
//! state machines derived from QHsm.
//!
//! @param[in] parent pointer to the state-handler function
//!
//! @returns
//! the child of a given `parent` state, which is an ancestor of the
//! currently active state
//!
//! @note
//! this function is designed to be called during state transitions, so it
//! does not necessarily start in a stable state configuration.
//! However, the function establishes stable state configuration upon exit.
//!
//! @tr{RQP103}
//! @tr{RQP120H}</documentation>
<!--${QEP::QMsm::childStateObj::parent}-->
<parameter name="parent" type="QMState const * const"/>
<code>QMState const *child = m_state.obj;
bool isFound = false; // start with the child not found
QMState const *s;
for (s = m_state.obj; s != nullptr; s = s-&gt;superstate) {
if (s == parent) {
isFound = true; // child is found
break;
}
else {
child = s;
}
}
if (!isFound) { // still not found?
for (s = m_temp.obj; s != nullptr; s = s-&gt;superstate) {
if (s == parent) {
isFound = true; // child is found
break;
}
else {
child = s;
}
}
}
//! @post the child must be found
Q_ENSURE_ID(810, isFound);
#ifdef Q_NASSERT
Q_UNUSED_PAR(isFound);
#endif
return child; // return the child</code>
</operation>
<!--${QEP::QMsm::getStateHandler}-->
<operation name="getStateHandler?def Q_SPY" type="QStateHandler" visibility="0x01" properties="0x02">
<specifiers>noexcept override</specifiers>
<documentation>//! Get the current state handler of the QMsm</documentation>
<code>return m_state.obj-&gt;stateHandler;</code>
</operation>
<!--${QEP::QMsm::execTatbl_}-->
<operation name="execTatbl_" type="QState" visibility="0x02" properties="0x00">
<documentation>//! Internal helper function to execute a transition-action table
//!
//! @details
//! Helper function to execute transition sequence in a tran-action table.
//!
//! @param[in] tatbl pointer to the transition-action table
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! the status of the last action from the transition-action table.
//!
//! @note
//! This function is for internal use inside the QEP event processor and
//! should **not** be called directly from the applications.</documentation>
<!--${QEP::QMsm::execTatbl_::tatbl}-->
<parameter name="tatbl" type="QMTranActTable const * const"/>
<!--${QEP::QMsm::execTatbl_::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>//! @pre the transition-action table pointer must not be nullptr
Q_REQUIRE_ID(400, tatbl != nullptr);
QState r = Q_RET_NULL;
QS_CRIT_STAT_
for (QActionHandler const *a = &amp;tatbl-&gt;act[0]; *a != nullptr; ++a) {
r = (*(*a))(this); // call the action through the 'a' pointer
#ifdef Q_SPY
if (r == Q_RET_ENTRY) {
QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_temp.obj-&gt;stateHandler); // entered state handler
QS_END_PRE_()
}
else if (r == Q_RET_EXIT) {
QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_temp.obj-&gt;stateHandler); // exited state handler
QS_END_PRE_()
}
else if (r == Q_RET_TRAN_INIT) {
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(tatbl-&gt;target-&gt;stateHandler); // source
QS_FUN_PRE_(m_temp.tatbl-&gt;target-&gt;stateHandler); // target
QS_END_PRE_()
}
else if (r == Q_RET_TRAN_EP) {
QS_BEGIN_PRE_(QS_QEP_TRAN_EP, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(tatbl-&gt;target-&gt;stateHandler); // source
QS_FUN_PRE_(m_temp.tatbl-&gt;target-&gt;stateHandler); // target
QS_END_PRE_()
}
else if (r == Q_RET_TRAN_XP) {
QS_BEGIN_PRE_(QS_QEP_TRAN_XP, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(tatbl-&gt;target-&gt;stateHandler); // source
QS_FUN_PRE_(m_temp.tatbl-&gt;target-&gt;stateHandler); // target
QS_END_PRE_()
}
else {
// empty
}
#endif // Q_SPY
}
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
m_state.obj = (r &gt;= Q_RET_TRAN)
? m_temp.tatbl-&gt;target
: tatbl-&gt;target;
return r;</code>
</operation>
<!--${QEP::QMsm::exitToTranSource_}-->
<operation name="exitToTranSource_" type="void" visibility="0x02" properties="0x00">
<documentation>//! Internal helper function to exit current state to transition source
//!
//! @details
//! Helper function to exit the current state configuration to the
//! transition source, which is a hierarchical state machine might be a
//! superstate of the current state.
//!
//! @param[in] s pointer to the current state
//! @param[in] ts pointer to the transition source state
//! @param[in] qs_id QS-id of this state machine (for QS local filter)</documentation>
<!--${QEP::QMsm::exitToTranSource~::s}-->
<parameter name="s" type="QMState const *"/>
<!--${QEP::QMsm::exitToTranSource~::ts}-->
<parameter name="ts" type="QMState const * const"/>
<!--${QEP::QMsm::exitToTranSource~::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>// exit states from the current state to the tran. source state
while (s != ts) {
// exit action provided in state 's'?
if (s-&gt;exitAction != nullptr) {
// execute the exit action
(*s-&gt;exitAction)(this);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(s-&gt;stateHandler); // the exited state handler
QS_END_PRE_()
}
s = s-&gt;superstate; // advance to the superstate
// reached the top of a submachine?
if (s == nullptr) {
s = m_temp.obj; // the superstate from QM_SM_EXIT()
Q_ASSERT_ID(510, s != nullptr);
}
}
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined</code>
</operation>
<!--${QEP::QMsm::enterHistory_}-->
<operation name="enterHistory_" type="QState" visibility="0x02" properties="0x00">
<documentation>//! Internal helper function to enter state history
//!
//! @details
//! Static helper function to execute the segment of transition to history
//! after entering the composite state and
//!
//! @param[in] hist pointer to the history substate
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! ::Q_RET_INIT, if an initial transition has been executed in the last
//! entered state or ::Q_RET_NULL if no such transition was taken.</documentation>
<!--${QEP::QMsm::enterHistory_::hist}-->
<parameter name="hist" type="QMState const * const"/>
<!--${QEP::QMsm::enterHistory_::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QMState const *s = hist;
QMState const *ts = m_state.obj; // transition source
QMState const *epath[MAX_ENTRY_DEPTH_];
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(ts-&gt;stateHandler); // source state handler
QS_FUN_PRE_(hist-&gt;stateHandler); // target state handler
QS_END_PRE_()
std::int_fast8_t i = 0; // entry path index
while (s != ts) {
if (s-&gt;entryAction != nullptr) {
Q_ASSERT_ID(620, i &lt; MAX_ENTRY_DEPTH_);
epath[i] = s;
++i;
}
s = s-&gt;superstate;
if (s == nullptr) {
ts = s; // force exit from the for-loop
}
}
// retrace the entry path in reverse (desired) order...
while (i &gt; 0) {
--i;
// run entry action in epath[i]
(*epath[i]-&gt;entryAction)(this);
QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
QS_OBJ_PRE_(this);
QS_FUN_PRE_(epath[i]-&gt;stateHandler); // entered state handler
QS_END_PRE_()
}
m_state.obj = hist; // set current state to the transition target
// initial tran. present?
QState r;
if (hist-&gt;initAction != nullptr) {
r = (*hist-&gt;initAction)(this); // execute the transition action
}
else {
r = Q_RET_NULL;
}
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
return r;</code>
</operation>
</class>
</package>
<!--${QF-config}-->
<package name="QF-config" stereotype="0x02">
<!--${QF-config::QF_MAX_ACTIVE}-->
<attribute name="QF_MAX_ACTIVE?ndef QF_MAX_ACTIVE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Maximum number of active objects (configurable value in qf_port.hpp)
//! Valid values: [1U..64U]; default 32U</documentation>
<code>32U</code>
</attribute>
<!--${QF-config::QF_MAX_ACTIVE exceeds the maximu~}-->
<attribute name="QF_MAX_ACTIVE exceeds the maximum of 64U? (QF_MAX_ACTIVE &gt; 64U)" type="#error" visibility="0x04" properties="0x00"/>
<!--${QF-config::QF_MAX_TICK_RATE}-->
<attribute name="QF_MAX_TICK_RATE?ndef QF_MAX_TICK_RATE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Maximum number of clock rates (configurable value in qf_port.hpp)
//! Valid values: [0U..15U]; default 1U</documentation>
<code>1U</code>
</attribute>
<!--${QF-config::QF_MAX_TICK_RATE exceeds the max~}-->
<attribute name="QF_MAX_TICK_RATE exceeds the maximum of 15U? (QF_MAX_TICK_RATE &gt; 15U)" type="#error" visibility="0x04" properties="0x00"/>
<!--${QF-config::QF_MAX_EPOOL}-->
<attribute name="QF_MAX_EPOOL?ndef QF_MAX_EPOOL" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Maximum number of event pools (configurable value in qf_port.hpp)
//! Valid values: [0U..15U]; default 3U
//!
//! @note
//! #QF_MAX_EPOOL set to zero means that dynamic events are NOT configured
//! and should not be used in the application.</documentation>
<code>3U</code>
</attribute>
<!--${QF-config::QF_MAX_EPOOL exceeds the maximum~}-->
<attribute name="QF_MAX_EPOOL exceeds the maximum of 15U? (QF_MAX_EPOOL &gt; 15U)" type="#error" visibility="0x04" properties="0x00"/>
<!--${QF-config::QF_TIMEEVT_CTR_SIZE}-->
<attribute name="QF_TIMEEVT_CTR_SIZE?ndef QF_TIMEEVT_CTR_SIZE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Size of the QTimeEvt counter (configurable value in qf_port.hpp)
//! Valid values: 1U, 2U, or 4U; default 4U</documentation>
<code>4U</code>
</attribute>
<!--${QF-config::QF_TIMEEVT_CTR_SIZE defined inco~}-->
<attribute name="QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QF_TIMEEVT_CTR_SIZE != 1U) &amp;&amp; (QF_TIMEEVT_CTR_SIZE != 2U) &amp;&amp; (QF_TIMEEVT_CTR_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
<!--${QF-config::QF_EVENT_SIZ_SIZE}-->
<attribute name="QF_EVENT_SIZ_SIZE?ndef QF_EVENT_SIZ_SIZE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Size of the event-size (configurable value in qf_port.hpp)
//! Valid values: 1U, 2U, or 4U; default 2U</documentation>
<code>2U</code>
</attribute>
<!--${QF-config::QF_EVENT_SIZ_SIZE defined incorr~}-->
<attribute name="QF_EVENT_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QF_EVENT_SIZ_SIZE != 1U) &amp;&amp; (QF_EVENT_SIZ_SIZE != 2U) &amp;&amp; (QF_EVENT_SIZ_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
</package>
<!--${QF-macros}-->
<package name="QF-macros" stereotype="0x02">
<!--${QF-macros::Q_PRIO}-->
<operation name="Q_PRIO" type="QP::QPrioSpec" visibility="0x03" properties="0x02">
<documentation>//! Create a QP::QPrioSpec object to specify priority of an AO or a thread</documentation>
<!--${QF-macros::Q_PRIO::prio_}-->
<parameter name="prio_" type="std::uint8_t"/>
<!--${QF-macros::Q_PRIO::pthre_}-->
<parameter name="pthre_" type="std::uint8_t"/>
<code>(static_cast&lt;QP::QPrioSpec&gt;((prio_) | (pthre_) &lt;&lt; 8U))</code>
</operation>
<!--${QF-macros::Q_NEW}-->
<operation name="Q_NEW?ndef Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
<documentation>//! Allocate a dynamic event (case when QP::QEvt is a POD)
//!
//! @details
//! The macro calls the internal QF function QF::newX_() with
//! margin == QF::NO_MARGIN, which causes an assertion when the event
//! cannot be successfully allocated.
//!
//! @param[in] evtT_ event type (class name) of the event to allocate
//! @param[in] sig_ signal to assign to the newly allocated event
//!
//! @returns a valid event pointer cast to the type `evtT_`.
//!
//! @note
//! If #Q_EVT_CTOR is defined, the Q_NEW() macro becomes variadic and
//! takes all the arguments needed by the constructor of the event
//! class being allocated. The constructor is then called by means
//! of the placement-new operator.
//!
//! @usage
//! The following example illustrates dynamic allocation of an event:
//! @include qf_post.cpp</documentation>
<!--${QF-macros::Q_NEW::evtT_}-->
<parameter name="evtT_" type="&lt;event class&gt;"/>
<!--${QF-macros::Q_NEW::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<code>(static_cast&lt;evtT_ *&gt;( \
QP::QF::newX_(sizeof(evtT_), QP::QF::NO_MARGIN, (sig_))))</code>
</operation>
<!--${QF-macros::Q_NEW}-->
<operation name="Q_NEW?def Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
<documentation>//! Allocate a dynamic event (case when QP::QEvt is not a POD)</documentation>
<!--${QF-macros::Q_NEW::evtT_}-->
<parameter name="evtT_" type="&lt;event class&gt;"/>
<!--${QF-macros::Q_NEW::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<!--${QF-macros::Q_NEW::...}-->
<parameter name="..." type="__VA_ARGS__"/>
<code>\
(new(QP::QF::newX_(sizeof(evtT_), QP::QF::NO_MARGIN, (sig_))) \
evtT_((sig_), ##__VA_ARGS__))</code>
</operation>
<!--${QF-macros::Q_NEW_X}-->
<operation name="Q_NEW_X?ndef Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
<documentation>//! Non-asserting allocate a dynamic event (case when QP::QEvt is a POD).
//!
//! @details
//! This macro allocates a new event and sets the pointer `e_`, while
//! leaving at least `margin_` of events still available in the pool
//!
//! @param[out] e_ pointer to the newly allocated event
//! @param[in] evtT_ event type (class name) of the event to allocate
//! @param[in] margin_ number of events that must remain available
//! in the given pool after this allocation. The
//! special value QF::NO_MARGIN causes asserting
//! failure in case event allocation fails.
//! @param[in] sig_ signal to assign to the newly allocated event
//!
//! @returns an event pointer cast to the type `evtT_` or NULL if the
//! event cannot be allocated with the specified `margin`.
//!
//! @note
//! If #Q_EVT_CTOR is defined, the Q_NEW_X() macro becomes variadic and
//! takes all the arguments needed by the constructor of the event
//! class being allocated. The constructor is then called by means
//! of the placement-new operator.
//!
//! @usage
//! The following example illustrates dynamic allocation of an event:
//! @include qf_postx.cpp</documentation>
<!--${QF-macros::Q_NEW_X::e_}-->
<parameter name="e_" type="&lt;QP::QEvt *&gt;"/>
<!--${QF-macros::Q_NEW_X::evtT_}-->
<parameter name="evtT_" type="&lt;event class&gt;"/>
<!--${QF-macros::Q_NEW_X::margin_}-->
<parameter name="margin_" type="std::uint16_t"/>
<!--${QF-macros::Q_NEW_X::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<code>\
((e_) = static_cast&lt;evtT_ *&gt;(QP::QF::newX_( \
sizeof(evtT_), (margin_), (sig_))))</code>
</operation>
<!--${QF-macros::Q_NEW_X}-->
<operation name="Q_NEW_X?def Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
<documentation>//! Non-asserting allocate a dynamic event
//! (case when QP::QEvt is not a POD)</documentation>
<!--${QF-macros::Q_NEW_X::e_}-->
<parameter name="e_" type="&lt;QP::QEvt *&gt;"/>
<!--${QF-macros::Q_NEW_X::evtT_}-->
<parameter name="evtT_" type="&lt;event class&gt;"/>
<!--${QF-macros::Q_NEW_X::margin_}-->
<parameter name="margin_" type="std::uint16_t"/>
<!--${QF-macros::Q_NEW_X::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<!--${QF-macros::Q_NEW_X::...}-->
<parameter name="..." type="__VA_ARGS__"/>
<code>do { \
(e_) = static_cast&lt;evtT_ *&gt;( \
QP::QF::newX_(sizeof(evtT_), (margin_), (sig_))); \
if ((e_) != nullptr) { \
new((e_)) evtT_((sig_), ##__VA_ARGS__); \
} \
} while (false)</code>
</operation>
<!--${QF-macros::Q_NEW_REF}-->
<operation name="Q_NEW_REF" type="void" visibility="0x03" properties="0x00">
<documentation>//! Create a new reference of the current event `e`
//!
//! @details
//! The current event processed by an active object is available only for
//! the duration of the run-to-completion (RTC) step. After that step, the
//! current event is no longer available and the framework might recycle
//! (garbage-collect) the event. The macro Q_NEW_REF() explicitly creates
//! a new reference to the current event that can be stored and used beyond
//! the current RTC step, until the reference is explicitly recycled by
//! means of the macro Q_DELETE_REF().
//!
//! @param[in,out] evtRef_ event reference to create
//! @param[in] evtT_ event type (class name) of the event reference
//!
//! @usage
//! The example **defer** in the directory `examples/win32/defer` illustrates
//! the use of Q_NEW_REF()
//!
//! @sa Q_DELETE_REF()</documentation>
<!--${QF-macros::Q_NEW_REF::evtRef_}-->
<parameter name="evtRef_" type="&lt;event class&gt;"/>
<!--${QF-macros::Q_NEW_REF::evtT_}-->
<parameter name="evtT_" type="&lt;event class&gt;"/>
<code>\
((evtRef_) = static_cast&lt;evtT_ const *&gt;(QP::QF::newRef_(e, (evtRef_))))</code>
</operation>
<!--${QF-macros::Q_DELETE_REF}-->
<operation name="Q_DELETE_REF" type="void" visibility="0x03" properties="0x00">
<documentation>//! Delete the event reference
//!
//! @details
//! Every event reference created with the macro Q_NEW_REF() needs to be
//! eventually deleted by means of the macro Q_DELETE_REF() to avoid leaking
//! the event.
//!
//! @param[in,out] evtRef_ event reference to delete
//!
//! @usage
//! The example **defer** in the directory `examples/win32/defer` illustrates
//! the use of Q_DELETE_REF()
//!
//! @sa Q_NEW_REF()</documentation>
<!--${QF-macros::Q_DELETE_REF::evtRef_}-->
<parameter name="evtRef_" type="&lt;event class&gt;"/>
<code>do { \
QP::QF::deleteRef_((evtRef_)); \
(evtRef_) = 0U; \
} while (false)</code>
</operation>
<!--${QF-macros::PUBLISH}-->
<operation name="PUBLISH?def Q_SPY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Invoke the event publishing facility QActive::publish_().
//!
//! @details
//! This macro is the recommended way of publishing events, because it
//! provides the vital information for software tracing and avoids any
//! overhead when the tracing is disabled.
//!
//! @param[in] e_ pointer to the posted event
//! @param[in] sender_ pointer to the sender object (actually used
//! only when #Q_SPY is defined)
//!
//! @note
//! The pointer to the `sender_` object is not necessarily a pointer
//! to an active object. In fact, if QActive::PUBLISH() is called from an
//! interrupt or other context, you can create a unique object just to
//! unambiguously identify the sender of the event.
//!
//! @sa QActive::publish_()</documentation>
<!--${QF-macros::PUBLISH::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::PUBLISH::sender_}-->
<parameter name="sender_" type="&lt;void const *&gt;"/>
<code>\
publish_((e_), (sender_), (sender_)-&gt;getPrio())</code>
</operation>
<!--${QF-macros::PUBLISH}-->
<operation name="PUBLISH?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
<!--${QF-macros::PUBLISH::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::PUBLISH::dummy}-->
<parameter name="dummy" type=""/>
<code>publish_((e_), nullptr, 0U)</code>
</operation>
<!--${QF-macros::POST}-->
<operation name="POST?def Q_SPY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Invoke the direct event posting facility QActive::post_()
//!
//! @details
//! This macro asserts if the queue overflows and cannot accept the event.
//!
//! @param[in] e_ pointer to the event to post
//! @param[in] sender_ pointer to the sender object.
//!
//! @note
//! The `sendedr_` parameter is actually only used when QS tracing
//! is enabled (macro #Q_SPY is defined). When QS software tracing is
//! disenabled, the POST() macro does not pass the `sender_` parameter,
//1 so the overhead of passing this extra parameter is entirely avoided.
//!
//! @note
//! the pointer to the sender object is not necessarily a pointer to an
//! active object. In fact, if POST() is called from an interrupt or
//! other context, you can create a unique object just to unambiguously
//! identify the sender of the event.
//!
//! @sa QActive::post_()</documentation>
<!--${QF-macros::POST::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::POST::sender_}-->
<parameter name="sender_" type="&lt;sender *&gt;"/>
<code>post_((e_), QP::QF::NO_MARGIN, (sender_))</code>
</operation>
<!--${QF-macros::POST}-->
<operation name="POST?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
<!--${QF-macros::POST::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::POST::dummy}-->
<parameter name="dummy" type=""/>
<code>post_((e_), QP::QF::NO_MARGIN, nullptr)</code>
</operation>
<!--${QF-macros::POST_X}-->
<operation name="POST_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Invoke the direct event posting facility QActive::post_()
//! without delivery guarantee
//!
//! @details
//! This macro does not assert if the queue overflows and cannot accept
//! the event with the specified margin of free slots remaining.
//!
//! @param[in] e_ pointer to the event to post
//! @param[in] margin_ the minimum free slots in the queue, which
//! must still be available after posting the event.
//! The special value QF::NO_MARGIN causes
//! asserting failure in case event posting fails.
//! @param[in] sender_ pointer to the sender object.
//!
//! @returns
//! 'true' if the posting succeeded, and 'false' if the posting
//! failed due to insufficient margin of free entries available in
//! the queue.
//!
//! @note
//! The `sender_` parameter is actually only used when QS tracing
//! is enabled (macro #Q_SPY is defined). When QS software tracing is
//! disabled, the POST_X() macro does not pass the `sender_` parameter,
//! so the overhead of passing this extra parameter is entirely avoided.
//!
//! @note
//! The pointer to the sender object is not necessarily a pointer
//! to an active object. In fact, if POST_X() is called from an
//! interrupt or other context, you can create a unique object just to
//! unambiguously identify the sender of the event.
//!
//! @usage
//! @include qf_postx.cpp</documentation>
<!--${QF-macros::POST_X::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::POST_X::margin_}-->
<parameter name="margin_" type="std::uint16_t"/>
<!--${QF-macros::POST_X::sender_}-->
<parameter name="sender_" type="&lt;sender *&gt;"/>
<code>\
post_((e_), (margin_), (sender_))</code>
</operation>
<!--${QF-macros::POST_X}-->
<operation name="POST_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
<!--${QF-macros::POST_X::e_}-->
<parameter name="e_" type="QP::QEvt const *"/>
<!--${QF-macros::POST_X::margin_}-->
<parameter name="margin_" type="std::uint16_t"/>
<!--${QF-macros::POST_X::dummy}-->
<parameter name="dummy" type=""/>
<code>post_((e_), (margin_), nullptr)</code>
</operation>
<!--${QF-macros::TICK_X}-->
<operation name="TICK_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Invoke the system clock tick processing QTimeEvt::tick_()
//!
//! @details
//! This macro is the recommended way of invoking clock tick processing,
//! because it provides the vital information for software tracing and
//! avoids any overhead when the tracing is disabled.
//!
//! @param[in] tickRate_ clock tick rate to be serviced through this call
//! @param[in] sender_ pointer to the sender object. This parameter
//! is actually only used when QS software tracing is enabled
//! (macro #Q_SPY is defined)
//! @note
//! When QS software tracing is disabled, the macro calls
//! QTimeEvt::tick_() without the `sender` parameter, so the overhead
//! of passing this extra parameter is entirely avoided.
//!
//! @note
//! The pointer to the sender object is not necessarily a pointer
//! to an active object. In fact, when TICK_X() is called from
//! an interrupt, you would create a unique object just to unambiguously
//! identify the ISR as the sender of the time events.
//!
//! @sa QTimeEvt::tick_()</documentation>
<!--${QF-macros::TICK_X::tickRate_}-->
<parameter name="tickRate_" type="uint8_t"/>
<!--${QF-macros::TICK_X::sender_}-->
<parameter name="sender_" type="&lt;sender *&gt;"/>
<code>tick_((tickRate_), (sender_))</code>
</operation>
<!--${QF-macros::TICK_X}-->
<operation name="TICK_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
<!--${QF-macros::TICK_X::tickRate_}-->
<parameter name="tickRate_" type="uint8_t"/>
<!--${QF-macros::TICK_X::dummy}-->
<parameter name="dummy" type=""/>
<code>tick_((tickRate_), nullptr)</code>
</operation>
<!--${QF-macros::TICK}-->
<operation name="TICK" type="void" visibility="0x03" properties="0x00">
<documentation>//! Invoke the system clock tick processing for rate 0
//! @sa TICK_X()</documentation>
<!--${QF-macros::TICK::sender_}-->
<parameter name="sender_" type="&lt;sender *&gt;"/>
<code>TICK_X(0U, (sender_))</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">
<documentation>//! No-operation for exiting a critical section
//!
//! @details
//! In some QF ports the critical section exit takes effect only on the
//! next machine instruction. If this next instruction is another entry
//! to a critical section, the critical section won't be really exited,
//! but rather the two adjecent critical sections would be merged.
//! The QF_CRIT_EXIT_NOP() macro contains minimal code required to
//! prevent such merging of critical sections in such merging of
//! critical sections in QF ports, in which it can occur.</documentation>
<code>(static_cast&lt;void&gt;(0))</code>
</operation>
</package>
<!--${QF-extern-C}-->
<package name="QF-extern-C" stereotype="0x02">
<!--${QF-extern-C::QF_onContextSw}-->
<operation name="QF_onContextSw?def QF_ON_CONTEXT_SW" type="void" visibility="0x00" properties="0x00">
<documentation>//! QF context switch callback used in built-in kernels
//!
//! @details
//! This callback function provides a mechanism to perform additional
//! custom operations when one of the built-in kernels switches context
//! from one thread to another.
//!
//! @param[in] prev pointer to the previous thread (active object)
//! (prev==0 means that `prev` was the QK idle loop)
//! @param[in] next pointer to the next thread (active object)
//! (next==0) means that `next` is the QK idle loop)
//! @attention
//! QF_onContextSw() is invoked with interrupts **disabled** and must also
//! return with interrupts **disabled**.
//!
//! @note
//! This callback is enabled by defining the macro #QF_ON_CONTEXT_SW.
//!
//! @include qf_oncontextsw.cpp</documentation>
<!--${QF-extern-C::QF_onContextSw::prev}-->
<parameter name="prev" type="QP::QActive *"/>
<!--${QF-extern-C::QF_onContextSw::next}-->
<parameter name="next" type="QP::QActive *"/>
</operation>
</package>
<!--${QF-types}-->
<package name="QF-types" stereotype="0x02" namespace="QP::">
<!--${QF-types::QPSetBits}-->
<attribute name="QPSetBits? (8U &lt; QF_MAX_ACTIVE) &amp;&amp; (QF_MAX_ACTIVE &lt;= 16U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! bitmask for the internal representation of QPSet elements</documentation>
<code>= std::uint16_t;</code>
</attribute>
<!--${QF-types::QPSetBits}-->
<attribute name="QPSetBits? (16 &lt; QF_MAX_ACTIVE)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint32_t;</code>
</attribute>
<!--${QF-types::QPSetBits}-->
<attribute name="QPSetBits? (QF_MAX_ACTIVE &lt;= 8U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint8_t;</code>
</attribute>
<!--${QF-types::QTimeEvtCtr}-->
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE== 2U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! Data type to store the block-size defined based on the macro
//! #QF_TIMEEVT_CTR_SIZE.
//!
//! @details
//! The dynamic range of this data type determines the maximum block
//! size that can be managed by the pool.</documentation>
<code>= std::uint16_t;</code>
</attribute>
<!--${QF-types::QTimeEvtCtr}-->
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE== 1U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint8_t;</code>
</attribute>
<!--${QF-types::QTimeEvtCtr}-->
<attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE== 4U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint32_t;</code>
</attribute>
<!--${QF-types::QPrioSpec}-->
<attribute name="QPrioSpec" type="using" visibility="0x04" properties="0x00">
<documentation>//! Priority specification for Active Objects in QP
//!
//! @details
//! Active Object priorities in QP are integer numbers in the range
//! [1..#QF_MAX_ACTIVE], whereas the special priority number 0 is reserved
//! for the lowest-priority idle thread. The QP framework uses the *direct*
//! priority numbering, in which higher numerical values denote higher
//! urgency. For example, an AO with priority 32 has higher urgency than
//! an AO with priority 23.
//!
//! QP::QPrioSpec allows an application developer to assign **two**
//! priorities to a given AO (see also Q_PRIO()):
//!
//! 1. The &quot;QF-priority&quot;, which resides in the least-significant byte
//! of the QP::QPrioSpec data type. The &quot;QF-priority&quot; must be **unique**
//! for each thread in the system and higher numerical values represent
//! higher urgency (direct pirority numbering).
//!
//! 2. The &quot;preemption-threshold&quot; priority, which resides in the most-
//! significant byte of the ::QPrioSpec data type. The second priority
//! cannot be lower than the &quot;QF-priority&quot;, but does NOT need to be
//! unuque.
//!
//! In the QP native preemptive kernels, like QK and QXK, the &quot;preemption-
//! threshold&quot; priority is used as to implement the &quot;preemption-threshold
//! scheduling&quot; (PTS). It determines the conditions under which a given
//! thread can be *preempted* by other threads. Specifically, a given
//! thread can be preempted only by another thread with a *higher*
//! priority than the &quot;preemption-threshold&quot; of the original thread.
//!
//! ![QF-priority and preemption-threshold relations](qp-prio.png)
//!
//! @note
//! For backwards-compatibility, QP::QPrioSpec data type might contain only
//! the &quot;QF-priority&quot; component (and the &quot;preemption-threshold&quot; component
//! left at zero). In that case, the &quot;preemption-threshold&quot; will be assumed
//! to be the same as the &quot;QF-priority&quot;. This corresponds exactly to the
//! previous semantics of AO priority.
//!
//! @remark
//! When QP runs on top of 3rd-party kernels/RTOSes or general-purpose
//! operating systems, sthe second priority can have different meaning,
//! depending on the specific RTOS/GPOS used.</documentation>
<code>= std::uint16_t;</code>
</attribute>
<!--${QF-types::QSchedStatus}-->
<attribute name="QSchedStatus" type="using" visibility="0x04" properties="0x00">
<documentation>//! The scheduler lock status used in some real-time kernels</documentation>
<code>= std::uint_fast16_t;</code>
</attribute>
<!--${QF-types::QPSet}-->
<class name="QPSet">
<documentation>//! Priority Set of up to #QF_MAX_ACTIVE elements
//!
//! @details
//! The priority set represents the set of active objects that are ready to
//! run and need to be considered by the scheduling algorithm. The set is
//! capable of storing up to #QF_MAX_ACTIVE priority levels, which can be
//! configured in the rage 1..64, inclusive.</documentation>
<!--${QF-types::QPSet::m_bits}-->
<attribute name="m_bits? (QF_MAX_ACTIVE &lt;= 32)" type="QPSetBits volatile" visibility="0x00" properties="0x00">
<documentation>//! bitmask with a bit for each element</documentation>
</attribute>
<!--${QF-types::QPSet::m_bits[2]}-->
<attribute name="m_bits[2]? (32 &lt; QF_MAX_ACTIVE)" type="QPSetBits volatile" visibility="0x00" properties="0x00">
<documentation>//! bitmasks with a bit for each element</documentation>
</attribute>
<!--${QF-types::QPSet::setEmpty}-->
<operation name="setEmpty" type="void" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Make the priority set empty</documentation>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
m_bits = 0U;
#else
m_bits[0] = 0U;
m_bits[1] = 0U;
#endif</code>
</operation>
<!--${QF-types::QPSet::isEmpty}-->
<operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Return 'true' if the priority set is empty</documentation>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
return (m_bits == 0U);
#else
return (m_bits[0] == 0U) ? (m_bits[1] == 0U) : false;
#endif</code>
</operation>
<!--${QF-types::QPSet::notEmpty}-->
<operation name="notEmpty" type="bool" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Return 'true' if the priority set is NOT empty</documentation>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
return (m_bits != 0U);
#else
return (m_bits[0] != 0U) ? true : (m_bits[1] != 0U);
#endif</code>
</operation>
<!--${QF-types::QPSet::hasElement}-->
<operation name="hasElement" type="bool" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Return 'true' if the priority set has the element n.</documentation>
<!--${QF-types::QPSet::hasElement::n}-->
<parameter name="n" type="std::uint_fast8_t const"/>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
return (m_bits &amp; (1U &lt;&lt; (n - 1U))) != 0U;
#else
return (n &lt;= 32U)
? ((m_bits[0] &amp; (static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 1U))) != 0U)
: ((m_bits[1] &amp; (static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 33U))) != 0U);
#endif</code>
</operation>
<!--${QF-types::QPSet::insert}-->
<operation name="insert" type="void" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! insert element `n` into the set (n = 1..QF_MAX_ACTIVE)</documentation>
<!--${QF-types::QPSet::insert::n}-->
<parameter name="n" type="std::uint_fast8_t const"/>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
m_bits = (m_bits | (1U &lt;&lt; (n - 1U)));
#else
if (n &lt;= 32U) {
m_bits[0] = (m_bits[0]
| (static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 1U)));
}
else {
m_bits[1] = (m_bits[1]
| (static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 33U)));
}
#endif</code>
</operation>
<!--${QF-types::QPSet::remove}-->
<operation name="remove" type="void" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Remove element `n` from the set (n = 1U..64U)</documentation>
<!--${QF-types::QPSet::remove::n}-->
<parameter name="n" type="std::uint_fast8_t const"/>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
m_bits = (m_bits &amp; static_cast&lt;QPSetBits&gt;(
~(static_cast&lt;QPSetBits&gt;(1) &lt;&lt; (n - 1U))));
#else
if (n &lt;= 32U) {
(m_bits[0] = (m_bits[0]
&amp; ~(static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 1U))));
}
else {
(m_bits[1] = (m_bits[1]
&amp; ~(static_cast&lt;std::uint32_t&gt;(1) &lt;&lt; (n - 33U))));
}
#endif</code>
</operation>
<!--${QF-types::QPSet::findMax}-->
<operation name="findMax" type="std::uint_fast8_t" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Find the maximum element in the set, returns zero if the set is empty</documentation>
<code>#if (QF_MAX_ACTIVE &lt;= 32U)
return QF_LOG2(m_bits);
#else
return (m_bits[1] != 0U)
? (QF_LOG2(m_bits[1]) + 32U)
: (QF_LOG2(m_bits[0]));
#endif</code>
</operation>
<!--${QF-types::QPSet::QF_LOG2}-->
<operation name="QF_LOG2?ndef QF_LOG2" type="std::uint_fast8_t" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Log-base-2 calculation when hardware acceleration
//! is NOT provided (#QF_LOG2 not defined).</documentation>
<!--${QF-types::QPSet::QF_LOG2::x}-->
<parameter name="x" type="QP::QPSetBits"/>
<code>static std::uint8_t const log2LUT[16] = {
0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
};
std::uint_fast8_t n = 0U;
QP::QPSetBits t;
#if (QF_MAX_ACTIVE &gt; 16U)
t = static_cast&lt;QP::QPSetBits&gt;(x &gt;&gt; 16U);
if (t != 0U) {
n += 16U;
x = t;
}
#endif
#if (QF_MAX_ACTIVE &gt; 8U)
t = (x &gt;&gt; 8U);
if (t != 0U) {
n += 8U;
x = t;
}
#endif
t = (x &gt;&gt; 4U);
if (t != 0U) {
n += 4U;
x = t;
}
return n + log2LUT[x];</code>
</operation>
</class>
<!--${QF-types::QSubscrList}-->
<attribute name="QSubscrList" type="using" visibility="0x04" properties="0x00">
<documentation>//! Subscriber List (for publish-subscribe)
//!
//! @details
//! This data type represents a set of Active Objects that subscribe to
//! a given signal. The set is represented as priority-set, where each bit
//! corresponds to the unique QF-priority of an AO (see QP::QPrioSpec).</documentation>
<code>= QPSet;</code>
</attribute>
</package>
<!--${QF}-->
<package name="QF" stereotype="0x05" namespace="QP::">
<!--${QF::QActive}-->
<class name="QActive" superclass="QEP::QHsm">
<documentation>//! QP::QActive active object class (based on the QP::QHsm-style
//! implementation strategy)
//!
//! @details
//! Active objects are encapsulated tasks (each containing an event queue and
//! a state machine) that communicate with one another asynchronously by
//! sending and receiving events. Within an active object, events are
//! processed in a run-to-completion (RTC) fashion, while QF encapsulates
//! all the details of thread-safe event exchange and queuing.&lt;br&gt;
//!
//! QP::QActive represents an active object that uses the QP::QHsm-style
//! implementation strategy for state machines. This strategy is tailored
//! to manual coding, but it is also supported by the QM modeling tool.
//! The resulting code is slower than in the QP::QMsm-style implementation
//! strategy.
//!
//! @note
//! QP::QActive is not intended to be instantiated directly, but rather serves
//! as the abstract base class for derivation of active objects in the
//! applications.
//!
//! @sa QP::QMActive
//!
//! @usage
//! The following example illustrates how to derive an active object from
//! QP::QActive.
//! @include qf_qactive.cpp</documentation>
<!--${QF::QActive::m_eQueue}-->
<attribute name="m_eQueue?def QF_EQUEUE_TYPE" type="QF_EQUEUE_TYPE" visibility="0x00" properties="0x00">
<documentation>//! OS-dependent event-queue type
//!
//! @details
//! The type of the queue depends on the underlying operating system or
//! a kernel. Many kernels support &quot;message queues&quot; that can be adapted
//! to deliver QF events to the active object. Alternatively, QF provides
//! a native event queue implementation that can be used as well.
//!
//! @note
//! The native QF event queue is configured by defining the macro
//! #QF_EQUEUE_TYPE as QP::QEQueue.</documentation>
</attribute>
<!--${QF::QActive::m_osObject}-->
<attribute name="m_osObject?def QF_OS_OBJECT_TYPE" type="QF_OS_OBJECT_TYPE" visibility="0x00" properties="0x00">
<documentation>//! OS-dependent per-thread object
//!
//! @details
//! This data might be used in various ways, depending on the QF port.
//! In some ports m_osObject is used to block the calling thread when
//! the native QF queue is empty. In other QF ports the OS-dependent
//! object might be used differently.</documentation>
</attribute>
<!--${QF::QActive::m_thread}-->
<attribute name="m_thread?def QF_THREAD_TYPE" type="QF_THREAD_TYPE" visibility="0x00" properties="0x00">
<documentation>//! OS-dependent representation of the thread of the active object
//!
//! @details
//! This data might be used in various ways, depending on the QF port.
//! In some ports m_thread is used store the thread handle. In other ports
//! m_thread can be a pointer to the Thread-Local-Storage (TLS).</documentation>
</attribute>
<!--${QF::QActive::m_prio}-->
<attribute name="m_prio" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! QF-priority [1..#QF_MAX_ACTIVE] of this AO.
//! @sa QP::QPrioSpec</documentation>
</attribute>
<!--${QF::QActive::m_pthre}-->
<attribute name="m_pthre" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! preemption-threshold [1..#QF_MAX_ACTIVE] of this AO.
//! @sa QP::QPrioSpec</documentation>
</attribute>
<!--${QF::QActive::QTimeEvt}-->
<attribute name="QTimeEvt" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::QTicker}-->
<attribute name="QTicker" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::QXThread}-->
<attribute name="QXThread?def QP_INC_QXK_HPP_" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::QXMutex}-->
<attribute name="QXMutex?def QP_INC_QXK_HPP_" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::QXSemaphore}-->
<attribute name="QXSemaphore?def QP_INC_QXK_HPP_" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::QActiveDummy}-->
<attribute name="QActiveDummy?def Q_UTEST" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::GuiQActive}-->
<attribute name="GuiQActive" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::GuiQMActive}-->
<attribute name="GuiQMActive" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}-->
<attribute name="registry_[QF_MAX_ACTIVE + 1U]" type="QActive *" visibility="0x00" properties="0x01">
<documentation>//! Internal array of registered active objects</documentation>
</attribute>
<!--${QF::QActive::subscrList_}-->
<attribute name="subscrList_" type="QSubscrList *" visibility="0x00" properties="0x01">
<documentation>//! pointer to the array of all subscriber AOs for a given event signal</documentation>
</attribute>
<!--${QF::QActive::maxPubSignal_}-->
<attribute name="maxPubSignal_" type="enum_t" visibility="0x00" properties="0x01">
<documentation>//! The maximum published signal (the size of the subscrList_ array)</documentation>
</attribute>
<!--${QF::QActive::QActive}-->
<operation name="QActive" type="" visibility="0x01" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! protected constructor (abstract class)</documentation>
<!--${QF::QActive::QActive::initial}-->
<parameter name="initial" type="QStateHandler const"/>
<code> : QHsm(initial),
m_prio(0U),
m_pthre(0U)
#ifdef QF_EQUEUE_TYPE
QF::bzero(&amp;m_eQueue, sizeof(m_eQueue));
#endif
#ifdef QF_OS_OBJECT_TYPE
QF::bzero(&amp;m_osObject, sizeof(m_osObject));
#endif
#ifdef QF_THREAD_TYPE
QF::bzero(&amp;m_thread, sizeof(m_thread));
#endif</code>
</operation>
<!--${QF::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<documentation>//! Starts execution of an active object and registers the object
//! with the framework
//!
//! @details
//! Starts execution of the AO and registers the AO with the framework.
//!
//! @param[in] prioSpec priority specification of the AO containing the
//! QF-priority and (optionally) preemption-threshold of this AO
//! (for preemptive kernels that support it). See also QP::QPrioSpec.
//! @param[in] qSto pointer to the storage for the ring buffer of the
//! event queue
//! @param[in] qLen length of the event queue [# QP::QEvt* pointers]
//! @param[in] stkSto pointer to the stack storage (might be nullptr)
//! @param[in] stkSize stack size [bytes]
//! @param[in] par pointer to an extra parameter (might be nullptr)
//!
//! @usage
//! The following example shows starting an AO when a per-task stack
//! is needed:
//! @include qf_start.cpp</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="std::uint_fast16_t const"/>
<!--${QF::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QF::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<!--${QF::QActive::start::par}-->
<parameter name="par" type="void const * const"/>
</operation>
<!--${QF::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x06">
<documentation>//! Overloaded start function (no initialization parameter)</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="std::uint_fast16_t const"/>
<!--${QF::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QF::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<code>this-&gt;start(prioSpec, qSto, qLen, stkSto, stkSize, nullptr);</code>
</operation>
<!--${QF::QActive::stop}-->
<operation name="stop?def QF_ACTIVE_STOP" type="void" visibility="0x00" properties="0x00">
<documentation>//! Stops execution of an active object and removes it from the
//! framework's supervision
//!
//! @attention
//! QActive::stop() must be called only from the AO that is about
//! to stop its execution. By that time, any pointers or references
//! to the AO are considered invalid (dangling) and it becomes
//! illegal for the rest of the application to post events to the AO.</documentation>
</operation>
<!--${QF::QActive::post_}-->
<operation name="post_" type="bool" visibility="0x00" properties="0x04">
<specifiers>noexcept</specifiers>
<documentation>//! Posts an event `e` directly to the event queue of the active object
//! using the First-In-First-Out (FIFO) policy.
//!
//! @details
//! Direct event posting is the simplest asynchronous communication
//! method available in QF.
//!
//! @param[in] e pointer to the event to be posted
//! @param[in] margin number of required free slots in the queue
//! after posting the event or QF::NO_MARGIN.
//! @param[in] sender pointer to a sender object (used in QS only)
//!
//! @returns
//! 'true' (success) if the posting succeeded (with the provided margin)
//! and 'false' (failure) when the posting fails.
//!
//! @attention
//! For `margin` == QF::NO_MARGIN, this function will assert internally
//! if the event posting fails. In that case, it is unnecessary to check
//! the retrun value from this function.
//!
//! @note
//! This function might be implemented differentyl in various QP/C++
//! ports. The provided implementation assumes that the QP::QEQueue
//! class is used for the QP::QActive event queue.
//!
//! @usage
//! @include qf_post.cpp
//!
//! @sa
//! QActive::postLIFO()</documentation>
<!--${QF::QActive::post_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QActive::post_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QActive::post_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>Q_UNUSED_PAR(sender); // when Q_SPY not defined
//! @pre event pointer must be valid
Q_REQUIRE_ID(100, e != nullptr);
QF_CRIT_STAT_
QF_CRIT_E_();
QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into the temporary
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_DEF(&amp;QActive::post_)
QS_TEST_PROBE_ID(1,
nFree = 0U;
)
bool status;
if (margin == QF::NO_MARGIN) {
if (nFree &gt; 0U) {
status = true; // can post
}
else {
status = false; // cannot post
Q_ERROR_CRIT_(110); // must be able to post the event
}
}
else if (nFree &gt; static_cast&lt;QEQueueCtr&gt;(margin)) {
status = true; // can post
}
else {
status = false; // cannot post, but don't assert
}
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
if (status) { // can post the event?
--nFree; // one free entry just used up
m_eQueue.m_nFree = nFree; // update the volatile
if (m_eQueue.m_nMin &gt; nFree) {
m_eQueue.m_nMin = nFree; // update minimum so far
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool-Id &amp; ref-ctr
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
QS_END_NOCRIT_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-&gt;prio') is set
//
if (QS_LOC_CHECK_(m_prio)) {
QS::onTestPost(sender, this, e, status);
}
#endif
// empty queue?
if (m_eQueue.m_frontEvt == nullptr) {
m_eQueue.m_frontEvt = e; // deliver event directly
QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
}
// queue is not empty, insert event into the ring-buffer
else {
// insert event pointer e into the buffer (FIFO)
m_eQueue.m_ring[m_eQueue.m_head] = e;
// need to wrap head?
if (m_eQueue.m_head == 0U) {
m_eQueue.m_head = m_eQueue.m_end; // wrap around
}
// advance the head (counter clockwise)
m_eQueue.m_head = (m_eQueue.m_head - 1U);
}
QF_CRIT_X_();
}
else { // cannot post the event
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool-Id &amp; ref-ctr
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(margin); // margin requested
QS_END_NOCRIT_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-&gt;prio') is set
//
if (QS_LOC_CHECK_(m_prio)) {
QS::onTestPost(sender, this, e, status);
}
#endif
QF_CRIT_X_();
#if (QF_MAX_EPOOL &gt; 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="0x00" properties="0x04">
<specifiers>noexcept</specifiers>
<documentation>//! Posts an event `e` directly to the event queue of the active object
//! using the Last-In-First-Out (LIFO) policy.
//!
//! @details
//! The LIFO policy should be used only for self-posting and with caution,
//! because it alters order of events in the queue.
//!
//! @param[in] e pointer to the event to be posted
//!
//! @attention
//! This function asserts internally if the posting fails.
//!
//! @note
//! This function might be implemented differentyl in various QP/C++
//! ports. The provided implementation assumes that the QP::QEQueue
//! class is used for the QActive event queue.
//!
//! @sa
//! QActive::post()</documentation>
<!--${QF::QActive::postLIFO::e}-->
<parameter name="e" type="QEvt const * const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QEQueueCtr nFree = m_eQueue.m_nFree;// tmp to avoid UB for volatile access
QS_TEST_PROBE_DEF(&amp;QActive::postLIFO)
QS_TEST_PROBE_ID(1,
nFree = 0U;
)
// the queue must be able to accept the event (cannot overflow)
Q_ASSERT_CRIT_(210, nFree != 0U);
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
--nFree; // one free entry just used up
m_eQueue.m_nFree = nFree; // update the volatile
if (m_eQueue.m_nMin &gt; nFree) {
m_eQueue.m_nMin = nFree; // update minimum so far
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_LIFO, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool-Id &amp; ref-ctr
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
QS_END_NOCRIT_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-&gt;prio') is set
//
if (QS_LOC_CHECK_(m_prio)) {
QS::onTestPost(nullptr, this, e, true);
}
#endif
// read volatile into temporary
QEvt const * const frontEvt = m_eQueue.m_frontEvt;
m_eQueue.m_frontEvt = e; // deliver the event directly to the front
// was the queue empty?
if (frontEvt == nullptr) {
QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
}
// queue was not empty, leave the event in the ring-buffer
else {
m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail?
m_eQueue.m_tail = 0U; // wrap around
}
m_eQueue.m_ring[m_eQueue.m_tail] = frontEvt;
}
QF_CRIT_X_();
</code>
</operation>
<!--${QF::QActive::get_}-->
<operation name="get_" type="QEvt const *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Get an event from the event queue of an active object
//!
//! @details
//! The behavior of this function depends on the kernel used in the
//! QF port. For built-in kernels (Vanilla or QK) the function can be
//! called only when the queue is not empty, so it doesn't block. For
//! a blocking kernel/OS the function can block and wait for delivery
//! of an event.
//!
//! @returns
//! A pointer to the received event. The returned pointer is guaranteed
//! to be valid (can't be nullptr).
//!
//! @note
//! This function might be implemented differentyl in various QP/C++
//! ports. The provided implementation assumes that the QP::QEQueue
//! class is used for the QActive event queue.</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly
// always remove evt from the front
QEvt const * const e = m_eQueue.m_frontEvt;
QEQueueCtr const nFree = m_eQueue.m_nFree + 1U;
m_eQueue.m_nFree = nFree; // upate the number of free
// any events in the ring buffer?
if (nFree &lt;= m_eQueue.m_end) {
// remove event from the tail
m_eQueue.m_frontEvt = m_eQueue.m_ring[m_eQueue.m_tail];
if (m_eQueue.m_tail == 0U) { // need to wrap?
m_eQueue.m_tail = m_eQueue.m_end; // wrap around
}
m_eQueue.m_tail = (m_eQueue.m_tail - 1U);
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool-Id &amp; ref-ctr
QS_EQC_PRE_(nFree); // number of free entries
QS_END_NOCRIT_PRE_()
}
else {
// the queue becomes empty
m_eQueue.m_frontEvt = nullptr;
// all entries in the queue must be free (+1 for fronEvt)
Q_ASSERT_CRIT_(310, nFree == (m_eQueue.m_end + 1U));
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET_LAST, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool-Id &amp; ref-ctr
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();
return e;</code>
</operation>
<!--${QF::QActive::subscribe}-->
<operation name="subscribe" type="void" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Subscribes for delivery of signal `sig` to the active object
//!
//! @details
//! This function is part of the Publish-Subscribe event delivery
//! mechanism available in QF. Subscribing to an event means that the
//! framework will start posting all published events with a given signal
//! `sig` to the event queue of the active object.
//!
//! @param[in] sig event signal to subscribe
//!
//! The following example shows how the Table active object subscribes
//! to three signals in the initial transition:
//! @include qf_subscribe.cpp
//!
//! @sa
//! QActive::publish_(), QActive::unsubscribe(), and
//! QActive::unsubscribeAll()</documentation>
<!--${QF::QActive::subscribe::sig}-->
<parameter name="sig" type="enum_t const"/>
<code>std::uint_fast8_t const p = static_cast&lt;std::uint_fast8_t&gt;(m_prio);
Q_REQUIRE_ID(300, (Q_USER_SIG &lt;= sig)
&amp;&amp; (sig &lt; maxPubSignal_)
&amp;&amp; (0U &lt; p) &amp;&amp; (p &lt;= QF_MAX_ACTIVE)
&amp;&amp; (registry_[p] == this));
QF_CRIT_STAT_
QF_CRIT_E_();
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_SUBSCRIBE, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_END_NOCRIT_PRE_()
subscrList_[sig].insert(p); // insert into subscriber-list
QF_CRIT_X_();</code>
</operation>
<!--${QF::QActive::unsubscribe}-->
<operation name="unsubscribe" type="void" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Unsubscribes from the delivery of signal `sig` to the active object
//!
//! @details
//! This function is part of the Publish-Subscribe event delivery
//! mechanism available in QF. Un-subscribing from an event means that
//! the framework will stop posting published events with a given signal
//! `sig` to the event queue of the active object.
//!
//! @param[in] sig event signal to unsubscribe
//!
//! @note
//! Due to the latency of event queues, an active object should NOT
//! assume that a given signal `sig` will never be dispatched to the
//! state machine of the active object after un-subscribing from that
//! signal. The event might be already in the queue, or just about to
//! be posted and the un-subscribe operation will not flush such events.
//!
//! @note
//! Un-subscribing from a signal that has never been subscribed in the
//! first place is considered an error and QF will raise an assertion.
//!
//! @sa
//! QActive::publish_(), QActive::subscribe(), and
//! QActive::unsubscribeAll()</documentation>
<!--${QF::QActive::unsubscribe::sig}-->
<parameter name="sig" type="enum_t const"/>
<code>std::uint_fast8_t const p = static_cast&lt;std::uint_fast8_t&gt;(m_prio);
//! @pre the signal and the priority must be in range, the AO must also
// be registered with the framework
Q_REQUIRE_ID(400, (Q_USER_SIG &lt;= sig)
&amp;&amp; (sig &lt; maxPubSignal_)
&amp;&amp; (0U &lt; p) &amp;&amp; (p &lt;= QF_MAX_ACTIVE)
&amp;&amp; (registry_[p] == this));
QF_CRIT_STAT_
QF_CRIT_E_();
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_END_NOCRIT_PRE_()
subscrList_[sig].remove(p); // remove from subscriber-list
QF_CRIT_X_();</code>
</operation>
<!--${QF::QActive::unsubscribeAll}-->
<operation name="unsubscribeAll" type="void" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Unsubscribes from the delivery of all signals to the active object
//!
//! @details
//! This function is part of the Publish-Subscribe event delivery
//! mechanism available in QF. Un-subscribing from all events means that
//! the framework will stop posting any published events to the event
//! queue of the active object.
//!
//! @note
//! Due to the latency of event queues, an active object should NOT
//! assume that no events will ever be dispatched to the state machine of
//! the active object after un-subscribing from all events.
//! The events might be already in the queue, or just about to be posted
//! and the un-subscribe operation will not flush such events. Also, the
//! alternative event-delivery mechanisms, such as direct event posting or
//! time events, can be still delivered to the event queue of the active
//! object.
//!
//! @sa
//! QActive::publish_(), QActive::subscribe(), and QActive::unsubscribe()</documentation>
<code>std::uint_fast8_t const p = static_cast&lt;std::uint_fast8_t&gt;(m_prio);
Q_REQUIRE_ID(500, (0U &lt; p) &amp;&amp; (p &lt;= QF_MAX_ACTIVE)
&amp;&amp; (registry_[p] == this));
for (enum_t sig = Q_USER_SIG; sig &lt; maxPubSignal_; ++sig) {
QF_CRIT_STAT_
QF_CRIT_E_();
if (subscrList_[sig].hasElement(p)) {
subscrList_[sig].remove(p);
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();
// prevent merging critical sections
QF_CRIT_EXIT_NOP();
}</code>
</operation>
<!--${QF::QActive::defer}-->
<operation name="defer" type="bool" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Defer an event to a given separate event queue
//!
//! @details
//! This function is part of the event deferral support. An active object
//! uses this function to defer an event `e` to the QF-supported native
//! event queue `eq`. QF correctly accounts for another outstanding
//! reference to the event and will not recycle the event at the end of
//! the RTC step. Later, the active object might recall one event at a
//! time from the event queue.
//!
//! @param[in] eq pointer to a &quot;raw&quot; thread-safe queue to recall
//! an event from.
//! @param[in] e pointer to the event to be deferred
//!
//! @returns
//! 'true' (success) when the event could be deferred and 'false'
//! (failure) if event deferral failed due to overflowing the queue.
//!
//! An active object can use multiple event queues to defer events of
//! different kinds.
//!
//! @sa
//! QActive::recall(), QP::QEQueue, QActive::flushDeferred()</documentation>
<!--${QF::QActive::defer::eq}-->
<parameter name="eq" type="QEQueue * const"/>
<!--${QF::QActive::defer::e}-->
<parameter name="e" type="QEvt const * const"/>
<code>bool const status = eq-&gt;post(e, 0U, m_prio);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QF_ACTIVE_DEFER, m_prio)
QS_TIME_PRE_(); // time stamp
QS_OBJ_PRE_(this); // this active object
QS_OBJ_PRE_(eq); // the deferred queue
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; ref Count
QS_END_PRE_()
return status;</code>
</operation>
<!--${QF::QActive::recall}-->
<operation name="recall" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Recall a deferred event from a given event queue
//!
//! @details
//! This function is part of the event deferral support. An active object
//! uses this function to recall a deferred event from a given QF
//! event queue. Recalling an event means that it is removed from the
//! deferred event queue `eq` and posted (LIFO) to the event queue of
//! the active object.
//!
//! @param[in] eq pointer to a &quot;raw&quot; thread-safe queue to recall
//! an event from.
//!
//! @returns
//! 'true' if an event has been recalled and 'false' if not.
//!
//! @note
//! An active object can use multiple event queues to defer events of
//! different kinds.
//!
//! @sa
//! QActive::recall(), QActive::postLIFO_(), QP::QEQueue</documentation>
<!--${QF::QActive::recall::eq}-->
<parameter name="eq" type="QEQueue * const"/>
<code>QEvt const * const e = eq-&gt;get(m_prio); // get evt from deferred queue
bool recalled;
// event available?
if (e != nullptr) {
QActive::postLIFO(e); // post it to the _front_ of the AO's queue
QF_CRIT_STAT_
QF_CRIT_E_();
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
// after posting to the AO's queue the event must be referenced
// at least twice: once in the deferred event queue (eq-&gt;get()
// did NOT decrement the reference counter) and once in the
// AO's event queue.
Q_ASSERT_CRIT_(210, e-&gt;refCtr_ &gt;= 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_NOCRIT_PRE_(QS_QF_ACTIVE_RECALL, m_prio)
QS_TIME_PRE_(); // time stamp
QS_OBJ_PRE_(this); // this active object
QS_OBJ_PRE_(eq); // the deferred queue
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; ref Count
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
recalled = true;
}
else {
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QF_ACTIVE_RECALL_ATTEMPT, m_prio)
QS_TIME_PRE_(); // time stamp
QS_OBJ_PRE_(this); // this active object
QS_OBJ_PRE_(eq); // the deferred queue
QS_END_PRE_()
recalled = false;
}
return recalled;
</code>
</operation>
<!--${QF::QActive::flushDeferred}-->
<operation name="flushDeferred" type="std::uint_fast16_t" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Flush the specified deferred queue 'eq'
//!
//! @details
//! This function is part of the event deferral support. An active object
//! can use this function to flush a given QF event queue. The function
//! makes sure that the events are not leaked.
//!
//! @param[in] eq pointer to a &quot;raw&quot; thread-safe queue to flush.
//!
//! @returns
//! the number of events actually flushed from the queue.
//!
//! @sa
//! QActive::defer(), QActive::recall(), QP::QEQueue</documentation>
<!--${QF::QActive::flushDeferred::eq}-->
<parameter name="eq" type="QEQueue * const"/>
<code>std::uint_fast16_t n = 0U;
for (QEvt const *e = eq-&gt;get(m_prio);
e != nullptr;
e = eq-&gt;get(m_prio))
{
++n; // count the flushed event
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e); // garbage collect
#endif
}
return n;</code>
</operation>
<!--${QF::QActive::getPrio}-->
<operation name="getPrio" type="std::uint_fast8_t" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Get the priority of the active object.</documentation>
<code>return static_cast&lt;std::uint_fast8_t&gt;(m_prio);</code>
</operation>
<!--${QF::QActive::setPrio}-->
<operation name="setPrio" type="void" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Set the priority of the active object.</documentation>
<!--${QF::QActive::setPrio::prio}-->
<parameter name="prio" type="QPrioSpec const"/>
<code>m_prio = static_cast&lt;std::uint8_t&gt;(prio &amp; 0xFFU);
m_pthre = static_cast&lt;std::uint8_t&gt;(prio &gt;&gt; 8U);</code>
</operation>
<!--${QF::QActive::setAttr}-->
<operation name="setAttr" type="void" visibility="0x00" properties="0x00">
<documentation>//! Generic setting of additional attributes (useful in QP ports)</documentation>
<!--${QF::QActive::setAttr::attr1}-->
<parameter name="attr1" type="std::uint32_t"/>
<!--${QF::QActive::setAttr::attr2 = nullptr}-->
<parameter name="attr2 = nullptr" type="void const *"/>
</operation>
<!--${QF::QActive::getOsObject}-->
<operation name="getOsObject?def QF_OS_OBJECT_TYPE" type="QF_OS_OBJECT_TYPE &amp;" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! accessor to the OS-object for extern &quot;C&quot; functions, such as
//! the QK or QXK schedulers</documentation>
<code>return m_osObject;</code>
</operation>
<!--${QF::QActive::getThread}-->
<operation name="getThread?def QF_THREAD_TYPE" type="QF_THREAD_TYPE &amp;" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! accessor to the Thread for extern &quot;C&quot; functions, such as
//! the QK or QXK schedulers</documentation>
<code>return m_thread;</code>
</operation>
<!--${QF::QActive::psInit}-->
<operation name="psInit" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Publish-subscribe initialization
//!
//! @details
//! This function initializes the publish-subscribe facilities of QF and must
//! be called exactly once before any subscriptions/publications occur in
//! the application.
//!
//! @param[in] subscrSto pointer to the array of subscriber lists
//! @param[in] maxSignal the dimension of the subscriber array and at
//! the same time the maximum signal that can be
//! published or subscribed.
//!
//! The array of subscriber-lists is indexed by signals and provides a mapping
//! between the signals and subscriber-lists. The subscriber-lists are
//! bitmasks of type QP::QSubscrList, each bit in the bit mask corresponding
//! to the unique priority of an active object. The size of the
//! QP::QSubscrList bitmask depends on the value of the #QF_MAX_ACTIVE macro.
//!
//! @note
//! The publish-subscribe facilities are optional, meaning that you might
//! choose not to use publish-subscribe. In that case calling QF::psInit()
//! and using up memory for the subscriber-lists is unnecessary.
//!
//! @sa
//! QP::QSubscrList
//!
//! @usage
//! The following example shows the typical initialization sequence of QF:
//! @include qf_main.cpp</documentation>
<!--${QF::QActive::psInit::subscrSto}-->
<parameter name="subscrSto" type="QSubscrList * const"/>
<!--${QF::QActive::psInit::maxSignal}-->
<parameter name="maxSignal" type="enum_t const"/>
<code>subscrList_ = subscrSto;
maxPubSignal_ = maxSignal;
QF::bzero(subscrSto, static_cast&lt;unsigned&gt;(maxSignal)
* sizeof(QSubscrList));</code>
</operation>
<!--${QF::QActive::publish_}-->
<operation name="publish_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Publish event to all subscribers of a given signal `e-&gt;sig`
//!
//! @details
//! This function posts (using the FIFO policy) the event @a e to **all**
//! active objects that have subscribed to the signal @a e-&gt;sig, which is
//! called _multicasting_. The multicasting performed in this function is
//! very efficient based on reference-counting inside the published event
//! (&quot;zero-copy&quot; event multicasting). This function is designed to be
//! callable from any part of the system, including ISRs, device drivers,
//! and active objects.
//!
//! @note
//! To avoid any unexpected re-ordering of events posted into AO queues,
//! the event multicasting is performed with scheduler **locked**.
//! However, the scheduler is locked only up to the priority level of
//! the highest-priority subscriber, so any AOs of even higher priority,
//! which did not subscribe to this event are *not* affected.</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="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(sender); // when Q_SPY not defined
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
//! @pre the published signal must be within the configured range
Q_REQUIRE_ID(100, static_cast&lt;enum_t&gt;(e-&gt;sig) &lt; maxPubSignal_);
QF_CRIT_STAT_
QF_CRIT_E_();
QS_BEGIN_NOCRIT_PRE_(QS_QF_PUBLISH, qs_id)
QS_TIME_PRE_(); // the timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; refCtr of the evt
QS_END_NOCRIT_PRE_()
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
// NOTE: The reference counter of a dynamic 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 list
QPSet subscrList = subscrList_[e-&gt;sig];
QF_CRIT_X_();
if (subscrList.notEmpty()) { // any subscribers?
// the highest-prio subscriber
std::uint_fast8_t p = subscrList.findMax();
QActive *a = registry_[p];
QF_SCHED_STAT_
QF_SCHED_LOCK_(a-&gt;m_prio); // lock the scheduler up to AO's prio
do { // loop over all subscribers
// the prio of the AO must be registered with the framework
Q_ASSERT_ID(210, a != nullptr);
// POST() asserts internally if the queue overflows
a-&gt;POST(e, sender);
subscrList.remove(p); // remove the handled subscriber
if (subscrList.notEmpty()) { // still more subscribers?
p = subscrList.findMax(); // the highest-prio subscriber
a = registry_[p];
}
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 &gt; 0U)
QF::gc(e);
#endif</code>
</operation>
<!--${QF::QActive::thread_}-->
<operation name="thread_" type="void" visibility="0x00" properties="0x01">
<documentation>//! Thread routine for executing an active object `act`</documentation>
<!--${QF::QActive::thread_::act}-->
<parameter name="act" type="QActive *"/>
</operation>
<!--${QF::QActive::register_}-->
<operation name="register_" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Register this active object to be managed by the framework
//!
//! @details
//! This function adds a given active object to the active objects
//! managed by the QF framework. It should not be called by the
//! application directly, only through the function QActive::start().
//!
//! @note
//! The priority of the active object a should be set before calling
//! this function.
//!
//! @sa QActive::unregister_()</documentation>
<code>if (m_pthre == 0U) { // preemption-threshold not defined?
m_pthre = m_prio; // apply the default
}
#ifndef Q_NASSERT
//! @pre
//! 1. the &quot;QF-priority&quot; of the AO must be in range
//! 2. the &quot;QF-priority&quot; must not be already in use (unique priority)
//! 3. the &quot;QF-priority&quot; must not exceed the &quot;preemption-threshold&quot;
Q_REQUIRE_ID(100, (0U &lt; m_prio) &amp;&amp; (m_prio &lt;= QF_MAX_ACTIVE)
&amp;&amp; (registry_[m_prio] == nullptr)
&amp;&amp; (m_prio &lt;= m_pthre));
std::uint8_t prev_thre = m_pthre;
std::uint8_t next_thre = m_pthre;
std::uint_fast8_t p;
for (p = static_cast&lt;std::uint_fast8_t&gt;(m_prio) - 1U; p &gt; 0U; --p) {
if (registry_[p] != nullptr) {
prev_thre = registry_[p]-&gt;m_pthre;
break;
}
}
for (p = static_cast&lt;std::uint_fast8_t&gt;(m_prio) + 1U;
p &lt;= QF_MAX_ACTIVE; ++p)
{
if (registry_[p] != nullptr) {
next_thre = registry_[p]-&gt;m_pthre;
break;
}
}
//! @post
//! 1. the preceding pre-thre must not exceed the preemption-threshold
//! 2. the preemption-threshold must not exceed the next pre-thre
Q_ENSURE_ID(110, (prev_thre &lt;= m_pthre) &amp;&amp; (m_pthre &lt;= next_thre));
#endif // Q_NASSERT
QF_CRIT_STAT_
QF_CRIT_E_();
// register the AO at the &quot;QF-priority&quot;
registry_[m_prio] = this;
QF_CRIT_X_();</code>
</operation>
<!--${QF::QActive::unregister_}-->
<operation name="unregister_" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Un-register the active object from the framework.
//!
//! @details
//! This function un-registers a given active object from the active objects
//! managed by the QF framework. It should not be called by the QP ports.
//!
//! @param[in] a pointer to the active object to remove from the
//! framework.
//!
//! @note
//! The active object that is removed from the framework can no longer
//! participate in any event exchange.
//!
//! @sa QActive::register_()</documentation>
<code>std::uint_fast8_t const p = static_cast&lt;std::uint_fast8_t&gt;(m_prio);
Q_REQUIRE_ID(200, (0U &lt; p) &amp;&amp; (p &lt;= QF_MAX_ACTIVE)
&amp;&amp; (registry_[p] == this));
QF_CRIT_STAT_
QF_CRIT_E_();
registry_[p] = nullptr; // free-up the priority level
m_state.fun = nullptr; // invalidate the state
QF_CRIT_X_();</code>
</operation>
<!--${QF::QActive::postFromISR_}-->
<operation name="postFromISR_?def QF_ISR_API" type="bool" visibility="0x00" properties="0x04">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QActive::postFromISR_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QActive::postFromISR_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QActive::postFromISR_::par}-->
<parameter name="par" type="void *"/>
<!--${QF::QActive::postFromISR_::sender}-->
<parameter name="sender" type="void const * const"/>
</operation>
<!--${QF::QActive::publishFromISR_}-->
<operation name="publishFromISR_?def QF_ISR_API" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QActive::publishFromISR_::e}-->
<parameter name="e" type="QEvt const *"/>
<!--${QF::QActive::publishFromISR_::par}-->
<parameter name="par" type="void *"/>
<!--${QF::QActive::publishFromISR_::sender}-->
<parameter name="sender" type="void const *"/>
</operation>
</class>
<!--${QF::QMActive}-->
<class name="QMActive" superclass="QF::QActive">
<documentation>//! QMActive active object (based on QP::QMsm implementation)
//!
//! @details
//! QP::QMActive represents an active object that uses the QP::QMsm-style
//! state machine implementation strategy. This strategy requires the use of
//! the QM modeling tool to generate state machine code automatically, but
//! the code is faster than in the QP::QHsm-style implementation strategy
//! and needs less run-time support (smaller event-processor).
//!
//! @note
//! QP::QMActive is not intended to be instantiated directly, but rather
//! serves as the base class for derivation of active objects in the
//! applications.
//!
//! @sa QP::QActive
//!
//! @usage
//! The following example illustrates how to derive an active object from
//! QP::QMActive.
//! @include qf_qmactive.cpp</documentation>
<!--${QF::QMActive::QHsm::isIn}-->
<attribute name="QHsm::isIn" type="using" visibility="0x04" properties="0x01">
<documentation>//! inherited from QP::QHsm, but disallowed in QP::QMActive</documentation>
<code>;</code>
</attribute>
<!--${QF::QMActive::QHsm::state}-->
<attribute name="QHsm::state" type="using" visibility="0x04" properties="0x01">
<documentation>//! inherited from QP::QHsm, but disallowed in QP::QMActive</documentation>
<code>;</code>
</attribute>
<!--${QF::QMActive::QHsm::childState}-->
<attribute name="QHsm::childState" type="using" visibility="0x04" properties="0x01">
<documentation>//! inherited from QP::QHsm, but disallowed in QP::QMActive</documentation>
<code>;</code>
</attribute>
<!--${QF::QMActive::QMActive}-->
<operation name="QMActive" type="" visibility="0x01" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! protected constructor (abstract class)</documentation>
<!--${QF::QMActive::QMActive::initial}-->
<parameter name="initial" type="QStateHandler const"/>
<code>: QActive(initial)
m_temp.fun = initial;</code>
</operation>
<!--${QF::QMActive::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! delegate to QP::QMsm::init()</documentation>
<!--${QF::QMActive::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QF::QMActive::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>m_state.obj = &amp;QMsm::msm_top_s;
QF_QMACTIVE_TO_QMSM_CAST_(this)-&gt;QMsm::init(e, qs_id);</code>
</operation>
<!--${QF::QMActive::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! delegate to QP::QMsm::init()</documentation>
<!--${QF::QMActive::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>m_state.obj = &amp;QMsm::msm_top_s;
QF_QMACTIVE_TO_QMSM_CAST_(this)-&gt;QMsm::init(qs_id);</code>
</operation>
<!--${QF::QMActive::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! delegate to QMsm::dispatch()</documentation>
<!--${QF::QMActive::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QMActive::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QF_QMACTIVE_TO_QMSM_CAST_(this)-&gt;QMsm::dispatch(e, qs_id);</code>
</operation>
<!--${QF::QMActive::isInState}-->
<operation name="isInState" type="bool" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Tests if a given state is part of the active state configuration</documentation>
<!--${QF::QMActive::isInState::st}-->
<parameter name="st" type="QMState const * const"/>
<code>return QF_QMACTIVE_TO_QMSM_CONST_CAST_(this)-&gt;QMsm::isInState(st);</code>
</operation>
<!--${QF::QMActive::stateObj}-->
<operation name="stateObj" type="QMState const *" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Return the current active state object (read only)</documentation>
<code>return m_state.obj;</code>
</operation>
<!--${QF::QMActive::childStateObj}-->
<operation name="childStateObj" type="QMState const *" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Return the current active state object (read only)</documentation>
<!--${QF::QMActive::childStateObj::parent}-->
<parameter name="parent" type="QMState const * const"/>
<code>return QF_QMACTIVE_TO_QMSM_CONST_CAST_(this)
-&gt;QMsm::childStateObj(parent);</code>
</operation>
<!--${QF::QMActive::getStateHandler}-->
<operation name="getStateHandler?def Q_SPY" type="QStateHandler" visibility="0x00" properties="0x00">
<specifiers>noexcept override</specifiers>
<documentation>//! Get the current state handler of the QP::QMsm</documentation>
<code>return QF_QMACTIVE_TO_QMSM_CAST_(this)-&gt;QMsm::getStateHandler();</code>
</operation>
</class>
<!--${QF::QTimeEvt}-->
<class name="QTimeEvt" superclass="QEP::QEvt">
<documentation>//! Time Event class (inherits QP:QEvt)
//!
//! @details
//! Time events are special QF events equipped with the notion of time
//! passage. The basic usage model of the time events is as follows. An
//! active object allocates one or more QTimeEvt objects (provides the
//! storage for them). When the active object needs to arrange for a timeout,
//! it arms one of its time events to fire either just once (one-shot) or
//! periodically. Each time event times out independently from the others,
//! so a QF application can make multiple parallel timeout requests (from the
//! same or different active objects). When QF detects that the appropriate
//! moment has arrived, it inserts the time event directly into the
//! recipient's event queue. The recipient then processes the time event just
//! like any other event.
//! &lt;br&gt;
//! //! Time events, as any other QF events derive from the QP::QEvt base
//! class. Typically, you will use a time event as-is, but you can also
//! further derive more specialized time events from it by adding some more
//! data members and/or specialized functions that operate on the specialized
//! time events.
//! &lt;br&gt;
//! Internally, the armed time events are organized into a bi-directional
//! linked list. This linked list is scanned in every invocation of the
//! QTimeEvt::tick_() function. Only armed (timing out) time events are in the
//! list, so only armed time events consume CPU cycles.
//!
//! @note
//! QF manages the time events in the macro TICK_X(), which must be called
//! periodically, from the clock tick ISR or from the special QP::QTicker
//! active object.
//!
//! @note
//! Even though QP::QTimeEvt is a subclass of QP::QEvt, QP::QTimeEvt instances
//! can NOT be allocated dynamically from event pools. In other words, it is
//! illegal to allocate QP::QTimeEvt instances with the Q_NEW() or Q_NEW_X()
//! macros.</documentation>
<!--${QF::QTimeEvt::m_next}-->
<attribute name="m_next" type="QTimeEvt * volatile" visibility="0x02" properties="0x00">
<documentation>//! link to the next time event in the list</documentation>
</attribute>
<!--${QF::QTimeEvt::m_act}-->
<attribute name="m_act" type="void *" visibility="0x02" properties="0x00">
<documentation>//! the active object that receives the time events
//!
//! @details
//! The m_act pointer is reused inside the QP implementation to hold
//! the head of the list of newly armed time events.</documentation>
</attribute>
<!--${QF::QTimeEvt::m_ctr}-->
<attribute name="m_ctr" type="QTimeEvtCtr volatile" visibility="0x02" properties="0x00">
<documentation>//! the internal down-counter of the time event
//!
//! @details
//! The down-counter is decremented by 1 in every TICK_X()
//! invocation. The time event fires (gets posted or published) when
//! the down-counter reaches zero.</documentation>
</attribute>
<!--${QF::QTimeEvt::m_interval}-->
<attribute name="m_interval" type="QTimeEvtCtr" visibility="0x02" properties="0x00">
<documentation>//! the interval for the periodic time event (zero for the one-shot
//! time event)
//!
//! @details
//! The value of the interval is re-loaded to the internal
//! down-counter when the time event expires, so that the time event
//! keeps timing out periodically.</documentation>
</attribute>
<!--${QF::QTimeEvt::timeEvtHead_[QF_MAX_TICK_RATE]}-->
<attribute name="timeEvtHead_[QF_MAX_TICK_RATE]" type="QTimeEvt" visibility="0x00" properties="0x01">
<documentation>//! heads of linked lists of time events, one for every clock tick rate</documentation>
</attribute>
<!--${QF::QTimeEvt::QXThread}-->
<attribute name="QXThread" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QTimeEvt::QTimeEvt}-->
<operation name="QTimeEvt" type="" visibility="0x00" properties="0x00">
<documentation>//! The Time Event constructor</documentation>
<!--${QF::QTimeEvt::QTimeEvt::act}-->
<parameter name="act" type="QActive * const"/>
<!--${QF::QTimeEvt::QTimeEvt::sgnl}-->
<parameter name="sgnl" type="enum_t const"/>
<!--${QF::QTimeEvt::QTimeEvt::tickRate = 0U}-->
<parameter name="tickRate = 0U" type="std::uint_fast8_t const"/>
<code>:
#ifndef Q_EVT_CTOR
QEvt(),
#else
QEvt(static_cast&lt;QSignal&gt;(sgnl), 0U),
#endif
m_next(nullptr),
m_act(act),
m_ctr(0U),
m_interval(0U)
//! @pre The signal must be valid and the tick rate in range
Q_REQUIRE_ID(300, (sgnl != 0)
&amp;&amp; (tickRate &lt; QF_MAX_TICK_RATE));
#ifndef Q_EVT_CTOR
sig = static_cast&lt;QSignal&gt;(sgnl); // set QEvt::sig of this time event
#endif
// Setting the POOL_ID event attribute to zero is correct only for
// events not allocated from event pools, which must be the case
// for Time Events.
//
poolId_ = 0U;
// The refCtr_ attribute is not used in time events, so it is
// reused to hold the tickRate as well as other information
//
refCtr_ = static_cast&lt;std::uint8_t&gt;(tickRate);</code>
</operation>
<!--${QF::QTimeEvt::armX}-->
<operation name="armX" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Arm a time event (one shot or periodic) for event posting
//!
//! @details
//! Arms a time event to fire in a specified number of clock ticks and
//! with a specified interval. If the interval is zero, the time event
//! is armed for one shot ('one-shot' time event). The time event gets
//! directly posted (using the FIFO policy) into the event queue of the
//! host active object. After posting, a one-shot time event gets
//! automatically disarmed while a periodic time event (interval != 0)
//! is automatically re-armed.
//!
//! A time event can be disarmed at any time by calling
//! QP::QTimeEvt::disarm(). Also, a time event can be re-armed to fire
//! in a different number of clock ticks by calling QP::QTimeEvt::rearm().
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to rearm the time event with.
//! @param[in] interval interval (in clock ticks) for periodic time event.
//!
//! @attention
//! Arming an already armed time event is __not__ allowed and is
//! considered a programming error. The QP/C++ framework will assert
//! if it detects an attempt to arm an already armed time event.
//!
//! @usage
//! The following example shows how to arm a one-shot time event from a
//! state machine of an active object:
//! @include qf_state.cpp</documentation>
<!--${QF::QTimeEvt::armX::nTicks}-->
<parameter name="nTicks" type="QTimeEvtCtr const"/>
<!--${QF::QTimeEvt::armX::interval = 0U}-->
<parameter name="interval = 0U" type="QTimeEvtCtr const"/>
<code>std::uint8_t const tickRate = refCtr_ &amp; TE_TICK_RATE;
QTimeEvtCtr const ctr = m_ctr; // temporary to hold volatile
//! @pre the host AO must be valid, time evnet must be disarmed,
//! number of clock ticks cannot be zero, and the signal must be valid.
Q_REQUIRE_ID(400, (m_act != nullptr)
&amp;&amp; (ctr == 0U)
&amp;&amp; (nTicks != 0U)
&amp;&amp; (tickRate &lt; static_cast&lt;std::uint8_t&gt;(QF_MAX_TICK_RATE))
&amp;&amp; (static_cast&lt;enum_t&gt;(sig) &gt;= Q_USER_SIG));
#ifdef Q_NASSERT
(void)ctr; // avoid compiler warning about unused variable
#endif
QF_CRIT_STAT_
QF_CRIT_E_();
m_ctr = nTicks;
m_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 the QF_tickX() function.
//
if (static_cast&lt;std::uint_fast8_t&gt;(
static_cast&lt;std::uint_fast8_t&gt;(refCtr_) &amp; TE_IS_LINKED) == 0U)
{
// mark as linked
refCtr_ = static_cast&lt;std::uint8_t&gt;(refCtr_ | TE_IS_LINKED);
// The time event is initially inserted into the separate
// &quot;freshly armed&quot; list based on timeEvtHead_[tickRate].act.
// Only later, inside QTimeEvt::tick_(), the &quot;freshly armed&quot;
// list is appended to the main list of armed time events based on
// timeEvtHead_[tickRate].next. Again, this is to keep any
// changes to the main list exclusively inside QTimeEvt::tick_().
m_next = timeEvtHead_[tickRate].toTimeEvt();
timeEvtHead_[tickRate].m_act = this;
}
#ifdef Q_SPY
std::uint_fast8_t const qs_id = static_cast&lt;QActive *&gt;(m_act)-&gt;m_prio;
#endif
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_ARM, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this time event object
QS_OBJ_PRE_(m_act); // the active object
QS_TEC_PRE_(nTicks); // the number of ticks
QS_TEC_PRE_(interval); // the interval
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();</code>
</operation>
<!--${QF::QTimeEvt::disarm}-->
<operation name="disarm" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Disarm a time event
//!
//! @details
//! Disarm the time event so it can be safely reused.
//!
//! @returns
//! 'true' if the time event was truly disarmed, that is, it was running.
//! The return of 'false' means that the time event was not truly
//! disarmed because it was not running. The 'false' return is only
//! possible for one-shot time events that have been automatically
//! disarmed upon expiration. In that case the 'false' return means that
//! the time event has already been posted or published and should be
//! expected in the active object's state machine.
//!
//! @note
//! there is no harm in disarming an already disarmed time event</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
#ifdef Q_SPY
std::uint_fast8_t const qs_id = static_cast&lt;QActive *&gt;(m_act)-&gt;m_prio;
#endif
// is the time event actually armed?
bool wasArmed;
if (m_ctr != 0U) {
wasArmed = true;
refCtr_ = static_cast&lt;std::uint8_t&gt;(refCtr_ | TE_WAS_DISARMED);
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_DISARM, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this time event object
QS_OBJ_PRE_(m_act); // the target AO
QS_TEC_PRE_(m_ctr); // the number of ticks
QS_TEC_PRE_(m_interval); // the interval
QS_U8_PRE_(refCtr_&amp; TE_TICK_RATE);
QS_END_NOCRIT_PRE_()
m_ctr = 0U; // schedule removal from the list
}
else { // the time event was already disarmed automatically
wasArmed = false;
refCtr_ = static_cast&lt;std::uint8_t&gt;(refCtr_
&amp; static_cast&lt;std::uint8_t&gt;(~TE_WAS_DISARMED));
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this time event object
QS_OBJ_PRE_(m_act); // the target AO
QS_U8_PRE_(refCtr_&amp; TE_TICK_RATE); // tick rate
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();
return wasArmed;</code>
</operation>
<!--${QF::QTimeEvt::rearm}-->
<operation name="rearm" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Rearm a time event
//!
//! @details
//! Rearms a time event with a new number of clock ticks. This function
//! can be used to adjust the current period of a periodic time event
//! or to prevent a one-shot time event from expiring (e.g., a watchdog
//! time event). Rearming a periodic timer leaves the interval unchanged
//! and is a convenient method to adjust the phasing of a periodic
//! time event.
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to rearm the time event with.
//!
//! @returns
//! 'true' if the time event was running as it was re-armed. The 'false'
//! return means that the time event was not truly rearmed because it was
//! not running. The 'false' return is only possible for one-shot time
//! events that have been automatically disarmed upon expiration. In that
//! case the 'false' return means that the time event has already been
//! posted and should be expected in the active object's state machine.</documentation>
<!--${QF::QTimeEvt::rearm::nTicks}-->
<parameter name="nTicks" type="QTimeEvtCtr const"/>
<code>std::uint8_t const tickRate = refCtr_ &amp; TE_TICK_RATE;
//! @pre AO must be valid, tick rate must be in range, nTicks must not
//! be zero, and the signal of this time event must be valid
Q_REQUIRE_ID(600, (m_act != nullptr)
&amp;&amp; (tickRate &lt; static_cast&lt;std::uint8_t&gt;(QF_MAX_TICK_RATE))
&amp;&amp; (nTicks != 0U)
&amp;&amp; (static_cast&lt;enum_t&gt;(sig) &gt;= Q_USER_SIG));
QF_CRIT_STAT_
QF_CRIT_E_();
// is the time evt not running?
bool wasArmed;
if (m_ctr == 0U) {
wasArmed = false;
// is the time event unlinked?
// NOTE: For a 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::tickX() function.
if (static_cast&lt;std::uint8_t&gt;(refCtr_ &amp; TE_IS_LINKED) == 0U) {
// mark as linked
refCtr_ = static_cast&lt;std::uint8_t&gt;(refCtr_ | TE_IS_LINKED);
// The time event is initially inserted into the separate
// &quot;freshly armed&quot; list based on timeEvtHead_[tickRate].act.
// Only later, inside QTimeEvt::tick_(), the &quot;freshly armed&quot;
// list is appended to the main list of armed time events based on
// timeEvtHead_[tickRate].next. Again, this is to keep any
// changes to the main list exclusively inside QTimeEvt::tick_().
m_next = timeEvtHead_[tickRate].toTimeEvt();
timeEvtHead_[tickRate].m_act = this;
}
}
else { // the time event is being disarmed
wasArmed = true;
}
m_ctr = nTicks; // re-load the tick counter (shift the phasing)
#ifdef Q_SPY
std::uint_fast8_t const qs_id = static_cast&lt;QActive *&gt;(m_act)-&gt;m_prio;
#endif
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_REARM, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this time event object
QS_OBJ_PRE_(m_act); // the target AO
QS_TEC_PRE_(m_ctr); // the number of ticks
QS_TEC_PRE_(m_interval); // the interval
QS_2U8_PRE_(tickRate, (wasArmed ? 1U : 0U));
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
return wasArmed;</code>
</operation>
<!--${QF::QTimeEvt::wasDisarmed}-->
<operation name="wasDisarmed" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Check the &quot;was disarmed&quot; status of a time event
//!
//! @details
//! Useful for checking whether a one-shot time event was disarmed in the
//! QTimeEvt_disarm() operation.
//!
//! @returns
//! 'true' if the time event was truly disarmed in the last
//! QTimeEvt::disarm() operation. The 'false' return means that the time
//! event was not truly disarmed, because it was not running at that time.
//! The 'false' return is only possible for one-shot time events that
//! have been automatically disarmed upon expiration. In this case the
//! 'false' return means that the time event has already been posted or
//! published and should be expected in the active object's event queue.
//!
//! @note
//! This function has a **side effect** of setting the &quot;was disarmed&quot;
//! status, which means that the second and subsequent times this
//! function is called the function will return 'true'.</documentation>
<code>std::uint8_t const isDisarmed = refCtr_ &amp; TE_WAS_DISARMED;
// mark as disarmed
refCtr_ = static_cast&lt;std::uint8_t&gt;(refCtr_ | TE_WAS_DISARMED);
return isDisarmed != 0U;</code>
</operation>
<!--${QF::QTimeEvt::getAct}-->
<operation name="getAct" type="void const *" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Gets the active object associated with the time event</documentation>
<code>return m_act;</code>
</operation>
<!--${QF::QTimeEvt::getCtr}-->
<operation name="getCtr" type="QTimeEvtCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Gets the current count of the time event</documentation>
<code>return m_ctr;</code>
</operation>
<!--${QF::QTimeEvt::getInterval}-->
<operation name="getInterval" type="QTimeEvtCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Gets the interval of the time event</documentation>
<code>return m_interval;</code>
</operation>
<!--${QF::QTimeEvt::tick_}-->
<operation name="tick_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Processes all armed time events at every clock tick
//!
//! @details
//! This function must be called periodically from a time-tick ISR or from
//! a task so that QF can manage the timeout events assigned to the given
//! system clock tick rate.
//!
//! @param[in] tickRate system clock tick rate serviced [1..15].
//! @param[in] sender pointer to a sender object (used in QS only).
//!
//! @attention
//! this function should be called only via the macros TICK_X() or TICK()
//!
//! @note
//! the calls to QTimeEvt::tick_() with different `tickRate` parameter can
//! preempt each other. For example, higher clock tick rates might be
//! serviced from interrupts while others from tasks (active objects).</documentation>
<!--${QF::QTimeEvt::tick_::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<!--${QF::QTimeEvt::tick_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>Q_UNUSED_PAR(sender); // when Q_SPY not defined
QTimeEvt *prev = &amp;timeEvtHead_[tickRate];
QF_CRIT_STAT_
QF_CRIT_E_();
QS_BEGIN_NOCRIT_PRE_(QS_QF_TICK, 0U)
prev-&gt;m_ctr = (prev-&gt;m_ctr + 1U);
QS_TEC_PRE_(prev-&gt;m_ctr); // tick ctr
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
// scan the linked-list of time events at this rate...
for (;;) {
QTimeEvt *t = prev-&gt;m_next; // advance down the time evt. list
// end of the list?
if (t == nullptr) {
// any new time events armed since the last run of tick_()?
if (timeEvtHead_[tickRate].m_act != nullptr) {
// sanity check
Q_ASSERT_CRIT_(110, prev != nullptr);
prev-&gt;m_next = timeEvtHead_[tickRate].toTimeEvt();
timeEvtHead_[tickRate].m_act = nullptr;
t = prev-&gt;m_next; // switch to the new list
}
else {
break; // all currently armed time evts. processed
}
}
// time event scheduled for removal?
if (t-&gt;m_ctr == 0U) {
prev-&gt;m_next = t-&gt;m_next;
// mark time event 't' as NOT linked
t-&gt;refCtr_ = static_cast&lt;std::uint8_t&gt;(t-&gt;refCtr_
&amp; static_cast&lt;std::uint8_t&gt;(~TE_IS_LINKED));
// do NOT advance the prev pointer
QF_CRIT_X_(); // exit crit. section to reduce latency
// prevent merging critical sections, see NOTE1 below
QF_CRIT_EXIT_NOP();
}
else {
t-&gt;m_ctr = (t-&gt;m_ctr - 1U);
// is time evt about to expire?
if (t-&gt;m_ctr == 0U) {
QActive * const act = t-&gt;toActive(); // temp for volatile
// periodic time evt?
if (t-&gt;m_interval != 0U) {
t-&gt;m_ctr = t-&gt;m_interval; // rearm the time event
prev = t; // advance to this time event
}
// one-shot time event: automatically disarm
else {
prev-&gt;m_next = t-&gt;m_next;
// mark time event 't' as NOT linked
t-&gt;refCtr_ = static_cast&lt;std::uint8_t&gt;(t-&gt;refCtr_
&amp; static_cast&lt;std::uint8_t&gt;(~TE_IS_LINKED));
// do NOT advance the prev pointer
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_AUTO_DISARM,
act-&gt;m_prio)
QS_OBJ_PRE_(t); // this time event object
QS_OBJ_PRE_(act); // the target AO
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_POST, act-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(t); // the time event object
QS_SIG_PRE_(t-&gt;sig); // signal of this time event
QS_OBJ_PRE_(act); // the target AO
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
QF_CRIT_X_(); // exit crit. section before posting
// asserts if queue overflows
act-&gt;POST(t, sender);
}
else {
prev = t; // advance to this time event
QF_CRIT_X_(); // exit crit. section to reduce latency
// prevent merging critical sections
// In some QF ports the critical section exit takes effect only
// on the next machine instruction. If this case, the next
// instruction is another entry to a critical section, the
// critical section won't 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();
}
}
QF_CRIT_E_(); // re-enter crit. section to continue
}
QF_CRIT_X_();</code>
</operation>
<!--${QF::QTimeEvt::tick1_}-->
<operation name="tick1_?def Q_UTEST" type="void" visibility="0x00" properties="0x01">
<documentation>//! Processes one clock tick for QUTest</documentation>
<!--${QF::QTimeEvt::tick1_::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<!--${QF::QTimeEvt::tick1_::sender}-->
<parameter name="sender" type="void const * const"/>
</operation>
<!--${QF::QTimeEvt::tickFromISR_}-->
<operation name="tickFromISR_?def QF_ISR_API" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QTimeEvt::tickFromISR_::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<!--${QF::QTimeEvt::tickFromISR_::par}-->
<parameter name="par" type="void *"/>
<!--${QF::QTimeEvt::tickFromISR_::sender}-->
<parameter name="sender" type="void const *"/>
</operation>
<!--${QF::QTimeEvt::noActive}-->
<operation name="noActive" type="bool" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Returns true if all time events are inactive and false
//! any time event is active
//!
//! @details
//! Find out if any time events are armed at the given clock tick rate.
//!
//! @param[in] tickRate system clock tick rate to find out about.
//!
//! @returns
//! 'true' if no time events are armed at the given tick rate and
//! 'false' otherwise.
//!
//! @note
//! This function should be called in critical section.</documentation>
<!--${QF::QTimeEvt::noActive::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<code>//! @pre the tick rate must be in range
Q_REQUIRE_ID(200, tickRate &lt; QF_MAX_TICK_RATE);
bool inactive;
if (timeEvtHead_[tickRate].m_next != nullptr) {
inactive = false;
}
else if (timeEvtHead_[tickRate].m_act != nullptr) {
inactive = false;
}
else {
inactive = true;
}
return inactive;</code>
</operation>
<!--${QF::QTimeEvt::toActive}-->
<operation name="toActive" type="QActive *" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! encapsulate the cast the m_act attribute to QActive*</documentation>
<code>return static_cast&lt;QActive *&gt;(m_act);</code>
</operation>
<!--${QF::QTimeEvt::toTimeEvt}-->
<operation name="toTimeEvt" type="QTimeEvt *" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! encapsulate the cast the `QTimeEvt.m_act` attribute</documentation>
<code>return static_cast&lt;QTimeEvt *&gt;(m_act);</code>
</operation>
<!--${QF::QTimeEvt::QTimeEvt}-->
<operation name="QTimeEvt" type="" visibility="0x02" properties="0x00">
<documentation>//! private default constructor only for friends
//!
//! @note
//! private default ctor for internal use only</documentation>
<code> :
#ifdef Q_EVT_CTOR
QEvt(0U, 0U),
#else
QEvt(),
#endif // Q_EVT_CTOR
m_next(nullptr),
m_act(nullptr),
m_ctr(0U),
m_interval(0U)
#ifndef Q_EVT_CTOR
sig = 0U;
// Setting the POOL_ID event attribute to zero is correct only for
// events not allocated from event pools, which must be the case
// for Time Events.
//
poolId_ = 0U; // not from any event pool
// The refCtr_ attribute is not used in time events, so it is
// reused to hold the tickRate as well as other information
//
refCtr_ = 0U; // default rate 0
#endif // Q_EVT_CTOR</code>
</operation>
<!--${QF::QTimeEvt::QTimeEvt}-->
<operation name="QTimeEvt" type="" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! private copy constructor to disallow copying of QTimeEvts</documentation>
<!--${QF::QTimeEvt::QTimeEvt::other}-->
<parameter name="other" type="QTimeEvt const &amp;"/>
</operation>
<!--${QF::QTimeEvt::operator=}-->
<operation name="operator=" type="QTimeEvt &amp;" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! disallow copying of QP::QTimeEvt</documentation>
<!--${QF::QTimeEvt::operator=::other}-->
<parameter name="other" type="QTimeEvt const &amp;"/>
</operation>
</class>
<!--${QF::QEQueue}-->
<class name="QEQueue">
<documentation>//! Native QF Event Queue class
//!
//! @details
//! This structure describes the native QF event queue, which can be used as
//! the event queue for active objects, or as a simple &quot;raw&quot; event queue for
//! thread-safe event passing among non-framework entities, such as ISRs,
//! device drivers, or other third-party components.&lt;br&gt;
//!
//! The native QF event queue is configured by defining the macro
//! #QF_EQUEUE_TYPE as QP::QEQueue in the specific QF port header file.&lt;br&gt;
//!
//! The QP::QEQueue class contains only data members for managing an event
//! queue, but does not contain the storage for the queue buffer, which must
//! be provided externally during the queue initialization.&lt;br&gt;
//!
//! The event queue can store only event pointers, not the whole events. The
//! internal implementation uses the standard ring-buffer plus one external
//! location that optimizes the queue operation for the most frequent case
//! of empty queue.&lt;br&gt;
//!
//! The QP::QEQueue class is used with two sets of functions. One set is for
//! the active object event queue, which needs to block the active object
//! task when the event queue is empty and unblock it when events are posted
//! to the queue. The interface for the native active object event queue
//! consists of the following functions: QActive::post(), QActive::postLIFO(),
//! and QActive::get_(). Additionally the function QEQueue::init() is used
//! to initialize the queue.&lt;br&gt;
//!
//! The other set of functions, uses this class as a simple &quot;raw&quot; event
//! queue to pass events between entities other than active objects, such as
//! ISRs. The &quot;raw&quot; event queue is not capable of blocking on the get()
//! operation, but is still thread-safe because it uses QF critical section
//! to protect its integrity. The interface for the &quot;raw&quot; thread-safe queue
//! consists of the following functions: QP::QEQueue::post(),
//! QP::QEQueue::postLIFO(), and QP::QEQueue::get(). Additionally the
//! function QP::QEQueue::init() is used to initialize the queue.
//!
//! @note
//! Most event queue operations (both the active object queues and the &quot;raw&quot;
//! queues) internally use the QF critical section. You should be careful
//! not to invoke those operations from other critical sections when nesting
//! of critical sections is not supported.</documentation>
<!--${QF::QEQueue::m_frontEvt}-->
<attribute name="m_frontEvt" type="QEvt const * volatile" visibility="0x02" properties="0x00">
<documentation>//! pointer to event at the front of the queue
//!
//! @details
//! All incoming and outgoing events pass through the m_frontEvt location.
//! When the queue is empty (which is most of the time), the extra
//! m_frontEvt location allows to bypass the ring buffer altogether,
//! greatly optimizing the performance of the queue. Only bursts of events
//! engage the ring buffer.&lt;br&gt;
//!
//! The additional role of this attribute is to indicate the empty status
//! of the queue. The queue is empty if the m_frontEvt location is nullptr.</documentation>
</attribute>
<!--${QF::QEQueue::m_ring}-->
<attribute name="m_ring" type="QEvt const **" visibility="0x02" properties="0x00">
<documentation>//! pointer to the start of the ring buffer</documentation>
</attribute>
<!--${QF::QEQueue::m_end}-->
<attribute name="m_end" type="QEQueueCtr" visibility="0x02" properties="0x00">
<documentation>//! offset of the end of the ring buffer from the start of the buffer</documentation>
</attribute>
<!--${QF::QEQueue::m_head}-->
<attribute name="m_head" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
<documentation>//! offset to where next event will be inserted into the buffer</documentation>
</attribute>
<!--${QF::QEQueue::m_tail}-->
<attribute name="m_tail" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
<documentation>//! offset of where next event will be extracted from the buffer</documentation>
</attribute>
<!--${QF::QEQueue::m_nFree}-->
<attribute name="m_nFree" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
<documentation>//! number of free events in the ring buffer</documentation>
</attribute>
<!--${QF::QEQueue::m_nMin}-->
<attribute name="m_nMin" type="QEQueueCtr" visibility="0x02" properties="0x00">
<documentation>//! minimum number of free events ever in the ring buffer.
//! @note this attribute remembers the low-watermark of the ring buffer,
//! which provides a valuable information for sizing event queues.
//! @sa QP::QF::getQueueMin().</documentation>
</attribute>
<!--${QF::QEQueue::QActive}-->
<attribute name="QActive" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QEQueue::QTicker}-->
<attribute name="QTicker" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QEQueue::QXMutex}-->
<attribute name="QXMutex" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QEQueue::QXThread}-->
<attribute name="QXThread" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QF::QEQueue::QEQueue}-->
<operation name="QEQueue" type="" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! public default constructor</documentation>
<code> : m_frontEvt(nullptr),
m_ring(nullptr),
m_end(0U),
m_head(0U),
m_tail(0U),
m_nFree(0U),
m_nMin(0U)</code>
</operation>
<!--${QF::QEQueue::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Initializes the native QF event queue
//!
//! @details
//! Initialize the event queue by giving it the storage for the
//! ring buffer.
//!
//! @param[in] qSto an array of pointers to QP::QEvt to serve as the
//! ring buffer for the event queue
//! @param[in] qLen the length of the qSto[] buffer (in QP::QEvt pointers)
//!
//! @note
//! The actual capacity of the queue is qLen + 1, because of the extra
//! location forntEvt.
//!
//! @note
//! This function is also used to initialize the event queues of active
//! objects in the built-int QV, QK and QXK kernels, as well as other
//! QP ports to OSes/RTOSes that do provide a suitable message queue.</documentation>
<!--${QF::QEQueue::init::qSto[]}-->
<parameter name="qSto[]" type="QEvt const *"/>
<!--${QF::QEQueue::init::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<code>m_frontEvt = nullptr; // no events in the queue
m_ring = &amp;qSto[0];
m_end = static_cast&lt;QEQueueCtr&gt;(qLen);
if (qLen &gt; 0U) {
m_head = 0U;
m_tail = 0U;
}
m_nFree = static_cast&lt;QEQueueCtr&gt;(qLen + 1U); //+1 for frontEvt
m_nMin = m_nFree;</code>
</operation>
<!--${QF::QEQueue::post}-->
<operation name="post" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Posts (FIFO) an event to the &quot;raw&quot; thread-safe QF event queue
//!
//! @details
//! Post an event to the &quot;raw&quot; thread-safe event queue using the
//! First-In-First-Out (FIFO) order.
//!
//! @param[in] e pointer to the event to be posted to the queue
//! @param[in] margin number of required free slots in the queue after
//! posting the event. The special value
//! QF::NO_MARGIN means that this function will
//! assert if posting
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @note
//! The QF::NO_MARGIN value of the `margin` argument is special and
//! denotes situation when the post() operation is assumed to succeed
//! (event delivery guarantee). An assertion fires, when the event cannot
//! be delivered in this case.
//!
//! @returns 'true' (success) when the posting succeeded with the provided
//! margin and 'false' (failure) when the posting fails.
//!
//! @note
//! This function can be called from any task context or ISR context.
//!
//! @sa QP::QEQueue::postLIFO(), QP::QEQueue::get()</documentation>
<!--${QF::QEQueue::post::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QEQueue::post::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QEQueue::post::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>//! @pre event must be valid
Q_REQUIRE_ID(200, e != nullptr);
QF_CRIT_STAT_
QF_CRIT_E_();
QEQueueCtr nFree = m_nFree; // temporary to avoid UB for volatile access
// margin available?
bool status;
if (((margin == QF::NO_MARGIN) &amp;&amp; (nFree &gt; 0U))
|| (nFree &gt; static_cast&lt;QEQueueCtr&gt;(margin)))
{
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
--nFree; // one free entry just used up
m_nFree = nFree; // update the volatile
if (m_nMin &gt; nFree) {
m_nMin = nFree; // update minimum so far
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST, qs_id)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this queue object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_);// pool Id &amp; refCtr of the evt
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(m_nMin); // min number of free entries
QS_END_NOCRIT_PRE_()
// is the queue empty?
if (m_frontEvt == nullptr) {
m_frontEvt = e; // deliver event directly
}
// queue is not empty, leave event in the ring-buffer
else {
// insert event into the ring buffer (FIFO)
m_ring[m_head] = e; // insert e into buffer
// need to wrap?
if (m_head == 0U) {
m_head = m_end; // wrap around
}
m_head = (m_head - 1U);
}
status = true; // event posted successfully
}
else {
//! @note assert if event cannot be posted and dropping events is
//! not acceptable
Q_ASSERT_CRIT_(210, margin != QF::NO_MARGIN);
QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST_ATTEMPT, qs_id)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this queue object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_);// pool Id &amp; refCtr of the evt
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(margin); // margin requested
QS_END_NOCRIT_PRE_()
status = false; // event not posted
}
QF_CRIT_X_();
Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
return status;</code>
</operation>
<!--${QF::QEQueue::postLIFO}-->
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Posts (LIFO) an event to the &quot;raw&quot; thread-safe QF event queue
//!
//! @details
//! Post an event to the &quot;raw&quot; thread-safe event queue using the
//! Last-In-First-Out (LIFO) order.
//!
//! @param[in] e pointer to the event to be posted to the queue
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! The LIFO policy should be used only with great __caution__,
//! because it alters the order of events in the queue.
//!
//! @note
//! This function can be called from any task context or ISR context.
//!
//! @note
//! This function is used for the &quot;raw&quot; thread-safe queues and __not__
//! for the queues of active objects.
//!
//! @sa
//! QEQueue::post(), QEQueue::get(), QActive::defer()</documentation>
<!--${QF::QEQueue::postLIFO::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QEQueue::postLIFO::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
QF_CRIT_STAT_
QF_CRIT_E_();
QEQueueCtr nFree = m_nFree; // temporary to avoid UB for volatile access
//! @pre the queue must be able to accept the event (cannot overflow)
Q_REQUIRE_CRIT_(300, nFree != 0U);
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
--nFree; // one free entry just used up
m_nFree = nFree; // update the volatile
if (m_nMin &gt; nFree) {
m_nMin = nFree; // update minimum so far
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST_LIFO, qs_id)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this queue object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; refCtr of the evt
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(m_nMin); // min number of free entries
QS_END_NOCRIT_PRE_()
QEvt const * const frontEvt = m_frontEvt; // read volatile into temporary
m_frontEvt = e; // deliver event directly to the front of the queue
// was the queue not empty?
if (frontEvt != nullptr) {
m_tail = (m_tail + 1U);
if (m_tail == m_end) { // need to wrap the tail?
m_tail = 0U; // wrap around
}
m_ring[m_tail] = frontEvt; // buffer the old front evt
}
QF_CRIT_X_();</code>
</operation>
<!--${QF::QEQueue::get}-->
<operation name="get" type="QEvt const *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Gets an event from the &quot;raw&quot; thread-safe QF event queue
//!
//! @details
//! Retrieves an event from the front of the &quot;raw&quot; thread-safe queue and
//! returns a pointer to this event to the caller.
//!
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! pointer to event at the front of the queue, if the queue is
//! not empty and NULL if the queue is empty.
//!
//! @note
//! this function is used for the &quot;raw&quot; thread-safe queues and **not**
//! for the queues of active objects.
//!
//! @sa
//! QEQueue::post(), QEQueue::postLIFO(), QActive::recall()</documentation>
<!--${QF::QEQueue::get::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
QF_CRIT_STAT_
QF_CRIT_E_();
QEvt const * const e = m_frontEvt; // always remove evt from the front
// is the queue not empty?
if (e != nullptr) {
QEQueueCtr const nFree = m_nFree + 1U;
m_nFree = nFree; // upate the number of free
// any events in the the ring buffer?
if (nFree &lt;= m_end) {
m_frontEvt = m_ring[m_tail]; // remove from the tail
if (m_tail == 0U) { // need to wrap?
m_tail = m_end; // wrap around
}
m_tail = (m_tail - 1U);
QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_GET, qs_id)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this queue object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_);
QS_EQC_PRE_(nFree); // # free entries
QS_END_NOCRIT_PRE_()
}
else {
m_frontEvt = nullptr; // queue becomes empty
// all entries in the queue must be free (+1 for fronEvt)
Q_ASSERT_CRIT_(410, nFree == (m_end + 1U));
QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_GET_LAST, qs_id)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this queue object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_);
QS_END_NOCRIT_PRE_()
}
}
QF_CRIT_X_();
return e;</code>
</operation>
<!--${QF::QEQueue::getNFree}-->
<operation name="getNFree" type="QEQueueCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Gets the number of free slots currently in &quot;raw&quot; thread-safe
//! QF event queue
//!
//! @note
//! This operation needs to be used with caution because the
//! number of free entries can change unexpectedly. The main intent for
//! using this operation is in conjunction with event deferral. In this
//! case the queue is accessed only from a single thread (by a single AO),
//! so the number of free entries cannot change unexpectedly.
//!
//! @sa QP::QMActive::defer(), QP::QMActive::recall()</documentation>
<code>return m_nFree;</code>
</operation>
<!--${QF::QEQueue::getNMin}-->
<operation name="getNMin" type="QEQueueCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! &quot;raw&quot; thread-safe QF event queue operation for obtaining the minimum
//! number of free entries ever in the queue (a.k.a. &quot;low-watermark&quot;).
//!
//! @details
//! This operation needs to be used with caution because the
//! &quot;low-watermark&quot; can change unexpectedly. The main intent for using
//! this operation is to get an idea of queue usage to size the queue
//! adequately.
//!
//! @returns the minimum number of free entries ever in the queue
//! since init.</documentation>
<code>return m_nMin;</code>
</operation>
<!--${QF::QEQueue::isEmpty}-->
<operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! &quot;raw&quot; thread-safe QF event queue operation to find out if the queue
//! is empty
//! @note
//! This operation needs to be used with caution because the
//! queue status can change unexpectedly. The main intent for using
//! this operation is in conjunction with event deferral. In this case
//! the queue is accessed only from a single thread (by a single AO),
//! so no other entity can post events to the queue.
//!
//! @sa QP::QMActive::defer(), QP::QMActive::recall()</documentation>
<code>return m_frontEvt == nullptr;</code>
</operation>
<!--${QF::QEQueue::QEQueue}-->
<operation name="QEQueue" type="" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! disallow copying of QP::QEQueue</documentation>
<!--${QF::QEQueue::QEQueue::other}-->
<parameter name="other" type="QEQueue const &amp;"/>
</operation>
<!--${QF::QEQueue::operator=}-->
<operation name="operator=" type="QEQueue &amp;" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! disallow copying of QP::QEQueue</documentation>
<!--${QF::QEQueue::operator=::other}-->
<parameter name="other" type="QEQueue const &amp;"/>
</operation>
</class>
<!--${QF::QMPool}-->
<class name="QMPool">
<documentation>//! Native QF memory pool class
//!
//! @details
//! A fixed block-size memory pool is a very fast and efficient data
//! structure for dynamic allocation of fixed block-size chunks of memory.
//! A memory pool offers fast and deterministic allocation and recycling of
//! memory blocks and is not subject to fragmenation.@n
//! @n
//! The QP::QMPool class describes the native QF memory pool, which can be
//! used as the event pool for dynamic event allocation, or as a fast,
//! deterministic fixed block-size heap for any other objects in your
//! application.
//!
//! @note
//! The QP::QMPool class contains only data members for managing a memory
//! pool, but does not contain the pool storage, which must be provided
//! externally during the pool initialization.
//!
//! @note
//! The native QF event pool is configured by defining the macro
//! #QF_EPOOL_TYPE_ as QP::QMPool in the specific QF port header file.</documentation>
<!--${QF::QMPool::m_start}-->
<attribute name="m_start" type="void *" visibility="0x02" properties="0x00">
<documentation>//! start of the memory managed by this memory pool</documentation>
</attribute>
<!--${QF::QMPool::m_end}-->
<attribute name="m_end" type="void *" visibility="0x02" properties="0x00">
<documentation>//! end of the memory managed by this memory pool</documentation>
</attribute>
<!--${QF::QMPool::m_free_head}-->
<attribute name="m_free_head" type="void * volatile" visibility="0x02" properties="0x00">
<documentation>//! head of linked list of free blocks</documentation>
</attribute>
<!--${QF::QMPool::m_blockSize}-->
<attribute name="m_blockSize" type="QMPoolSize" visibility="0x02" properties="0x00">
<documentation>//! maximum block size (in bytes)</documentation>
</attribute>
<!--${QF::QMPool::m_nTot}-->
<attribute name="m_nTot" type="QMPoolCtr" visibility="0x02" properties="0x00">
<documentation>//! total number of blocks</documentation>
</attribute>
<!--${QF::QMPool::m_nFree}-->
<attribute name="m_nFree" type="QMPoolCtr volatile" visibility="0x02" properties="0x00">
<documentation>//! number of free blocks remaining</documentation>
</attribute>
<!--${QF::QMPool::m_nMin}-->
<attribute name="m_nMin" type="QMPoolCtr" visibility="0x02" properties="0x00">
<documentation>//! minimum number of free blocks ever present in this pool
//!
//! @note
//! This attribute remembers the low watermark of the pool,
//! which provides a valuable information for sizing event pools.
//!
//! @sa QF::getPoolMin().</documentation>
</attribute>
<!--${QF::QMPool::QMPool}-->
<operation name="QMPool" type="" visibility="0x00" properties="0x00">
<documentation>//! public default constructor</documentation>
<code> : m_start(nullptr),
m_end(nullptr),
m_free_head(nullptr),
m_blockSize(0U),
m_nTot(0U),
m_nFree(0U),
m_nMin(0U)</code>
</operation>
<!--${QF::QMPool::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Initializes the native QF event pool
//!
//! @details
//! Initialize a fixed block-size memory pool by providing it with the
//! pool memory to manage, size of this memory, and the block size.
//!
//! @param[in] poolSto pointer to the memory buffer for pool storage
//! @param[in] poolSize size of the storage buffer in bytes
//! @param[in] blockSize fixed-size of the memory blocks in bytes
//!
//! @attention
//! The caller of QMPool::init() must make sure that the `poolSto`
//! pointer is properly **aligned**. In particular, it must be possible to
//! efficiently store a pointer at the location pointed to by `poolSto`.
//! Internally, the QMPool::init() function rounds up the block size
//! `blockSize` so that it can fit an integer number of pointers. This
//! is done to achieve proper alignment of the blocks within the pool.
//!
//! @note
//! Due to the rounding of block size the actual capacity of the pool
//! might be less than (`poolSize` / `blockSize`). You can check the
//! capacity of the pool by calling the QF::getPoolMin() function.
//!
//! @note
//! This function is **not** protected by a critical section, because
//! it is intended to be called only during the initialization of the
//! system, when interrupts are not allowed yet.
//!
//! @note
//! Many QF ports use memory pools to implement the event pools.</documentation>
<!--${QF::QMPool::init::poolSto}-->
<parameter name="poolSto" type="void * const"/>
<!--${QF::QMPool::init::poolSize}-->
<parameter name="poolSize" type="std::uint_fast32_t"/>
<!--${QF::QMPool::init::blockSize}-->
<parameter name="blockSize" type="std::uint_fast16_t"/>
<code>//! @pre The memory block must be valid and
//! the poolSize must fit at least one free block and
//! the blockSize must not be too close to the top of the dynamic range
Q_REQUIRE_ID(100, (poolSto != nullptr)
&amp;&amp; (poolSize &gt;= static_cast&lt;std::uint_fast32_t&gt;(sizeof(QFreeBlock)))
&amp;&amp; (static_cast&lt;std::uint_fast16_t&gt;(blockSize + sizeof(QFreeBlock))
&gt; blockSize));
m_free_head = poolSto;
// round up the blockSize to fit an integer number of pointers...
//start with one
m_blockSize = static_cast&lt;QMPoolSize&gt;(sizeof(QFreeBlock));
//# free blocks in a memory block
std::uint_fast16_t nblocks = 1U;
while (m_blockSize &lt; static_cast&lt;QMPoolSize&gt;(blockSize)) {
m_blockSize += static_cast&lt;QMPoolSize&gt;(sizeof(QFreeBlock));
++nblocks;
}
// use rounded-up value
blockSize = static_cast&lt;std::uint_fast16_t&gt;(m_blockSize);
// the whole pool buffer must fit at least one rounded-up block
Q_ASSERT_ID(110, poolSize &gt;= blockSize);
// chain all blocks together in a free-list...
// don't count the last block
poolSize -= static_cast&lt;std::uint_fast32_t&gt;(blockSize);
m_nTot = 1U; // one (the last) block in the pool
// start at the head of the free list
QFreeBlock *fb = static_cast&lt;QFreeBlock *&gt;(m_free_head);
// chain all blocks together in a free-list...
while (poolSize &gt;= blockSize) {
fb-&gt;m_next = &amp;fb[nblocks]; // setup the next link
fb = fb-&gt;m_next; // advance to next block
// reduce the available pool size
poolSize -= static_cast&lt;std::uint_fast32_t&gt;(blockSize);
++m_nTot; // increment the number of blocks so far
}
fb-&gt;m_next = nullptr; // the last link points to NULL
m_nFree = m_nTot; // all blocks are free
m_nMin = m_nTot; // the minimum number of free blocks
m_start = poolSto; // the original start this pool buffer
m_end = fb; // the last block in this pool</code>
</operation>
<!--${QF::QMPool::get}-->
<operation name="get" type="void *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Obtains a memory block from a memory pool
//!
//! @details
//! The function allocates a memory block from the pool and returns a
//! pointer to the block back to the caller.
//!
//! @param[in] margin the minimum number of unused blocks still
//! available in the pool after the allocation.
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! A pointer to a memory block or NULL if no more blocks are available
//! in the memory pool.
//!
//! @note
//! This function can be called from any task level or ISR level.
//!
//! @note
//! The memory pool must be initialized before any events can
//! be requested from it. Also, the QP::QMPool::get() function uses
//! internally a QF critical section, so you should be careful not to
//! call it from within a critical section when nesting of critical
//! section is not supported.
//!
//! @attention
//! An allocated block must be later returned back to the **same** pool
//! from which it has been allocated.
//!
//! @sa
//! QP::QMPool::put()</documentation>
<!--${QF::QMPool::get::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QMPool::get::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
QF_CRIT_STAT_
QF_CRIT_E_();
// have the than margin?
QFreeBlock *fb;
if (m_nFree &gt; static_cast&lt;QMPoolCtr&gt;(margin)) {
fb = static_cast&lt;QFreeBlock *&gt;(m_free_head); // get a free block
// the pool has some free blocks, so a free block must be available
Q_ASSERT_CRIT_(310, fb != nullptr);
// put volatile to a temporary to avoid UB
void * const fb_next = fb-&gt;m_next;
// is the pool becoming empty?
m_nFree = (m_nFree - 1U); // one free block less
if (m_nFree == 0U) {
// pool is becoming empty, so the next free block must be NULL
Q_ASSERT_CRIT_(320, fb_next == nullptr);
m_nMin = 0U;// remember that 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.
//!
//! @tr{PQP18_3}
// 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_CRIT_(330, QF_PTR_RANGE_(fb_next, m_start, m_end));
// is the number of free blocks the new minimum so far?
if (m_nMin &gt; m_nFree) {
m_nMin = m_nFree; // remember the minimum so far
}
}
m_free_head = fb_next; // set the head to the next free block
QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_GET, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this memory pool
QS_MPC_PRE_(m_nFree); // # of free blocks in the pool
QS_MPC_PRE_(m_nMin); // min # free blocks ever in the pool
QS_END_NOCRIT_PRE_()
}
// don't have enough free blocks at this point
else {
fb = nullptr;
QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_GET_ATTEMPT, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(m_start); // the memory managed by this pool
QS_MPC_PRE_(m_nFree); // the # free blocks in the pool
QS_MPC_PRE_(margin); // the requested margin
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();
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">
<specifiers>noexcept</specifiers>
<documentation>//! Returns a memory block back to a memory pool
//!
//! @details
//! Recycle a memory block to the fixed block-size memory pool.
//!
//! @param[in] b pointer to the memory block that is being recycled
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @attention
//! The recycled block must be allocated from the **same** memory pool
//! to which it is returned.
//!
//! @note
//! This function can be called from any task level or ISR level.
//!
//! @sa
//! QP::QMPool::get()</documentation>
<!--${QF::QMPool::put::b}-->
<parameter name="b" type="void * const"/>
<!--${QF::QMPool::put::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id); // when Q_SPY not defined
//! @pre # free blocks cannot exceed the total # blocks and
//! the block pointer must be in range to come from this pool.
//!
Q_REQUIRE_ID(200, (m_nFree &lt; m_nTot)
&amp;&amp; QF_PTR_RANGE_(b, m_start, m_end));
QF_CRIT_STAT_
QF_CRIT_E_();
static_cast&lt;QFreeBlock*&gt;(b)-&gt;m_next =
static_cast&lt;QFreeBlock *&gt;(m_free_head); // link into the free list
m_free_head = b; // set as new head of the free list
m_nFree = (m_nFree + 1U); // one more free block in this pool
QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_PUT, qs_id)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this memory pool
QS_MPC_PRE_(m_nFree); // the number of free blocks in the pool
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();</code>
</operation>
<!--${QF::QMPool::getBlockSize}-->
<operation name="getBlockSize" type="QMPoolSize" visibility="0x00" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! return the fixed block-size of the blocks managed by this pool</documentation>
<code>return m_blockSize;</code>
</operation>
<!--${QF::QMPool::getNMin}-->
<operation name="getNMin" type="QMPoolCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Memory pool operation for obtaining the minimum number of free
//! blocks ever in the pool (a.k.a. &quot;low-watermark&quot;).
//!
//! @details
//! This operation needs to be used with caution because the
//! &quot;low-watermark&quot; can change unexpectedly. The main intent for using
//! this operation is to get an idea of pool usage to size the pool
//! adequately.
//!
//! @returns the minimum number of free entries ever in the memory pool
//! since init.</documentation>
<code>return m_nMin;</code>
</operation>
<!--${QF::QMPool::getNFree}-->
<operation name="getNFree" type="QMPoolCtr" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! Memory pool operation for obtaining the current number of free
//! blocks in the pool.
//!
//! @details
//! This operation needs to be used with caution because the number
//! of free blocks can change unexpectedly.
//!
//! @returns the current number of free blocks in the memory pool.</documentation>
<code>return m_nFree;</code>
</operation>
<!--${QF::QMPool::QMPool}-->
<operation name="QMPool" type="" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! disallow copying of QP::QMPool</documentation>
<!--${QF::QMPool::QMPool::other}-->
<parameter name="other" type="QEQueue const &amp;"/>
</operation>
<!--${QF::QMPool::operator=}-->
<operation name="operator=" type="QMPool &amp;" visibility="0x02" properties="0x00">
<specifiers>= delete</specifiers>
<documentation>//! disallow copying of QP::QMPool</documentation>
<!--${QF::QMPool::operator=::other}-->
<parameter name="other" type="QMPool const &amp;"/>
</operation>
<!--${QF::QMPool::getFromISR}-->
<operation name="getFromISR?def QF_ISR_API" type="void *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QMPool::getFromISR::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QMPool::getFromISR::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
</operation>
<!--${QF::QMPool::putFromISR}-->
<operation name="putFromISR?def QF_ISR_API" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QMPool::putFromISR::b}-->
<parameter name="b" type="void * const"/>
<!--${QF::QMPool::putFromISR::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
</operation>
</class>
<!--${QF::QTicker}-->
<class name="QTicker" superclass="QF::QActive">
<documentation>//! &quot;Ticker&quot; Active Object class (inherits QP::QActive)
//!
//! @details
//! QP::QTicker is an efficient active object specialized to process
//! QF system clock tick at a specified tick frequency [0..#QF_MAX_TICK_RATE].
//! Placing system clock tick processing in an active object allows you
//! to remove the non-deterministic TICK_X() processing from the interrupt
//! level and move it into the thread-level, where you can prioritize it
//! as low as you wish.
//!
//! @usage
//! The following example illustrates use of QP::QTicker active objects:
//! @include qf_ticker.cpp</documentation>
<!--${QF::QTicker::QTicker}-->
<operation name="QTicker" type="explicit" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! constructor</documentation>
<!--${QF::QTicker::QTicker::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<code>: QActive(nullptr)
// reuse m_head for tick-rate
m_eQueue.m_head = static_cast&lt;QEQueueCtr&gt;(tickRate);</code>
</operation>
<!--${QF::QTicker::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QF::QTicker::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QF::QTicker::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
m_eQueue.m_tail = 0U;</code>
</operation>
<!--${QF::QTicker::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QF::QTicker::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QTicker::init(nullptr, qs_id);</code>
</operation>
<!--${QF::QTicker::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QF::QTicker::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QTicker::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
QF_CRIT_STAT_
QF_CRIT_E_();
QEQueueCtr nTicks = m_eQueue.m_tail; // # ticks since the last call
m_eQueue.m_tail = 0U; // clear the # ticks
QF_CRIT_X_();
for (; nTicks &gt; 0U; --nTicks) {
QTimeEvt::TICK_X(static_cast&lt;std::uint_fast8_t&gt;(m_eQueue.m_head),
this);
}</code>
</operation>
<!--${QF::QTicker::post_}-->
<operation name="post_" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept override</specifiers>
<!--${QF::QTicker::post_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QTicker::post_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QTicker::post_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(margin);
Q_UNUSED_PAR(sender); // when Q_SPY not defined
QF_CRIT_STAT_
QF_CRIT_E_();
if (m_eQueue.m_frontEvt == nullptr) {
#ifdef Q_EVT_CTOR
static QEvt const tickEvt(0U, 0U);
#else
static QEvt const tickEvt = { 0U, 0U, 0U };
#endif // Q_EVT_CTOR
m_eQueue.m_frontEvt = &amp;tickEvt; // deliver event directly
m_eQueue.m_nFree = (m_eQueue.m_nFree - 1U); // one less free event
QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
}
// account for one more tick event
m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(0U); // the signal of the event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(0U, 0U); // pool-Id &amp; ref-ctr
QS_EQC_PRE_(0U); // number of free entries
QS_EQC_PRE_(0U); // min number of free entries
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
return true; // the event is always posted correctly</code>
</operation>
</class>
<!--${QF::QF-base}-->
<package name="QF-base" stereotype="0x02" namespace="QF::">
<!--${QF::QF-base::intLock_}-->
<attribute name="intLock_" type="std::uint_fast8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! Interrupt lock up-down counter (used in some QF ports)</documentation>
</attribute>
<!--${QF::QF-base::intNest_}-->
<attribute name="intNest_" type="std::uint_fast8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! Interrupt nesting up-down counter (used in some QF ports)</documentation>
</attribute>
<!--${QF::QF-base::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x01">
<documentation>//! QF initialization
//!
//! @details
//! Initializes QF and must be called exactly once before any other QF
//! function. Typcially, QP::QF::init() is called from main() even before
//! initializing the Board Support Package (BSP).
//!
//! @note
//! QP::QF::init() clears 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).</documentation>
</operation>
<!--${QF::QF-base::stop}-->
<operation name="stop" type="void" visibility="0x00" properties="0x01">
<documentation>//! Function invoked by the application layer to stop the QF
//! application and return control to the OS/Kernel
//!
//! @details
//! This function stops the QF application. After calling this function,
//! QF attempts to gracefully stop the application. This graceful shutdown
//! might take some time to complete. The typical use of this function is
//! for terminating the QF application to return back to the operating
//! system or for handling fatal errors that require shutting down
//! (and possibly re-setting) the system.
//!
//! @attention
//! After calling QF::stop() the application must terminate and cannot
//! continue. In particular, QF::stop() is **not** intended to be followed
//! by a call to QF::init() to &quot;resurrect&quot; the application.
//!
//! @sa QP::QF::onCleanup()</documentation>
</operation>
<!--${QF::QF-base::run}-->
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
<documentation>//! Transfers control to QF to run the application
//!
//! @details
//! QF::run() is typically called from your startup code after you
//! initialize the QF and start at least one active object with
//! QActive::start().
//!
//! @returns
//! In QK, the QP::QF::run() function does not return.</documentation>
</operation>
<!--${QF::QF-base::onStartup}-->
<operation name="onStartup" type="void" visibility="0x00" properties="0x01">
<documentation>//! Startup QF callback (defined in applications/ports)
//!
//! @details
//! The purpose of the QF::onStartup() callback is to configure and enable
//! hardware interrupts. The callback is invoked from QF::run(), right before
//! starting the underlying real-time kernel. By that time, the application
//! is considered ready to receive and service interrupts.
//!
//! This function is application-specific and is not implemented in QF, but
//! rather in the Board Support Package (BSP) for the given application.</documentation>
</operation>
<!--${QF::QF-base::onCleanup}-->
<operation name="onCleanup" type="void" visibility="0x00" properties="0x01">
<documentation>//! Cleanup QF callback (defined in applications/ports)</documentation>
</operation>
<!--${QF::QF-base::getQueueMin}-->
<operation name="getQueueMin" type="std::uint_fast16_t" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! This function returns the minimum of free entries of the given
//! event queue of an active object (indicated by priority `prio`)
//!
//! @details
//! Queries the minimum of free ever present in the given event queue of
//! an active object with priority `prio`, since the active object
//! was started.
//!
//! @note
//! QF::getQueueMin() is available only when the native QF event queue
//! implementation is used. Requesting the queue minimum of an unused
//! priority level raises an assertion in the QF. (A priority level
//! becomes used in QF after the call to QActive::register_().)
//!
//! @param[in] prio Priority of the active object, whose queue is queried
//!
//! @returns
//! the minimum of free ever present in the given event queue of an active
//! object with priority `prio`, since the active object was started.</documentation>
<!--${QF::QF-base::getQueueMin::prio}-->
<parameter name="prio" type="std::uint_fast8_t const"/>
<code>Q_REQUIRE_ID(400, (prio &lt;= QF_MAX_ACTIVE)
&amp;&amp; (QActive::registry_[prio] != nullptr));
QF_CRIT_STAT_
QF_CRIT_E_();
std::uint_fast16_t const min = static_cast&lt;std::uint_fast16_t&gt;(
QActive::registry_[prio]-&gt;m_eQueue.getNMin());
QF_CRIT_X_();
return min;</code>
</operation>
<!--${QF::QF-base::psInit}-->
<operation name="psInit" type="void" visibility="0x00" properties="0x03">
<specifiers>noexcept</specifiers>
<documentation>//! Publish-subscribe initialization
//!
//! @deprecated
//! superseded by QActive::psInit()</documentation>
<!--${QF::QF-base::psInit::subscrSto}-->
<parameter name="subscrSto" type="QSubscrList * const"/>
<!--${QF::QF-base::psInit::maxSignal}-->
<parameter name="maxSignal" type="enum_t const"/>
<code>QActive::psInit(subscrSto, maxSignal);</code>
</operation>
<!--${QF::QF-base::publish_}-->
<operation name="publish_" type="void" visibility="0x00" properties="0x03">
<specifiers>noexcept</specifiers>
<documentation>//! Publish event to all subscribers of a given signal `e-&gt;sig`
//!
//! @deprecated
//! superseded by QActive::publish_()</documentation>
<!--${QF::QF-base::publish_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QF-base::publish_::sender}-->
<parameter name="sender" type="void const * const"/>
<!--${QF::QF-base::publish_::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QActive::publish_(e, sender, qs_id);</code>
</operation>
<!--${QF::QF-base::tick_}-->
<operation name="tick_" type="void" visibility="0x00" properties="0x03">
<specifiers>noexcept</specifiers>
<documentation>//! Processes all armed time events at every clock tick
//!
//! @deprecated
//! superseded by QTimeEvt::tick_()</documentation>
<!--${QF::QF-base::tick_::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<!--${QF::QF-base::tick_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>QTimeEvt::tick_(tickRate, sender);</code>
</operation>
<!--${QF::QF-base::NO_MARGIN}-->
<attribute name="NO_MARGIN" type="constexpr std::uint_fast16_t" visibility="0x04" properties="0x00">
<documentation>//! Special value of margin that causes asserting failure in case
//! event allocation or event posting fails</documentation>
<code>{0xFFFFU};</code>
</attribute>
</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">
<specifiers>noexcept</specifiers>
<documentation>//! Event pool initialization for dynamic allocation of events.
//!
//! @details
//! This function initializes one event pool at a time and must be called
//! exactly once for each event pool before the pool can be used.
//!
//! @param[in] poolSto pointer to the storage for the event pool
//! @param[in] poolSize size of the storage for the pool in bytes
//! @param[in] evtSize the block-size of the pool in bytes, which
//! determines the maximum size of events that
//! can be allocated from the pool
//! @note
//! You might initialize many event pools by making many consecutive calls
//! to the QF::poolInit() function. However, for the simplicity of the
//! internal implementation, you must initialize event pools in the
//! ascending order of the event size.
//!
//! @note
//! The actual number of events available in the pool might be actually
//! less than (`poolSize / evtSize`) due to the internal alignment of
//! the blocks that the pool might perform. You can always check the
//! capacity of the pool by calling QF::getPoolMin().
//!
//! @note
//! The dynamic allocation of events is optional, meaning that you might
//! choose not to use dynamic events. In that case calling
//! QF::poolInit() and using up memory for the memory blocks is
//! unnecessary.
//!
//! @sa QF initialization example for QF::init()</documentation>
<!--${QF::QF-dyn::poolInit::poolSto}-->
<parameter name="poolSto" type="void * const"/>
<!--${QF::QF-dyn::poolInit::poolSize}-->
<parameter name="poolSize" type="std::uint_fast32_t const"/>
<!--${QF::QF-dyn::poolInit::evtSize}-->
<parameter name="evtSize" type="std::uint_fast16_t const"/>
<code>//! @pre cannot exceed the number of available memory pools
Q_REQUIRE_ID(200, QF::maxPool_ &lt; QF_MAX_EPOOL);
//! @pre QF event pools must be initialized in ascending order of evtSize
if (QF::maxPool_ &gt; 0U) {
Q_REQUIRE_ID(201,
QF_EPOOL_EVENT_SIZE_(QF::ePool_[QF::maxPool_ - 1U]) &lt; evtSize);
}
QF_EPOOL_INIT_(QF::ePool_[QF::maxPool_], poolSto, poolSize, evtSize);
++QF::maxPool_; // one more pool
#ifdef Q_SPY
// generate the object-dictionary entry for the initialized pool
char obj_name[9] = &quot;EvtPool?&quot;;
obj_name[7] = static_cast&lt;char&gt;(
static_cast&lt;std::int8_t&gt;('0')
+ static_cast&lt;std::int8_t&gt;(QF::maxPool_));
QS::obj_dict_pre_(&amp;QF::ePool_[QF::maxPool_ - 1U], &amp;obj_name[0]);
#endif // Q_SPY</code>
</operation>
<!--${QF::QF-dyn::newX_}-->
<operation name="newX_" type="QEvt *" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Internal QF implementation of creating new dynamic mutable event
//!
//! @details
//! Allocates an event dynamically from one of the QF event pools.
//!
//! @param[in] evtSize the size (in bytes) of the event to allocate
//! @param[in] margin the number of un-allocated events still available
//! in a given event pool after the allocation
//! completes. The special value QF::NO_MARGIN
//! means that this function will assert if allocation
//! fails.
//! @param[in] sig the signal to be assigned to the allocated event
//!
//! @returns
//! pointer to the newly allocated event. This pointer can be nullptr
//! only if margin!=0 and the event cannot be allocated with the
//! specified margin still available in the given pool.
//!
//! @note
//! The internal QF function QF::newX_() raises an assertion when
//! the margin argument is QF::NO_MARGIN and allocation of the event
//! turns out to be impossible due to event pool depletion, or incorrect
//! (too big) size of the requested event.
//!
//! @note
//! The application code should not call this function directly.
//! The only allowed use is thorough the macros Q_NEW() or Q_NEW_X().</documentation>
<!--${QF::QF-dyn::newX_::evtSize}-->
<parameter name="evtSize" type="std::uint_fast16_t const"/>
<!--${QF::QF-dyn::newX_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QF-dyn::newX_::sig}-->
<parameter name="sig" type="enum_t const"/>
<code>std::uint_fast8_t idx;
// find the pool id that fits the requested event size ...
for (idx = 0U; idx &lt; QF::maxPool_; ++idx) {
if (evtSize &lt;= QF_EPOOL_EVENT_SIZE_(QF::ePool_[idx])) {
break;
}
}
// cannot run out of registered pools
Q_ASSERT_ID(310, idx &lt; QF::maxPool_);
// get e -- platform-dependent
QEvt *e;
#ifdef Q_SPY
QF_EPOOL_GET_(QF::ePool_[idx], e, ((margin != QF::NO_MARGIN) ? margin : 0U),
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID) + idx + 1U);
#else
QF_EPOOL_GET_(QF::ePool_[idx], e, ((margin != QF::NO_MARGIN) ? margin : 0U),
0U);
#endif
// was e allocated correctly?
QS_CRIT_STAT_
if (e != nullptr) {
e-&gt;sig = static_cast&lt;QSignal&gt;(sig); // set the signal
e-&gt;poolId_ = static_cast&lt;std::uint8_t&gt;(idx + 1U); // store pool ID
e-&gt;refCtr_ = 0U; // initialize the reference counter to 0
QS_BEGIN_PRE_(QS_QF_NEW,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_))
QS_TIME_PRE_(); // timestamp
QS_EVS_PRE_(evtSize); // the size of the evt
QS_SIG_PRE_(sig); // the signal of the evt
QS_END_PRE_()
}
else {
// 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_ID(320, margin != QF::NO_MARGIN);
QS_BEGIN_PRE_(QS_QF_NEW_ATTEMPT,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID) + idx + 1U)
QS_TIME_PRE_(); // timestamp
QS_EVS_PRE_(evtSize); // the size of the evt
QS_SIG_PRE_(sig); // the signal of the evt
QS_END_PRE_()
}
return e; // can't be NULL if we can't tolerate bad allocation</code>
</operation>
<!--${QF::QF-dyn::gc}-->
<operation name="gc" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Recycle a dynamic event
//!
//! @details
//! This function implements a garbage collector for dynamic events.
//! Only dynamic events are candidates for recycling. (A dynamic event
//! is one that is allocated from an event pool, which is determined as
//! non-zero `e-&gt;poolId_` attribute.) Next, the function decrements the
//! reference counter of the event (`e-&gt;refCtr_`), and recycles the event
//! only if the counter drops to zero (meaning that no more references
//! are outstanding for this event). The dynamic event is recycled by
//! returning it to the pool from which it was originally allocated.
//!
//! @param[in] e pointer to the event to recycle
//!
//! @note
//! QF invokes the garbage collector at all appropriate contexts, when
//! an event can become garbage (automatic garbage collection), so the
//! application code should have no need to call QF::gc() directly.
//! The QF::gc() function is exposed only for special cases when your
//! application sends dynamic events to the &quot;raw&quot; thread-safe queues
//! (see QP::QEQueue). Such queues are processed outside of QF and the
//! automatic garbage collection is **NOT** performed for these events.
//! In this case you need to call QF::gc() explicitly.</documentation>
<!--${QF::QF-dyn::gc::e}-->
<parameter name="e" type="QEvt const * const"/>
<code>// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QF_CRIT_STAT_
QF_CRIT_E_();
// isn't this the last reference?
if (e-&gt;refCtr_ &gt; 1U) {
QS_BEGIN_NOCRIT_PRE_(QS_QF_GC_ATTEMPT,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_))
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; refCtr
QS_END_NOCRIT_PRE_()
QEvt_refCtr_dec_(e); // decrement the ref counter
QF_CRIT_X_();
}
// this is the last reference to this event, recycle it
else {
std::uint_fast8_t const idx =
static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_) - 1U;
QS_BEGIN_NOCRIT_PRE_(QS_QF_GC,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_))
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_);
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
// pool ID must be in range
Q_ASSERT_ID(410, idx &lt; QF::maxPool_);
#ifdef Q_EVT_XTOR
// explicitly exectute the destructor'
// NOTE: casting 'const' away is legitimate,
// because it's a pool event
QF_CONST_CAST_(QEvt*, e)-&gt;~QEvt(); // xtor,
#endif
#ifdef Q_SPY
// cast 'const' away, which is OK, because it's a pool event
QF_EPOOL_PUT_(QF::ePool_[idx], QF_CONST_CAST_(QEvt*, e),
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_));
#else
QF_EPOOL_PUT_(QF::ePool_[idx], QF_CONST_CAST_(QEvt*, e), 0U);
#endif
}
}</code>
</operation>
<!--${QF::QF-dyn::poolGetMaxBlockSize}-->
<operation name="poolGetMaxBlockSize" type="std::uint_fast16_t" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Obtain the block size of any registered event pools</documentation>
<code>return QF_EPOOL_EVENT_SIZE_(QF::ePool_[QF::maxPool_ - 1U]);</code>
</operation>
<!--${QF::QF-dyn::newRef_}-->
<operation name="newRef_" type="QEvt const *" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Internal QF implementation of creating new event reference
//!
//! @details
//! Creates and returns a new reference to the current event e
//!
//! @param[in] e pointer to the current event
//! @param[in] evtRef the event reference
//!
//! @returns
//! the newly created reference to the event `e`
//!
//! @note
//! The application code should not call this function directly.
//! The only allowed use is thorough the macro Q_NEW_REF().</documentation>
<!--${QF::QF-dyn::newRef_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QF::QF-dyn::newRef_::evtRef}-->
<parameter name="evtRef" type="QEvt const * const"/>
<code>//! @pre the event must be dynamic and the provided event reference
//! must not be already in use
Q_REQUIRE_ID(500, (e-&gt;poolId_ != 0U)
&amp;&amp; (evtRef == nullptr));
QF_CRIT_STAT_
QF_CRIT_E_();
QEvt_refCtr_inc_(e); // increments the ref counter
QS_BEGIN_NOCRIT_PRE_(QS_QF_NEW_REF,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(e-&gt;poolId_))
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; ref Count
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
return e;</code>
</operation>
<!--${QF::QF-dyn::deleteRef_}-->
<operation name="deleteRef_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Internal QF implementation of deleting event reference
//!
//! @details
//! Deletes an existing reference to the event e
//!
//! @param[in] evtRef the event reference
//!
//! @note
//! The application code should not call this function directly.
//! The only allowed use is thorough the macro Q_DELETE_REF().</documentation>
<!--${QF::QF-dyn::deleteRef_::evtRef}-->
<parameter name="evtRef" type="QEvt const * const"/>
<code>QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QF_DELETE_REF,
static_cast&lt;std::uint_fast8_t&gt;(QS_EP_ID)
+ static_cast&lt;std::uint_fast8_t&gt;(evtRef-&gt;poolId_))
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(evtRef-&gt;sig); // the signal of the event
QS_2U8_PRE_(evtRef-&gt;poolId_, evtRef-&gt;refCtr_); // pool Id &amp; ref Count
QS_END_PRE_()
#if (QF_MAX_EPOOL &gt; 0U)
gc(evtRef); // recycle the referenced event
#endif</code>
</operation>
<!--${QF::QF-dyn::getPoolMin}-->
<operation name="getPoolMin" type="std::uint_fast16_t" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! This function returns the minimum of free entries of the given
//! event pool
//!
//! @details
//! This function obtains the minimum number of free blocks in the given
//! event pool since this pool has been initialized by a call to
//! QP::QF::poolInit().
//!
//! @param[in] poolId event pool ID in the range 1..QF::maxPool_, where
//! QF::maxPool_ is the number of event pools
//! initialized with the function QF::poolInit().
//! @returns
//! the minimum number of unused blocks in the given event pool.</documentation>
<!--${QF::QF-dyn::getPoolMin::poolId}-->
<parameter name="poolId" type="std::uint_fast8_t const"/>
<code>//! @pre the poolId must be in range
Q_REQUIRE_ID(400, (QF::maxPool_ &lt;= QF_MAX_EPOOL)
&amp;&amp; (0U &lt; poolId) &amp;&amp; (poolId &lt;= QF::maxPool_));
QF_CRIT_STAT_
QF_CRIT_E_();
std::uint_fast16_t const min = static_cast&lt;std::uint_fast16_t&gt;(
QF::ePool_[poolId - 1U].getNMin());
QF_CRIT_X_();
return min;</code>
</operation>
<!--${QF::QF-dyn::newXfromISR_}-->
<operation name="newXfromISR_?def QF_ISR_API" type="QEvt *" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QF-dyn::newXfromISR_::evtSize}-->
<parameter name="evtSize" type="std::uint_fast16_t const"/>
<!--${QF::QF-dyn::newXfromISR_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QF::QF-dyn::newXfromISR_::sig}-->
<parameter name="sig" type="enum_t const"/>
</operation>
<!--${QF::QF-dyn::gcFromISR}-->
<operation name="gcFromISR?def QF_ISR_API" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! the &quot;FromISR&quot; variant used in the QP port to &quot;FreeRTOS&quot;</documentation>
<!--${QF::QF-dyn::gcFromISR::e}-->
<parameter name="e" type="QEvt const *"/>
</operation>
</package>
<!--${QF::QF-pkg}-->
<package name="QF-pkg" stereotype="0x02" namespace="QF::">
<!--${QF::QF-pkg::readySet_}-->
<attribute name="readySet_" type="QPSet" visibility="0x00" properties="0x01">
<documentation>//! &quot;Ready-set&quot; of all threads used in the built-in kernels</documentation>
</attribute>
<!--${QF::QF-pkg::ePool_[QF_MAX_EPOOL]}-->
<attribute name="ePool_[QF_MAX_EPOOL]? (QF_MAX_EPOOL &gt; 0U)" type="QF_EPOOL_TYPE_" visibility="0x00" properties="0x00">
<documentation>//! event pools managed by QF</documentation>
</attribute>
<!--${QF::QF-pkg::maxPool_}-->
<attribute name="maxPool_" type="std::uint_fast8_t" visibility="0x00" properties="0x00">
<documentation>//! number of initialized event pools</documentation>
</attribute>
<!--${QF::QF-pkg::bzero}-->
<operation name="bzero" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Clear a specified region of memory to zero
//!
//! @details
//! Clears a memory buffer by writing zeros byte-by-byte.
//!
//! @param[in] start pointer to the beginning of a memory buffer.
//! @param[in] len length of the memory buffer to clear (in bytes)
//!
//! @note The main application of this function is clearing the internal
//! QF variables upon startup. This is done to avoid problems with
//! non-standard startup code provided with some compilers and toolchains
//! (e.g., TI DSPs or Microchip MPLAB), which does not zero the
//! uninitialized variables, as required by the C++ standard.</documentation>
<!--${QF::QF-pkg::bzero::start}-->
<parameter name="start" type="void * const"/>
<!--${QF::QF-pkg::bzero::len}-->
<parameter name="len" type="std::uint_fast16_t const"/>
<code>std::uint8_t *ptr = static_cast&lt;std::uint8_t *&gt;(start);
for (std::uint_fast16_t n = len; n &gt; 0U; --n) {
*ptr = 0U;
++ptr;
}</code>
</operation>
</package>
</package>
<!--${QF-QMPool-impl}-->
<package name="QF-QMPool-impl" stereotype="0x02">
<!--${QF-QMPool-impl::QF_EPOOL_TYPE_}-->
<attribute name="QF_EPOOL_TYPE_" type="" visibility="0x03" properties="0x00">
<documentation>Native QF event pool</documentation>
<code>QMPool</code>
</attribute>
<!--${QF-QMPool-impl::QF_EPOOL_INIT_}-->
<operation name="QF_EPOOL_INIT_" type="" visibility="0x03" properties="0x00">
<documentation>Native QF event pool initialization</documentation>
<!--${QF-QMPool-impl::QF_EPOOL_INIT_::p_}-->
<parameter name="p_" type="QMPool *"/>
<!--${QF-QMPool-impl::QF_EPOOL_INIT_::poolSto_}-->
<parameter name="poolSto_" type="void *"/>
<!--${QF-QMPool-impl::QF_EPOOL_INIT_::poolSize_}-->
<parameter name="poolSize_" type="std::uint_fast32_t"/>
<!--${QF-QMPool-impl::QF_EPOOL_INIT_::evtSize_}-->
<parameter name="evtSize_" type="std::uint_fast16_t"/>
<code>\
(p_).init((poolSto_), (poolSize_), (evtSize_))</code>
</operation>
<!--${QF-QMPool-impl::QF_EPOOL_EVENT_SIZE_}-->
<operation name="QF_EPOOL_EVENT_SIZE_" type="" visibility="0x03" properties="0x00">
<documentation>Native QF event pool event-size getter</documentation>
<!--${QF-QMPool-impl::QF_EPOOL_EVENT_S~::p_}-->
<parameter name="p_" type="QMPool const *"/>
<code>((p_).getBlockSize())</code>
</operation>
<!--${QF-QMPool-impl::QF_EPOOL_GET_}-->
<operation name="QF_EPOOL_GET_" type="" visibility="0x03" properties="0x00">
<documentation>Native QF event pool get-event</documentation>
<!--${QF-QMPool-impl::QF_EPOOL_GET_::p_}-->
<parameter name="p_" type="QMPool *"/>
<!--${QF-QMPool-impl::QF_EPOOL_GET_::e_}-->
<parameter name="e_" type="QEvt *"/>
<!--${QF-QMPool-impl::QF_EPOOL_GET_::m_}-->
<parameter name="m_" type="std::uint_fast16_t"/>
<!--${QF-QMPool-impl::QF_EPOOL_GET_::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>\
((e_) = static_cast&lt;QEvt *&gt;((p_).get((m_), (qs_id_))))</code>
</operation>
<!--${QF-QMPool-impl::QF_EPOOL_PUT_}-->
<operation name="QF_EPOOL_PUT_" type="" visibility="0x03" properties="0x00">
<documentation>Native QF event pool put-event</documentation>
<!--${QF-QMPool-impl::QF_EPOOL_PUT_::p_}-->
<parameter name="p_" type="QMPool *"/>
<!--${QF-QMPool-impl::QF_EPOOL_PUT_::e_}-->
<parameter name="e_" type="QEvt *"/>
<!--${QF-QMPool-impl::QF_EPOOL_PUT_::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>((p_).put((e_), (qs_id_)))</code>
</operation>
</package>
<!--${QS-config}-->
<package name="QS-config" stereotype="0x02">
<!--${QS-config::QS_CTR_SIZE}-->
<attribute name="QS_CTR_SIZE?ndef QS_CTR_SIZE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! The size [bytes] of the internal QS buffer-counters. Valid values: 2U or 4U;
//! default 2U.
//!
//! @details
//! This macro can be defined in the QS port file (qs_port.hpp) to
//! configure the QS::QSCtr type. Here the macro is not defined so the
//! default of 2 byte is chosen.</documentation>
<code>2U</code>
</attribute>
<!--${QS-config::QS_CTR_SIZE defined incorrectly,~}-->
<attribute name="QS_CTR_SIZE defined incorrectly, expected 2U or 4U? (QS_CTR_SIZE != 2U) &amp;&amp; (QS_CTR_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
<!--${QS-config::QS_TIME_SIZE}-->
<attribute name="QS_TIME_SIZE?ndef QS_TIME_SIZE" type="unsigned" visibility="0x03" properties="0x00">
<documentation>//! Size (in bytes) of the QS time stamp
//!
//! @details
//! This macro can be defined in the QS port file (qs_port.hpp) to configure
//! the QP::QSTimeCtr type. Valid values 1U, 2U, 4U. Default 4U.</documentation>
<code>4U</code>
</attribute>
<!--${QS-config::QS_TIME_SIZE defined incorrectly~}-->
<attribute name="QS_TIME_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QS_TIME_SIZE != 1U) &amp;&amp; (QS_TIME_SIZE != 2U) &amp;&amp; (QS_TIME_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
</package>
<!--${QS-macros}-->
<package name="QS-macros" stereotype="0x02">
<!--${QS-macros::QS_INIT}-->
<operation name="QS_INIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! Initialize the QS facility
//!
//! @details
//! This macro provides an indirection layer to invoke the QS initialization
//! routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
//! @sa QP::QS::onStartup(), example of setting up a QS filter in
//! QS_GLB_FILTER()</documentation>
<!--${QS-macros::QS_INIT::arg_}-->
<parameter name="arg_" type="void *"/>
<code>(QP::QS::onStartup(arg_))</code>
</operation>
<!--${QS-macros::QS_EXIT}-->
<operation name="QS_EXIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! Cleanup the QS facility
//!
//! @details
//! This macro provides an indirection layer to invoke the QS cleanup
//! routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
//! @sa QP::QS::onCleanup()</documentation>
<code>(QP::QS::onCleanup())</code>
</operation>
<!--${QS-macros::QS_OUTPUT}-->
<operation name="QS_OUTPUT" type="void" visibility="0x03" properties="0x00">
<documentation>//! macro to handle the QS output from the application
//!
//! @note
//! If this macro is used, the application must define QS::doOutput().</documentation>
<code>(QP::QS::doOutput())</code>
</operation>
<!--${QS-macros::QS_RX_INPUT}-->
<operation name="QS_RX_INPUT" type="void" visibility="0x03" properties="0x00">
<documentation>//! macro to handle the QS-RX input to the application
//!
//! @note
//! If this macro is used, the application must define QS::doInput().</documentation>
<code>(QP::QS::doInput())</code>
</operation>
<!--${QS-macros::QS_GLB_FILTER}-->
<operation name="QS_GLB_FILTER" type="void" visibility="0x03" properties="0x00">
<documentation>//! Global Filter ON for a given record type `rec_`
//!
//! @details
//! This macro provides an indirection layer to call QP::QS::filterOn()
//! if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
//!
//! @sa
//! - QP::QSpyRecordGroups - QS record groups that can be used as `rec_`
//! - QP::QSpyRecords - individual QS records that can be used as `rec_`
//!
//! @usage
//! The following example shows how to use QS filters:
//! @include qs_filter.cpp</documentation>
<!--${QS-macros::QS_GLB_FILTER::rec_}-->
<parameter name="rec_" type="std::uint8_t"/>
<code>\
(QP::QS::glbFilter_(static_cast&lt;std::int_fast16_t&gt;(rec_)))</code>
</operation>
<!--${QS-macros::QS_LOC_FILTER}-->
<operation name="QS_LOC_FILTER" type="void" visibility="0x03" properties="0x00">
<documentation>//! Local Filter for a given state machine object `qs_id`
//! @details
//! This macro provides an indirection layer to call QS_locFilter_()
//! if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
//!
//! @sa
//! - QP::QSpyIdGroups - QS ID groups that can be used as `qs_id_`
//! - QP::QSpyIdOffsets - QS ID offsets for `qs_id_` (e.g., QS_AP_IDS + 5)
//!
//! The following example shows how to use QS filters:
//! @include qs_filter.cpp</documentation>
<!--${QS-macros::QS_LOC_FILTER::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>\
(QP::QS::locFilter_(static_cast&lt;std::int_fast16_t&gt;(qs_id_)))</code>
</operation>
<!--${QS-macros::QS_BEGIN_ID}-->
<operation name="QS_BEGIN_ID" type="void" visibility="0x03" properties="0x00">
<documentation>//! Begin an application-specific QS record with entering critical section
//!
//! @details
//! The following example shows how to build a user QS record using the
//! macros QS_BEGIN_ID(), QS_END(), and the formatted output macros:
//! QS_U8(), QS_STR(), etc.
//!
//! @note
//! Must always be used in pair with QS_END()
//!
//! @include qs_user.cpp</documentation>
<!--${QS-macros::QS_BEGIN_ID::rec_}-->
<parameter name="rec_" type="std::uint8_t"/>
<!--${QS-macros::QS_BEGIN_ID::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>\
if (QS_GLB_CHECK_(rec_) &amp;&amp; QS_LOC_CHECK_(qs_id_)) { \
QS_CRIT_STAT_ \
QS_CRIT_E_(); \
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(rec_)); \
QS_TIME_PRE_();</code>
</operation>
<!--${QS-macros::QS_END}-->
<operation name="QS_END" type="void" visibility="0x03" properties="0x00">
<documentation>//! End an applicationi-specific QS record with exiting critical section.
//! @sa example for QS_BEGIN_ID()
//! @note Must always be used in pair with QS_BEGIN_ID()</documentation>
<code>\
QP::QS::endRec_(); \
QS_CRIT_X_(); \
}</code>
</operation>
<!--${QS-macros::QS_FLUSH}-->
<operation name="QS_FLUSH" type="void" visibility="0x03" properties="0x00">
<documentation>//! Flush the QS trace data to the host
//!
//! @details
//! This macro invokes the QP::QS::flush() platform-dependent callback
//! function to flush the QS trace buffer to the host. The function
//! typically busy-waits until all the data in the buffer is sent to
//! the host. This is acceptable only in the initial transient.</documentation>
<code>(QP::QS::onFlush())</code>
</operation>
<!--${QS-macros::QS_BEGIN_NOCRIT}-->
<operation name="QS_BEGIN_NOCRIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! Begin an application-specific QS record WITHOUT entering critical section</documentation>
<!--${QS-macros::QS_BEGIN_NOCRIT::rec_}-->
<parameter name="rec_" type="std::uint8_t"/>
<!--${QS-macros::QS_BEGIN_NOCRIT::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>\
if (QS_GLB_CHECK_(rec_) &amp;&amp; QS_LOC_CHECK_(qs_id_)) { \
QP::QS::beginRec_(rec_); \
QS_TIME_PRE_();</code>
</operation>
<!--${QS-macros::QS_END_NOCRIT}-->
<operation name="QS_END_NOCRIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! End an application-specific QS record WITHOUT exiting critical section.</documentation>
<code>\
QP::QS::endRec_(); \
}</code>
</operation>
<!--${QS-macros::QS_GLB_CHECK_}-->
<operation name="QS_GLB_CHECK_" type="void" visibility="0x03" properties="0x00">
<documentation>//! Helper macro for checking the global QS filter</documentation>
<!--${QS-macros::QS_GLB_CHECK_::rec_}-->
<parameter name="rec_" type="std::uint8_t"/>
<code>\
((static_cast&lt;std::uint_fast8_t&gt;(QP::QS::priv_.glbFilter[ \
static_cast&lt;std::uint_fast8_t&gt;(rec_) &gt;&gt; 3U]) \
&amp; (static_cast&lt;std::uint_fast8_t&gt;(1U) \
&lt;&lt; (static_cast&lt;std::uint_fast8_t&gt;(rec_) &amp; 7U))) != 0U)</code>
</operation>
<!--${QS-macros::QS_LOC_CHECK_}-->
<operation name="QS_LOC_CHECK_" type="void" visibility="0x03" properties="0x00">
<documentation>//! Helper macro for checking the local QS filter</documentation>
<!--${QS-macros::QS_LOC_CHECK_::qs_id_}-->
<parameter name="qs_id_" type="std::uint8_t"/>
<code>\
((static_cast&lt;std::uint_fast8_t&gt;(QP::QS::priv_.locFilter \
[static_cast&lt;std::uint_fast8_t&gt;(qs_id_) &gt;&gt; 3U]) \
&amp; (static_cast&lt;std::uint_fast8_t&gt;(1U) \
&lt;&lt; (static_cast&lt;std::uint_fast8_t&gt;(qs_id_) &amp; 7U))) != 0U)</code>
</operation>
<!--${QS-macros::QS_REC_DONE}-->
<operation name="QS_REC_DONE?ndef QS_REC_DONE" type="void" visibility="0x03" properties="0x00">
<documentation>//! Macro to execute user code when a QS record is produced
//!
//! @note
//! This is a dummy definition in case this macro is undefined.</documentation>
<code>(static_cast&lt;void&gt;(0))</code>
</operation>
<!--${QS-macros::QS_I8}-->
<operation name="QS_I8" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::int8_t to the QS record</documentation>
<!--${QS-macros::QS_I8::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_I8::data_}-->
<parameter name="data_" type="std::int8_t"/>
<code>\
(QP::QS::u8_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;(((width_) &lt;&lt; 4U) &amp; 0x7U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::I8_ENUM_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_U8}-->
<operation name="QS_U8" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::uint8_t to the QS record</documentation>
<!--${QS-macros::QS_U8::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_U8::data_}-->
<parameter name="data_" type="std:u:int8_t"/>
<code>\
(QP::QS::u8_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::U8_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_I16}-->
<operation name="QS_I16" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::int16_t to the QS record</documentation>
<!--${QS-macros::QS_I16::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_I16::data_}-->
<parameter name="data_" type="std::int16_t"/>
<code>\
(QP::QS::u16_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::I16_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_U16}-->
<operation name="QS_U16" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::uint16_t to the QS record</documentation>
<!--${QS-macros::QS_U16::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_U16::data_}-->
<parameter name="data_" type="std:u:int16_t"/>
<code>\
(QP::QS::u16_fmt_(static_cast&lt;std::uint8_t&gt;((((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::U16_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_I32}-->
<operation name="QS_I32" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::int32_t to the QS record</documentation>
<!--${QS-macros::QS_I32::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_I32::data_}-->
<parameter name="data_" type="std::int32_t"/>
<code>\
(QP::QS::u32_fmt_( \
static_cast&lt;std::uint8_t&gt;((static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::I32_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_U32}-->
<operation name="QS_U32" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::uint32_t to the QS record</documentation>
<!--${QS-macros::QS_U32::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_U32::data_}-->
<parameter name="data_" type="std:u:int32_t"/>
<code>\
(QP::QS::u32_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::U32_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_I64}-->
<operation name="QS_I64" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::int64_t to the QS record</documentation>
<!--${QS-macros::QS_I64::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_I64::data_}-->
<parameter name="data_" type="std::int64_t"/>
<code>\
(QP::QS::u64_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::I64_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_U64}-->
<operation name="QS_U64" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted std::uint64_t to the QS record</documentation>
<!--${QS-macros::QS_U64::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_U64::data_}-->
<parameter name="data_" type="std:u:int64_t"/>
<code>\
(QP::QS::u64_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::U64_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_F32}-->
<operation name="QS_F32" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted 32-bit floating point number to the QS record</documentation>
<!--${QS-macros::QS_F32::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_F32::data_}-->
<parameter name="data_" type="float32_t"/>
<code>\
(QP::QS::f32_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::F32_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_F64}-->
<operation name="QS_F64" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted 64-bit floating point number to the QS record</documentation>
<!--${QS-macros::QS_F64::width_}-->
<parameter name="width_" type="std::uint8_t"/>
<!--${QS-macros::QS_F64::data_}-->
<parameter name="data_" type="float64_t"/>
<code> \
(QP::QS::f64_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::F64_T)), (data_)))</code>
</operation>
<!--${QS-macros::QS_STR}-->
<operation name="QS_STR" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted zero-terminated ASCII string to the QS record</documentation>
<!--${QS-macros::QS_STR::str_}-->
<parameter name="str_" type="char const *"/>
<code>(QP::QS::str_fmt_(str_))</code>
</operation>
<!--${QS-macros::QS_MEM}-->
<operation name="QS_MEM" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted memory block of up to 255 bytes to the QS record</documentation>
<!--${QS-macros::QS_MEM::mem_}-->
<parameter name="mem_" type="void *"/>
<!--${QS-macros::QS_MEM::size_}-->
<parameter name="size_" type="std:u:int8_t"/>
<code>(QP::QS::mem_fmt_((mem_), (size_)))</code>
</operation>
<!--${QS-macros::QS_ENUM}-->
<operation name="QS_ENUM" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted enumeration to the QS record</documentation>
<!--${QS-macros::QS_ENUM::group_}-->
<parameter name="group_" type="std::uint8_t const"/>
<!--${QS-macros::QS_ENUM::value_}-->
<parameter name="value_" type="enum_t const"/>
<code>\
(QP::QS::u8_fmt_(static_cast&lt;std::uint8_t&gt;(0x80U | ((group_) &lt;&lt; 4U)) \
| static_cast&lt;std::uint8_t&gt;(QP::QS::I8_ENUM_T),\
static_cast&lt;std::uint8_t&gt;(value_)))</code>
</operation>
<!--${QS-macros::QS_TIME_PRE_}-->
<operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output time stamp to a QS record (used in predefined
//! and application-specific trace records)</documentation>
<code>(QP::QS::u32_raw_(QP::QS::onGetTime()))</code>
</operation>
<!--${QS-macros::QS_TIME_PRE_}-->
<operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
<code>(QP::QS::u16_raw_(QP::QS::onGetTime()))</code>
</operation>
<!--${QS-macros::QS_TIME_PRE_}-->
<operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
<code>(QP::QS::u8_raw_(QP::QS::onGetTime()))</code>
</operation>
<!--${QS-macros::QS_OBJ}-->
<operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted object pointer to the QS record</documentation>
<!--${QS-macros::QS_OBJ::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>(QP::QS::u32_fmt_(QP::QS::OBJ_T, \
reinterpret_cast&lt;std::uint32_t&gt;(obj_)))</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>(QP::QS::u16_fmt_(QP::QS::OBJ_T, \
reinterpret_cast&lt;std::uint16_t&gt;(obj_)))</code>
</operation>
<!--${QS-macros::QS_OBJ}-->
<operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
<!--${QS-macros::QS_OBJ::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>(QP::QS::u8_fmt_(QP::QS::OBJ_T, \
reinterpret_cast&lt;std::uint8_t&gt;(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>(QP::QS::u64_fmt_(QP::QS::OBJ_T, \
reinterpret_cast&lt;std::uint64_t&gt;(obj_)))</code>
</operation>
<!--${QS-macros::QS_FUN}-->
<operation name="QS_FUN? (QS_FUN_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted function pointer to the QS record</documentation>
<!--${QS-macros::QS_FUN::fun_}-->
<parameter name="fun_" type="QSpyFunPtr"/>
<code>(QP::QS::u32_fmt_(QP::QS::FUN_T, \
reinterpret_cast&lt;std::uint32_t&gt;(fun_)))</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>(QP::QS::u16_fmt_(QP::QS::FUN_T, \
reinterpret_cast&lt;std::uint16_t&gt;(fun_)))</code>
</operation>
<!--${QS-macros::QS_FUN}-->
<operation name="QS_FUN? (QS_FUN_PTR_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
<!--${QS-macros::QS_FUN::fun_}-->
<parameter name="fun_" type="QSpyFunPtr"/>
<code>(QP::QS::u8_fmt_(QP::QS::FUN_T, \
reinterpret_cast&lt;std::uint8_t&gt;(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>(QP::QS::u64_fmt_(QP::QS::FUN_T, \
reinterpret_cast&lt;std::uint64_t&gt;(fun_)))</code>
</operation>
<!--${QS-macros::QS_SIG}-->
<operation name="QS_SIG? (Q_SIGNAL_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output formatted event signal (of type QP::QSignal) and
//! the state machine object to the user QS record</documentation>
<!--${QS-macros::QS_SIG::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<!--${QS-macros::QS_SIG::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>\
QP::QS::u32_fmt_(QP::QS::SIG_T, static_cast&lt;std::uint32_t&gt;(sig_)); \
QP::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="QP::QSignal"/>
<!--${QS-macros::QS_SIG::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>\
QP::QS::u16_fmt_(QP::QS::SIG_T, static_cast&lt;std::uint16_t&gt;(sig_)); \
QP::QS::obj_raw_(obj_)</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="QP::QSignal"/>
<!--${QS-macros::QS_SIG::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>\
QP::QS::u8_fmt_(QP::QS::SIG_T, static_cast&lt;std::uint8_t&gt;(sig_)); \
QP::QS::obj_raw_(obj_)</code>
</operation>
<!--${QS-macros::QS_SIG_DICTIONARY}-->
<operation name="QS_SIG_DICTIONARY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output signal dictionary record
//!
//! @details
//! A signal dictionary record associates the numerical value of the signal
//! and the binary address of the state machine that consumes that signal
//! with the human-readable name of the signal.
//!
//! @param[in] sig_ event signal (typically enumerated, e.g. `TIMEOUT_SIG`)
//! @param[in] obj_ pointer to the associated state machine object
//! (might be `nullptr` for globally recognized signals)
//!
//! A signal dictionary entry is associated with both the signal value `sig_`
//! and the state machine `obj_`, because signals are required to be unique
//! only within a given state machine and therefore the same numerical values
//! can represent different signals in different state machines.
//!
//! For the &quot;global&quot; signals that have the same meaning in all state machines
//! (such as globally published signals), you can specify a signal dictionary
//! entry with the `obj_` parameter set to `nullptr`.
//!
//! The following example shows the definition of signal dictionary entries
//! in the initial transition of the Table active object. Please note that
//! signals HUNGRY_SIG and DONE_SIG are associated with the Table state
//! machine only (&quot;me&quot; `obj_` pointer). The EAT_SIG signal, on the other
//! hand, is global (`obj_ == nullptr`):
//! @include qs_sigDic.cpp
//!
//! The following QSpy log example shows the signal dictionary records
//! generated from the Table initial transition and subsequent records that
//! show human-readable names of the signals:
//! @include qs_sigLog.txt</documentation>
<!--${QS-macros::QS_SIG_DICTIONAR~::sig_}-->
<parameter name="sig_" type="QP::QSignal"/>
<!--${QS-macros::QS_SIG_DICTIONAR~::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>\
(QP::QS::sig_dict_pre_((sig_), (obj_), #sig_))</code>
</operation>
<!--${QS-macros::QS_OBJ_DICTIONARY}-->
<operation name="QS_OBJ_DICTIONARY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output QS object dictionary record
//!
//! @details
//! An object dictionary record associates the binary address of an object
//! in the target's memory with the human-readable name of the object.
//!
//! @param[in] obj_ pointer to the object (any object)
//!
//! The following example shows the definition of object dictionary entry
//! for the Table active object:
//! @include qs_objDic.cpp</documentation>
<!--${QS-macros::QS_OBJ_DICTIONAR~::obj_}-->
<parameter name="obj_" type="void const *"/>
<code>\
(QP::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">
<documentation>//! Output QS object-array dictionary record
//!
//! @details
//! An object array dictionary record associates the binary address of the
//! object element in the target's memory with the human-readable name
//! of the object.
//!
//! @param[in] obj_ pointer to the object (any object)
//! @param[in] idx_ array index
//!
//! The following example shows the definition of object array dictionary
//! for `Philo::inst[n]` and `Philo::inst[n].m_timeEvt`:
//! @include qs_objArrDic.cpp</documentation>
<!--${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>\
(QP::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">
<documentation>//! Output function dictionary record
//!
//! @details
//! A function dictionary record associates the binary address of a function
//! in the target's memory with the human-readable name of the function.
//!
//! Providing a function dictionary QS record can vastly improve readability
//! of the QS log, because instead of dealing with cryptic machine addresses
//! the QSpy host utility can display human-readable function names.
//!
//! The example from #QS_SIG_DICTIONARY shows the definition of a function
//! dictionary.</documentation>
<!--${QS-macros::QS_FUN_DICTIONAR~::fun_}-->
<parameter name="fun_" type="QSpyFunPtr"/>
<code>\
(QP::QS::fun_dict_pre_( \
QP::QS::force_cast&lt;void (*)(void)&gt;(fun_), #fun_))</code>
</operation>
<!--${QS-macros::QS_USR_DICTIONARY}-->
<operation name="QS_USR_DICTIONARY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output user QS record dictionary record
//!
//! @details
//! A user QS record dictionary record associates the numerical value of a
//! user record with the human-readable identifier.</documentation>
<!--${QS-macros::QS_USR_DICTIONAR~::rec_}-->
<parameter name="rec_" type="std::unit8_t"/>
<code>\
(QP::QS::usr_dict_pre_((rec_), #rec_))</code>
</operation>
<!--${QS-macros::QS_ENUM_DICTIONARY}-->
<operation name="QS_ENUM_DICTIONARY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output enumeration dictionary record
//!
//! @details
//! An enum QS record dictionary record associates the numerical value of
//! an enumeration with the human-readable identifier.</documentation>
<!--${QS-macros::QS_ENUM_DICTIONA~::value_}-->
<parameter name="value_" type="enum_t const"/>
<!--${QS-macros::QS_ENUM_DICTIONA~::group_}-->
<parameter name="group_" type="std::uint8_t const"/>
<code>\
(QP::QS::enum_dict_pre_((value_), (group_), #value_))</code>
</operation>
<!--${QS-macros::QF_QS_CRIT_ENTRY}-->
<operation name="QF_QS_CRIT_ENTRY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output the critical section entry record</documentation>
<code>(QP::QS::crit_entry_pre_())</code>
</operation>
<!--${QS-macros::QF_QS_CRIT_EXIT}-->
<operation name="QF_QS_CRIT_EXIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output the critical section exit record</documentation>
<code>(QP::QS::crit_exit_pre_())</code>
</operation>
<!--${QS-macros::QF_QS_ISR_ENTRY}-->
<operation name="QF_QS_ISR_ENTRY" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output the interrupt entry record</documentation>
<!--${QS-macros::QF_QS_ISR_ENTRY::isrnest_}-->
<parameter name="isrnest_" type="std::uint_fast8_t"/>
<!--${QS-macros::QF_QS_ISR_ENTRY::prio_}-->
<parameter name="prio_" type="std::uint_fast8_t"/>
<code>\
(QP::QS::isr_entry_pre_((isrnest_), (prio_)))</code>
</operation>
<!--${QS-macros::QF_QS_ISR_EXIT}-->
<operation name="QF_QS_ISR_EXIT" type="void" visibility="0x03" properties="0x00">
<documentation>//! Output the interrupt exit record</documentation>
<!--${QS-macros::QF_QS_ISR_EXIT::isrnest_}-->
<parameter name="isrnest_" type="std::uint_fast8_t"/>
<!--${QS-macros::QF_QS_ISR_EXIT::prio_}-->
<parameter name="prio_" type="std::uint_fast8_t"/>
<code>\
(QP::QS::isr_exit_pre_((isrnest_), (prio_)))</code>
</operation>
<!--${QS-macros::QF_QS_ACTION}-->
<operation name="QF_QS_ACTION" type="void" visibility="0x03" properties="0x00">
<documentation>//! Execute an action that is only necessary for QS output</documentation>
<!--${QS-macros::QF_QS_ACTION::act_}-->
<parameter name="act_" type="&lt;action code&gt;"/>
<code>(act_)</code>
</operation>
<!--${QS-macros::QS_ASSERTION}-->
<operation name="QS_ASSERTION" type="void" visibility="0x03" properties="0x00">
<documentation>//! Produce the assertion failure trace record</documentation>
<!--${QS-macros::QS_ASSERTION::module_}-->
<parameter name="module_" type="char const *"/>
<!--${QS-macros::QS_ASSERTION::loc_}-->
<parameter name="loc_" type="int_t"/>
<!--${QS-macros::QS_ASSERTION::delay_}-->
<parameter name="delay_" type="unsigned"/>
<code>\
(QP::QS::assertion_pre_((module_), (loc_), (delay_)))</code>
</operation>
<!--${QS-macros::QS_EOD}-->
<attribute name="QS_EOD" type="std::uint16_t" visibility="0x03" properties="0x00">
<documentation>//! Constant representing End-Of-Data condition returned from the
//! QS::getByte() function.</documentation>
<code>(static_cast&lt;std::uint16_t&gt;(0xFFFFU))</code>
</attribute>
<!--${QS-macros::QS_CMD}-->
<attribute name="QS_CMD" type="std::uint8_t" visibility="0x03" properties="0x00">
<documentation>//! Constant representing command enumeration group
//! in QS_ENUM_DICTIONARY() and QS_ENUM()
//! @sa QS::onCommand()</documentation>
<code>(static_cast&lt;std::uint8_t&gt;(7U))</code>
</attribute>
<!--${QS-macros::QS_HEX_FMT}-->
<attribute name="QS_HEX_FMT" type="std::uint8_t" visibility="0x03" properties="0x00">
<documentation>//! Constant representing HEX format for the &quot;width&quot; filed
//! in QS_U8(), QS_U16(), QS_U32(), and QS_U64().</documentation>
<code>(static_cast&lt;std::uint8_t&gt;(0x0FU))</code>
</attribute>
</package>
<!--${QS}-->
<package name="QS" stereotype="0x05" namespace="QP::">
<!--${QS::QSCtr}-->
<attribute name="QSCtr? (QS_CTR_SIZE == 2U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! QS ring buffer counter and offset type</documentation>
<code>= std::uint16_t;</code>
</attribute>
<!--${QS::QSCtr}-->
<attribute name="QSCtr? (QS_CTR_SIZE == 4U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint32_t;</code>
</attribute>
<!--${QS::QSTimeCtr}-->
<attribute name="QSTimeCtr? (QS_TIME_SIZE == 4U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! QS time stamp type, which determines the dynamic range of QS time stamps</documentation>
<code>= std::uint32_t;</code>
</attribute>
<!--${QS::QSTimeCtr}-->
<attribute name="QSTimeCtr? (QS_TIME_SIZE == 2U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint16_t;</code>
</attribute>
<!--${QS::QSTimeCtr}-->
<attribute name="QSTimeCtr? (QS_TIME_SIZE == 1U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint8_t;</code>
</attribute>
<!--${QS::QSFun}-->
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 4U)" type="using" visibility="0x04" properties="0x00">
<documentation>//! QS function pointer type (for serializing function pointers)</documentation>
<code>= std::uint32_t;</code>
</attribute>
<!--${QS::QSFun}-->
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 8U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint64_t;</code>
</attribute>
<!--${QS::QSFun}-->
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 2U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint16_t;</code>
</attribute>
<!--${QS::QSFun}-->
<attribute name="QSFun? (QS_FUN_PTR_SIZE == 1U)" type="using" visibility="0x04" properties="0x00">
<code>= std::uint8_t;</code>
</attribute>
<!--${QS::QSpyPre}-->
<attribute name="QSpyPre" type="enum" visibility="0x04" properties="0x00">
<documentation>//! QS pre-defined record types (TX channel)
//!
//! @details
//! This enumeration specifies the record types used in the QP components.
//! You can specify your own record types starting from QP::QS_USER offset.
//! Currently, the maximum of all records cannot exceed 125.
//!
//! @note
//! The QS records labeled as &quot;not maskable&quot; are always enabled and cannot
//! be turend off with the QS_GLB_FILTER() macro. Other QS trace records
//! can be disabled by means of the &quot;global filters&quot;
//!
//! @sa QS_GLB_FILTER() macro</documentation>
<code>: std::int8_t {
// [0] QS session (not maskable)
QS_EMPTY, //!&lt; QS record for cleanly starting a session
// [1] SM records
QS_QEP_STATE_ENTRY, //!&lt; a state was entered
QS_QEP_STATE_EXIT, //!&lt; a state was exited
QS_QEP_STATE_INIT, //!&lt; an initial transition was taken in a state
QS_QEP_INIT_TRAN, //!&lt; the top-most initial transition was taken
QS_QEP_INTERN_TRAN, //!&lt; an internal transition was taken
QS_QEP_TRAN, //!&lt; a regular transition was taken
QS_QEP_IGNORED, //!&lt; an event was ignored (silently discarded)
QS_QEP_DISPATCH, //!&lt; an event was dispatched (begin of RTC step)
QS_QEP_UNHANDLED, //!&lt; an event was unhandled due to a guard
// [10] Active Object (AO) records
QS_QF_ACTIVE_DEFER, //!&lt; AO deferred an event
QS_QF_ACTIVE_RECALL, //!&lt; AO recalled an event
QS_QF_ACTIVE_SUBSCRIBE, //!&lt; an AO subscribed to an event
QS_QF_ACTIVE_UNSUBSCRIBE,//!&lt; an AO unsubscribed to an event
QS_QF_ACTIVE_POST, //!&lt; an event was posted (FIFO) directly to AO
QS_QF_ACTIVE_POST_LIFO, //!&lt; an event was posted (LIFO) directly to AO
QS_QF_ACTIVE_GET, //!&lt; AO got an event and its queue is not empty
QS_QF_ACTIVE_GET_LAST,//!&lt; AO got an event and its queue is empty
QS_QF_ACTIVE_RECALL_ATTEMPT, //!&lt; AO attempted to recall an event
// [19] Event Queue (EQ) records
QS_QF_EQUEUE_POST, //!&lt; an event was posted (FIFO) to a raw queue
QS_QF_EQUEUE_POST_LIFO, //!&lt; an event was posted (LIFO) to a raw queue
QS_QF_EQUEUE_GET, //!&lt; get an event and queue still not empty
QS_QF_EQUEUE_GET_LAST,//!&lt; get the last event from the queue
// [23] Framework (QF) records
QS_QF_NEW_ATTEMPT, //!&lt; an attempt to allocate an event failed
// [24] Memory Pool (MP) records
QS_QF_MPOOL_GET, //!&lt; a memory block was removed from memory pool
QS_QF_MPOOL_PUT, //!&lt; a memory block was returned to memory pool
// [26] Additional Framework (QF) records
QS_QF_PUBLISH, //!&lt; an event was published to active objects
QS_QF_NEW_REF, //!&lt; new event reference was created
QS_QF_NEW, //!&lt; new event was created
QS_QF_GC_ATTEMPT, //!&lt; garbage collection attempt
QS_QF_GC, //!&lt; garbage collection
QS_QF_TICK, //!&lt; QTimeEvt::tick_() was called
// [32] Time Event (TE) records
QS_QF_TIMEEVT_ARM, //!&lt; a time event was armed
QS_QF_TIMEEVT_AUTO_DISARM, //!&lt; a time event expired and was disarmed
QS_QF_TIMEEVT_DISARM_ATTEMPT,//!&lt; attempt to disarm a disarmed QTimeEvt
QS_QF_TIMEEVT_DISARM, //!&lt; true disarming of an armed time event
QS_QF_TIMEEVT_REARM, //!&lt; rearming of a time event
QS_QF_TIMEEVT_POST, //!&lt; a time event posted itself directly to an AO
// [38] Additional Framework (QF) records
QS_QF_DELETE_REF, //!&lt; an event reference is about to be deleted
QS_QF_CRIT_ENTRY, //!&lt; critical section was entered
QS_QF_CRIT_EXIT, //!&lt; critical section was exited
QS_QF_ISR_ENTRY, //!&lt; an ISR was entered
QS_QF_ISR_EXIT, //!&lt; an ISR was exited
QS_QF_INT_DISABLE, //!&lt; interrupts were disabled
QS_QF_INT_ENABLE, //!&lt; interrupts were enabled
// [45] Additional Active Object (AO) records
QS_QF_ACTIVE_POST_ATTEMPT, //!&lt; attempt to post an evt to AO failed
// [46] Additional Event Queue (EQ) records
QS_QF_EQUEUE_POST_ATTEMPT, //!&lt; attempt to post evt to QEQueue failed
// [47] Additional Memory Pool (MP) records
QS_QF_MPOOL_GET_ATTEMPT, //!&lt; attempt to get a memory block failed
// [48] Scheduler (SC) records
QS_SCHED_PREEMPT, //!&lt; scheduler asynchronously preempted a task
QS_SCHED_RESTORE, //!&lt; scheduler restored preempted task
QS_SCHED_LOCK, //!&lt; scheduler was locked
QS_SCHED_UNLOCK, //!&lt; scheduler was unlocked
QS_SCHED_NEXT, //!&lt; scheduler found next task to execute
QS_SCHED_IDLE, //!&lt; scheduler became idle
// [54] Miscellaneous QS records (not maskable)
QS_ENUM_DICT, //!&lt; enumeration dictionary entry
// [55] Additional QEP records
QS_QEP_TRAN_HIST, //!&lt; a tran to history was taken
QS_QEP_TRAN_EP, //!&lt; a tran to entry point into a submachine
QS_QEP_TRAN_XP, //!&lt; a tran to exit point out of a submachine
// [58] Miscellaneous QS records (not maskable)
QS_TEST_PAUSED, //!&lt; test has been paused
QS_TEST_PROBE_GET, //!&lt; reports that Test-Probe has been used
QS_SIG_DICT, //!&lt; signal dictionary entry
QS_OBJ_DICT, //!&lt; object dictionary entry
QS_FUN_DICT, //!&lt; function dictionary entry
QS_USR_DICT, //!&lt; user QS record dictionary entry
QS_TARGET_INFO, //!&lt; reports the Target information
QS_TARGET_DONE, //!&lt; reports completion of a user callback
QS_RX_STATUS, //!&lt; reports QS data receive status
QS_QUERY_DATA, //!&lt; reports the data from &quot;current object&quot; query
QS_PEEK_DATA, //!&lt; reports the data from the PEEK query
QS_ASSERT_FAIL, //!&lt; assertion failed in the code
QS_QF_RUN, //!&lt; QF_run() was entered
// [71] Semaphore (SEM) records
QS_SEM_TAKE, //!&lt; a semaphore was taken by a thread
QS_SEM_BLOCK, //!&lt; a semaphore blocked a thread
QS_SEM_SIGNAL, //!&lt; a semaphore was signaled
QS_SEM_BLOCK_ATTEMPT, //!&lt; a semaphore blocked was attempted
// [75] Mutex (MTX) records
QS_MTX_LOCK, //!&lt; a mutex was locked
QS_MTX_BLOCK, //!&lt; a mutex blocked a thread
QS_MTX_UNLOCK, //!&lt; a mutex was unlocked
QS_MTX_LOCK_ATTEMPT, //!&lt; a mutex lock was attempted
QS_MTX_BLOCK_ATTEMPT, //!&lt; a mutex blocking was attempted
QS_MTX_UNLOCK_ATTEMPT,//!&lt; a mutex unlock was attempted
// [81]
QS_PRE_MAX, //!&lt; the number of predefined signals
};</code>
</attribute>
<!--${QS::QSpyGroups}-->
<attribute name="QSpyGroups" type="enum" visibility="0x04" properties="0x00">
<documentation>//! QS record groups for QS_GLB_FILTER()</documentation>
<code>: std::int16_t {
QS_ALL_RECORDS = static_cast&lt;std::uint8_t&gt;(0xF0U), //!&lt; all QS records
QS_SM_RECORDS, //!&lt; State Machine QS records
QS_AO_RECORDS, //!&lt; Active Object QS records
QS_EQ_RECORDS, //!&lt; Event Queues QS records
QS_MP_RECORDS, //!&lt; Memory Pools QS records
QS_TE_RECORDS, //!&lt; Time Events QS records
QS_QF_RECORDS, //!&lt; QF QS records
QS_SC_RECORDS, //!&lt; Scheduler QS records
QS_SEM_RECORDS, //!&lt; Semaphore QS records
QS_MTX_RECORDS, //!&lt; Mutex QS records
QS_U0_RECORDS, //!&lt; User Group 100-104 records
QS_U1_RECORDS, //!&lt; User Group 105-109 records
QS_U2_RECORDS, //!&lt; User Group 110-114 records
QS_U3_RECORDS, //!&lt; User Group 115-119 records
QS_U4_RECORDS, //!&lt; User Group 120-124 records
QS_UA_RECORDS, //!&lt; All User records
};</code>
</attribute>
<!--${QS::QSpyUserOffsets}-->
<attribute name="QSpyUserOffsets" type="enum" visibility="0x04" properties="0x00">
<documentation>//! QS user record group offsets for QS_GLB_FILTER()</documentation>
<code>: std::int16_t {
QS_USER = 100, //!&lt; the first record available to QS users
QS_USER0 = QS_USER, //!&lt; offset for User Group 0
QS_USER1 = QS_USER0 + 5, //!&lt; offset of Group 1
QS_USER2 = QS_USER1 + 5, //!&lt; offset of Group 2
QS_USER3 = QS_USER2 + 5, //!&lt; offset of Group 3
QS_USER4 = QS_USER3 + 5, //!&lt; offset of Group 4
};</code>
</attribute>
<!--${QS::QSpyIdOffsets}-->
<attribute name="QSpyIdOffsets" type="enum" visibility="0x04" properties="0x00">
<documentation>//! QS ID offsets for QS_LOC_FILTER()</documentation>
<code>: std::int16_t {
QS_AO_ID = 0, //!&lt; offset for AO priorities
QS_EP_ID = 64, //!&lt; offset for event-pool IDs
QS_EQ_ID = 80, //!&lt; offset for event-queue IDs
QS_AP_ID = 96, //!&lt; offset for Appl-spec IDs
};</code>
</attribute>
<!--${QS::QSpyIdGroups}-->
<attribute name="QSpyIdGroups" type="enum" visibility="0x04" properties="0x00">
<documentation>//! QS ID groups for QS_LOC_FILTER()</documentation>
<code>: std::int16_t {
QS_ALL_IDS = 0xF0, //!&lt; all QS IDs
QS_AO_IDS = 0x80 + QS_AO_ID, //!&lt; AO IDs (priorities)
QS_EP_IDS = 0x80 + QS_EP_ID, //!&lt; event-pool IDs
QS_EQ_IDS = 0x80 + QS_EQ_ID, //!&lt; event-queue IDs
QS_AP_IDS = 0x80 + QS_AP_ID, //!&lt; Application-specific IDs
};</code>
</attribute>
<!--${QS::QSpyFunPtr}-->
<attribute name="QSpyFunPtr" type="using" visibility="0x04" properties="0x01">
<documentation>//! function pointer type for fun_dict_pre_()</documentation>
<code>= void (*)();</code>
</attribute>
<!--${QS::QSpyId}-->
<attribute name="QSpyId" type="struct" visibility="0x04" properties="0x00">
<documentation>//! QS ID type for applying local filtering</documentation>
<code>{
std::uint8_t m_prio; //!&lt; &quot;priority&quot; (qs_id) for the QS &quot;local filter&quot;
//! get the &quot;priority&quot; (qs_id) from the QSpyId opbject
std::uint_fast8_t getPrio() const noexcept {
return static_cast&lt;std::uint_fast8_t&gt;(m_prio);
}
};</code>
</attribute>
<!--${QS::QS-tx}-->
<package name="QS-tx" stereotype="0x02" namespace="QS::">
<!--${QS::QS-tx::QStx}-->
<class name="QStx">
<documentation>//! QS software tracing, output QS-TX</documentation>
<!--${QS::QS-tx::QStx::glbFilter[16]}-->
<attribute name="glbFilter[16]" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! global on/off QS filter</documentation>
</attribute>
<!--${QS::QS-tx::QStx::locFilter[16]}-->
<attribute name="locFilter[16]" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! local on/off QS filter</documentation>
</attribute>
<!--${QS::QS-tx::QStx::locFilter_AP}-->
<attribute name="locFilter_AP" type="void const *" visibility="0x00" properties="0x00">
<documentation>//! old local QS filter
// @deprecated</documentation>
</attribute>
<!--${QS::QS-tx::QStx::buf}-->
<attribute name="buf" type="std::uint8_t *" visibility="0x00" properties="0x00">
<documentation>//! pointer to the start of the QS-TX ring buffer</documentation>
</attribute>
<!--${QS::QS-tx::QStx::end}-->
<attribute name="end" type="QSCtr" visibility="0x00" properties="0x00">
<documentation>//! offset of the end of the ring buffer</documentation>
</attribute>
<!--${QS::QS-tx::QStx::head}-->
<attribute name="head" type="QSCtr volatile" visibility="0x00" properties="0x00">
<documentation>//! offset to where next byte will be inserted</documentation>
</attribute>
<!--${QS::QS-tx::QStx::tail}-->
<attribute name="tail" type="QSCtr volatile" visibility="0x00" properties="0x00">
<documentation>//! offset of where next record will be extracted</documentation>
</attribute>
<!--${QS::QS-tx::QStx::used}-->
<attribute name="used" type="QSCtr volatile" visibility="0x00" properties="0x00">
<documentation>//! number of bytes currently in the ring buffer</documentation>
</attribute>
<!--${QS::QS-tx::QStx::seq}-->
<attribute name="seq" type="std::uint8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! sequence number of the last inserted QS record</documentation>
</attribute>
<!--${QS::QS-tx::QStx::chksum}-->
<attribute name="chksum" type="std::uint8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! checksum of the currently inserted record</documentation>
</attribute>
<!--${QS::QS-tx::QStx::critNest}-->
<attribute name="critNest" type="std::uint8_t volatile" visibility="0x00" properties="0x00">
<documentation>//! critical section nesting level</documentation>
</attribute>
<!--${QS::QS-tx::QStx::flags}-->
<attribute name="flags" type="std::uint8_t" visibility="0x00" properties="0x00">
<documentation>//! flags for internal use</documentation>
</attribute>
</class>
<!--${QS::QS-tx::QSType}-->
<attribute name="QSType" type="enum" visibility="0x04" properties="0x01">
<documentation>//! Enumerates data elements for app-specific trace records</documentation>
<code>: std::uint8_t {
I8_ENUM_T, //!&lt; signed 8-bit integer or enum format
U8_T, //!&lt; unsigned 8-bit integer format
I16_T, //!&lt; signed 16-bit integer format
U16_T, //!&lt; unsigned 16-bit integer format
I32_T, //!&lt; signed 32-bit integer format
U32_T, //!&lt; unsigned 32-bit integer format
F32_T, //!&lt; 32-bit floating point format
F64_T, //!&lt; 64-bit floating point format
STR_T, //!&lt; zero-terminated ASCII string format
MEM_T, //!&lt; up to 255-bytes memory block format
SIG_T, //!&lt; event signal format
OBJ_T, //!&lt; object pointer format
FUN_T, //!&lt; function pointer format
I64_T, //!&lt; signed 64-bit integer format
U64_T, //!&lt; unsigned 64-bit integer format
};</code>
</attribute>
<!--${QS::QS-tx::priv_}-->
<attribute name="priv_" type="QStx" visibility="0x00" properties="0x01">
<documentation>//! the only instance of the QS-TX object (Singleton)</documentation>
</attribute>
<!--${QS::QS-tx::force_cast}-->
<operation name="force_cast" type="template&lt;typename T_OUT, typename T_IN&gt; T_OUT" visibility="0x00" properties="0x02">
<documentation>//! template for forcing cast of member functions for function
//! dictionaries and test probes.
//!
//! @tparam T_OUT type of the returned representation
//! @tparam T_IN type of the provided representation
//!
//! @returns the binary representation of `T_IN` as `T_OUT`</documentation>
<!--${QS::QS-tx::force_cast::in}-->
<parameter name="in" type="T_IN"/>
<code>union TCast {
T_IN in;
T_OUT out;
} u = { in };
return u.out;</code>
</operation>
<!--${QS::QS-tx::initBuf}-->
<operation name="initBuf" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Initialize the QS data buffer
//!
//! @details
//! This function should be called from QP::QS::onStartup() to provide
//! QS with the data buffer. The first argument `sto[]` is the address
//! of the memory block, and the second argument `stoSize` is the size
//! of this block [in bytes]. Currently the size of the QS buffer cannot
//! exceed 64KB.
//!
//! @note
//! QS can work with quite small data buffers, but you will start losing
//! data if the buffer is too small for the bursts of tracing activity.
//! The right size of the buffer depends on the data production rate and
//! the data output rate. QS offers flexible filtering to reduce the data
//! production rate.
//!
//! @note
//! If the data output rate cannot keep up with the production rate,
//! QS will start overwriting the older data with newer data. This is
//! consistent with the &quot;last-is-best&quot; QS policy. The record sequence
//! counters and check sums on each record allow the QSPY host utility
//! to easily detect any data loss.</documentation>
<!--${QS::QS-tx::initBuf::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${QS::QS-tx::initBuf::stoSize}-->
<parameter name="stoSize" type="std::uint_fast32_t const"/>
<code>// the provided buffer must be at least 8 bytes long
Q_REQUIRE_ID(100, stoSize &gt; 8U);
// This function initializes all the internal QS variables, so that the
// tracing can start correctly even if the startup code fails to clear
// any uninitialized data (as is required by the C Standard).
//
glbFilter_(-static_cast&lt;enum_t&gt;(QS_ALL_RECORDS));// all global filters OFF
locFilter_(static_cast&lt;enum_t&gt;(QS_ALL_IDS)); // all local filters ON
priv_.locFilter_AP = nullptr; // deprecated &quot;AP-filter&quot;
priv_.buf = sto;
priv_.end = static_cast&lt;QSCtr&gt;(stoSize);
priv_.head = 0U;
priv_.tail = 0U;
priv_.used = 0U;
priv_.seq = 0U;
priv_.chksum = 0U;
priv_.critNest = 0U;
// produce an empty record to &quot;flush&quot; the QS trace buffer
beginRec_(QS_REC_NUM_(QS_EMPTY));
endRec_();
// produce the Target info QS record
target_info_pre_(0xFFU);
// wait with flushing after successful initialization (see QS_INIT())</code>
</operation>
<!--${QS::QS-tx::getByte}-->
<operation name="getByte" type="std::uint16_t" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Byte-oriented interface to the QS data buffer
//!
//! @details
//! This function delivers one byte at a time from the QS data buffer.
//!
//! @returns
//! the byte in the least-significant 8-bits of the 16-bit return
//! value if the byte is available. If no more data is available at the
//! time, the function returns ::QS_EOD (End-Of-Data).
//!
//! @note
//! QS::getByte() is NOT protected with a critical section.</documentation>
<code>std::uint16_t ret;
if (priv_.used == 0U) {
ret = QS_EOD; // set End-Of-Data
}
else {
std::uint8_t const * const buf_ = priv_.buf; // put in a temporary
QSCtr tail_ = priv_.tail; // put in a temporary (register)
// the byte to return
ret = static_cast&lt;std::uint16_t&gt;(buf_[tail_]);
++tail_; // advance the tail
if (tail_ == priv_.end) { // tail wrap around?
tail_ = 0U;
}
priv_.tail = tail_; // update the tail
priv_.used = (priv_.used - 1U); // one less byte used
}
return ret; // return the byte or EOD</code>
</operation>
<!--${QS::QS-tx::getBlock}-->
<operation name="getBlock" type="std::uint8_t const *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Block-oriented interface to the QS data buffer
//!
//! @details
//! This function delivers a contiguous block of data from the QS data
//! buffer. The function returns the pointer to the beginning of the
//! block, and writes the number of bytes in the block to the location
//! pointed to by `pNbytes`. The argument `pNbytes` is also used as
//! input to provide the maximum size of the data block that the caller
//! can accept.
//!
//! @returns
//! if data is available, the function returns pointer to the
//! contiguous block of data and sets the value pointed to by `pNbytes`
//! to the # available bytes. If data is available at the time the
//! function is called, the function returns NULL pointer and sets the
//! value pointed to by `pNbytes` to zero.
//!
//! @note
//! Only the NULL return from QP::QS::getBlock() indicates that the QS
//! buffer is empty at the time of the call. The non-NULL return often
//! means that the block is at the end of the buffer and you need to call
//! QP::QS::getBlock() again to obtain the rest of the data that
//! &quot;wrapped around&quot; to the beginning of the QS data buffer.
//!
//! @note QP::QS::getBlock() is __not__ protected with a critical section.</documentation>
<!--${QS::QS-tx::getBlock::pNbytes}-->
<parameter name="pNbytes" type="std::uint16_t * const"/>
<code>QSCtr const used_ = priv_.used; // put in a temporary (register)
std::uint8_t *buf_;
// any bytes used in the ring buffer?
if (used_ == 0U) {
*pNbytes = 0U; // no bytes available right now
buf_ = nullptr; // no bytes available right now
}
else {
QSCtr tail_ = priv_.tail; // put in a temporary (register)
QSCtr const end_ = priv_.end; // put in a temporary (register)
QSCtr n = static_cast&lt;QSCtr&gt;(end_ - tail_);
if (n &gt; used_) {
n = used_;
}
if (n &gt; static_cast&lt;QSCtr&gt;(*pNbytes)) {
n = static_cast&lt;QSCtr&gt;(*pNbytes);
}
*pNbytes = static_cast&lt;std::uint16_t&gt;(n); // n-bytes available
buf_ = priv_.buf;
buf_ = &amp;buf_[tail_]; // the bytes are at the tail
priv_.used = (priv_.used - n);
tail_ += n;
if (tail_ == end_) {
tail_ = 0U;
}
priv_.tail = tail_;
}
return buf_;</code>
</operation>
<!--${QS::QS-tx::glbFilter_}-->
<operation name="glbFilter_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Set/clear the global Filter for a given QS record
//! or a group of records
//!
//! @details
//! This function sets up the QS filter to enable record types specified
//! in the `filter` parameter. The value #QS_ALL_RECORDS specifies to
//! filter-in all records. This function should be called indirectly
//! through the macro QS_GLB_FILTER()
//!
//! @param[in] filter the QS record-d or group to enable in the filter,
//! if positive or disable, if negative. The record-id
//! numbers must be in the range -127..127.
//! @note
//! Filtering based on the record-type is only the first layer of
//! filtering. The second layer is based on the object-type. Both filter
//! layers must be enabled for the QS record to be inserted in the
//! QS buffer.
//!
//! @sa QP::QS::locFilter_()</documentation>
<!--${QS::QS-tx::glbFilter_::filter}-->
<parameter name="filter" type="std::int_fast16_t const"/>
<code>bool const isRemove = (filter &lt; 0);
std::uint16_t const rec = isRemove
? static_cast&lt;std::uint16_t&gt;(-filter)
: static_cast&lt;std::uint16_t&gt;(filter);
switch (rec) {
case QS_ALL_RECORDS: {
std::uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
std::uint_fast8_t i;
// set all global filters (partially unrolled loop)
for (i = 0U; i &lt; Q_DIM(priv_.glbFilter); i += 4U) {
priv_.glbFilter[i ] = tmp;
priv_.glbFilter[i + 1U] = tmp;
priv_.glbFilter[i + 2U] = tmp;
priv_.glbFilter[i + 3U] = tmp;
}
if (isRemove) {
// leave the &quot;not maskable&quot; filters enabled,
// see qs.h, Miscellaneous QS records (not maskable)
//
priv_.glbFilter[0] = 0x01U;
priv_.glbFilter[6] = 0x40U;
priv_.glbFilter[7] = 0xFCU;
priv_.glbFilter[8] = 0x7FU;
}
else {
// never turn the last 3 records on (0x7D, 0x7E, 0x7F)
priv_.glbFilter[15] = 0x1FU;
}
break;
}
case QS_SM_RECORDS:
if (isRemove) {
priv_.glbFilter[0] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xFEU &amp; 0xFFU);
priv_.glbFilter[1] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x03U &amp; 0xFFU);
priv_.glbFilter[6] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x80U &amp; 0xFFU);
priv_.glbFilter[7] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x03U &amp; 0xFFU);
}
else {
priv_.glbFilter[0] |= 0xFEU;
priv_.glbFilter[1] |= 0x03U;
priv_.glbFilter[6] |= 0x80U;
priv_.glbFilter[7] |= 0x03U;
}
break;
case QS_AO_RECORDS:
if (isRemove) {
priv_.glbFilter[1] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xFCU &amp; 0xFFU);
priv_.glbFilter[2] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x07U &amp; 0xFFU);
priv_.glbFilter[5] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x20U &amp; 0xFFU);
}
else {
priv_.glbFilter[1] |= 0xFCU;
priv_.glbFilter[2] |= 0x07U;
priv_.glbFilter[5] |= 0x20U;
}
break;
case QS_EQ_RECORDS:
if (isRemove) {
priv_.glbFilter[2] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x78U &amp; 0xFFU);
priv_.glbFilter[5] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x40U &amp; 0xFFU);
}
else {
priv_.glbFilter[2] |= 0x78U;
priv_.glbFilter[5] |= 0x40U;
}
break;
case QS_MP_RECORDS:
if (isRemove) {
priv_.glbFilter[3] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x03U &amp; 0xFFU);
priv_.glbFilter[5] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x80U &amp; 0xFFU);
}
else {
priv_.glbFilter[3] |= 0x03U;
priv_.glbFilter[5] |= 0x80U;
}
break;
case QS_QF_RECORDS:
if (isRemove) {
priv_.glbFilter[2] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x80U &amp; 0xFFU);
priv_.glbFilter[3] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xFCU &amp; 0xFFU);
priv_.glbFilter[4] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xC0U &amp; 0xFFU);
priv_.glbFilter[5] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x1FU &amp; 0xFFU);
}
else {
priv_.glbFilter[2] |= 0x80U;
priv_.glbFilter[3] |= 0xFCU;
priv_.glbFilter[4] |= 0xC0U;
priv_.glbFilter[5] |= 0x1FU;
}
break;
case QS_TE_RECORDS:
if (isRemove) {
priv_.glbFilter[4] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x3FU &amp; 0xFFU);
}
else {
priv_.glbFilter[4] |= 0x3FU;
}
break;
case QS_SC_RECORDS:
if (isRemove) {
priv_.glbFilter[6] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x3FU &amp; 0xFFU);
}
else {
priv_.glbFilter[6] |= 0x3FU;
}
break;
case QS_SEM_RECORDS:
if (isRemove) {
priv_.glbFilter[8] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x80U &amp; 0xFFU);
priv_.glbFilter[9] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x07U &amp; 0xFFU);
}
else {
priv_.glbFilter[8] |= 0x80U;
priv_.glbFilter[9] |= 0x07U;
}
break;
case QS_MTX_RECORDS:
if (isRemove) {
priv_.glbFilter[9] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xF8U &amp; 0xFFU);
priv_.glbFilter[10] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x01U &amp; 0xFFU);
}
else {
priv_.glbFilter[9] |= 0xF8U;
priv_.glbFilter[10] |= 0x01U;
}
break;
case QS_U0_RECORDS:
if (isRemove) {
priv_.glbFilter[12] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xF0U &amp; 0xFFU);
priv_.glbFilter[13] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x01U &amp; 0xFFU);
}
else {
priv_.glbFilter[12] |= 0xF0U;
priv_.glbFilter[13] |= 0x01U;
}
break;
case QS_U1_RECORDS:
if (isRemove) {
priv_.glbFilter[13] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x3EU &amp; 0xFFU);
}
else {
priv_.glbFilter[13] |= 0x3EU;
}
break;
case QS_U2_RECORDS:
if (isRemove) {
priv_.glbFilter[13] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xC0U &amp; 0xFFU);
priv_.glbFilter[14] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x07U &amp; 0xFFU);
}
else {
priv_.glbFilter[13] |= 0xC0U;
priv_.glbFilter[14] |= 0x07U;
}
break;
case QS_U3_RECORDS:
if (isRemove) {
priv_.glbFilter[14] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xF8U &amp; 0xFFU);
}
else {
priv_.glbFilter[14] |= 0xF8U;
}
break;
case QS_U4_RECORDS:
if (isRemove) {
priv_.glbFilter[15] &amp;= 0x1FU;
}
else {
priv_.glbFilter[15] |= 0x1FU;
}
break;
case QS_UA_RECORDS:
if (isRemove) {
priv_.glbFilter[12] &amp;=
static_cast&lt;std::uint8_t&gt;(~0xF0U &amp; 0xFFU);
priv_.glbFilter[13] = 0U;
priv_.glbFilter[14] = 0U;
priv_.glbFilter[15] &amp;=
static_cast&lt;std::uint8_t&gt;(~0x1FU &amp; 0xFFU);
}
else {
priv_.glbFilter[12] |= 0xF0U;
priv_.glbFilter[13] |= 0xFFU;
priv_.glbFilter[14] |= 0xFFU;
priv_.glbFilter[15] |= 0x1FU;
}
break;
default:
// QS rec number can't exceed 0x7D, so no need for escaping
Q_ASSERT_ID(210, rec &lt; 0x7DU);
if (isRemove) {
priv_.glbFilter[rec &gt;&gt; 3U]
&amp;= static_cast&lt;std::uint8_t&gt;(~(1U &lt;&lt; (rec &amp; 7U)) &amp; 0xFFU);
}
else {
priv_.glbFilter[rec &gt;&gt; 3U]
|= static_cast&lt;std::uint8_t&gt;(1U &lt;&lt; (rec &amp; 7U));
// never turn the last 3 records on (0x7D, 0x7E, 0x7F)
priv_.glbFilter[15] &amp;= 0x1FU;
}
break;
}</code>
</operation>
<!--${QS::QS-tx::locFilter_}-->
<operation name="locFilter_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Set/clear the local Filter for a given object-id
//! or a group of object-ids
//!
//! @details
//! This function sets up the local QS filter to enable or disable the
//! given QS object-id or a group of object-ids @a filter.
//! This function should be called indirectly through the macro
//! QS_LOC_FILTER()
//!
//! @param[in] filter the QS object-id or group to enable in the filter,
//! if positive or disable, if negative. The qs_id numbers
//! must be in the range 1..127.
//! @note
//! Filtering based on the object-id (local filter) is the second layer
//! of filtering. The first layer is based on the QS record-type (global
//! filter). Both filter layers must be enabled for the QS record to be
//! inserted into the QS buffer.
//!
//! @sa QP::QS::glbFilter_()</documentation>
<!--${QS::QS-tx::locFilter_::filter}-->
<parameter name="filter" type="std::int_fast16_t const"/>
<code>bool const isRemove = (filter &lt; 0);
std::uint16_t const qs_id = isRemove
? static_cast&lt;std::uint16_t&gt;(-filter)
: static_cast&lt;std::uint16_t&gt;(filter);
std::uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
std::uint_fast8_t i;
switch (qs_id) {
case QS_ALL_IDS:
// set all global filters (partially unrolled loop)
for (i = 0U; i &lt; Q_DIM(priv_.locFilter); i += 4U) {
priv_.locFilter[i ] = tmp;
priv_.locFilter[i + 1U] = tmp;
priv_.locFilter[i + 2U] = tmp;
priv_.locFilter[i + 3U] = tmp;
}
break;
case QS_AO_IDS:
for (i = 0U; i &lt; 8U; i += 4U) {
priv_.locFilter[i ] = tmp;
priv_.locFilter[i + 1U] = tmp;
priv_.locFilter[i + 2U] = tmp;
priv_.locFilter[i + 3U] = tmp;
}
break;
case QS_EP_IDS:
i = 8U;
priv_.locFilter[i ] = tmp;
priv_.locFilter[i + 1U] = tmp;
break;
case QS_AP_IDS:
i = 12U;
priv_.locFilter[i ] = tmp;
priv_.locFilter[i + 1U] = tmp;
priv_.locFilter[i + 2U] = tmp;
priv_.locFilter[i + 3U] = tmp;
break;
default:
if (qs_id &lt; 0x7FU) {
if (isRemove) {
priv_.locFilter[qs_id &gt;&gt; 3U] &amp;=
static_cast&lt;std::uint8_t&gt;(
~(1U &lt;&lt; (qs_id &amp; 7U)) &amp; 0xFFU);
}
else {
priv_.locFilter[qs_id &gt;&gt; 3U]
|= (1U &lt;&lt; (qs_id &amp; 7U));
}
}
else {
Q_ERROR_ID(310); // incorrect qs_id
}
break;
}
priv_.locFilter[0] |= 0x01U; // leave QS_ID == 0 always on
</code>
</operation>
<!--${QS::QS-tx::doOutput}-->
<operation name="doOutput" type="void" visibility="0x00" properties="0x00">
<documentation>//! Perform the QS-TX output (implemented in some QS ports)</documentation>
</operation>
<!--${QS::QS-tx::beginRec_}-->
<operation name="beginRec_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Mark the begin of a QS record `rec`
//!
//! @details
//! This function must be called at the beginning of each QS record.
//! This function should be called indirectly through the macro
//! QS_BEGIN_ID(), or QS_BEGIN_NOCRIT(), depending if it's called in
//! a normal code or from a critical section.</documentation>
<!--${QS::QS-tx::beginRec_::rec}-->
<parameter name="rec" type="std::uint_fast8_t const"/>
<code>std::uint8_t const b = priv_.seq + 1U;
std::uint8_t chksum_ = 0U; // reset the checksum
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_ = priv_.end; // put in a temporary (register)
priv_.seq = b; // store the incremented sequence num
priv_.used = (priv_.used + 2U); // 2 bytes about to be added
QS_INSERT_ESC_BYTE_(b)
chksum_ += static_cast&lt;std::uint8_t&gt;(rec);
QS_INSERT_BYTE_(static_cast&lt;std::uint8_t&gt;(rec)) // no need for escaping
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::endRec_}-->
<operation name="endRec_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Mark the end of a QS record `rec`
//!
//! @details
//! This function must be called at the end of each QS record.
//! This function should be called indirectly through the macro QS_END(),
//! or QS_END_NOCRIT(), depending if it's called in a normal code or from
//! a critical section.</documentation>
<code>std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head;
QSCtr const end_ = priv_.end;
std::uint8_t b = priv_.chksum;
b ^= 0xFFU; // invert the bits in the checksum
priv_.used = (priv_.used + 2U); // 2 bytes about to be added
if ((b != QS_FRAME) &amp;&amp; (b != QS_ESC)) {
QS_INSERT_BYTE_(b)
}
else {
QS_INSERT_BYTE_(QS_ESC)
QS_INSERT_BYTE_(b ^ QS_ESC_XOR)
priv_.used = (priv_.used + 1U); // account for the ESC byte
}
QS_INSERT_BYTE_(QS_FRAME) // do not escape this QS_FRAME
priv_.head = head_; // save the head
if (priv_.used &gt; end_) { // overrun over the old data?
priv_.used = end_; // the whole buffer is used
priv_.tail = head_; // shift the tail to the old data
}</code>
</operation>
<!--${QS::QS-tx::u8_raw_}-->
<operation name="u8_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! output std::uint8_t data element without format information</documentation>
<!--${QS::QS-tx::u8_raw_::d}-->
<parameter name="d" type="std::uint8_t const"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 1U); // 1 byte about to be added
QS_INSERT_ESC_BYTE_(d)
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::u8u8_raw_}-->
<operation name="u8u8_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! output two std::uint8_t data elements without format information</documentation>
<!--${QS::QS-tx::u8u8_raw_::d1}-->
<parameter name="d1" type="std::uint8_t const"/>
<!--${QS::QS-tx::u8u8_raw_::d2}-->
<parameter name="d2" type="std::uint8_t const"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 2U); // 2 bytes about to be added
QS_INSERT_ESC_BYTE_(d1)
QS_INSERT_ESC_BYTE_(d2)
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::u16_raw_}-->
<operation name="u16_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint16_t data element without format information</documentation>
<!--${QS::QS-tx::u16_raw_::d}-->
<parameter name="d" type="std::uint16_t"/>
<code>std::uint8_t b = static_cast&lt;std::uint8_t&gt;(d);
std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 2U); // 2 bytes about to be added
QS_INSERT_ESC_BYTE_(b)
d &gt;&gt;= 8U;
b = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(b)
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::u32_raw_}-->
<operation name="u32_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint32_t data element without format information</documentation>
<!--${QS::QS-tx::u32_raw_::d}-->
<parameter name="d" type="std::uint32_t"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 4U); // 4 bytes about to be added
for (std::uint_fast8_t i = 4U; i != 0U; --i) {
std::uint8_t const b = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(b)
d &gt;&gt;= 8U;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::obj_raw_}-->
<operation name="obj_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output object pointer data element without format information</documentation>
<!--${QS::QS-tx::obj_raw_::obj}-->
<parameter name="obj" type="void const * const"/>
<code>#if (QS_OBJ_PTR_SIZE == 1U)
u8_raw_(reinterpret_cast&lt;std::uint8_t&gt;(obj));
#elif (QS_OBJ_PTR_SIZE == 2U)
u16_raw_(reinterpret_cast&lt;std::uint16_t&gt;(obj));
#elif (QS_OBJ_PTR_SIZE == 4U)
u32_raw_(reinterpret_cast&lt;std::uint32_t&gt;(obj));
#elif (QS_OBJ_PTR_SIZE == 8U)
u64_raw_(reinterpret_cast&lt;std::uint64_t&gt;(obj));
#else
u32_raw_(reinterpret_cast&lt;std::uint32_t&gt;(obj));
#endif</code>
</operation>
<!--${QS::QS-tx::str_raw_}-->
<operation name="str_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output zero-terminated ASCII string element without format information</documentation>
<!--${QS::QS-tx::str_raw_::s}-->
<parameter name="s" type="char const *"/>
<code>std::uint8_t b = static_cast&lt;std::uint8_t&gt;(*s);
std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
QSCtr used_ = priv_.used; // put in a temporary (register)
while (b != 0U) {
chksum_ += b; // update checksum
QS_INSERT_BYTE_(b) // ASCII characters don't need escaping
++s;
b = static_cast&lt;std::uint8_t&gt;(*s);
++used_;
}
QS_INSERT_BYTE_(0U) // zero-terminate the string
++used_;
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum
priv_.used = used_; // save # of used buffer space</code>
</operation>
<!--${QS::QS-tx::u8_fmt_}-->
<operation name="u8_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint8_t data element with format information
//! @sa QS_U8(), QS_I8()</documentation>
<!--${QS::QS-tx::u8_fmt_::format}-->
<parameter name="format" type="std::uint8_t const"/>
<!--${QS::QS-tx::u8_fmt_::d}-->
<parameter name="d" type="std::uint8_t const"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t *const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 2U); // 2 bytes about to be added
QS_INSERT_ESC_BYTE_(format)
QS_INSERT_ESC_BYTE_(d)
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::u16_fmt_}-->
<operation name="u16_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint16_t data element with format information
//! @sa QS_U16(), QS_I16()</documentation>
<!--${QS::QS-tx::u16_fmt_::format}-->
<parameter name="format" type="std::uint8_t"/>
<!--${QS::QS-tx::u16_fmt_::d}-->
<parameter name="d" type="std::uint16_t"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 3U); // 3 bytes about to be added
QS_INSERT_ESC_BYTE_(format)
format = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(format)
d &gt;&gt;= 8U;
format = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(format)
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::u32_fmt_}-->
<operation name="u32_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint32_t data element with format information
//! @sa QS_U32(), QS_I32()</documentation>
<!--${QS::QS-tx::u32_fmt_::format}-->
<parameter name="format" type="std::uint8_t"/>
<!--${QS::QS-tx::u32_fmt_::d}-->
<parameter name="d" type="std::uint32_t"/>
<code>std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + 5U); // 5 bytes about to be added
QS_INSERT_ESC_BYTE_(format) // insert the format byte
for (std::uint_fast8_t i = 4U; i != 0U; --i) {
format = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(format)
d &gt;&gt;= 8U;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::str_fmt_}-->
<operation name="str_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output zero-terminated ASCII string element with format information
//! @sa QS_STR()</documentation>
<!--${QS::QS-tx::str_fmt_::s}-->
<parameter name="s" type="char const *"/>
<code>std::uint8_t b = static_cast&lt;std::uint8_t&gt;(*s);
std::uint8_t chksum_ = static_cast&lt;std::uint8_t&gt;(
priv_.chksum + static_cast&lt;std::uint8_t&gt;(STR_T));
std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
QSCtr used_ = priv_.used; // put in a temporary (register)
used_ += 2U; // the format byte and the terminating-0
QS_INSERT_BYTE_(static_cast&lt;std::uint8_t&gt;(STR_T))
while (b != 0U) {
// ASCII characters don't need escaping
chksum_ += b; // update checksum
QS_INSERT_BYTE_(b)
++s;
b = static_cast&lt;std::uint8_t&gt;(*s);
++used_;
}
QS_INSERT_BYTE_(0U) // zero-terminate the string
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum
priv_.used = used_; // save # of used buffer space</code>
</operation>
<!--${QS::QS-tx::mem_fmt_}-->
<operation name="mem_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output memory block of up to 255-bytes with format information
//! @sa QS_MEM()</documentation>
<!--${QS::QS-tx::mem_fmt_::blk}-->
<parameter name="blk" type="std::uint8_t const *"/>
<!--${QS::QS-tx::mem_fmt_::size}-->
<parameter name="size" type="std::uint8_t"/>
<code>std::uint8_t b = static_cast&lt;std::uint8_t&gt;(MEM_T);
std::uint8_t chksum_ = priv_.chksum + b;
std::uint8_t * const buf_= priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_= priv_.end; // put in a temporary (register)
priv_.used = (priv_.used + size + 2U); // size+2 bytes to be added
QS_INSERT_BYTE_(b)
QS_INSERT_ESC_BYTE_(size)
// output the 'size' number of bytes
for (; size != 0U; --size) {
b = *blk;
QS_INSERT_ESC_BYTE_(b)
++blk;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx::sig_dict_pre_}-->
<operation name="sig_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output signal dictionary record
//! @sa QS_SIG_DICTIONARY()</documentation>
<!--${QS::QS-tx::sig_dict_pre_::sig}-->
<parameter name="sig" type="enum_t const"/>
<!--${QS::QS-tx::sig_dict_pre_::obj}-->
<parameter name="obj" type="void const * const"/>
<!--${QS::QS-tx::sig_dict_pre_::name}-->
<parameter name="name" type="char const * const"/>
<code>QS_CRIT_STAT_
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_SIG_DICT));
QS_SIG_PRE_(sig);
QS_OBJ_PRE_(obj);
QS_STR_PRE_((*name == '&amp;') ? &amp;name[1] : name);
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::obj_dict_pre_}-->
<operation name="obj_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output object dictionary record
//! @sa QS_OBJ_DICTIONARY()</documentation>
<!--${QS::QS-tx::obj_dict_pre_::obj}-->
<parameter name="obj" type="void const * const"/>
<!--${QS::QS-tx::obj_dict_pre_::name}-->
<parameter name="name" type="char const * const"/>
<code>QS_CRIT_STAT_
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_OBJ_DICT));
QS_OBJ_PRE_(obj);
QS_STR_PRE_((*name == '&amp;') ? &amp;name[1] : name);
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::obj_arr_dict_pre_}-->
<operation name="obj_arr_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output predefined object-array dictionary record
//! @sa QS_OBJ_ARR_DICTIONARY()</documentation>
<!--${QS::QS-tx::obj_arr_dict_pre~::obj}-->
<parameter name="obj" type="void const * const"/>
<!--${QS::QS-tx::obj_arr_dict_pre~::idx}-->
<parameter name="idx" type="std::uint_fast16_t const"/>
<!--${QS::QS-tx::obj_arr_dict_pre~::name}-->
<parameter name="name" type="char const * const"/>
<code>Q_REQUIRE_ID(400, idx &lt; 1000U);
// format idx into a char buffer as &quot;xxx\0&quot;
std::uint8_t idx_str[4];
std::uint_fast16_t tmp = idx;
std::uint8_t i;
idx_str[3] = 0U; // zero-terminate
idx_str[2] = static_cast&lt;std::uint8_t&gt;(
static_cast&lt;std::uint8_t&gt;('0') + (tmp % 10U));
tmp /= 10U;
idx_str[1] = static_cast&lt;std::uint8_t&gt;(
static_cast&lt;std::uint8_t&gt;('0') + (tmp % 10U));
if (idx_str[1] == static_cast&lt;std::uint8_t&gt;('0')) {
i = 2U;
}
else {
tmp /= 10U;
idx_str[0] = static_cast&lt;std::uint8_t&gt;(
static_cast&lt;std::uint8_t&gt;('0') + (tmp % 10U));
if (idx_str[0] == static_cast&lt;std::uint8_t&gt;('0')) {
i = 1U;
}
else {
i = 0U;
}
}
QS_CRIT_STAT_
std::uint8_t j = ((*name == '&amp;') ? 1U : 0U);
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(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
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::fun_dict_pre_}-->
<operation name="fun_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output function dictionary record
//! @sa QS_FUN_DICTIONARY()</documentation>
<!--${QS::QS-tx::fun_dict_pre_::fun}-->
<parameter name="fun" type="QSpyFunPtr"/>
<!--${QS::QS-tx::fun_dict_pre_::name}-->
<parameter name="name" type="char const * const"/>
<code>QS_CRIT_STAT_
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_FUN_DICT));
QS_FUN_PRE_(fun);
QS_STR_PRE_((*name == '&amp;') ? &amp;name[1] : name);
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::usr_dict_pre_}-->
<operation name="usr_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output user dictionary record
//! @sa QS_USR_DICTIONARY()</documentation>
<!--${QS::QS-tx::usr_dict_pre_::rec}-->
<parameter name="rec" type="enum_t const"/>
<!--${QS::QS-tx::usr_dict_pre_::name}-->
<parameter name="name" type="char const * const"/>
<code>QS_CRIT_STAT_
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_USR_DICT));
QS_U8_PRE_(rec);
QS_STR_PRE_(name);
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::enum_dict_pre_}-->
<operation name="enum_dict_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output enumeration dictionary record
//! @sa QS_ENUM_DICTIONARY()</documentation>
<!--${QS::QS-tx::enum_dict_pre_::value}-->
<parameter name="value" type="enum_t const"/>
<!--${QS::QS-tx::enum_dict_pre_::group}-->
<parameter name="group" type="std::uint8_t const"/>
<!--${QS::QS-tx::enum_dict_pre_::name}-->
<parameter name="name" type="char const * const"/>
<code>QS_CRIT_STAT_
QS_CRIT_E_();
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_ENUM_DICT));
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(value), group);
QS_STR_PRE_(name);
endRec_();
QS_CRIT_X_();
onFlush();</code>
</operation>
<!--${QS::QS-tx::assertion_pre_}-->
<operation name="assertion_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! internal function to produce the assertion failure trace record
//! @sa QS_ASSERTION()</documentation>
<!--${QS::QS-tx::assertion_pre_::module}-->
<parameter name="module" type="char const * const"/>
<!--${QS::QS-tx::assertion_pre_::loc}-->
<parameter name="loc" type="int_t const"/>
<!--${QS::QS-tx::assertion_pre_::delay}-->
<parameter name="delay" type="std::uint32_t const"/>
<code>QS_BEGIN_NOCRIT_PRE_(QP::QS_ASSERT_FAIL, 0U)
QS_TIME_PRE_();
QS_U16_PRE_(loc);
QS_STR_PRE_((module != nullptr) ? module : &quot;?&quot;);
QS_END_NOCRIT_PRE_()
QP::QS::onFlush();
for (std::uint32_t volatile ctr = delay; ctr &gt; 0U; ) {
ctr = (ctr - 1U);
}
QP::QS::onCleanup();</code>
</operation>
<!--${QS::QS-tx::crit_entry_pre_}-->
<operation name="crit_entry_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! internal function to produce the critical section entry record
//! @sa QF_QS_CRIT_ENTRY()</documentation>
<code>QS_BEGIN_NOCRIT_PRE_(QP::QS_QF_CRIT_ENTRY, 0U)
QS_TIME_PRE_();
QS::priv_.critNest = (QS::priv_.critNest + 1U);
QS_U8_PRE_(QS::priv_.critNest);
QS_END_NOCRIT_PRE_()</code>
</operation>
<!--${QS::QS-tx::crit_exit_pre_}-->
<operation name="crit_exit_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! internal function to produce the critical section exit record
//! @sa QF_QS_CRIT_EXIT()</documentation>
<code>QS_BEGIN_NOCRIT_PRE_(QP::QS_QF_CRIT_EXIT, 0U)
QS_TIME_PRE_();
QS_U8_PRE_(QS::priv_.critNest);
QS::priv_.critNest = (QS::priv_.critNest - 1U);
QS_END_NOCRIT_PRE_()</code>
</operation>
<!--${QS::QS-tx::isr_entry_pre_}-->
<operation name="isr_entry_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! internal function to produce the ISR entry record
//! @sa QF_QS_ISR_ENTRY()</documentation>
<!--${QS::QS-tx::isr_entry_pre_::isrnest}-->
<parameter name="isrnest" type="std::uint8_t const"/>
<!--${QS::QS-tx::isr_entry_pre_::prio}-->
<parameter name="prio" type="std::uint8_t const"/>
<code>QS_BEGIN_NOCRIT_PRE_(QP::QS_QF_ISR_ENTRY, 0U)
QS_TIME_PRE_();
QS_U8_PRE_(isrnest);
QS_U8_PRE_(prio);
QS_END_NOCRIT_PRE_()</code>
</operation>
<!--${QS::QS-tx::isr_exit_pre_}-->
<operation name="isr_exit_pre_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! internal function to produce the ISR exit record
//! @sa QF_QS_ISR_EXIT()</documentation>
<!--${QS::QS-tx::isr_exit_pre_::isrnest}-->
<parameter name="isrnest" type="std::uint8_t const"/>
<!--${QS::QS-tx::isr_exit_pre_::prio}-->
<parameter name="prio" type="std::uint8_t const"/>
<code>QS_BEGIN_NOCRIT_PRE_(QP::QS_QF_ISR_EXIT, 0U)
QS_TIME_PRE_();
QS_U8_PRE_(isrnest);
QS_U8_PRE_(prio);
QS_END_NOCRIT_PRE_()</code>
</operation>
<!--${QS::QS-tx::target_info_pre_}-->
<operation name="target_info_pre_" type="void" visibility="0x00" properties="0x00">
<documentation>//! Helper function to output the predefined Target-info trace record.</documentation>
<!--${QS::QS-tx::target_info_pre_::isReset}-->
<parameter name="isReset" type="std::uint8_t const"/>
<code>static constexpr std::uint8_t ZERO = static_cast&lt;std::uint8_t&gt;('0');
static std::uint8_t const * const TIME =
reinterpret_cast&lt;std::uint8_t const *&gt;(&amp;BUILD_TIME[0]);
static std::uint8_t const * const DATE =
reinterpret_cast&lt;std::uint8_t const *&gt;(&amp;BUILD_DATE[0]);
QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_TARGET_INFO));
QS::u8_raw_(isReset);
static union {
std::uint16_t u16;
std::uint8_t u8[2];
} endian_test;
endian_test.u16 = 0x0102U;
// big endian ? add the 0x8000U flag
QS_U16_PRE_(((endian_test.u8[0] == 0x01U)
? (0x8000U | QP_VERSION)
: QP_VERSION)); // target endianness + version number
// send the object sizes...
QS::u8_raw_(Q_SIGNAL_SIZE
| static_cast&lt;std::uint8_t&gt;(QF_EVENT_SIZ_SIZE &lt;&lt; 4U));
#ifdef QF_EQUEUE_CTR_SIZE
QS::u8_raw_(QF_EQUEUE_CTR_SIZE
| static_cast&lt;std::uint8_t&gt;(QF_TIMEEVT_CTR_SIZE &lt;&lt; 4U));
#else
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(QF_TIMEEVT_CTR_SIZE &lt;&lt; 4U));
#endif // ifdef QF_EQUEUE_CTR_SIZE
#ifdef QF_MPOOL_CTR_SIZE
QS::u8_raw_(QF_MPOOL_SIZ_SIZE
| static_cast&lt;std::uint8_t&gt;(QF_MPOOL_CTR_SIZE &lt;&lt; 4U));
#else
QS::u8_raw_(0U);
#endif // ifdef QF_MPOOL_CTR_SIZE
QS::u8_raw_(QS_OBJ_PTR_SIZE | (QS_FUN_PTR_SIZE &lt;&lt; 4U));
QS::u8_raw_(QS_TIME_SIZE);
// send the limits...
QS::u8_raw_(QF_MAX_ACTIVE);
QS::u8_raw_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE &lt;&lt; 4U));
// send the build time in three bytes (sec, min, hour)...
QS::u8_raw_((10U * (TIME[6] - ZERO)) + (TIME[7] - ZERO));
QS::u8_raw_((10U * (TIME[3] - ZERO)) + (TIME[4] - ZERO));
if (BUILD_TIME[0] == static_cast&lt;std::uint8_t&gt;(' ')) {
QS::u8_raw_(TIME[1] - ZERO);
}
else {
QS::u8_raw_((10U * (TIME[0] - ZERO)) + (TIME[1] - ZERO));
}
// send the build date in three bytes (day, month, year) ...
if (BUILD_DATE[4] == static_cast&lt;std::uint8_t&gt;(' ')) {
QS::u8_raw_(DATE[5] - ZERO);
}
else {
QS::u8_raw_((10U * (DATE[4] - ZERO)) + (DATE[5] - ZERO));
}
// convert the 3-letter month to a number 1-12 ...
std::uint8_t b;
switch (DATE[0] + DATE[1] + DATE[2]) {
case 'J' + 'a' +'n':
b = 1U;
break;
case 'F' + 'e' + 'b':
b = 2U;
break;
case 'M' + 'a' +'r':
b = 3U;
break;
case 'A' + 'p' + 'r':
b = 4U;
break;
case 'M' + 'a' + 'y':
b = 5U;
break;
case 'J' + 'u' + 'n':
b = 6U;
break;
case 'J' + 'u' + 'l':
b = 7U;
break;
case 'A' + 'u' + 'g':
b = 8U;
break;
case 'S' + 'e' + 'p':
b = 9U;
break;
case 'O' + 'c' + 't':
b = 10U;
break;
case 'N' + 'o' + 'v':
b = 11U;
break;
case 'D' + 'e' + 'c':
b = 12U;
break;
default:
b = 0U;
break;
}
QS::u8_raw_(b); // store the month
QS::u8_raw_((10U * (DATE[9] - ZERO)) + (DATE[10] - ZERO));
QS::endRec_();
</code>
</operation>
<!--${QS::QS-tx::onStartup}-->
<operation name="onStartup" type="bool" visibility="0x00" properties="0x00">
<documentation>//! Callback to startup the QS facility</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>//! Callback to cleanup the QS facility</documentation>
</operation>
<!--${QS::QS-tx::onFlush}-->
<operation name="onFlush" type="void" visibility="0x00" properties="0x00">
<documentation>//! Callback to flush the QS trace data to the host</documentation>
</operation>
<!--${QS::QS-tx::onGetTime}-->
<operation name="onGetTime" type="QSTimeCtr" visibility="0x00" properties="0x00">
<documentation>//! Callback to obtain a timestamp for a QS record</documentation>
</operation>
</package>
<!--${QS::QS-tx-64bit}-->
<package name="QS-tx-64bit" stereotype="0x02" namespace="QS::">
<!--${QS::QS-tx-64bit::u64_raw_}-->
<operation name="u64_raw_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint64_t data element without format information</documentation>
<!--${QS::QS-tx-64bit::u64_raw_::d}-->
<parameter name="d" type="std::uint64_t"/>
<code>std::uint8_t chksum_ = priv_.chksum;
std::uint8_t * const buf_ = priv_.buf;
QSCtr head_ = priv_.head;
QSCtr const end_ = priv_.end;
priv_.used = (priv_.used + 8U); // 8 bytes are about to be added
for (std::int_fast8_t i = 8U; i != 0U; --i) {
std::uint8_t const b = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(b)
d &gt;&gt;= 8U;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx-64bit::u64_fmt_}-->
<operation name="u64_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output std::uint64_t data element with format information
//! @sa QS_U64(), QS_I64()</documentation>
<!--${QS::QS-tx-64bit::u64_fmt_::format}-->
<parameter name="format" type="std::uint8_t"/>
<!--${QS::QS-tx-64bit::u64_fmt_::d}-->
<parameter name="d" type="std::uint64_t"/>
<code>std::uint8_t chksum_ = priv_.chksum;
std::uint8_t * const buf_ = priv_.buf;
QSCtr head_ = priv_.head;
QSCtr const end_ = priv_.end;
priv_.used = (priv_.used + 9U); // 9 bytes are about to be added
QS_INSERT_ESC_BYTE_(format) // insert the format byte
for (std::int_fast8_t i = 8U; i != 0U; --i) {
format = static_cast&lt;std::uint8_t&gt;(d);
QS_INSERT_ESC_BYTE_(format)
d &gt;&gt;= 8U;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
</package>
<!--${QS::QS-tx-fp}-->
<package name="QS-tx-fp" stereotype="0x02" namespace="QS::">
<!--${QS::QS-tx-fp::f32_fmt_}-->
<operation name="f32_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output 32-bit floating point data element with format information
//! @sa QS_F32()</documentation>
<!--${QS::QS-tx-fp::f32_fmt_::format}-->
<parameter name="format" type="std::uint8_t"/>
<!--${QS::QS-tx-fp::f32_fmt_::d}-->
<parameter name="d" type="float32_t"/>
<code>union F32Rep {
float32_t f;
std::uint32_t u;
} fu32; // the internal binary representation
std::uint8_t chksum_ = priv_.chksum; // put in a temporary (register)
std::uint8_t * const buf_ = priv_.buf; // put in a temporary (register)
QSCtr head_ = priv_.head; // put in a temporary (register)
QSCtr const end_ = priv_.end; // put in a temporary (register)
fu32.f = d; // assign the binary representation
priv_.used = (priv_.used + 5U); // 5 bytes about to be added
QS_INSERT_ESC_BYTE_(format) // insert the format byte
for (std::uint_fast8_t i = 4U; i != 0U; --i) {
format = static_cast&lt;std::uint8_t&gt;(fu32.u);
QS_INSERT_ESC_BYTE_(format)
fu32.u &gt;&gt;= 8U;
}
priv_.head = head_; // save the head
priv_.chksum = chksum_; // save the checksum</code>
</operation>
<!--${QS::QS-tx-fp::f64_fmt_}-->
<operation name="f64_fmt_" type="void" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Output 64-bit floating point data element with format information
//! @sa QS_F64()</documentation>
<!--${QS::QS-tx-fp::f64_fmt_::format}-->
<parameter name="format" type="std::uint8_t"/>
<!--${QS::QS-tx-fp::f64_fmt_::d}-->
<parameter name="d" type="float32_t"/>
<code>union F64Rep {
float64_t d;
std::uint32_t u[2];
} fu64; // the internal binary representation
std::uint8_t chksum_ = priv_.chksum;
std::uint8_t * const buf_ = priv_.buf;
QSCtr head_ = priv_.head;
QSCtr const end_ = priv_.end;
std::uint32_t i;
// static constant untion to detect endianness of the machine
static union U32Rep {
std::uint32_t u32;
std::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] &lt;-&gt; fu64.u[1]...
i = fu64.u[0];
fu64.u[0] = fu64.u[1];
fu64.u[1] = i;
}
priv_.used = (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_(static_cast&lt;std::uint8_t&gt;(fu64.u[0]))
fu64.u[0] &gt;&gt;= 8U;
}
// output 4 bytes from fu64.u[1]...
for (i = 4U; i != 0U; --i) {
QS_INSERT_ESC_BYTE_(static_cast&lt;std::uint8_t&gt;(fu64.u[1]))
fu64.u[1] &gt;&gt;= 8U;
}
priv_.head = head_; // update the head
priv_.chksum = chksum_; // update the checksum</code>
</operation>
</package>
<!--${QS::QS-rx}-->
<package name="QS-rx" stereotype="0x02" namespace="QS::">
<!--${QS::QS-rx::QSrx}-->
<class name="QSrx">
<documentation>//! QS software tracing parameters for QS input (QS-RX)</documentation>
<!--${QS::QS-rx::QSrx::currObj[8]}-->
<attribute name="currObj[8]" type="void *" visibility="0x00" properties="0x00">
<documentation>//! current objects</documentation>
</attribute>
<!--${QS::QS-rx::QSrx::buf}-->
<attribute name="buf" type="std::uint8_t *" visibility="0x00" properties="0x00">
<documentation>//! pointer to the start of the ring buffer</documentation>
</attribute>
<!--${QS::QS-rx::QSrx:: end}-->
<attribute name=" end" type="QSCtr" visibility="0x00" properties="0x00">
<documentation>//! offset of the end of the ring buffer</documentation>
</attribute>
<!--${QS::QS-rx::QSrx::head}-->
<attribute name="head" type="QSCtr volatile" visibility="0x00" properties="0x00">
<documentation>//! offset to where next byte will be inserted</documentation>
</attribute>
<!--${QS::QS-rx::QSrx::tail}-->
<attribute name="tail" type="QSCtr volatile" visibility="0x00" properties="0x00">
<documentation>//! offset of where next byte will be extracted</documentation>
</attribute>
<!--${QS::QS-rx::QSrx::inTestLoop}-->
<attribute name="inTestLoop?def Q_UTEST" type="bool" visibility="0x00" properties="0x00">
<documentation>//! QUTest event loop is running</documentation>
</attribute>
</class>
<!--${QS::QS-rx::rxPriv_}-->
<attribute name="rxPriv_" type="QSrx" visibility="0x00" properties="0x01">
<documentation>//! the only instance of the QS-RX object (Singleton)</documentation>
</attribute>
<!--${QS::QS-rx::QSpyObjKind}-->
<attribute name="QSpyObjKind" type="enum" visibility="0x04" properties="0x01">
<documentation>//! Kinds of objects used in QS::setCurrObj() and QS::queryCurrObj()</documentation>
<code>: std::uint8_t {
SM_OBJ, //!&lt; state machine object for QEP
AO_OBJ, //!&lt; active object
MP_OBJ, //!&lt; event pool object
EQ_OBJ, //!&lt; raw queue object
TE_OBJ, //!&lt; time event object
AP_OBJ, //!&lt; generic Application-specific object
MAX_OBJ
};</code>
</attribute>
<!--${QS::QS-rx::OSpyObjCombnation}-->
<attribute name="OSpyObjCombnation" type="enum" visibility="0x04" properties="0x01">
<documentation>//! Object combinations for QS::setCurrObj() and QS::queryCurrObj()</documentation>
<code>: std::uint8_t {
SM_AO_OBJ = MAX_OBJ //!&lt; combination of SM and AO
};</code>
</attribute>
<!--${QS::QS-rx::rxInitBuf}-->
<operation name="rxInitBuf" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Initialize the QS RX data buffer
//!
//! @details
//! This function should be called from QS::onStartup() to provide QS-RX
//! with the receive data buffer.
//!
//! @param[in] sto[] the address of the memory block
//! @param[in] stoSize the size of this block [bytes]. The size of the
//! QS RX buffer cannot exceed 64KB.
//!
//! @note
//! QS-RX can work with quite small data buffers, but you will start
//! losing data if the buffer is not drained fast enough (e.g., in the
//! idle task).
//!
//! @note
//! If the data input rate exceeds the QS-RX processing rate, the data
//! will be lost, but the QS protocol will notice that:
//! (1) that the checksum in the incomplete QS records will fail; and
//! (2) the sequence counter in QS records will show discontinuities.
//!
//! The QS-RX channel will report any data errors by sending the
//! QS_RX_DATA_ERROR trace record.</documentation>
<!--${QS::QS-rx::rxInitBuf::sto}-->
<parameter name="sto" type="std::uint8_t * const"/>
<!--${QS::QS-rx::rxInitBuf::stoSize}-->
<parameter name="stoSize" type="std::uint16_t const"/>
<code>rxPriv_.buf = &amp;sto[0];
rxPriv_.end = static_cast&lt;QSCtr&gt;(stoSize);
rxPriv_.head = 0U;
rxPriv_.tail = 0U;
rxPriv_.currObj[QS::SM_OBJ] = nullptr;
rxPriv_.currObj[QS::AO_OBJ] = nullptr;
rxPriv_.currObj[QS::MP_OBJ] = nullptr;
rxPriv_.currObj[QS::EQ_OBJ] = nullptr;
rxPriv_.currObj[QS::TE_OBJ] = nullptr;
rxPriv_.currObj[QS::AP_OBJ] = nullptr;
tran_(WAIT4_SEQ);
l_rx.esc = 0U;
l_rx.seq = 0U;
l_rx.chksum = 0U;
beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_OBJ_DICT));
QS_OBJ_PRE_(&amp;rxPriv_);
QS_STR_PRE_(&quot;QS_RX&quot;);
endRec_();
// no QS_REC_DONE(), because QS is not running yet
#ifdef Q_UTEST
QP::QS::testData.tpNum = 0U;
QP::QS::testData.testTime = 0U;
#endif // Q_UTEST</code>
</operation>
<!--${QS::QS-rx::rxPut}-->
<operation name="rxPut" type="bool" visibility="0x00" properties="0x02">
<specifiers>noexcept</specifiers>
<documentation>//! Put one byte into the QS RX lock-free buffer</documentation>
<!--${QS::QS-rx::rxPut::b}-->
<parameter name="b" type="std::uint8_t const"/>
<code>QSCtr head = rxPriv_.head + 1U;
if (head == rxPriv_.end) {
head = 0U;
}
if (head != rxPriv_.tail) { // buffer NOT full?
rxPriv_.buf[rxPriv_.head] = b;
rxPriv_.head = head;
return true; // byte placed in the buffer
}
else {
return false; // byte NOT placed in the buffer
}</code>
</operation>
<!--${QS::QS-rx::rxGetNfree}-->
<operation name="rxGetNfree" type="std::uint16_t" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Obtain the number of free bytes in the QS RX data buffer
//!
//! @details
//! This function is intended to be called from the ISR that reads the
//! QS-RX bytes from the QSPY application. The function returns the
//! conservative number of free bytes currently available in the buffer,
//! assuming that the head pointer is not being moved concurrently.
//! The tail pointer might be moving, meaning that bytes can be
//! concurrently removed from the buffer.</documentation>
<code>QSCtr const head = rxPriv_.head;
if (head == rxPriv_.tail) { // buffer empty?
return static_cast&lt;std::uint16_t&gt;(rxPriv_.end - 1U);
}
else if (head &lt; rxPriv_.tail) {
return static_cast&lt;std::uint16_t&gt;(rxPriv_.tail - head - 1U);
}
else {
return static_cast&lt;std::uint16_t&gt;(rxPriv_.end + rxPriv_.tail
- head - 1U);
}</code>
</operation>
<!--${QS::QS-rx::doInput}-->
<operation name="doInput" type="void" visibility="0x00" properties="0x00">
<documentation>//! Perform the QS-RX input (implemented in some QS ports)</documentation>
</operation>
<!--${QS::QS-rx::setCurrObj}-->
<operation name="setCurrObj" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Set the &quot;current object&quot; in the Target
//!
//! @details
//! This function sets the &quot;current object&quot; in the Target.</documentation>
<!--${QS::QS-rx::setCurrObj::obj_kind}-->
<parameter name="obj_kind" type="std::uint8_t"/>
<!--${QS::QS-rx::setCurrObj::obj_ptr}-->
<parameter name="obj_ptr" type="void *"/>
<code>Q_REQUIRE_ID(100, obj_kind &lt; Q_DIM(rxPriv_.currObj));
rxPriv_.currObj[obj_kind] = obj_ptr;</code>
</operation>
<!--${QS::QS-rx::queryCurrObj}-->
<operation name="queryCurrObj" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Query the &quot;current object&quot; in the Target
//!
//! @details
//! This function programmatically generates the response to the query for
//! a &quot;current object&quot;.</documentation>
<!--${QS::QS-rx::queryCurrObj::obj_kind}-->
<parameter name="obj_kind" type="std::uint8_t"/>
<code>Q_REQUIRE_ID(200, obj_kind &lt; Q_DIM(rxPriv_.currObj));
if (QS::rxPriv_.currObj[obj_kind] != nullptr) {
QS_CRIT_STAT_
QS_CRIT_E_();
QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_QUERY_DATA));
QS_TIME_PRE_(); // timestamp
QS_U8_PRE_(obj_kind); // object kind
QS_OBJ_PRE_(QS::rxPriv_.currObj[obj_kind]); // object pointer
switch (obj_kind) {
case SM_OBJ: // intentionally fall through
case AO_OBJ:
QS_FUN_PRE_(
reinterpret_cast&lt;QHsm *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getStateHandler());
break;
case QS::MP_OBJ:
QS_MPC_PRE_(reinterpret_cast&lt;QMPool *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getNFree());
QS_MPC_PRE_(reinterpret_cast&lt;QMPool *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getNMin());
break;
case QS::EQ_OBJ:
QS_EQC_PRE_(reinterpret_cast&lt;QEQueue *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getNFree());
QS_EQC_PRE_(reinterpret_cast&lt;QEQueue *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getNMin());
break;
case QS::TE_OBJ:
QS_OBJ_PRE_(reinterpret_cast&lt;QTimeEvt *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getAct());
QS_TEC_PRE_(reinterpret_cast&lt;QTimeEvt *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getCtr());
QS_TEC_PRE_(reinterpret_cast&lt;QTimeEvt *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;getInterval());
QS_SIG_PRE_(reinterpret_cast&lt;QTimeEvt *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;sig);
QS_U8_PRE_ (reinterpret_cast&lt;QTimeEvt *&gt;(
QS::rxPriv_.currObj[obj_kind])-&gt;refCtr_);
break;
default:
break;
}
QS::endRec_();
QS_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
}
else {
rxReportError_(static_cast&lt;std::uint8_t&gt;(QS_RX_AO_FILTER));
}</code>
</operation>
<!--${QS::QS-rx::rxParse}-->
<operation name="rxParse" type="void" visibility="0x00" properties="0x00">
<documentation>//! Parse all bytes present in the QS RX data buffer</documentation>
<code>QSCtr tail = rxPriv_.tail;
while (rxPriv_.head != tail) { // QS-RX buffer NOT empty?
std::uint8_t b = rxPriv_.buf[tail];
++tail;
if (tail == rxPriv_.end) {
tail = 0U;
}
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;
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;
tran_(WAIT4_SEQ);
if (l_rx.chksum == QS_GOOD_CHKSUM) {
l_rx.chksum = 0U;
rxHandleGoodFrame_(b);
}
else { // bad checksum
l_rx.chksum = 0U;
rxReportError_(0x41U);
rxHandleBadFrame_(b);
}
}
else {
l_rx.chksum += b;
rxParseData_(b);
}
}</code>
</operation>
<!--${QS::QS-rx::rxHandleGoodFrame_}-->
<operation name="rxHandleGoodFrame_" type="void" visibility="0x00" properties="0x00">
<documentation>//! internal function to handle incoming (QS-RX) packet</documentation>
<!--${QS::QS-rx::rxHandleGoodFram~::state}-->
<parameter name="state" type="std::uint8_t const"/>
<code>std::uint8_t i;
std::uint8_t *ptr;
QS_CRIT_STAT_
switch (state) {
case WAIT4_INFO_FRAME: {
// no need to report Ack or Done
QS_CRIT_E_();
target_info_pre_(0U); // send only Target info
QS_CRIT_X_();
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: {
rxReportAck_(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
rxReportDone_(QS_RX_COMMAND);
break;
}
case WAIT4_TICK_FRAME: {
rxReportAck_(QS_RX_TICK);
#ifdef Q_UTEST
QTimeEvt::tick1_(
static_cast&lt;std::uint_fast8_t&gt;(l_rx.var.tick.rate),
&amp;QS::rxPriv_);
#if Q_UTEST != 0
QS::processTestEvts_(); // process all events produced
#endif // Q_UTEST != 0
#else
QTimeEvt::tick_(
static_cast&lt;std::uint_fast8_t&gt;(l_rx.var.tick.rate),
&amp;QS::rxPriv_);
#endif // Q_UTEST
rxReportDone_(QS_RX_TICK);
break;
}
case WAIT4_PEEK_FRAME: {
// no need to report Ack or Done
QS_CRIT_E_();
QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QS_PEEK_DATA));
ptr = static_cast&lt;std::uint8_t*&gt;(
QS::rxPriv_.currObj[QS::AP_OBJ]);
ptr = &amp;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); // number of data items
for (i = 0U; i &lt; 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_(
reinterpret_cast&lt;std::uint16_t*&gt;(ptr)[i]);
break;
case 4:
QS_U32_PRE_(
reinterpret_cast&lt;std::uint32_t*&gt;(ptr)[i]);
break;
default:
break;
}
}
QS::endRec_();
QS_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
break;
}
case WAIT4_POKE_DATA: {
// received less than expected poke data items
rxReportError_(static_cast&lt;std::uint8_t&gt;(QS_RX_POKE));
break;
}
case WAIT4_POKE_FRAME: {
rxReportAck_(QS_RX_POKE);
// no need to report done
break;
}
case WAIT4_FILL_FRAME: {
rxReportAck_(QS_RX_FILL);
ptr = static_cast&lt;std::uint8_t *&gt;(
QS::rxPriv_.currObj[QS::AP_OBJ]);
ptr = &amp;ptr[l_rx.var.poke.offs];
for (i = 0U; i &lt; l_rx.var.poke.num; ++i) {
switch (l_rx.var.poke.size) {
case 1:
ptr[i] =
static_cast&lt;std::uint8_t&gt;(l_rx.var.poke.data);
break;
case 2:
reinterpret_cast&lt;std::uint16_t *&gt;(ptr)[i] =
static_cast&lt;std::uint16_t&gt;(l_rx.var.poke.data);
break;
case 4:
reinterpret_cast&lt;std::uint32_t *&gt;(ptr)[i] =
l_rx.var.poke.data;
break;
default:
break;
}
}
break;
}
case WAIT4_FILTER_FRAME: {
rxReportAck_(static_cast&lt;enum QSpyRxRecords&gt;(l_rx.var.flt.recId));
// apply the received filters
if (l_rx.var.flt.recId
== static_cast&lt;std::uint8_t&gt;(QS_RX_GLB_FILTER))
{
for (i = 0U;
i &lt; static_cast&lt;std::uint8_t&gt;(sizeof(priv_.glbFilter));
++i)
{
priv_.glbFilter[i] = l_rx.var.flt.data[i];
}
// leave the &quot;not maskable&quot; filters enabled,
// see qs.h, Miscellaneous QS records (not maskable)
//
priv_.glbFilter[0] |= 0x01U;
priv_.glbFilter[7] |= 0xFCU;
priv_.glbFilter[8] |= 0x7FU;
// never enable the last 3 records (0x7D, 0x7E, 0x7F)
priv_.glbFilter[15] &amp;= 0x1FU;
}
else if (l_rx.var.flt.recId
== static_cast&lt;std::uint8_t&gt;(QS_RX_LOC_FILTER))
{
for (i = 0U; i &lt; Q_DIM(priv_.locFilter); ++i) {
priv_.locFilter[i] = l_rx.var.flt.data[i];
}
// leave QS_ID == 0 always on
priv_.locFilter[0] |= 0x01U;
}
else {
rxReportError_(l_rx.var.flt.recId);
}
// no need to report Done
break;
}
case WAIT4_OBJ_FRAME: {
i = l_rx.var.obj.kind;
if (i &lt; static_cast&lt;std::uint8_t&gt;(QS::MAX_OBJ)) {
if (l_rx.var.obj.recId
== static_cast&lt;std::uint8_t&gt;(QS_RX_CURR_OBJ))
{
rxPriv_.currObj[i] =
reinterpret_cast&lt;void *&gt;(l_rx.var.obj.addr);
rxReportAck_(QS_RX_CURR_OBJ);
}
else if (l_rx.var.obj.recId
== static_cast&lt;std::uint8_t&gt;(QS_RX_AO_FILTER))
{
if (l_rx.var.obj.addr != 0U) {
std::int_fast16_t const filter =
static_cast&lt;std::int_fast16_t&gt;(
reinterpret_cast&lt;QActive *&gt;(
l_rx.var.obj.addr)-&gt;m_prio);
locFilter_((i == 0)
? filter
:-filter);
rxReportAck_(QS_RX_AO_FILTER);
}
else {
rxReportError_(static_cast&lt;enum_t&gt;(QS_RX_AO_FILTER));
}
}
else {
rxReportError_(l_rx.var.obj.recId);
}
}
// both SM and AO
else if (i == static_cast&lt;std::uint8_t&gt;(QS::SM_AO_OBJ)) {
if (l_rx.var.obj.recId
== static_cast&lt;std::uint8_t&gt;(QS_RX_CURR_OBJ))
{
rxPriv_.currObj[SM_OBJ]
= reinterpret_cast&lt;void *&gt;(l_rx.var.obj.addr);
rxPriv_.currObj[AO_OBJ]
= reinterpret_cast&lt;void *&gt;(l_rx.var.obj.addr);
}
rxReportAck_(
static_cast&lt;enum QSpyRxRecords&gt;(l_rx.var.obj.recId));
}
else {
rxReportError_(l_rx.var.obj.recId);
}
break;
}
case WAIT4_QUERY_FRAME: {
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); // &quot;massage&quot; the event, if needed
#endif // Q_UTEST
// use 'i' as status, 0 == success,no-recycle
i = 0U;
if (l_rx.var.evt.prio == 0U) { // publish
QActive::publish_(l_rx.var.evt.e, &amp;QS::rxPriv_, 0U);
}
else if (l_rx.var.evt.prio &lt; QF_MAX_ACTIVE) {
if (!QActive::registry_[l_rx.var.evt.prio]-&gt;POST_X(
l_rx.var.evt.e,
0U, // margin
&amp;QS::rxPriv_))
{
// failed QACTIVE_POST() recycles the event
i = 0x80U; // failure, no recycle
}
}
else if (l_rx.var.evt.prio == 255U) {
// dispatch to the current SM object
if (QS::rxPriv_.currObj[QS::SM_OBJ] != nullptr) {
// 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.
//
QEvt_refCtr_inc_(l_rx.var.evt.e);
static_cast&lt;QHsm *&gt;(QS::rxPriv_.currObj[QS::SM_OBJ])
-&gt;dispatch(l_rx.var.evt.e, 0U);
i = 0x01U; // success, recycle
}
else {
i = 0x81U; // failure, recycle
}
}
else if (l_rx.var.evt.prio == 254U) {
// init the current SM object&quot;
if (QS::rxPriv_.currObj[QS::SM_OBJ] != nullptr) {
// 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.
//
QEvt_refCtr_inc_(l_rx.var.evt.e);
static_cast&lt;QHsm *&gt;(QS::rxPriv_.currObj[QS::SM_OBJ])
-&gt;init(l_rx.var.evt.e, 0U);
i = 0x01U; // success, recycle
}
else {
i = 0x81U; // failure, recycle
}
}
else if (l_rx.var.evt.prio == 253U) {
// post to the current AO
if (QS::rxPriv_.currObj[QS::AO_OBJ] != nullptr) {
if (!static_cast&lt;QActive *&gt;(
QS::rxPriv_.currObj[QS::AO_OBJ])-&gt;POST_X(
l_rx.var.evt.e,
0U, // margin
&amp;QS::rxPriv_))
{
// failed QACTIVE_POST() recycles the event
i = 0x80U; // failure, no recycle
}
}
else {
i = 0x81U; // failure, recycle
}
}
else {
i = 0x81U; // failure, recycle
}
#if (QF_MAX_EPOOL &gt; 0U)
// recycle needed?
if ((i &amp; 1U) != 0U) {
QF::gc(l_rx.var.evt.e);
}
#endif
// failure?
if ((i &amp; 0x80U) != 0U) {
rxReportError_(static_cast&lt;std::uint8_t&gt;(QS_RX_EVENT));
}
else {
#ifdef Q_UTEST
#if Q_UTEST != 0
QS::processTestEvts_(); // process all events produced
#endif // Q_UTEST != 0
#endif // Q_UTEST
rxReportDone_(QS_RX_EVENT);
}
break;
}
#ifdef Q_UTEST
case WAIT4_TEST_SETUP_FRAME: {
rxReportAck_(QS_RX_TEST_SETUP);
QP::QS::testData.tpNum = 0U; // clear Test-Probes
QP::QS::testData.testTime = 0U; //clear time tick
// don't clear current objects
QS::onTestSetup(); // application-specific test setup
// no need to report Done
break;
}
case WAIT4_TEST_TEARDOWN_FRAME: {
rxReportAck_(QS_RX_TEST_TEARDOWN);
QS::onTestTeardown(); // application-specific test teardown
// no need to report Done
break;
}
case WAIT4_TEST_CONTINUE_FRAME: {
rxReportAck_(QS_RX_TEST_CONTINUE);
QS::rxPriv_.inTestLoop = false; // exit the QUTest loop
// no need to report Done
break;
}
case WAIT4_TEST_PROBE_FRAME: {
rxReportAck_(QS_RX_TEST_PROBE);
Q_ASSERT_ID(815,
QP::QS::testData.tpNum
&lt; (sizeof(QP::QS::testData.tpBuf)
/ sizeof(QP::QS::testData.tpBuf[0])));
QP::QS::testData.tpBuf[QP::QS::testData.tpNum] = l_rx.var.tp;
++QP::QS::testData.tpNum;
// no need to report Done
break;
}
#endif // Q_UTEST
case ERROR_STATE: {
// keep ignoring all bytes until new frame
break;
}
default: {
rxReportError_(0x47U);
break;
}
}</code>
</operation>
<!--${QS::QS-rx::onReset}-->
<operation name="onReset" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback function to reset the Target (to be implemented in the BSP)</documentation>
</operation>
<!--${QS::QS-rx::onCommand}-->
<operation name="onCommand" type="void" visibility="0x00" properties="0x00">
<documentation>//! Callback function to execute user commands (to be implemented in BSP)</documentation>
<!--${QS::QS-rx::onCommand::cmdId}-->
<parameter name="cmdId" type="std::uint8_t"/>
<!--${QS::QS-rx::onCommand::param1}-->
<parameter name="param1" type="std::uint32_t"/>
<!--${QS::QS-rx::onCommand::param2}-->
<parameter name="param2" type="std::uint32_t"/>
<!--${QS::QS-rx::onCommand::param3}-->
<parameter name="param3" type="std::uint32_t"/>
</operation>
</package>
</package>
<!--${QUTest}-->
<package name="QUTest" stereotype="0x05" namespace="QP::">
<!--${QUTest::QS}-->
<package name="QS" stereotype="0x02" namespace="QS::">
<!--${QUTest::QS::QUTEST_ON_POST}-->
<attribute name="QUTEST_ON_POST" type="constexpr std::uint8_t" visibility="0x04" properties="0x00">
<documentation>//! record ID for posting events</documentation>
<code>{124U};</code>
</attribute>
<!--${QUTest::QS::TProbe}-->
<attribute name="TProbe" type="struct" visibility="0x04" properties="0x00">
<documentation>//! Test Probe attributes</documentation>
<code>{
QSFun addr; //!&lt; pointer to function hosting the Test Probe
std::uint32_t data; //!&lt; data associated with the Test Probe
std::uint8_t idx; //!&lt; index of the Test Probe
};</code>
</attribute>
<!--${QUTest::QS::TestData}-->
<attribute name="TestData" type="struct" visibility="0x04" properties="0x00">
<documentation>//! QUTest data</documentation>
<code>{
TProbe tpBuf[16]; //!&lt; up to 16 Test Probes
std::uint8_t tpNum; //!&lt; # of registered Test Probes
QSTimeCtr testTime; //!&lt; test time stamp
};</code>
</attribute>
<!--${QUTest::QS::testData}-->
<attribute name="testData" type="TestData" visibility="0x00" properties="0x00">
<documentation>//! QUTest data</documentation>
</attribute>
<!--${QUTest::QS::test_pause_}-->
<operation name="test_pause_" type="void" visibility="0x00" properties="0x00">
<documentation>//! internal function to pause test and enter the test event loop</documentation>
<code>beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QP::QS_TEST_PAUSED));
endRec_();
onTestLoop();</code>
</operation>
<!--${QUTest::QS::getTestProbe_}-->
<operation name="getTestProbe_" type="std::uint32_t" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! get the test probe data for the given API</documentation>
<!--${QUTest::QS::getTestProbe_::api}-->
<parameter name="api" type="QP::QSpyFunPtr const"/>
<code>std::uint32_t data = 0U;
for (std::uint8_t i = 0U; i &lt; testData.tpNum; ++i) {
if (testData.tpBuf[i].addr == reinterpret_cast&lt;QSFun&gt;(api)) {
data = testData.tpBuf[i].data;
QS_CRIT_STAT_
QS_CRIT_E_();
QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(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_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
--testData.tpNum; // one less Test-Probe
// move all remaining entries in the buffer up by one
for (std::uint8_t j = i; j &lt; testData.tpNum; ++j) {
testData.tpBuf[j] = testData.tpBuf[j + 1U];
}
break; // we are done (Test-Probe retreived)
}
}
return data;</code>
</operation>
<!--${QUTest::QS::onTestSetup}-->
<operation name="onTestSetup" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback to setup a unit test inside the Target</documentation>
</operation>
<!--${QUTest::QS::onTestTeardown}-->
<operation name="onTestTeardown" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback to teardown after a unit test inside the Target</documentation>
</operation>
<!--${QUTest::QS::onTestEvt}-->
<operation name="onTestEvt" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback to &quot;massage&quot; the test event before dispatching/posting it</documentation>
<!--${QUTest::QS::onTestEvt::e}-->
<parameter name="e" type="QEvt *"/>
</operation>
<!--${QUTest::QS::onTestPost}-->
<operation name="onTestPost" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback to examine an event that is about to be posted</documentation>
<!--${QUTest::QS::onTestPost::sender}-->
<parameter name="sender" type="void const *"/>
<!--${QUTest::QS::onTestPost::recipient}-->
<parameter name="recipient" type="QActive *"/>
<!--${QUTest::QS::onTestPost::e}-->
<parameter name="e" type="QEvt const *"/>
<!--${QUTest::QS::onTestPost::status}-->
<parameter name="status" type="bool"/>
</operation>
<!--${QUTest::QS::onTestLoop}-->
<operation name="onTestLoop" type="void" visibility="0x00" properties="0x00">
<documentation>//! callback to run the test loop</documentation>
</operation>
</package>
</package>
<!--${QUTest-stub}-->
<package name="QUTest-stub" stereotype="0x05" namespace="QP::">
<!--${QUTest-stub::QS}-->
<package name="QS" stereotype="0x02" namespace="QS::">
<!--${QUTest-stub::QS::processTestEvts_}-->
<operation name="processTestEvts_" type="void" visibility="0x00" properties="0x00">
<documentation>//! internal function to process posted events during test</documentation>
<code>QS_TEST_PROBE_DEF(&amp;QS::processTestEvts_)
// return immediately (do nothing) for Test Probe != 0
QS_TEST_PROBE(return;)
while (QF::readySet_.notEmpty()) {
std::uint_fast8_t const p = QF::readySet_.findMax();
QActive * const a = QActive::registry_[p];
// perform the run-to-completion (RTC) step...
// 1. retrieve the event from the AO's event queue, which by this
// time must be non-empty and the &quot;Vanialla&quot; kernel asserts it.
// 2. dispatch the event to the AO's state machine.
// 3. determine if event is garbage and collect it if so
//
QEvt const * const e = a-&gt;get_();
a-&gt;dispatch(e, a-&gt;m_prio);
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e);
#endif
if (a-&gt;m_eQueue.isEmpty()) { // empty queue?
QF::readySet_.remove(p);
}
}</code>
</operation>
</package>
<!--${QUTest-stub::QF}-->
<package name="QF" stereotype="0x02" namespace="QF::">
<!--${QUTest-stub::QF::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x01">
<documentation>//! QF initialization 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).
QActive::subscrList_ = nullptr;
QActive::maxPubSignal_ = 0;
QF::intLock_ = 0U;
QF::intNest_ = 0U;
QF::maxPool_ = 0U;
bzero(&amp;QActive::registry_[0], sizeof(QActive::registry_));
bzero(&amp;QF::readySet_, sizeof(QF::readySet_));</code>
</operation>
<!--${QUTest-stub::QF::stop}-->
<operation name="stop" type="void" visibility="0x00" properties="0x01">
<documentation>//! stop the QF customization for QUTest
//!
//! @sa QF::onCleanup()</documentation>
<code>QS::onReset();</code>
</operation>
<!--${QUTest-stub::QF::run}-->
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
<documentation>//! QF::run() customization for QUTest</documentation>
<code>// function dictionaries for the standard API
QS_FUN_DICTIONARY(&amp;QActive::post_);
QS_FUN_DICTIONARY(&amp;QActive::postLIFO);
QS_FUN_DICTIONARY(&amp;QS::processTestEvts_);
// produce the QS_QF_RUN trace record
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QF_RUN, 0U)
QS_END_PRE_()
QS::processTestEvts_(); // process all events posted so far
QS::onTestLoop(); // run the unit test
QS::onCleanup(); // application cleanup
return 0; // return no error</code>
</operation>
</package>
<!--${QUTest-stub::QActive}-->
<class name="QActive" superclass="QEP::QHsm">
<documentation>//! QActive active object class customization for QUTest</documentation>
<!--${QUTest-stub::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<documentation>//! Starts execution of an active object and registers the object
//! with the framework customized for QUTest</documentation>
<!--${QUTest-stub::QActive::start::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<!--${QUTest-stub::QActive::start::qSto}-->
<parameter name="qSto" type="QEvt const * * const"/>
<!--${QUTest-stub::QActive::start::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QUTest-stub::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActive::start::par}-->
<parameter name="par" type="void const * const"/>
<code>Q_UNUSED_PAR(stkSto);
Q_UNUSED_PAR(stkSize);
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-priol
m_pthre = static_cast&lt;std::uint8_t&gt;(prioSpec &gt;&gt; 8U); // preemption-thre.
register_(); // make QF aware of this AO
m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
this-&gt;init(par, m_prio); // take the top-most initial tran. (virtual)</code>
</operation>
<!--${QUTest-stub::QActive::stop}-->
<operation name="stop?def QF_ACTIVE_STOP" type="void" visibility="0x00" properties="0x00">
<documentation>//! Stops execution of an active object and unregisters the object
//! with the framework customized for QUTest</documentation>
<code>unsubscribeAll(); // unsubscribe from all events
unregister_(); // remove this object from QF</code>
</operation>
</class>
<!--${QUTest-stub::QTimeEvt}-->
<class name="QTimeEvt" superclass="QEP::QEvt">
<documentation>//! QTimeEvt class customization for QUTest</documentation>
<!--${QUTest-stub::QTimeEvt::tick1_}-->
<operation name="tick1_" type="void" visibility="0x00" properties="0x01">
<documentation>//! Processes one clock tick for QUTest</documentation>
<!--${QUTest-stub::QTimeEvt::tick1_::tickRate}-->
<parameter name="tickRate" type="std::uint_fast8_t const"/>
<!--${QUTest-stub::QTimeEvt::tick1_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>// The testing version of system tick processing performs as follows:
// 1. If the Current Time Event (TE) Object is defined and the TE is armed,
// the TE is disarmed (if one-shot) and then posted to the recipient AO.
// 2. The linked-list of all armed Time Events is updated.
//
QF_CRIT_STAT_
QF_CRIT_E_();
QTimeEvt *prev = &amp;QTimeEvt::timeEvtHead_[tickRate];
QS_BEGIN_NOCRIT_PRE_(QS_QF_TICK, 0U)
prev-&gt;m_ctr = (prev-&gt;m_ctr + 1U);
QS_TEC_PRE_(prev-&gt;m_ctr); // tick ctr
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
// is current Time Event object provided?
QTimeEvt *t = static_cast&lt;QTimeEvt *&gt;(QS::rxPriv_.currObj[QS::TE_OBJ]);
if (t != nullptr) {
// the time event must be armed
Q_ASSERT_ID(810, t-&gt;m_ctr != 0U);
// temp. for volatile
QActive * const act = static_cast&lt;QActive *&gt;(t-&gt;m_act);
// the recipient AO must be provided
Q_ASSERT_ID(820, act != nullptr);
// periodic time evt?
if (t-&gt;m_interval != 0U) {
t-&gt;m_ctr = t-&gt;m_interval; // rearm the time event
}
else { // one-shot time event: automatically disarm
t-&gt;m_ctr = 0U; // auto-disarm
// mark time event 't' as NOT linked
t-&gt;refCtr_ = static_cast&lt;std::uint8_t&gt;(t-&gt;refCtr_
&amp; static_cast&lt;std::uint8_t&gt;(~TE_IS_LINKED));
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act-&gt;m_prio)
QS_OBJ_PRE_(t); // this time event object
QS_OBJ_PRE_(act); // the target AO
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_POST, act-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(t); // the time event object
QS_SIG_PRE_(t-&gt;sig); // signal of this time event
QS_OBJ_PRE_(act); // the target AO
QS_U8_PRE_(tickRate); // tick rate
QS_END_NOCRIT_PRE_()
QF_CRIT_X_(); // exit crit. section before posting
// asserts if queue overflows
static_cast&lt;void&gt;(act-&gt;POST(t, sender));
QF_CRIT_E_();
}
// update the linked list of time events
for (;;) {
t = prev-&gt;m_next; // advance down the time evt. list
// end of the list?
if (t == nullptr) {
// any new time events armed since the last run of tick_()?
if (QTimeEvt::timeEvtHead_[tickRate].m_act != nullptr) {
// sanity check
Q_ASSERT_CRIT_(830, prev != nullptr);
prev-&gt;m_next = QTimeEvt::timeEvtHead_[tickRate].toTimeEvt();
QTimeEvt::timeEvtHead_[tickRate].m_act = nullptr;
t = prev-&gt;m_next; // switch to the new list
}
else {
break; // all currently armed time evts. processed
}
}
// time event scheduled for removal?
if (t-&gt;m_ctr == 0U) {
prev-&gt;m_next = t-&gt;m_next;
// mark time event 't' as NOT linked
t-&gt;refCtr_ = static_cast&lt;std::uint8_t&gt;(t-&gt;refCtr_
&amp; static_cast&lt;std::uint8_t&gt;(~TE_IS_LINKED));
// do NOT advance the prev pointer
QF_CRIT_X_(); // exit crit. section to reduce latency
// prevent merging critical sections, see NOTE1 below
QF_CRIT_EXIT_NOP();
}
else {
prev = t; // advance to this time event
QF_CRIT_X_(); // exit crit. section to reduce latency
// prevent merging critical sections, see NOTE1 below
QF_CRIT_EXIT_NOP();
}
QF_CRIT_E_(); // re-enter crit. section to continue
}
QF_CRIT_X_();</code>
</operation>
</class>
<!--${QUTest-stub::QHsmDummy}-->
<class name="QHsmDummy" superclass="QEP::QHsm">
<documentation>//! Dummy HSM class for testing (inherits QP::QHsm)
//!
//! @details
//! QHsmDummy is a test double for the role of &quot;Orthogonal Components&quot;
//! HSM objects in QUTest unit testing.</documentation>
<!--${QUTest-stub::QHsmDummy::QHsmDummy}-->
<operation name="QHsmDummy" type="" visibility="0x00" properties="0x00">
<documentation>//! ctor</documentation>
<code>: QHsm(nullptr)</code>
</operation>
<!--${QUTest-stub::QHsmDummy::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QHsmDummy::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QUTest-stub::QHsmDummy::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
#ifdef Q_SPY
if ((QS::priv_.flags &amp; 0x01U) == 0U) {
QS::priv_.flags |= 0x01U;
QS_FUN_DICTIONARY(&amp;QP::QHsm::top);
}
#else
Q_UNUSED_PAR(qs_id);
#endif
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.fun); // the source state
QS_FUN_PRE_(m_temp.fun); // the target of the initial transition
QS_END_PRE_()</code>
</operation>
<!--${QUTest-stub::QHsmDummy::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QHsmDummy::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QHsmDummy::init(nullptr, qs_id);</code>
</operation>
<!--${QUTest-stub::QHsmDummy::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QHsmDummy::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QUTest-stub::QHsmDummy::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>#ifndef Q_SPY
Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
#endif
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.fun); // the current state
QS_END_PRE_()</code>
</operation>
</class>
<!--${QUTest-stub::QActiveDummy}-->
<class name="QActiveDummy" superclass="QF::QActive">
<documentation>//! Dummy Active Object class for testing (inherits QP::QActive)
//!
//! @details
//! QActiveDummy is a test double for the role of collaborating active
//! objects in QUTest unit testing.</documentation>
<!--${QUTest-stub::QActiveDummy::QActiveDummy}-->
<operation name="QActiveDummy" type="" visibility="0x00" properties="0x00">
<documentation>//! ctor</documentation>
<code>: QActive(nullptr)</code>
</operation>
<!--${QUTest-stub::QActiveDummy::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<specifiers>override</specifiers>
<!--${QUTest-stub::QActiveDummy::start::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<!--${QUTest-stub::QActiveDummy::start::qSto}-->
<parameter name="qSto" type="QEvt const * * const"/>
<!--${QUTest-stub::QActiveDummy::start::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActiveDummy::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QUTest-stub::QActiveDummy::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActiveDummy::start::par}-->
<parameter name="par" type="void const * const"/>
<code>// No special preconditions for checking parameters to allow starting
// dummy AOs the exact same way as the real counterparts.
Q_UNUSED_PAR(qSto);
Q_UNUSED_PAR(qLen);
Q_UNUSED_PAR(stkSto);
Q_UNUSED_PAR(stkSize);
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-prio.
m_pthre = static_cast&lt;std::uint8_t&gt;(prioSpec &gt;&gt; 8U); // preemption-thre.
register_(); // make QF aware of this AO
QActiveDummy::init(par, m_prio); // take the top-most initial tran.</code>
</operation>
<!--${QUTest-stub::QActiveDummy::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x06">
<specifiers>override</specifiers>
<!--${QUTest-stub::QActiveDummy::start::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<!--${QUTest-stub::QActiveDummy::start::qSto}-->
<parameter name="qSto" type="QEvt const * * const"/>
<!--${QUTest-stub::QActiveDummy::start::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActiveDummy::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QUTest-stub::QActiveDummy::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<code>this-&gt;start(prioSpec, qSto, qLen, stkSto, stkSize, nullptr);</code>
</operation>
<!--${QUTest-stub::QActiveDummy::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QActiveDummy::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QUTest-stub::QActiveDummy::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
#ifdef Q_SPY
if ((QS::priv_.flags &amp; 0x01U) == 0U) {
QS::priv_.flags |= 0x01U;
QS_FUN_DICTIONARY(&amp;QP::QHsm::top);
}
#endif
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_STATE_INIT, m_prio)
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.fun); // the source state
QS_FUN_PRE_(m_temp.fun); // the target of the initial transition
QS_END_PRE_()</code>
</operation>
<!--${QUTest-stub::QActiveDummy::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QActiveDummy::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>QActiveDummy::init(nullptr, qs_id);</code>
</operation>
<!--${QUTest-stub::QActiveDummy::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<!--${QUTest-stub::QActiveDummy::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QUTest-stub::QActiveDummy::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id);
QS_CRIT_STAT_
QS_BEGIN_PRE_(QS_QEP_DISPATCH, m_prio)
QS_TIME_PRE_(); // time stamp
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this state machine object
QS_FUN_PRE_(m_state.fun); // the current state
QS_END_PRE_()</code>
</operation>
<!--${QUTest-stub::QActiveDummy::post_}-->
<operation name="post_" type="bool" visibility="0x00" properties="0x04">
<specifiers>noexcept override</specifiers>
<!--${QUTest-stub::QActiveDummy::post_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QUTest-stub::QActiveDummy::post_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QUTest-stub::QActiveDummy::post_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>QS_TEST_PROBE_DEF(&amp;QActive::post_)
// 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_onAssert(&quot;qf_actq&quot;, 110);
}
)
QF_CRIT_STAT_
QF_CRIT_E_();
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
std::uint_fast8_t const rec =
(status ? static_cast&lt;std::uint8_t&gt;(QS_QF_ACTIVE_POST)
: static_cast&lt;std::uint8_t&gt;(QS_QF_ACTIVE_POST_ATTEMPT));
QS_BEGIN_NOCRIT_PRE_(rec, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; refCtr of the evt
QS_EQC_PRE_(0U); // number of free entries
QS_EQC_PRE_(margin); // margin requested
QS_END_NOCRIT_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-&gt;prio') is set
//
if ((QS::priv_.locFilter[m_prio &gt;&gt; 3U]
&amp; (1U &lt;&lt; (m_prio &amp; 7U))) != 0U)
{
QS::onTestPost(sender, this, e, status);
}
QF_CRIT_X_();
// recycle the event immediately, because it was not really posted
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e);
#endif
return status;</code>
</operation>
<!--${QUTest-stub::QActiveDummy::postLIFO}-->
<operation name="postLIFO" type="void" visibility="0x00" properties="0x04">
<specifiers>noexcept override</specifiers>
<!--${QUTest-stub::QActiveDummy::postLIFO::e}-->
<parameter name="e" type="QEvt const * const"/>
<code>QS_TEST_PROBE_DEF(&amp;QActive::postLIFO)
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_ID(1,
// fake assertion Mod=qf_actq,Loc=210
Q_onAssert(&quot;qf_actq&quot;, 210);
)
QF_CRIT_STAT_
QF_CRIT_E_();
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_LIFO, m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // pool Id &amp; refCtr of the evt
QS_EQC_PRE_(0U); // number of free entries
QS_EQC_PRE_(0U); // min number of free entries
QS_END_NOCRIT_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-&gt;prio') is set
//
if ((QS::priv_.locFilter[m_prio &gt;&gt; 3U]
&amp; (1U &lt;&lt; (m_prio &amp; 7U))) != 0U)
{
QS::onTestPost(nullptr, this, e, true);
}
QF_CRIT_X_();
// recycle the event immediately, because it was not really posted
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e);
#endif</code>
</operation>
</class>
</package>
<!--${QV}-->
<package name="QV" stereotype="0x05" namespace="QP::">
<!--${QV::QV-base}-->
<package name="QV-base" stereotype="0x02" namespace="QV::">
<!--${QV::QV-base::onIdle}-->
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
<documentation>//! QV idle callback (customized in BSPs for QV)
//!
//! @attention
//! QV::onIdle() must be called with interrupts DISABLED because the
//! determination of the idle condition (no events in the queues) can
//! change at any time by an interrupt posting events to a queue.
//! QV::onIdle() MUST enable interrupts internally, ideally **atomically**
//! with putting the CPU into a power-saving mode.</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>//! QF initialization for QV</documentation>
<code>#if (QF_MAX_EPOOL &gt; 0U)
QF::maxPool_ = 0U;
#endif
bzero(&amp;QTimeEvt::timeEvtHead_[0], sizeof(QTimeEvt::timeEvtHead_));
bzero(&amp;QActive::registry_[0], sizeof(QActive::registry_));
bzero(&amp;QF::readySet_, sizeof(QF::readySet_));
#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>//! stop the QF customization for QV
//!
//! @sa QP::QF::onCleanup()</documentation>
<code>onCleanup(); // cleanup callback
// nothing else to do for the QV kernel</code>
</operation>
<!--${QV::QF-cust::run}-->
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
<documentation>//! QF::run() customization for QV kernel</documentation>
<code>#ifdef Q_SPY
// produce the QS_QF_RUN trace record
QF_INT_DISABLE();
QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
QS::endRec_();
QF_INT_ENABLE();
#endif
onStartup(); // startup callback
QF_INT_DISABLE();
#ifdef QV_START
QV_START(); // port-specific startup of the QV kernel
#endif
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
std::uint_fast8_t pprev = 0U; // previous priority
#endif
for (;;) { // QV event loop...
// find the maximum priority AO ready to run
if (readySet_.notEmpty()) {
std::uint_fast8_t const p = readySet_.findMax();
QActive * const a = QActive::registry_[p];
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, p)
QS_TIME_PRE_(); // timestamp
QS_2U8_PRE_(p, pprev); // scheduled prio &amp; previous prio
QS_END_NOCRIT_PRE_()
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(((pprev != 0U)
? QActive::registry_[pprev]
: nullptr), a);
#endif // QF_ON_CONTEXT_SW
pprev = p; // update previous priority
#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
QF_INT_ENABLE();
// perform the run-to-completion (RTC) step...
// 1. retrieve the event from the AO's event queue, which by
// this time must be non-empty and The QV kernel asserts it.
// 2. dispatch the event to the AO's state machine.
// 3. determine if event is garbage and collect it if so
//
QEvt const * const e = a-&gt;get_();
a-&gt;dispatch(e, a-&gt;m_prio);
#if (QF_MAX_EPOOL &gt; 0U)
gc(e);
#endif
QF_INT_DISABLE();
if (a-&gt;m_eQueue.isEmpty()) { // empty queue?
readySet_.remove(p);
}
}
else { // no AO ready to run --&gt; idle
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (pprev != 0U) {
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, pprev)
QS_TIME_PRE_(); // timestamp
QS_U8_PRE_(pprev); // previous prio
QS_END_NOCRIT_PRE_()
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QActive::registry_[pprev], nullptr);
#endif // QF_ON_CONTEXT_SW
pprev = 0U; // update previous prio
}
#endif // (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
// QV::onIdle() must be called with interrupts DISABLED because
// the determination of the idle condition (no events in the
// queues) can change at any time by an interrupt posting events
// to a queue. QV::onIdle() MUST enable interrupts internally,
// perhaps at the same time as putting the CPU into a power-saving
// mode.
QV::onIdle();
QF_INT_DISABLE();
}
}
#ifdef __GNUC__ // GNU compiler?
return 0;
#endif</code>
</operation>
</package>
<!--${QV::QActive}-->
<class name="QActive" superclass="QEP::QHsm">
<documentation>//! QActive active object class customization for QV</documentation>
<!--${QV::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<documentation>//! Starts execution of an active object and registers the object
//! with the framework customized for QV</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="std::uint_fast16_t const"/>
<!--${QV::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QV::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::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
//! @pre stack storage must not be provided because the QV kernel
//! does not need per-AO stacks.
//!
Q_REQUIRE_ID(500, stkSto == nullptr);
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-prio.
m_pthre = static_cast&lt;std::uint8_t&gt;(prioSpec &gt;&gt; 8U); // preemption-thre.
register_(); // make QF aware of this AO
m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
this-&gt;init(par, m_prio); // take the top-most initial tran. (virtual)
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">
<documentation>//! QV scheduler lock status (not needed in QV)</documentation>
</attribute>
<!--${QV-impl::QF_SCHED_LOCK_}-->
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
<documentation>//! QV scheduler locking (not needed in QV)</documentation>
<!--${QV-impl::QF_SCHED_LOCK_::dummy}-->
<parameter name="dummy" type=""/>
<code>(static_cast&lt;void&gt;(0))</code>
</operation>
<!--${QV-impl::QF_SCHED_UNLOCK_}-->
<operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
<documentation>//! QV scheduler unlocking (not needed in QV)</documentation>
<code>(static_cast&lt;void&gt;(0))</code>
</operation>
<!--${QV-impl::QACTIVE_EQUEUE_WAIT_}-->
<operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
<documentation>//! QV native event queue waiting</documentation>
<!--${QV-impl::QACTIVE_EQUEUE_W~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>\
Q_ASSERT_ID(110, (me_)-&gt;m_eQueue.m_frontEvt != nullptr)</code>
</operation>
<!--${QV-impl::QACTIVE_EQUEUE_SIGNAL_}-->
<operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
<documentation>//! QV native event queue signaling</documentation>
<!--${QV-impl::QACTIVE_EQUEUE_S~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>\
(QF::readySet_.insert(static_cast&lt;std::uint_fast8_t&gt;((me_)-&gt;m_prio)))</code>
</operation>
</package>
<!--${QK}-->
<package name="QK" stereotype="0x05" namespace="QP::">
<!--${QK::QK-base}-->
<package name="QK-base" stereotype="0x02" namespace="QK::">
<!--${QK::QK-base::onIdle}-->
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
<documentation>//! QK idle callback (customized in BSPs for QK)
//!
//! @details
//! QK::onIdle() is called continuously by the QK idle loop. This callback
//! gives the application an opportunity to enter a power-saving CPU mode,
//! or perform some other idle processing.
//!
//! @note
//! QK::onIdle() is invoked with interrupts enabled and must also return
//! with interrupts enabled.
//!
//! @sa QV::onIdle(), QXK::onIdle()</documentation>
</operation>
<!--${QK::QK-base::schedLock}-->
<operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! QK selective scheduler lock
//!
//! @details
//! This function locks the QK scheduler to the specified ceiling.
//!
//! @param[in] ceiling priority ceiling to which the QK scheduler
//! needs to be locked
//!
//! @returns
//! The previous QK Scheduler lock status, which is to be used to unlock
//! the scheduler by restoring its previous lock status in
//! QP::QK::schedUnlock().
//!
//! @note
//! QP::QK::schedLock() must be always followed by the corresponding
//! QP::QK::schedUnlock().
//!
//! @sa QK_schedUnlock()
//!
//! @usage
//! The following example shows how to lock and unlock the QK scheduler:
//! @include qk_lock.cpp</documentation>
<!--${QK::QK-base::schedLock::ceiling}-->
<parameter name="ceiling" type="std::uint_fast8_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
//! @pre The QK scheduler lock cannot be called from an ISR
Q_REQUIRE_ID(600, !QK_ISR_CONTEXT_());
// first store the previous lock prio
QSchedStatus stat;
if (ceiling &gt; QK_attr_.lockCeil) { // raising the lock ceiling?
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_LOCK, 0U)
QS_TIME_PRE_(); // timestamp
// the previous lock ceiling &amp; new lock ceiling
QS_2U8_PRE_(QK_attr_.lockCeil,
static_cast&lt;std::uint8_t&gt;(ceiling));
QS_END_NOCRIT_PRE_()
// previous status of the lock
stat = static_cast&lt;QSchedStatus&gt;(QK_attr_.lockHolder);
stat = stat | (static_cast&lt;QSchedStatus&gt;(QK_attr_.lockCeil) &lt;&lt; 8U);
// new status of the lock
QK_attr_.lockHolder = QK_attr_.actPrio;
QK_attr_.lockCeil = static_cast&lt;std::uint8_t&gt;(ceiling);
}
else {
stat = 0xFFU; // scheduler not locked
}
QF_CRIT_X_();
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">
<specifiers>noexcept</specifiers>
<documentation>//! QK selective scheduler unlock
//!
//! @details
//! This function unlocks the QK scheduler to the previous status.
//!
//! @param[in] stat previous QK Scheduler lock status returned from
//! QP::QK::schedLock()
//! @note
//! QP::QK::schedUnlock() must always follow the corresponding
//! QP::QK::schedLock().
//!
//! @sa QP::QK::schedLock()
//!
//! @usage
//! The following example shows how to lock and unlock the QK scheduler:
//! @include qk_lock.cpp</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) {
std::uint8_t const lockCeil = QK_attr_.lockCeil;
std::uint8_t const prevCeil = static_cast&lt;std::uint8_t&gt;(stat &gt;&gt; 8U);
QF_CRIT_STAT_
QF_CRIT_E_();
//! @pre The scheduler cannot be unlocked:
//! - from the ISR context; and
//! - the current lock ceiling must be greater than the previous
Q_REQUIRE_ID(700, (!QK_ISR_CONTEXT_())
&amp;&amp; (lockCeil &gt; prevCeil));
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U)
QS_TIME_PRE_(); // timestamp
// current lock ceiling (old), previous lock ceiling (new)
QS_2U8_PRE_(lockCeil, prevCeil);
QS_END_NOCRIT_PRE_()
// restore the previous lock ceiling and lock holder
QK_attr_.lockCeil = prevCeil;
QK_attr_.lockHolder = static_cast&lt;std::uint8_t&gt;(stat &amp; 0xFFU);
// find if any AOs should be run after unlocking the scheduler
if (QK_sched_() != 0U) { // synchronous preemption needed?
QK_activate_(); // synchronously activate any unlocked AOs
}
QF_CRIT_X_();
}</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>//! QF initialization for QK</documentation>
<code>#if (QF_MAX_EPOOL &gt; 0U)
QF::maxPool_ = 0U;
#endif
bzero(&amp;QTimeEvt::timeEvtHead_[0], sizeof(QTimeEvt::timeEvtHead_));
bzero(&amp;QActive::registry_[0], sizeof(QActive::registry_));
bzero(&amp;QF::readySet_, sizeof(QF::readySet_));
bzero(&amp;QK_attr_, sizeof(QK_attr_));
// setup the QK scheduler as initially locked and not running
QK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
// storage capable for holding a blank QActive object (const in ROM)
static void* const
idle_ao[((sizeof(QActive) + sizeof(void*)) - 1U) / sizeof(void*)]
= { nullptr };
// register the blank QActive object as the idle-AO (cast 'const' away)
QActive::registry_[0] = QF_CONST_CAST_(QActive*,
reinterpret_cast&lt;QActive const*&gt;(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>//! stop the QF customization for QK
//!
//! @sa QF::onCleanup()</documentation>
<code>onCleanup(); // cleanup callback
// nothing else to do for the QK preemptive kernel</code>
</operation>
<!--${QK::QF-cust::run}-->
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
<documentation>//! QF::run() customization for QK kernel</documentation>
<code>#ifdef Q_SPY
// produce the QS_QF_RUN trace record
QF_INT_DISABLE();
QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
QS::endRec_();
QF_INT_ENABLE();
#endif
onStartup(); // startup callback
QF_INT_DISABLE();
QK_attr_.lockCeil = 0U; // unlock the QK scheduler
// activate AOs to process events posted so far
if (QK_sched_() != 0U) {
QK_activate_();
}
onStartup(); // application-specific startup callback
#ifdef QK_START
QK_START(); // port-specific startup of the QK kernel
#endif
QF_INT_ENABLE();
for (;;) { // QK idle loop...
QK::onIdle(); // application-specific QK on-idle callback
}
#ifdef __GNUC__ // GNU compiler?
return 0;
#endif</code>
</operation>
</package>
<!--${QK::QActive}-->
<class name="QActive" superclass="QEP::QHsm">
<documentation>//! QActive active object class customization for QV</documentation>
<!--${QK::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<documentation>//! Starts execution of an active object and registers the object
//! with the framework customized for QK</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="std::uint_fast16_t const"/>
<!--${QK::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QK::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::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
//! @pre
//! AO cannot be started from an ISR, and the stack storage must not
//! be provided, because the QK kernel does not need per-AO stacks.
Q_REQUIRE_ID(300, (!QK_ISR_CONTEXT_())
&amp;&amp; (stkSto == nullptr));
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-prio.
m_pthre = static_cast&lt;std::uint8_t&gt;(prioSpec &gt;&gt; 8U); // preemption-thre.
register_(); // make QF aware of this AO
m_eQueue.init(qSto, qLen); // initialize the built-in queue
this-&gt;init(par, m_prio); // take the top-most initial tran. (virtual)
QS_FLUSH(); // flush the trace buffer to the host
// See if this AO needs to be scheduled in case QK is already running
QF_CRIT_STAT_
QF_CRIT_E_();
if (QK_sched_() != 0U) { // synchronous preemption needed?
QK_activate_(); // synchronously activate AOs
}
QF_CRIT_X_();</code>
</operation>
</class>
</package>
<!--${QK-extern-C}-->
<package name="QK-extern-C" stereotype="0x02">
<!--${QK-extern-C::QK_Attr}-->
<attribute name="QK_Attr" type="struct" visibility="0x04" properties="0x00">
<documentation>//! attributes of the QK kernel (extern &quot;C&quot; for easy access in assembly)</documentation>
<code>{
std::uint8_t volatile actPrio; //!&lt; prio of the active AO
std::uint8_t volatile nextPrio; //!&lt; prio of the next AO to execute
std::uint8_t volatile actThre; //!&lt; active preemption-threshold
std::uint8_t volatile lockCeil; //!&lt; lock preemption-ceiling (0==no-lock)
std::uint8_t volatile lockHolder; //!&lt; prio of the lock holder
};</code>
</attribute>
<!--${QK-extern-C::QK_attr_}-->
<attribute name="QK_attr_" type="QK_Attr" visibility="0x00" properties="0x00">
<documentation>//! attributes of the QK kernel (extern &quot;C&quot; to be accessible from C)</documentation>
</attribute>
<!--${QK-extern-C::QK_sched_}-->
<operation name="QK_sched_" type="std::uint_fast8_t" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! QK scheduler finds the highest-priority thread ready to run
//!
//! @details
//! The QK scheduler finds out the priority of the highest-priority AO
//! that (1) has events to process and (2) has priority that is above the
//! current priority.
//!
//! @returns
//! The QF-priority of the next active object to activate, or zero
//! if no activation of AO is needed.
//!
//! @attention
//! QK_sched_() must be always called with interrupts **disabled** and
//! returns with interrupts **disabled**.</documentation>
<code>std::uint_fast8_t p;
if (QP::QF::readySet_.isEmpty()) {
p = 0U; // no activation needed
}
else {
// find the highest-prio AO with non-empty event queue
p = QP::QF::readySet_.findMax();
// is the AO's priority below the active preemption-threshold?
if (p &lt;= QK_attr_.actThre) {
p = 0U; // no activation needed
}
// is the AO's priority below the lock preemption-ceiling?
else if (p &lt;= QK_attr_.lockCeil) {
p = 0U; // no activation needed
}
else {
QK_attr_.nextPrio = static_cast&lt;std::uint8_t&gt;(p);
}
}
return p;</code>
</operation>
<!--${QK-extern-C::QK_activate_}-->
<operation name="QK_activate_" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! QK activator activates the next active object. The activated AO preempts
//! the currently executing AOs
//!
//! @details
//! QK_activate_() activates ready-to run AOs that are above the initial
//! preemption-threshold.
//!
//! @note
//! The activator might enable interrupts internally, but always returns with
//! interrupts **disabled**.</documentation>
<code>std::uint8_t const prio_in = QK_attr_.actPrio; // saved initial priority
std::uint8_t p = QK_attr_.nextPrio; // next prio to run
QK_attr_.nextPrio = 0U; // clear for the next time
// QK_attr_.actPrio and QK_attr_.nextPrio must be in range
Q_REQUIRE_ID(500, (prio_in &lt;= QF_MAX_ACTIVE)
&amp;&amp; (0U &lt; p) &amp;&amp; (p &lt;= QF_MAX_ACTIVE));
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
std::uint8_t pprev = prio_in;
#endif // QF_ON_CONTEXT_SW || Q_SPY
// loop until no more ready-to-run AOs of higher prio than the initial
QP::QActive *a;
do {
a = QP::QActive::registry_[p]; // obtain the pointer to the AO
Q_ASSERT_ID(505, a != nullptr); // the AO must be registered
// set new active priority and preemption-ceiling
QK_attr_.actPrio = p;
QK_attr_.actThre = a-&gt;m_pthre;
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (p != pprev) { // changing threads?
QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, p)
QS_TIME_PRE_(); // timestamp
QS_2U8_PRE_(p, // priority of the scheduled AO
pprev); // previous priority
QS_END_NOCRIT_PRE_()
#ifdef QF_ON_CONTEXT_SW
// context-switch callback
QF_onContextSw(((pprev != 0U)
? QP::QActive::registry_[pprev]
: nullptr), a);
#endif // QF_ON_CONTEXT_SW
pprev = p; // update previous priority
}
#endif // QF_ON_CONTEXT_SW || Q_SPY
QF_INT_ENABLE(); // unconditionally enable interrupts
// perform the run-to-completion (RTC) step...
// 1. retrieve the event from the AO's event queue, which by this
// time must be non-empty and QActive::get_() asserts it.
// 2. dispatch the event to the AO's state machine.
// 3. determine if event is garbage and collect it if so
QP::QEvt const * const e = a-&gt;get_();
a-&gt;dispatch(e, a-&gt;m_prio);
#if (QF_MAX_EPOOL &gt; 0U)
QP::QF::gc(e);
#endif
// determine the next highest-priority AO ready to run...
QF_INT_DISABLE(); // unconditionally disable interrupts
if (a-&gt;m_eQueue.isEmpty()) { // empty queue?
QP::QF::readySet_.remove(p);
}
if (QP::QF::readySet_.isEmpty()) {
p = 0U; // no activation needed
}
else {
// find new highest-prio AO ready to run...
p = static_cast&lt;std::uint8_t&gt;(QP::QF::readySet_.findMax());
// is the new priority below the initial preemption-threshold?
if (p &lt;= QP::QActive::registry_[prio_in]-&gt;m_pthre) {
p = 0U; // no activation needed
}
// is the AO's priority below the lock preemption-ceiling?
else if (p &lt;= QK_attr_.lockCeil) {
p = 0U; // no activation needed
}
else {
Q_ASSERT_ID(510, p &lt;= QF_MAX_ACTIVE);
}
}
} while (p != 0U);
// restore the active priority and preemption-threshold
QK_attr_.actPrio = prio_in;
QK_attr_.actThre = QP::QActive::registry_[prio_in]-&gt;m_pthre;
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (prio_in != 0U) { // resuming an active object?
a = QP::QActive::registry_[prio_in]; // pointer to preempted AO
QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, prio_in)
QS_TIME_PRE_(); // timestamp
// priority of the resumed AO, previous priority
QS_2U8_PRE_(prio_in, pprev);
QS_END_NOCRIT_PRE_()
}
else { // resuming priority==0 --&gt; idle
a = nullptr; // QK idle loop
QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, pprev)
QS_TIME_PRE_(); // timestamp
QS_U8_PRE_(pprev); // previous priority
QS_END_NOCRIT_PRE_()
}
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QP::QActive::registry_[pprev], a);
#endif // QF_ON_CONTEXT_SW
#endif // QF_ON_CONTEXT_SW || Q_SPY</code>
</operation>
</package>
<!--${QK-impl}-->
<package name="QK-impl" stereotype="0x02">
<!--${QK-impl::QK_ISR_CONTEXT_}-->
<operation name="QK_ISR_CONTEXT_?ndef QK_ISR_CONTEXT_" type="" visibility="0x03" properties="0x00">
<documentation>//! Internal port-specific macro that checks the execution context
//! (ISR vs. thread). Might be overridden in qk_port.hpp.
//!
//! @returns
//! 'true' if the code executes in the ISR context and 'false' otherwise.</documentation>
<code>(QF::intNest_ != 0U)</code>
</operation>
<!--${QK-impl::QF_SCHED_STAT_}-->
<attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
<documentation>//! QK scheduler lock status</documentation>
<code>QSchedStatus lockStat_;</code>
</attribute>
<!--${QK-impl::QF_SCHED_LOCK_}-->
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
<documentation>//! QK selective scheduler locking</documentation>
<!--${QK-impl::QF_SCHED_LOCK_::ceil_}-->
<parameter name="ceil_" type="std::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">
<documentation>//! QK selective scheduler unlocking</documentation>
<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">
<documentation>// QK native event queue waiting</documentation>
<!--${QK-impl::QACTIVE_EQUEUE_W~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>\
Q_ASSERT_ID(110, (me_)-&gt;m_eQueue.m_frontEvt != nullptr)</code>
</operation>
<!--${QK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
<operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
<documentation>// QK native event queue signaling</documentation>
<!--${QK-impl::QACTIVE_EQUEUE_S~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>do { \
QF::readySet_.insert( \
static_cast&lt;std::uint_fast8_t&gt;((me_)-&gt;m_prio)); \
if (!QK_ISR_CONTEXT_()) { \
if (QK_sched_() != 0U) { \
QK_activate_(); \
} \
} \
} while (false)</code>
</operation>
</package>
<!--${QXK}-->
<package name="QXK" stereotype="0x05" namespace="QP::">
<!--${QXK::QXK-base}-->
<package name="QXK-base" stereotype="0x02" namespace="QXK::">
<!--${QXK::QXK-base::onIdle}-->
<operation name="onIdle" type="void" visibility="0x00" properties="0x01">
<documentation>//! QXK idle callback (customized in BSPs for QXK)
//!
//! @details
//! QXK::onIdle() is called continously by the QXK idle loop. This
//! callback gives the application an opportunity to enter a power-saving
//! CPU mode, or perform some other idle processing.
//!
//! @note
//! QXK::onIdle() is invoked with interrupts enabled and must also return
//! with interrupts enabled.
//!
//! @sa
//! QK::onIdle(), QXK::onIdle()</documentation>
</operation>
<!--${QXK::QXK-base::schedLock}-->
<operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! QXK selective scheduler lock
//!
//! @details
//! This function locks the QXK scheduler to the specified ceiling.
//!
//! @param[in] ceiling priority ceiling to which the QXK scheduler
//! needs to be locked
//!
//! @returns
//! The previous QXK Scheduler lock status, which is to be used to unlock
//! the scheduler by restoring its previous lock status in
//! QXK::schedUnlock().
//!
//! @note
//! QXK::schedLock() must be always followed by the corresponding
//! QXK::schedUnlock().
//!
//! @sa QXK::schedUnlock()
//!
//! @usage
//! The following example shows how to lock and unlock the QXK scheduler:
//! @include qxk_lock.cpp</documentation>
<!--${QXK::QXK-base::schedLock::ceiling}-->
<parameter name="ceiling" type="std::uint_fast8_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
//! @pre The QXK scheduler lock cannot be called from an ISR;
Q_REQUIRE_ID(400, !QXK_ISR_CONTEXT_());
QSchedStatus stat; // saved lock status to be returned
// is the lock ceiling being raised?
if (ceiling &gt; static_cast&lt;std::uint_fast8_t&gt;(QXK_attr_.lockCeil)) {
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_LOCK, 0U)
QS_TIME_PRE_(); // timestamp
// the previous lock prio &amp; new lock prio
QS_2U8_PRE_(QXK_attr_.lockCeil,
static_cast&lt;std::uint8_t&gt;(ceiling));
QS_END_NOCRIT_PRE_()
// previous status of the lock
stat = static_cast&lt;QSchedStatus&gt;(QXK_attr_.lockHolder);
stat |= static_cast&lt;QSchedStatus&gt;(QXK_attr_.lockCeil) &lt;&lt; 8U;
// new status of the lock
QXK_attr_.lockHolder = (QXK_attr_.curr != nullptr)
? QXK_attr_.curr-&gt;m_prio
: 0U;
QXK_attr_.lockCeil = static_cast&lt;std::uint8_t&gt;(ceiling);
}
else {
stat = 0xFFU; // scheduler not locked
}
QF_CRIT_X_();
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">
<specifiers>noexcept</specifiers>
<documentation>//! QXK selective scheduler unlock
//!
//! @details
//! This function unlocks the QXK scheduler to the previous status.
//!
//! @param[in] stat previous QXK Scheduler lock status returned
//! from QXK::schedLock()
//! @note
//! A QXK scheduler can be locked from both basic threads (AOs) and
//! extended threads and the scheduler locks can nest.
//!
//! @note
//! QXK::schedUnlock() must always follow the corresponding
//! QXK::schedLock().
//!
//! @sa QXK::schedLock()
//!
//! @usage
//! The following example shows how to lock and unlock the QXK scheduler:
//! @include qxk_lock.cpp</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) {
std::uint8_t const lockCeil = QXK_attr_.lockCeil;
std::uint8_t const prevCeil = static_cast&lt;std::uint8_t&gt;(stat &gt;&gt; 8U);
QF_CRIT_STAT_
QF_CRIT_E_();
//! @pre The scheduler cannot be unlocked:
//! - from the ISR context; and
//! - the current lock priority must be greater than the previous
Q_REQUIRE_ID(500, (!QXK_ISR_CONTEXT_())
&amp;&amp; (lockCeil &gt; prevCeil));
QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U)
QS_TIME_PRE_(); // timestamp
// ceiling before unlocking &amp; prio after unlocking
QS_2U8_PRE_(lockCeil, prevCeil);
QS_END_NOCRIT_PRE_()
// restore the previous lock priority and lock holder
QXK_attr_.lockCeil = prevCeil;
QXK_attr_.lockHolder = static_cast&lt;std::uint8_t&gt;(stat &amp; 0xFFU);
// find the highest-prio thread ready to run
if (QXK_sched_() != 0U) { // synchronous preemption needed?
QXK_activate_(); // synchronously activate unlocked AOs
}
QF_CRIT_X_();
}</code>
</operation>
<!--${QXK::QXK-base::Timeouts}-->
<attribute name="Timeouts" type="enum" visibility="0x04" properties="0x00">
<documentation>//! timeout signals for extended threads</documentation>
<code>: enum_t {
DELAY_SIG = 1,
TIMEOUT_SIG
};</code>
</attribute>
</package>
<!--${QXK::QXThread}-->
<class name="QXThread" superclass="QF::QActive">
<documentation>//! Extended (blocking) thread of the QXK preemptive kernel
//!
//! @details
//! QP::QXThread represents the extended (blocking) thread of the QXK kernel.
//! Each blocking thread in the application must be represented by the
//! corresponding QP::QXThread instance
//!
//! @note
//! Typically QP::QXThread is instantiated directly in the application code.
//! The customization of the thread occurs in the constructor, where you
//! provide the thread-handler function as the parameter.
//!
//! @sa QP::QActive
//!
//! @usage
//! The following example illustrates how to instantiate and use an extended
//! thread in your application.
//! @include qxk_thread.cpp
//!</documentation>
<!--${QXK::QXThread::m_timeEvt}-->
<attribute name="m_timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00">
<documentation>//! time event to handle blocking timeouts</documentation>
</attribute>
<!--${QXK::QXThread::QXSemaphore}-->
<attribute name="QXSemaphore" type="friend class" visibility="0x02" properties="0x00">
<documentation>// friends...</documentation>
</attribute>
<!--${QXK::QXThread::QXMutex}-->
<attribute name="QXMutex" type="friend class" visibility="0x02" properties="0x00"/>
<!--${QXK::QXThread::QXThread}-->
<operation name="QXThread" type="" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! public constructor
//!
//! @details
//! Performs the first step of QXThread initialization by assigning the
//! thread-handler function and the tick rate at which it will handle
//! the timeouts.
//!
//! @param[in] handler the thread-handler function
//! @param[in] tickRate the ticking rate associated with this thread
//! for timeouts in this thread (see QXThread::delay() and
//! TICK_X())
//! @note
//! Must be called only ONCE before QXThread::start().</documentation>
<!--${QXK::QXThread::QXThread::handler}-->
<parameter name="handler" type="QXThreadHandler const"/>
<!--${QXK::QXThread::QXThread::tickRate = 0U}-->
<parameter name="tickRate = 0U" type="std::uint_fast8_t const"/>
<code> : QActive(Q_STATE_CAST(handler)),
m_timeEvt(this, static_cast&lt;enum_t&gt;(QXK::DELAY_SIG),
static_cast&lt;std::uint_fast8_t&gt;(tickRate))
m_state.act = nullptr; // mark as extended thread</code>
</operation>
<!--${QXK::QXThread::getTimeEvt}-->
<operation name="getTimeEvt" type="QTimeEvt const *" visibility="0x00" properties="0x02">
<specifiers>const noexcept</specifiers>
<documentation>//! obtain the time event</documentation>
<code>return &amp;m_timeEvt;</code>
</operation>
<!--${QXK::QXThread::delay}-->
<operation name="delay" type="bool" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! delay (block) the current extended thread for a specified # ticks
//!
//! @details
//! Blocking delay for the number of clock tick at the associated
//! tick rate.
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to wait for the event to arrive.
//! @returns
//! 'true' if the delay expired and `false` if it was cancelled
//! by call to QTimeEvt::delayCancel()
//!
//! @note
//! For the delay to work, the TICK_X() macro needs to be called
//! periodically at the associated clock tick rate.
//!
//! @sa
//! QP::QXThread, QTimeEvt::tick_()</documentation>
<!--${QXK::QXThread::delay::nTicks}-->
<parameter name="nTicks" type="std::uint_fast16_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QXThread * const thr = QXK_PTR_CAST_(QXThread*, QXK_attr_.curr);
//! @pre 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_ID(800, (!QXK_ISR_CONTEXT_())
&amp;&amp; (nTicks != 0U)
&amp;&amp; (thr != nullptr)
&amp;&amp; (thr-&gt;m_temp.obj == nullptr));
//! @pre also: the thread must NOT be holding a scheduler lock
Q_REQUIRE_ID(801, QXK_attr_.lockHolder != thr-&gt;m_prio);
// remember the blocking object
thr-&gt;m_temp.obj = QXK_PTR_CAST_(QMState const*, &amp;thr-&gt;m_timeEvt);
thr-&gt;teArm_(static_cast&lt;enum_t&gt;(QXK::DELAY_SIG), nTicks);
thr-&gt;block_();
QF_CRIT_X_();
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_E_();
// the blocking object must be the time event
Q_ENSURE_ID(890, thr-&gt;m_temp.obj
== QXK_PTR_CAST_(QMState*, &amp;thr-&gt;m_timeEvt));
thr-&gt;m_temp.obj = nullptr; // clear
QF_CRIT_X_();
// signal of zero means that the time event was posted without
// being canceled.
return (thr-&gt;m_timeEvt.sig == 0U);</code>
</operation>
<!--${QXK::QXThread::delayCancel}-->
<operation name="delayCancel" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! cancel the delay
//!
//! @details
//! Cancel the blocking delay and cause return from the QXThread::delay()
//! function.
//!
//! @returns
//! &quot;true&quot; if the thread was actually blocked on QXThread::delay() and
//! &quot;false&quot; otherwise.</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
bool wasArmed;
if (m_temp.obj == QXK_PTR_CAST_(QMState*, &amp;m_timeEvt)) {
wasArmed = teDisarm_();
unblock_();
}
else {
wasArmed = false;
}
QF_CRIT_X_();
return wasArmed;</code>
</operation>
<!--${QXK::QXThread::queueGet}-->
<operation name="queueGet" type="QEvt const *" visibility="0x00" properties="0x01">
<specifiers>noexcept</specifiers>
<documentation>//! Get a message from the private message queue (block if no messages)
//!
//! @details
//! The QXThread::queueGet() operation allows the calling extended thread
//! to receive QP events (see QP::QEvt) directly into its own built-in
//! event queue from an ISR, basic thread (AO), or another extended thread.
//!
//! If QXThread::queueGet() is called when no events are present in the
//! thread's private event queue, the operation blocks the current
//! extended thread until either an event is received, or a user-specified
//! timeout expires.
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to wait for the event to arrive. The value of
//! QP::QXTHREAD_NO_TIMEOUT indicates that no timeout
//! will occur and the queue will block indefinitely.
//! @returns
//! A pointer to the event. If the pointer is not nullptr, the event
//! was delivered. Otherwise the event pointer of nullptr indicates that
//! the queue has timed out.</documentation>
<!--${QXK::QXThread::queueGet::nTicks = QXTHREAD_NO_TIMEOUT}-->
<parameter name="nTicks = QXTHREAD_NO_TIMEOUT" type="std::uint_fast16_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QXThread * const thr = QXTHREAD_CAST_(QXK_attr_.curr);
//! @pre 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_ID(500, (!QXK_ISR_CONTEXT_())
&amp;&amp; (thr != nullptr)
&amp;&amp; (thr-&gt;m_temp.obj == nullptr));
//! @pre also: the thread must NOT be holding a scheduler lock.
Q_REQUIRE_ID(501, QXK_attr_.lockHolder != thr-&gt;m_prio);
// is the queue empty? -- block and wait for event(s)
if (thr-&gt;m_eQueue.m_frontEvt == nullptr) {
// remember the blocking object (the thread's queue)
thr-&gt;m_temp.obj = QXK_PTR_CAST_(QMState*, &amp;thr-&gt;m_eQueue);
thr-&gt;teArm_(static_cast&lt;enum_t&gt;(QXK::TIMEOUT_SIG), nTicks);
QF::readySet_.remove(
static_cast&lt;std::uint_fast8_t&gt;(thr-&gt;m_prio));
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
QF_CRIT_X_();
QF_CRIT_EXIT_NOP(); // BLOCK here
QF_CRIT_E_();
// the blocking object must be this queue
Q_ASSERT_ID(510, thr-&gt;m_temp.obj ==
QXK_PTR_CAST_(QMState *, &amp;thr-&gt;m_eQueue));
thr-&gt;m_temp.obj = nullptr; // clear
}
// is the queue not empty?
QEvt const *e;
if (thr-&gt;m_eQueue.m_frontEvt != nullptr) {
e = thr-&gt;m_eQueue.m_frontEvt; // remove from the front
// volatile into tmp
QEQueueCtr const nFree = thr-&gt;m_eQueue.m_nFree + 1U;
thr-&gt;m_eQueue.m_nFree = nFree; // update the number of free
// any events in the ring buffer?
if (nFree &lt;= thr-&gt;m_eQueue.m_end) {
// remove event from the tail
thr-&gt;m_eQueue.m_frontEvt =
thr-&gt;m_eQueue.m_ring[thr-&gt;m_eQueue.m_tail];
if (thr-&gt;m_eQueue.m_tail == 0U) {
thr-&gt;m_eQueue.m_tail = thr-&gt;m_eQueue.m_end; // wrap
}
// advance the tail (counter clockwise)
thr-&gt;m_eQueue.m_tail = (thr-&gt;m_eQueue.m_tail - 1U);
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET, thr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(&amp;thr); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // poolID &amp; ref Count
QS_EQC_PRE_(nFree); // number of free entries
QS_END_NOCRIT_PRE_()
}
else {
thr-&gt;m_eQueue.m_frontEvt = nullptr; // the queue becomes empty
// all entries in the queue must be free (+1 for fronEvt)
Q_ASSERT_ID(520, nFree == (thr-&gt;m_eQueue.m_end + 1U));
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET_LAST, thr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_SIG_PRE_(e-&gt;sig); // the signal of this event
QS_OBJ_PRE_(&amp;thr); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // poolID &amp; ref Count
QS_END_NOCRIT_PRE_()
}
}
else { // the queue is still empty -- the timeout must have fired
e = nullptr;
}
QF_CRIT_X_();
return e;
</code>
</operation>
<!--${QXK::QXThread::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! Overrides QHsm::init()</documentation>
<!--${QXK::QXThread::init::e}-->
<parameter name="e" type="void const * const"/>
<!--${QXK::QXThread::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
Q_ERROR_ID(110);</code>
</operation>
<!--${QXK::QXThread::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! Overrides QHsm::init()</documentation>
<!--${QXK::QXThread::init::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(qs_id);
Q_ERROR_ID(111);</code>
</operation>
<!--${QXK::QXThread::dispatch}-->
<operation name="dispatch" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! Overrides QHsm::dispatch()</documentation>
<!--${QXK::QXThread::dispatch::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QXK::QXThread::dispatch::qs_id}-->
<parameter name="qs_id" type="std::uint_fast8_t const"/>
<code>Q_UNUSED_PAR(e);
Q_UNUSED_PAR(qs_id);
Q_ERROR_ID(120);</code>
</operation>
<!--${QXK::QXThread::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x00">
<specifiers>override</specifiers>
<documentation>//! Starts execution of an extended thread and registers the thread
//! with the framework
//!
//! @details
//! Starts execution of an extended thread and registers it with the
//! framework. The extended thread becomes ready-to-run immediately and
//! is scheduled if the QXK is already running.
//!
//! @param[in] prioSpec priority specification at which to start the
//! extended thread
//! @param[in] qSto pointer to the storage for the ring buffer of
//! the event queue. This cold be NULL, if this
//! extended thread does not use the built-in
//! event queue.
//! @param[in] qLen length of the event queue [in events],
//! or zero if queue not used
//! @param[in] stkSto pointer to the stack storage (must be provided)
//! @param[in] stkSize stack size [in bytes] (must not be zero)
//! @param[in] par pointer to an extra parameter (might be NULL)
//!
//! @usage
//! The following example shows starting an extended thread:
//! @include qxk_start.cpp</documentation>
<!--${QXK::QXThread::start::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<!--${QXK::QXThread::start::qSto}-->
<parameter name="qSto" type="QEvt const * * const"/>
<!--${QXK::QXThread::start::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<!--${QXK::QXThread::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QXK::QXThread::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<!--${QXK::QXThread::start::par}-->
<parameter name="par" type="void const * const"/>
<code>Q_UNUSED_PAR(par);
//! @pre this function must:
//! - NOT be called from an ISR;
//! - the stack storage must be provided;
//! - the thread must be instantiated (see #QXThread).
//! - preemption-threshold is NOT provided (because QXK kernel
//! does not support preemption-threshold scheduling)
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_())
&amp;&amp; (stkSto != nullptr)
&amp;&amp; (stkSize != 0U)
&amp;&amp; (m_state.act == nullptr)
&amp;&amp; ((prioSpec &amp; 0xFF00U) == 0U));
// is storage for the queue buffer provided?
if (qSto != nullptr) {
m_eQueue.init(qSto, qLen);
}
// extended threads provide their thread function in place of
// the top-most initial transition 'm_temp.act'
QXK_stackInit_(this, m_temp.thr, stkSto, stkSize);
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-prio.
m_pthre = 0U; // preemption-threshold NOT used
register_(); // make QF aware of this AO
// the new thread is not blocked on any object
m_temp.obj = nullptr;
QF_CRIT_STAT_
QF_CRIT_E_();
// extended-thread becomes ready immediately
QF::readySet_.insert(static_cast&lt;std::uint_fast8_t&gt;(m_prio));
// see if this thread needs to be scheduled in case QXK is running
if (QXK_attr_.lockCeil &lt;= QF_MAX_ACTIVE) {
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
}
QF_CRIT_X_();</code>
</operation>
<!--${QXK::QXThread::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x02">
<specifiers>override</specifiers>
<documentation>//! Overloaded start function (no initialization event)</documentation>
<!--${QXK::QXThread::start::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<!--${QXK::QXThread::start::qSto}-->
<parameter name="qSto" type="QEvt const * * const"/>
<!--${QXK::QXThread::start::qLen}-->
<parameter name="qLen" type="std::uint_fast16_t const"/>
<!--${QXK::QXThread::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QXK::QXThread::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<code>this-&gt;start(prioSpec, qSto, qLen, stkSto, stkSize, nullptr);</code>
</operation>
<!--${QXK::QXThread::post_}-->
<operation name="post_" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept override</specifiers>
<documentation>//! Posts an event `e` directly to the event queue of the extended
//! thread using the First-In-First-Out (FIFO) policy
//!
//! @details
//! Extended threads can be configured (in QXThread::start()) to have
//! a private event queue. In that case, QP events (see QP::QEvt) can
//! be asynchronously posted or published to the extended thread.
//! The thread can wait (and block) on its queue and then it can
//! process the delivered event.
//!
//! @param[in] e pointer to the event to be posted
//! @param[in] margin number of required free slots in the queue
//! after posting the event. The special value
//! QF::NO_MARGIN means that this function will
//! assert if posting fails.
//! @param[in] sender pointer to a sender object (used in QS only)
//!
//! @returns
//! 'true' (success) if the posting succeeded (with the provided margin)
//! and 'false' (failure) when the posting fails.
//!
//! @attention
//! Should be called only via the macro POST() or POST_X().
//!
//! @note
//! The QF::NO_MARGIN value of the `margin` parameter is special and
//! denotes situation when the post() operation is assumed to succeed
//! (event delivery guarantee). An assertion fires, when the event cannot
//! be delivered in this case.</documentation>
<!--${QXK::QXThread::post_::e}-->
<parameter name="e" type="QEvt const * const"/>
<!--${QXK::QXThread::post_::margin}-->
<parameter name="margin" type="std::uint_fast16_t const"/>
<!--${QXK::QXThread::post_::sender}-->
<parameter name="sender" type="void const * const"/>
<code>QF_CRIT_STAT_
QS_TEST_PROBE_DEF(&amp;QXThread::post_)
// is it the private time event?
bool status;
if (e == &amp;m_timeEvt) {
QF_CRIT_E_();
// the private time event is 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.
m_timeEvt.sig = 0U;
unblock_();
QF_CRIT_X_();
status = true;
}
// is the event queue provided?
else if (m_eQueue.m_end != 0U) {
//! @pre event pointer must be valid
Q_REQUIRE_ID(300, e != nullptr);
QF_CRIT_E_();
QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary
// test-probe#1 for faking queue overflow
QS_TEST_PROBE_ID(1,
nFree = 0U;
)
if (margin == QF::NO_MARGIN) {
if (nFree &gt; 0U) {
status = true; // can post
}
else {
status = false; // cannot post
Q_ERROR_CRIT_(310); // must be able to post the event
}
}
else if (nFree &gt; static_cast&lt;QEQueueCtr&gt;(margin)) {
status = true; // can post
}
else {
status = false; // cannot post, but don't assert
}
// is it a dynamic event?
if (e-&gt;poolId_ != 0U) {
QEvt_refCtr_inc_(e); // increment the reference counter
}
if (status) { // can post the event?
--nFree; // one free entry just used up
m_eQueue.m_nFree = nFree; // update the volatile
if (m_eQueue.m_nMin &gt; nFree) {
m_eQueue.m_nMin = nFree; // update minimum so far
}
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this active object
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // poolID &amp; refCtr
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(m_eQueue.m_nMin); // min number of free entries
QS_END_NOCRIT_PRE_()
// queue empty?
if (m_eQueue.m_frontEvt == nullptr) {
m_eQueue.m_frontEvt = e; // deliver event directly
// is this thread blocked on the queue?
if (m_temp.obj == QXK_PTR_CAST_(QMState*, &amp;m_eQueue)) {
static_cast&lt;void&gt;(teDisarm_());
QF::readySet_.insert(
static_cast&lt;std::uint_fast8_t&gt;(m_prio));
if (!QXK_ISR_CONTEXT_()) {
static_cast&lt;void&gt;(QXK_sched_());
}
}
}
// queue is not empty, insert event into the ring-buffer
else {
// insert event into the ring buffer (FIFO)
m_eQueue.m_ring[m_eQueue.m_head] = e;
// need to wrap the head couner?
if (m_eQueue.m_head == 0U) {
m_eQueue.m_head = m_eQueue.m_end; // wrap around
}
// advance the head (counter clockwise)
m_eQueue.m_head = (m_eQueue.m_head - 1U);
}
QF_CRIT_X_();
}
else { // cannot post the event
QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(sender); // the sender object
QS_SIG_PRE_(e-&gt;sig); // the signal of the event
QS_OBJ_PRE_(this); // this active object (recipient)
QS_2U8_PRE_(e-&gt;poolId_, e-&gt;refCtr_); // poolID &amp; ref Count
QS_EQC_PRE_(nFree); // number of free entries
QS_EQC_PRE_(margin); // margin
QS_END_NOCRIT_PRE_()
QF_CRIT_X_();
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e); // recycle the event to avoid a leak
#endif
}
}
else { // the queue is not available
#if (QF_MAX_EPOOL &gt; 0U)
QF::gc(e); // make sure the event is not leaked
#endif
status = false;
Q_ERROR_ID(320); // this extended thread cannot accept events
}
return status;</code>
</operation>
<!--${QXK::QXThread::postLIFO}-->
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept override</specifiers>
<documentation>//! Posts an event directly to the event queue of the extended thread
//! using the Last-In-First-Out (LIFO) policy
//!
//! @details
//! Last-In-First-Out (LIFO) policy is not supported for extended threads.
//!
//! @param[in] e pointer to the event to post to the queue
//!
//! @sa
//! QXThread::post_(), QActive::postLIFO_()</documentation>
<!--${QXK::QXThread::postLIFO::e}-->
<parameter name="e" type="QEvt const * const"/>
<code>Q_UNUSED_PAR(e);
Q_ERROR_ID(410);</code>
</operation>
<!--${QXK::QXThread::block_}-->
<operation name="block_" type="void" visibility="0x02" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Block the extended thread
//!
//! @details
//! Internal implementation of blocking the given extended thread.
//!
//! @note
//! Must be called from within a critical section</documentation>
<code>//! @pre the thread holding the lock cannot block!
Q_REQUIRE_ID(600, (QXK_attr_.lockHolder != m_prio));
QF::readySet_.remove(static_cast&lt;std::uint_fast8_t&gt;(m_prio));
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling</code>
</operation>
<!--${QXK::QXThread::unblock_}-->
<operation name="unblock_" type="void" visibility="0x02" properties="0x00">
<specifiers>const noexcept</specifiers>
<documentation>//! Unblock the extended thread
//!
//! @details
//! Internal implementation of unblocking the given extended thread.
//!
//! @note
//! must be called from within a critical section</documentation>
<code>QF::readySet_.insert(static_cast&lt;std::uint_fast8_t&gt;(m_prio));
if ((!QXK_ISR_CONTEXT_()) // not inside ISR?
&amp;&amp; (QActive::registry_[0] != nullptr)) // kernel started?
{
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
}</code>
</operation>
<!--${QXK::QXThread::teArm_}-->
<operation name="teArm_" type="void" visibility="0x02" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Arm the private time event
//!
//! @details
//! Internal implementation of arming the private time event for
//! a given timeout at a given system tick rate.
//!
//! @note
//! Must be called from within a critical section</documentation>
<!--${QXK::QXThread::teArm_::sig}-->
<parameter name="sig" type="enum_t const"/>
<!--${QXK::QXThread::teArm_::nTicks}-->
<parameter name="nTicks" type="std::uint_fast16_t const"/>
<code>//! @pre the time event must be unused
Q_REQUIRE_ID(700, m_timeEvt.m_ctr == 0U);
m_timeEvt.sig = static_cast&lt;QSignal&gt;(sig);
if (nTicks != QXTHREAD_NO_TIMEOUT) {
m_timeEvt.m_ctr = static_cast&lt;QTimeEvtCtr&gt;(nTicks);
m_timeEvt.m_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::tickX().
if (static_cast&lt;std::uint8_t&gt;(m_timeEvt.refCtr_ &amp; TE_IS_LINKED) == 0U)
{
std::uint_fast8_t const tickRate =
static_cast&lt;std::uint_fast8_t&gt;(m_timeEvt.refCtr_);
// mark as linked
m_timeEvt.refCtr_ = static_cast&lt;std::uint8_t&gt;(
m_timeEvt.refCtr_ | TE_IS_LINKED);
// The time event is initially inserted into the separate
// &quot;freshly armed&quot; list based on timeEvtHead_[tickRate].act.
// Only later, inside QTimeEvt::tick_(), the &quot;freshly armed&quot;
// list is appended to the main list of armed time events based on
// timeEvtHead_[tickRate].next. Again, this is to keep any
// changes to the main list exclusively inside QTimeEvt::tick_().
//
m_timeEvt.m_next
= QXK_PTR_CAST_(QTimeEvt*,
QTimeEvt::timeEvtHead_[tickRate].m_act);
QTimeEvt::timeEvtHead_[tickRate].m_act = &amp;m_timeEvt;
}
}</code>
</operation>
<!--${QXK::QXThread::teDisarm_}-->
<operation name="teDisarm_" type="bool" visibility="0x02" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! Disarm the private time event
//!
//! @details
//! Internal implementation of disarming the private time event.
//!
//! @note
//! Must be called from within a critical section</documentation>
<code>bool wasArmed;
// is the time evt running?
if (m_timeEvt.m_ctr != 0U) {
wasArmed = true;
// schedule removal from list
m_timeEvt.m_ctr = 0U;
}
// the time event was already automatically disarmed
else {
wasArmed = false;
}
return wasArmed;</code>
</operation>
</class>
<!--${QXK::QXSemaphore}-->
<class name="QXSemaphore">
<documentation>//! Counting Semaphore of the QXK preemptive kernel
//!
//! @details
//! QP::QXSemaphore is a blocking mechanism intended primarily for signaling
//! @ref QP::QXThread &quot;extended threads&quot;. The semaphore is initialized with
//! the maximum count (see QP::QXSemaphore::init()), which allows you to
//! create a binary semaphore (when the maximum count is 1) and
//! counting semaphore when the maximum count is &gt; 1.
//!
//! @usage
//! The following example illustrates how to instantiate and use the semaphore
//! in your application.
//! @include qxk_sema.cpp
//!</documentation>
<!--${QXK::QXSemaphore::m_waitSet}-->
<attribute name="m_waitSet" type="QPSet" visibility="0x02" properties="0x00">
<documentation>//! set of extended threads waiting on this semaphore</documentation>
</attribute>
<!--${QXK::QXSemaphore::m_count}-->
<attribute name="m_count" type="std::uint16_t volatile" visibility="0x02" properties="0x00">
<documentation>//! semaphore up-down counter</documentation>
</attribute>
<!--${QXK::QXSemaphore::m_max_count}-->
<attribute name="m_max_count" type="std::uint16_t" visibility="0x02" properties="0x00">
<documentation>//! maximum value of the semaphore counter</documentation>
</attribute>
<!--${QXK::QXSemaphore::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! initialize the counting semaphore
//!
//! @details
//! Initializes a semaphore with the specified count and maximum count.
//! If the semaphore is used for resource sharing, both the initial count
//! and maximum count should be set to the number of identical resources
//! guarded by the semaphore. If the semaphore is used as a signaling
//! mechanism, the initial count should set to 0 and maximum count to 1
//! (binary semaphore).
//!
//! @param[in] count initial value of the semaphore counter
//! @param[in] max_count maximum value of the semaphore counter.
//! The purpose of the max_count is to limit the counter
//! so that the semaphore cannot unblock more times than
//! the maximum.
//! @note
//! QXSemaphore::init() must be called **before** the semaphore can be
//! used (signaled or waited on).</documentation>
<!--${QXK::QXSemaphore::init::count}-->
<parameter name="count" type="std::uint_fast16_t const"/>
<!--${QXK::QXSemaphore::init::max_count = 0xFFFFU}-->
<parameter name="max_count = 0xFFFFU" type="std::uint_fast16_t const"/>
<code>//! @pre max_count must be greater than zero
Q_REQUIRE_ID(100, max_count &gt; 0U);
m_count = static_cast&lt;std::uint16_t&gt;(count);
m_max_count = static_cast&lt;std::uint16_t&gt;(max_count);
m_waitSet.setEmpty();</code>
</operation>
<!--${QXK::QXSemaphore::wait}-->
<operation name="wait" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! wait (block) on the semaphore
//!
//! @details
//! When an extended thread calls QXSemaphore::wait() and the value of the
//! semaphore counter is greater than 0, QXSemaphore_wait() decrements the
//! semaphore counter and returns (true) to its caller. However, if the
//! value of the semaphore counter is 0, the function places the calling
//! thread in the waiting list for the semaphore. The thread waits until
//! the semaphore is signaled by calling QXSemaphore::signal(), or the
//! specified timeout expires. If the semaphore is signaled before the
//! timeout expires, QXK resumes the highest-priority extended thread
//! waiting for the semaphore.
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to wait for the semaphore. The value of
//! QP::QXTHREAD_NO_TIMEOUT indicates that no
//! timeout will occur and the semaphore will wait
//! indefinitely.
//! @returns
//! true if the semaphore has been signaled, and false if the timeout
//! occurred.
//!
//! @note
//! Multiple extended threads can wait for a given semaphore.</documentation>
<!--${QXK::QXSemaphore::wait::nTicks = QXTHREAD_NO_TIMEOUT}-->
<parameter name="nTicks = QXTHREAD_NO_TIMEOUT" type="std::uint_fast16_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
// volatile into temp.
QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_attr_.curr);
//! @pre 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_ID(200, (!QXK_ISR_CONTEXT_()) // can't wait inside an ISR
&amp;&amp; (m_max_count &gt; 0U)
&amp;&amp; (curr != nullptr)
&amp;&amp; (curr-&gt;m_temp.obj == nullptr));
//! @pre also: the thread must NOT be holding a scheduler lock.
Q_REQUIRE_ID(201, QXK_attr_.lockHolder != curr-&gt;m_prio);
bool signaled = true; // assume that the semaphore will be signaled
if (m_count &gt; 0U) {
m_count = m_count - 1U; // semaphore taken: decrement
QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(curr-&gt;m_prio, m_count);
QS_END_NOCRIT_PRE_()
}
else {
std::uint_fast8_t const p =
static_cast&lt;std::uint_fast8_t&gt;(curr-&gt;m_prio);
// remove the curr prio from the ready set (will block)
// and insert to the waiting set on this semaphore
QF::readySet_.remove(p);
m_waitSet.insert(p);
// remember the blocking object (this semaphore)
curr-&gt;m_temp.obj = QXK_PTR_CAST_(QMState*, this);
curr-&gt;teArm_(static_cast&lt;enum_t&gt;(QXK::TIMEOUT_SIG), nTicks);
QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(curr-&gt;m_prio, m_count);
QS_END_NOCRIT_PRE_()
// schedule the next thread if multitasking started
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
QF_CRIT_X_();
QF_CRIT_EXIT_NOP(); // BLOCK here !!!
QF_CRIT_E_(); // AFTER unblocking...
// the blocking object must be this semaphore
Q_ASSERT_ID(240, curr-&gt;m_temp.obj
== QXK_PTR_CAST_(QMState*, this));
// did the blocking time-out? (signal of zero means that it did)
if (curr-&gt;m_timeEvt.sig == 0U) {
if (m_waitSet.hasElement(p)) { // still waiting?
m_waitSet.remove(p); // remove unblocked thread
signaled = false; // the semaphore was NOT signaled
// semaphore NOT taken: do NOT decrement the count
}
else { // semaphore was both signaled and timed out
m_count = m_count - 1U; // semaphore taken: decrement
}
}
else { // blocking did NOT time out
// the thread must NOT be waiting on this semaphore
Q_ASSERT_ID(250, !m_waitSet.hasElement(p));
m_count = m_count - 1U; // semaphore taken: decrement
}
curr-&gt;m_temp.obj = nullptr; // clear blocking obj.
}
QF_CRIT_X_();
return signaled;</code>
</operation>
<!--${QXK::QXSemaphore::tryWait}-->
<operation name="tryWait" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! try wait on the semaphore (non-blocking)
//!
//! @details
//! This operation checks if the semaphore counter is greater than 0,
//! in which case the counter is decremented.
//!
//! @returns
//! 'true' if the semaphore has count available and 'false' NOT available.
//!
//! @note
//! This function can be called from any context, including ISRs and
//! basic threads (active objects).</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
//! @pre the semaphore must be initialized
Q_REQUIRE_ID(300, m_max_count &gt; 0U);
#ifdef Q_SPY
// volatile into temp.
QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_attr_.curr);
#endif // Q_SPY
bool isAvailable;
// is the semaphore available?
if (m_count &gt; 0U) {
m_count = m_count - 1U; // semaphore signaled: decrement
isAvailable = true;
QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(curr-&gt;m_prio, m_count);
QS_END_NOCRIT_PRE_()
}
else { // the semaphore is NOT available (would block)
isAvailable = false;
QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK_ATTEMPT, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(curr-&gt;m_prio,
m_count);
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();
return isAvailable;</code>
</operation>
<!--${QXK::QXSemaphore::signal}-->
<operation name="signal" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! signal (unblock) the semaphore
//!
//! @details
//! If the semaphore counter value is 0 or more, it is incremented, and
//! this function returns to its caller. If the extended threads are
//! waiting for the semaphore to be signaled, QXSemaphore::signal()
//! removes the highest-priority thread waiting for the semaphore from
//! the waiting list and makes this thread ready-to-run. The QXK
//! scheduler is then called to determine if the awakened thread is now
//! the highest-priority thread that is ready-to-run.
//!
//! @returns
//! 'true' when the semaphore gets signaled and 'false' when the
//! semaphore count exceeded the maximum.
//!
//! @note
//! A semaphore can be signaled from many places, including from ISRs,
//! basic threads (AOs), and extended threads.</documentation>
<code>//! @pre the semaphore must be initialized
Q_REQUIRE_ID(400, m_max_count &gt; 0U);
QF_CRIT_STAT_
QF_CRIT_E_();
bool signaled = true; // assume that the semaphore will be signaled
if (m_count &lt; m_max_count) {
m_count = m_count + 1U; // semaphore signaled: increment
#ifdef Q_SPY
// volatile into temp.
QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_attr_.curr);
#endif // Q_SPY
QS_BEGIN_NOCRIT_PRE_(QS_SEM_SIGNAL, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(curr-&gt;m_prio,
m_count);
QS_END_NOCRIT_PRE_()
if (m_waitSet.notEmpty()) {
// find the highest-priority thread waiting on this semaphore
std::uint_fast8_t const p = m_waitSet.findMax();
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_ID(410, (thr != nullptr)
&amp;&amp; (thr-&gt;m_osObject != nullptr)
&amp;&amp; (thr-&gt;m_temp.obj
== QXK_PTR_CAST_(QMState*, this)));
// disarm the internal time event
static_cast&lt;void&gt;(thr-&gt;teDisarm_());
// make the thread ready to run and remove from the wait-list
QF::readySet_.insert(p);
m_waitSet.remove(p);
QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, thr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this semaphore
QS_2U8_PRE_(thr-&gt;m_prio, m_count);
QS_END_NOCRIT_PRE_()
if (!QXK_ISR_CONTEXT_()) { // not inside ISR?
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
}
}
}
else {
signaled = false; // semaphore NOT signaled
}
QF_CRIT_X_();
return signaled;</code>
</operation>
</class>
<!--${QXK::QXMutex}-->
<class name="QXMutex" superclass="QF::QActive">
<documentation>//! Blocking, Priority-Ceiling Mutex the QXK preemptive kernel
//!
//! @details
//! QP::QXMutex is a blocking mutual exclusion mechanism that can also apply
//! the **priority-ceiling protocol** to avoid unbounded priority inversion
//! (if initialized with a non-zero ceiling priority, see QXMutex::init()).
//! In that case, QP::QXMutex requires its own uinque QP priority level,
//! which cannot be used by any thread or any other QP::QXMutex.
//! If initialized with preemption-ceiling of zero, QXMutex does **not**
//! use the priority-ceiling protocol and does not require a unique QP
//! priority (see QXMutex::init()).
//! QP::QXMutex is **recursive** (re-entrant), which means that it can be
//! locked multiple times (up to 255 levels) by the *same* thread without
//! causing deadlock.&lt;br&gt;
//!
//! QP::QXMutex is primarily intended for the @ref QP::QXThread
//! &quot;extended (blocking) threads&quot;, but can also be used by the
//! @ref QPP::QActive &quot;basic threads&quot; through the non-blocking
//! QXMutex::tryLock() API.
//!
//! @note
//! QP::QXMutex should be used in situations when at least one of the extended
//! threads contending for the mutex blocks while holding the mutex (between
//! the QXMutex::lock() and QXMutex_unlock() operations). If no blocking is
//! needed while holding the mutex, the more efficient non-blocking mechanism
//! of @ref srs_qxk_schedLock() &quot;selective QXK scheduler locking&quot; should be
//! used instead. @ref srs_qxk_schedLock() &quot;Selective scheduler locking&quot; is
//! available for both @ref QP::QActive &quot;basic threads&quot; and @ref QP::QXThread
//! &quot;extended threads&quot;, so it is applicable to situations where resources
//! are shared among all these threads.
//!
//! @usage
//! The following example illustrates how to instantiate and use the mutex
//! in your application.
//! @include qxk_mutex.cpp
//!</documentation>
<!--${QXK::QXMutex::m_waitSet}-->
<attribute name="m_waitSet" type="QPSet" visibility="0x02" properties="0x00">
<documentation>//! set of extended-threads waiting on this mutex</documentation>
</attribute>
<!--${QXK::QXMutex::QXMutex}-->
<operation name="QXMutex" type="" visibility="0x00" properties="0x00">
<documentation>//! default constructor</documentation>
<code> : QActive(Q_STATE_CAST(0))</code>
</operation>
<!--${QXK::QXMutex::init}-->
<operation name="init" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! initialize the QXK priority-ceiling mutex QP::QXMutex
//!
//! @details
//! Initialize the QXK priority ceiling mutex.
//!
//! @param[in] prioSpec the priority specification for the mutex
//! (See also QP::QPrioSpec). This value might
//! also be zero.
//! @note
//! `prioSpec == 0` means that the priority-ceiling protocol shall **not**
//! be used by this mutex. Such mutex will **not** change (boost) the
//! priority of the holding thread.
//!
//! @note
//! `prioSpec == 0` means that the priority-ceiling protocol shall **not**
//! be used by this mutex. Such mutex will **not** change (boost) the
//! priority of the holding threads.&lt;br&gt;
//!
//! Conversely, `prioSpec != 0` means that the priority-ceiling protocol
//! shall be used by this mutex. Such mutex **will** temporarily boost
//! the priority and priority-threshold of the holding thread to the
//! priority specification in `prioSpec` (see QP::QPrioSpec).
//!
//! @usage
//! @include qxk_mutex.cpp</documentation>
<!--${QXK::QXMutex::init::prioSpec}-->
<parameter name="prioSpec" type="QPrioSpec const"/>
<code>//! @pre preemption-threshold must not be used
Q_REQUIRE_ID(100, (prioSpec &amp; 0xFF00U) == 0U);
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU);
m_pthre = 0U; // preemption-threshold not used
if (prioSpec != 0U) { // priority-ceiling protocol used?
register_(); // register this mutex as AO
}</code>
</operation>
<!--${QXK::QXMutex::tryLock}-->
<operation name="tryLock" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! try to lock the QXK priority-ceiling mutex QP::QXMutex
//!
//! @details
//! Try to lock the QXK priority ceiling mutex QP::QXMutex.
//!
//! @returns
//! 'true' if the mutex was successfully locked and 'false' if the mutex
//! was unavailable and was NOT locked.
//!
//! @note
//! This function **can** be called from both basic threads (active
//! objects) and extended threads.
//!
//! @note
//! The mutex locks are allowed to nest, meaning that the same extended
//! thread can lock the same mutex multiple times (&lt; 255). However, each
//! successful call to QXMutex::tryLock() must be balanced by the
//! matching call to QXMutex::unlock().</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QActive *curr = QXK_attr_.curr;
if (curr == nullptr) { // called from a basic thread?
curr = registry_[QXK_attr_.actPrio];
}
//! @pre this function must:
//! - NOT be called from an ISR;
//! - the calling thread must be valid;
//! - the mutex-priority must be in range
Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) // don't call from an ISR!
&amp;&amp; (curr != nullptr) // current thread must be valid
&amp;&amp; (m_prio &lt;= QF_MAX_ACTIVE));
//! @pre also: the thread must NOT be holding a scheduler lock.
Q_REQUIRE_ID(301, QXK_attr_.lockHolder != curr-&gt;m_prio);
// is the mutex available?
if (m_eQueue.m_nFree == 0U) {
m_eQueue.m_nFree = 1U; // mutex lock nesting
//! @pre also: the newly locked mutex must have no holder yet
Q_REQUIRE_ID(302, m_thread == nullptr);
// set the new mutex holder to the curr thread and
// save the thread's prio/pthre in the mutex
// NOTE: reuse the otherwise unused eQueue data member.
m_thread = curr;
m_eQueue.m_head = static_cast&lt;QEQueueCtr&gt;(curr-&gt;m_prio);
m_eQueue.m_tail = static_cast&lt;QEQueueCtr&gt;(curr-&gt;m_pthre);
QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
if (m_prio != 0U) { // priority-ceiling protocol used?
// the holder priority must be lower than that of the mutex
// and the priority slot must be occupied by this mutex
Q_ASSERT_ID(210, (curr-&gt;m_prio &lt; m_prio)
&amp;&amp; (registry_[m_prio] == this));
// remove the thread's original prio from the ready set
// and insert the mutex's prio into the ready set
QF::readySet_.remove(
static_cast&lt;std::uint_fast8_t&gt;(m_eQueue.m_head));
QF::readySet_.insert(
static_cast&lt;std::uint_fast8_t&gt;(m_prio));
// put the thread into the AO registry in place of the mutex
registry_[m_prio] = curr;
// set thread's prio/pthre to that of the mutex
curr-&gt;m_prio = m_prio;
curr-&gt;m_pthre = m_pthre;
}
}
// is the mutex locked by this thread already (nested locking)?
else if (m_thread == curr) {
// the nesting level must not exceed the specified limit
Q_ASSERT_ID(320, m_eQueue.m_nFree &lt; 0xFFU);
m_eQueue.m_nFree = m_eQueue.m_nFree + 1U; // lock one more level
QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
}
else { // the mutex is already locked by a different thread
if (m_prio != 0U) { // priority-ceiling protocol used?
// the prio slot must be occupied by the thr. holding the mutex
Q_ASSERT_ID(340, registry_[m_prio]
== QXK_PTR_CAST_(QActive *, m_thread));
}
QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK_ATTEMPT, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
curr-&gt;m_prio); // trying thread prio
QS_END_NOCRIT_PRE_()
curr = nullptr; // means that mutex is NOT available
}
QF_CRIT_X_();
return curr != nullptr;</code>
</operation>
<!--${QXK::QXMutex::lock}-->
<operation name="lock" type="bool" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! lock the QXK priority-ceiling mutex QP::QXMutex
//!
//! @details
//! Lock the QXK priority ceiling mutex QP::QXMutex.
//!
//! @param[in] nTicks number of clock ticks (at the associated rate)
//! to wait for the mutex. The value of
//! QXTHREAD_NO_TIMEOUT indicates that no timeout will
//! occur and the mutex could block indefinitely.
//! @returns
//! 'true' if the mutex has been acquired and 'false' if a timeout
//! occurred.
//!
//! @note
//! The mutex locks are allowed to nest, meaning that the same extended
//! thread can lock the same mutex multiple times (&lt; 255). However,
//! each call to QXMutex::lock() must be balanced by the matching call to
//! QXMutex::unlock().
//!
//! @usage
//! @include qxk_mutex.cpp</documentation>
<!--${QXK::QXMutex::lock::nTicks = QXTHREAD_NO_TIMEOUT}-->
<parameter name="nTicks = QXTHREAD_NO_TIMEOUT" type="std::uint_fast16_t const"/>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_attr_.curr);
//! @pre this function must:
//! - NOT be called from an ISR;
//! - be called from an extended thread;
//! - the mutex-priority must be in range
//! - the thread must NOT be already blocked on any object.
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) // don't call from an ISR!
&amp;&amp; (curr != nullptr) // current thread must be extended
&amp;&amp; (m_prio &lt;= QF_MAX_ACTIVE)
&amp;&amp; (curr-&gt;m_temp.obj == nullptr)); // not blocked
//! @pre also: the thread must NOT be holding a scheduler lock
Q_REQUIRE_ID(201, QXK_attr_.lockHolder != curr-&gt;m_prio);
// is the mutex available?
bool locked = true; // assume that the mutex will be locked
if (m_eQueue.m_nFree == 0U) {
m_eQueue.m_nFree = 1U; // mutex lock nesting
//! @pre also: the newly locked mutex must have no holder yet
Q_REQUIRE_ID(202, m_thread == nullptr);
// set the new mutex holder to the curr thread and
// save the thread's prio/pthre in the mutex
// NOTE: reuse the otherwise unused eQueue data member.
m_thread = curr;
m_eQueue.m_head = static_cast&lt;QEQueueCtr&gt;(curr-&gt;m_prio);
m_eQueue.m_tail = static_cast&lt;QEQueueCtr&gt;(curr-&gt;m_pthre);
QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
if (m_prio != 0U) { // priority-ceiling protocol used?
// the holder priority must be lower than that of the mutex
// and the priority slot must be occupied by this mutex
Q_ASSERT_ID(210, (curr-&gt;m_prio &lt; m_prio)
&amp;&amp; (registry_[m_prio] == this));
// remove the thread's original prio from the ready set
// and insert the mutex's prio into the ready set
QF::readySet_.remove(
static_cast&lt;std::uint_fast8_t&gt;(m_eQueue.m_head));
QF::readySet_.insert(static_cast&lt;std::uint_fast8_t&gt;(m_prio));
// put the thread into the AO registry in place of the mutex
registry_[m_prio] = curr;
// set thread's prio/pthre to that of the mutex
curr-&gt;m_prio = m_prio;
curr-&gt;m_pthre = m_pthre;
}
}
// is the mutex locked by this thread already (nested locking)?
else if (m_thread == curr) {
// the nesting level beyond the arbitrary but high limit
// most likely means cyclic or recursive locking of a mutex.
Q_ASSERT_ID(220, m_eQueue.m_nFree &lt; 0xFFU);
m_eQueue.m_nFree = m_eQueue.m_nFree + 1U; // lock one more level
QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
}
else { // the mutex is already locked by a different thread
// the mutex holder must be valid
Q_ASSERT_ID(230, m_thread != nullptr);
if (m_prio != 0U) { // priority-ceiling protocol used?
// the prio slot must be occupied by the thr. holding the mutex
Q_ASSERT_ID(240, registry_[m_prio]
== QXK_PTR_CAST_(QActive *, m_thread));
}
// remove the curr thread's prio from the ready set (will block)
// and insert it to the waiting set on this mutex
std::uint_fast8_t const p =
static_cast&lt;std::uint_fast8_t&gt;(curr-&gt;m_prio);
QF::readySet_.remove(p);
m_waitSet.insert(p);
// set the blocking object (this mutex)
curr-&gt;m_temp.obj = QXK_PTR_CAST_(QMState*, this);
curr-&gt;teArm_(static_cast&lt;enum_t&gt;(QXK::TIMEOUT_SIG), nTicks);
QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
curr-&gt;m_prio);
QS_END_NOCRIT_PRE_()
// schedule the next thread if multitasking started
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
QF_CRIT_X_();
QF_CRIT_EXIT_NOP(); // BLOCK here !!!
// AFTER unblocking...
QF_CRIT_E_();
// the blocking object must be this mutex
Q_ASSERT_ID(240, curr-&gt;m_temp.obj
== QXK_PTR_CAST_(QMState*, this));
// did the blocking time-out? (signal of zero means that it did)
if (curr-&gt;m_timeEvt.sig == 0U) {
if (m_waitSet.hasElement(p)) { // still waiting?
m_waitSet.remove(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_ID(250, !m_waitSet.hasElement(p));
}
curr-&gt;m_temp.obj = nullptr; // clear blocking obj.
}
QF_CRIT_X_();
return locked;</code>
</operation>
<!--${QXK::QXMutex::unlock}-->
<operation name="unlock" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! unlock the QXK priority-ceiling mutex QP::QXMutex
//!
//! @details
//! Unlock the QXK priority ceiling mutex.
//!
//! @note
//! This function **can** be called from both basic threads (active
//! objects) and extended threads.
//!
//! @note
//! The mutex locks are allowed to nest, meaning that the same extended
//! thread can lock the same mutex multiple times (&lt; 255). However, each
//! call to QXMutex::lock() or a *successful* call to QXMutex::tryLock()
//! must be balanced by the matching call to QXMutex::unlock().
//!
//! @usage
//! @include qxk_mutex.cpp</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QActive *curr = QXK_attr_.curr;
if (curr == nullptr) { // called from a basic thread?
curr = registry_[QXK_attr_.actPrio];
}
//! @pre this function must:
//! - NOT be called from an ISR;
//! - the calling thread must be valid;
Q_REQUIRE_ID(400, (!QXK_ISR_CONTEXT_()) // don't call from an ISR!
&amp;&amp; (curr != nullptr)); // current thread must be valid
//! @pre also: the mutex must be already locked at least once
Q_REQUIRE_ID(401, m_eQueue.m_nFree &gt; 0U);
//! @pre also: the mutex must be held by this thread
Q_REQUIRE_ID(402, m_thread == curr);
// is this the last nesting level?
if (m_eQueue.m_nFree == 1U) {
if (m_prio != 0U) { // priority-ceiling protocol used?
// restore the holding thread's prio/pthre from the mutex
curr-&gt;m_prio = static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head);
curr-&gt;m_pthre = static_cast&lt;std::uint8_t&gt;(m_eQueue.m_tail);
// put the mutex back into the AO registry
registry_[m_prio] = this;
// remove the mutex' prio from the ready set
// and insert the original thread's priority
QF::readySet_.remove(
static_cast&lt;std::uint_fast8_t&gt;(m_prio));
QF::readySet_.insert(
static_cast&lt;std::uint_fast8_t&gt;(m_eQueue.m_head));
}
QS_BEGIN_NOCRIT_PRE_(QS_MTX_UNLOCK, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
0U);
QS_END_NOCRIT_PRE_()
// are any other threads waiting on this mutex?
if (m_waitSet.notEmpty()) {
// find the highest-priority thread waiting on this mutex
std::uint_fast8_t const p = m_waitSet.findMax();
// remove this thread from waiting on the mutex
// and insert it into the ready set.
m_waitSet.remove(p);
QF::readySet_.insert(p);
QXThread * const thr = QXK_PTR_CAST_(QXThread*, registry_[p]);
// the waiting thread must:
// - be registered in QF
// - have the priority corresponding to the registration
// - be an extended thread
// - be blocked on this mutex
Q_ASSERT_ID(410, (thr != (QXThread *)0)
&amp;&amp; (thr-&gt;m_prio == static_cast&lt;std::uint8_t&gt;(p))
&amp;&amp; (thr-&gt;m_state.act == Q_ACTION_CAST(0))
&amp;&amp; (thr-&gt;m_temp.obj == QXK_PTR_CAST_(QMState*, this)));
// disarm the internal time event
static_cast&lt;void&gt;(thr-&gt;teDisarm_());
// set the new mutex holder to the curr thread and
// save the thread's prio/pthre in the mutex
// NOTE: reuse the otherwise unused eQueue data member.
m_thread = thr;
m_eQueue.m_head = static_cast&lt;QEQueueCtr&gt;(thr-&gt;m_prio);
m_eQueue.m_tail = static_cast&lt;QEQueueCtr&gt;(thr-&gt;m_pthre);
QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, thr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
if (m_prio != 0U) { // priority-ceiling protocol used?
// the holder priority must be lower than that of the mutex
Q_ASSERT_ID(410, thr-&gt;m_prio &lt; m_prio);
// set thread's preemption-threshold to that of the mutex
thr-&gt;m_pthre = m_pthre;
// put the thread into AO registry in place of the mutex
registry_[m_prio] = thr;
}
}
else { // no threads are waiting for this mutex
m_eQueue.m_nFree = 0U; // free up the nesting count
// the mutex no longer held by any thread
m_thread = nullptr;
m_eQueue.m_head = 0U;
m_eQueue.m_tail = 0U;
if (m_prio != 0U) { // priority-ceiling protocol used?
// put the mutex back at the original mutex slot
registry_[m_prio] = QXK_PTR_CAST_(QActive*, this);
}
}
// schedule the next thread if multitasking started
if (QXK_sched_() != 0U) { // synchronous preemption needed?
QXK_activate_(); // synchronously activate basic threads
}
}
else { // releasing one level of nested mutex lock
Q_ASSERT_ID(420, m_eQueue.m_nFree &gt; 0U);
m_eQueue.m_nFree = m_eQueue.m_nFree - 1U; // unlock one level
QS_BEGIN_NOCRIT_PRE_(QS_MTX_UNLOCK_ATTEMPT, curr-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_OBJ_PRE_(this); // this mutex
QS_2U8_PRE_(static_cast&lt;std::uint8_t&gt;(m_eQueue.m_head),
static_cast&lt;std::uint8_t&gt;(m_eQueue.m_nFree));
QS_END_NOCRIT_PRE_()
}
QF_CRIT_X_();</code>
</operation>
</class>
<!--${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>//! QF initialization for QXK</documentation>
<code>#if (QF_MAX_EPOOL &gt; 0U)
QF::maxPool_ = 0U;
#endif
bzero(&amp;QTimeEvt::timeEvtHead_[0], sizeof(QTimeEvt::timeEvtHead_));
bzero(&amp;QActive::registry_[0], sizeof(QActive::registry_));
bzero(&amp;QF::readySet_, sizeof(QF::readySet_));
bzero(&amp;QXK_attr_, sizeof(QXK_attr_));
// setup the QXK scheduler as initially locked and not running
QXK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked
// storage capable for holding a blank QActive object (const in ROM)
static void* const
idle_ao[((sizeof(QActive) + sizeof(void*)) - 1U) / sizeof(void*)]
= { nullptr };
// register the blank QActive object as the idle-AO (cast 'const' away)
QActive::registry_[0] = QF_CONST_CAST_(QActive*,
reinterpret_cast&lt;QActive const*&gt;(idle_ao));
#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>//! stop the QF customization for QXK
//!
//! @sa QF::onCleanup()</documentation>
<code>onCleanup(); // cleanup callback
// nothing else to do for the QXK preemptive kernel</code>
</operation>
<!--${QXK::QF-cust::run}-->
<operation name="run" type="int_t" visibility="0x00" properties="0x01">
<documentation>//! QF::run() customization for QXK kernel</documentation>
<code>#ifdef Q_SPY
QS_SIG_DICTIONARY(QP::QXK::DELAY_SIG, nullptr);
QS_SIG_DICTIONARY(QP::QXK::TIMEOUT_SIG, nullptr);
// produce the QS_QF_RUN trace record
QF_INT_DISABLE();
QS::beginRec_(QS_REC_NUM_(QS_QF_RUN));
QS::endRec_();
QF_INT_ENABLE();
#endif
onStartup(); // startup callback
QF_INT_DISABLE();
QXK_attr_.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_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::QHsm">
<documentation>//! QP::QActive port for QXK</documentation>
<!--${QXK::QActive::start}-->
<operation name="start" type="void" visibility="0x00" properties="0x04">
<documentation>//! Starts execution of an active object and registers the object
//! with the framework customized for QXK</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="std::uint_fast16_t const"/>
<!--${QXK::QActive::start::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QXK::QActive::start::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
<!--${QXK::QActive::start::par}-->
<parameter name="par" type="void const * const"/>
<code>Q_UNUSED_PAR(stkSto); // not needed in QXK
Q_UNUSED_PAR(stkSize); // not needed in QXK
//! @pre AO cannot be started:
//! - from an ISR;
//! - the stack storage must NOT be provided
//! - preemption-threshold is NOT provided (because QXK kernel
//! does not support preemption-threshold scheduling)
Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_())
&amp;&amp; (stkSto == nullptr)
&amp;&amp; ((prioSpec &amp; 0xFF00U) == 0U));
m_prio = static_cast&lt;std::uint8_t&gt;(prioSpec &amp; 0xFFU); // QF-prio.
m_pthre = 0U; // preemption-threshold NOT used
register_(); // make QF aware of this AO
m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
m_osObject = nullptr; // no private stack for AO
this-&gt;init(par, m_prio); // take the top-most initial tran. (virtual)
QS_FLUSH(); // flush the trace buffer to the host
// see if this AO needs to be scheduled in case QXK is running
QF_CRIT_STAT_
QF_CRIT_E_();
if (QXK_attr_.lockCeil &lt;= QF_MAX_ACTIVE) { // scheduler running?
if (QXK_sched_() != 0U) { // synchronous preemption needed?
QXK_activate_(); // synchronously activate basic threads
}
}
QF_CRIT_X_();</code>
</operation>
</class>
<!--${QXK::QXTHREAD_NO_TIMEOUT}-->
<attribute name="QXTHREAD_NO_TIMEOUT" type="constexpr std::uint_fast16_t" visibility="0x04" properties="0x00">
<documentation>//! No-timeout when blocking on semaphores, mutextes, and queues</documentation>
<code>{0U};</code>
</attribute>
</package>
<!--${QXK-extern-C}-->
<package name="QXK-extern-C" stereotype="0x02">
<!--${QXK-extern-C::QXK_Attr}-->
<attribute name="QXK_Attr" type="struct" visibility="0x04" properties="0x00">
<documentation>//! attributes of the QXK kernel (extern &quot;C&quot; for easy access in assembly)</documentation>
<code>{
QP::QActive * volatile curr; //!&lt; currently executing thread
QP::QActive * volatile next; //!&lt; next thread to execute
QP::QActive * volatile prev; //!&lt; previous thread
std::uint8_t volatile actPrio; //!&lt; QF-prio of the active AO
std::uint8_t volatile lockCeil; //!&lt; lock preemption-ceiling (0==no-lock)
std::uint8_t volatile lockHolder; //!&lt; prio of the lock holder
};</code>
</attribute>
<!--${QXK-extern-C::QXK_attr_}-->
<attribute name="QXK_attr_" type="QXK_Attr" visibility="0x00" properties="0x00">
<documentation>//! attributes of the QXK kernel (extern &quot;C&quot; to be accessible from C)</documentation>
</attribute>
<!--${QXK-extern-C::QXK_sched_}-->
<operation name="QXK_sched_" type="std::uint_fast8_t" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! QXK scheduler finds the highest-priority thread ready to run
//!
//! @details
//! The QXK scheduler finds the priority of the highest-priority thread
//! that is ready to run.
//!
//! @returns the 1-based priority of the the active object to run next,
//! or zero if no eligible active object is found.
//!
//! @attention
//! QXK_sched_() must be always called with interrupts **disabled** and
//! returns with interrupts **disabled**.</documentation>
<code>std::uint_fast8_t p;
if (QP::QF::readySet_.isEmpty()) {
p = 0U; // no activation needed
}
else {
// find the highest-prio thread ready to run
p = QP::QF::readySet_.findMax();
if (p &lt;= QXK_attr_.lockCeil) {
// priority of the thread holding the lock
p = static_cast&lt;std::uint_fast8_t&gt;(
QP::QActive::registry_[QXK_attr_.lockHolder]-&gt;m_prio);
if (p != 0U) {
Q_ASSERT_ID(610, QP::QF::readySet_.hasElement(p));
}
}
}
QP::QActive const * const curr = QXK_attr_.curr;
QP::QActive * const next = QP::QActive::registry_[p];
// the thread found must be registered in QF
Q_ASSERT_ID(620, next != nullptr);
// is the current thread a basic-thread?
if (curr == nullptr) {
// is the new priority above the active priority?
if (p &gt; QXK_attr_.actPrio) {
QXK_attr_.next = next; // set the next AO to activate
if (next-&gt;m_osObject != nullptr) { // is next extended?
QXK_CONTEXT_SWITCH_();
p = 0U; // no activation needed
}
}
else { // below the pre-thre
QXK_attr_.next = nullptr;
p = 0U; // no activation needed
}
}
else { // currently executing an extended-thread
// is the current thread different from the next?
if (curr != next) {
QXK_attr_.next = next;
QXK_CONTEXT_SWITCH_();
}
else { // next is the same as current
QXK_attr_.next = nullptr; // no need to context-switch
}
p = 0U; // no activation needed
}
return p;</code>
</operation>
<!--${QXK-extern-C::QXK_activate_}-->
<operation name="QXK_activate_" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! QXK activator activates the next active object. The activated AO preempts
//! the currently executing AOs
//!
//! @attention
//! QXK_activate_() must be always called with interrupts **disabled** and
//! returns with interrupts **disabled**.
//!
//! @note
//! The activate function might enable interrupts internally, but it always
//! returns with interrupts **disabled**.</documentation>
<code>std::uint8_t const prio_in = QXK_attr_.actPrio;
QP::QActive *next = QXK_attr_.next; // the next AO (basic-thread) to run
//! @pre QXK_attr_.next must be valid and the prio must be in range
Q_REQUIRE_ID(700, (next != nullptr) &amp;&amp; (prio_in &lt;= 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_attr_.next = nullptr; // clear the next AO
QXK_attr_.curr = nullptr; // current is basic-thread
// priority of the next thread
std::uint8_t p = next-&gt;m_prio;
// loop until no more ready-to-run AOs of higher prio than the initial
do {
QXK_attr_.actPrio = p; // next active prio
QF_INT_ENABLE(); // unconditionally enable interrupts
// perform the run-to-completion (RTC) step...
// 1. retrieve the event from the AO's event queue, which by this
// time must be non-empty and QActive_get_() asserts it.
// 2. dispatch the event to the AO's state machine.
// 3. determine if event is garbage and collect it if so
//
QP::QEvt const * const e = next-&gt;get_();
next-&gt;dispatch(e, next-&gt;m_prio);
#if (QF_MAX_EPOOL &gt; 0U)
QP::QF::gc(e);
#endif
QF_INT_DISABLE(); // unconditionally disable interrupts
if (next-&gt;m_eQueue.isEmpty()) { // empty queue?
QP::QF::readySet_.remove(p);
}
if (QP::QF::readySet_.isEmpty()) {
QXK_attr_.next = nullptr;
next = QP::QActive::registry_[0];
p = 0U; // no activation needed
}
else {
// find next highest-prio below the lock ceiling
p = static_cast&lt;std::uint8_t&gt;(QP::QF::readySet_.findMax());
if (p &lt;= QXK_attr_.lockCeil) {
p = QXK_attr_.lockHolder;
if (p != 0U) {
Q_ASSERT_ID(710, QP::QF::readySet_.hasElement(p));
}
}
// set the next thread and ensure that it is registered
next = QP::QActive::registry_[p];
Q_ASSERT_ID(720, next != nullptr);
// is next a basic thread?
if (next-&gt;m_osObject == nullptr) {
// is the next priority above the initial priority?
if (p &gt; QP::QActive::registry_[prio_in]-&gt;m_prio) {
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (p != QXK_attr_.actPrio) { // changing threads?
QXK_contextSw(next);
}
#endif // QF_ON_CONTEXT_SW || Q_SPY
QXK_attr_.next = next;
}
else {
QXK_attr_.next = nullptr;
p = 0U; // no activation needed
}
}
else { // next is the extended-thread
QXK_attr_.next = next;
QXK_CONTEXT_SWITCH_();
p = 0U; // no activation needed
}
}
} while (p != 0U); // while activation needed
// restore the active priority
QXK_attr_.actPrio = prio_in;
#if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
if (next-&gt;m_osObject == nullptr) {
QXK_contextSw((prio_in == 0U)
? nullptr
: QP::QActive::registry_[prio_in]);
}
#endif // QF_ON_CONTEXT_SW || Q_SPY</code>
</operation>
<!--${QXK-extern-C::QXK_current}-->
<operation name="QXK_current" type="QP::QActive *" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! obtain the currently executing active-object/thread
//!
//! @returns
//! pointer to the currently executing active-object/thread</documentation>
<code>//! @pre the QXK kernel must be running
Q_REQUIRE_ID(800, QXK_attr_.lockCeil &lt;= QF_MAX_ACTIVE);
QF_CRIT_STAT_
QF_CRIT_E_();
QP::QActive *curr = QXK_attr_.curr;
if (curr == nullptr) { // basic thread?
curr = QP::QActive::registry_[QXK_attr_.actPrio];
}
QF_CRIT_X_();
//! @post the current thread must be valid
Q_ENSURE_ID(890, curr != nullptr);
return curr;</code>
</operation>
<!--${QXK-extern-C::QXK_stackInit_}-->
<operation name="QXK_stackInit_" type="void" visibility="0x00" properties="0x00">
<specifiers>noexcept</specifiers>
<documentation>//! initialize the private stack of a given AO</documentation>
<!--${QXK-extern-C::QXK_stackInit_::thr}-->
<parameter name="thr" type="void *"/>
<!--${QXK-extern-C::QXK_stackInit_::handler}-->
<parameter name="handler" type=" QP::QXThreadHandler const"/>
<!--${QXK-extern-C::QXK_stackInit_::stkSto}-->
<parameter name="stkSto" type="void * const"/>
<!--${QXK-extern-C::QXK_stackInit_::stkSize}-->
<parameter name="stkSize" type="std::uint_fast16_t const"/>
</operation>
<!--${QXK-extern-C::QXK_contextSw}-->
<operation name="QXK_contextSw? defined(Q_SPY) || defined(QF_ON_CONTEXT_SW)" type="void" visibility="0x00" properties="0x00">
<documentation>//! QXK context switch management
//!
//! @details
//! This function performs software tracing (if #Q_SPY is defined)
//! and calls QXK_onContextSw() (if #QF_ON_CONTEXT_SW is defined)
//!
//! @param[in] next pointer to the next thread (NULL for basic-thread)
//!
//! @attention
//! QXK_contextSw() is invoked with interrupts **disabled** and must also
//! return with interrupts **disabled**.</documentation>
<!--${QXK-extern-C::QXK_contextSw::next}-->
<parameter name="next" type="QP::QActive * const"/>
<code>#ifdef Q_SPY
std::uint8_t const prev_prio = (QXK_attr_.prev != nullptr)
? QXK_attr_.prev-&gt;m_prio
: 0U;
#endif // Q_SPY
if (next != nullptr) { // next is NOT idle?
QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next-&gt;m_prio)
QS_TIME_PRE_(); // timestamp
QS_2U8_PRE_(next-&gt;m_prio, prev_prio);
QS_END_NOCRIT_PRE_()
}
else { // going to idle
QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, prev_prio)
QS_TIME_PRE_(); // timestamp
QS_U8_PRE_(prev_prio);
QS_END_NOCRIT_PRE_()
}
#ifdef QF_ON_CONTEXT_SW
QF_onContextSw(QXK_attr_.prev, next);
#endif // QF_ON_CONTEXT_SW
QXK_attr_.prev = next; // update the previous thread</code>
</operation>
<!--${QXK-extern-C::QXK_threadExit_}-->
<operation name="QXK_threadExit_" type="void" visibility="0x00" properties="0x00">
<documentation>//! called when a thread function exits
//!
//! @details
//! Called when the extended-thread handler function exits.
//!
//! @note
//! Most thread handler functions are structured as endless loops that never
//! exit. But it is also possible to structure threads as one-shot functions
//! that perform their job and exit. In that case this function peforms
//! cleanup after the thread.</documentation>
<code>QF_CRIT_STAT_
QF_CRIT_E_();
QP::QXThread const * const thr = QXTHREAD_CAST_(QXK_attr_.curr);
//! @pre this function must:
//! - NOT be called from an ISR;
//! - be called from an extended thread;
Q_REQUIRE_ID(900, (!QXK_ISR_CONTEXT_())
&amp;&amp; (thr != nullptr));
//! @pre also: the thread must NOT be holding a scheduler lock.
Q_REQUIRE_ID(901, QXK_attr_.lockHolder != thr-&gt;m_prio);
std::uint_fast8_t const p =
static_cast&lt;std::uint_fast8_t&gt;(thr-&gt;m_prio);
// remove this thread from the QF
QP::QActive::registry_[p] = nullptr;
QP::QF::readySet_.remove(p);
static_cast&lt;void&gt;(QXK_sched_()); // synchronous scheduling
QF_CRIT_X_();</code>
</operation>
<!--${QXK-extern-C::QXK_PTR_CAST_}-->
<operation name="QXK_PTR_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
<specifiers>&lt;type_&gt;</specifiers>
<documentation>//! intertnal macro to encapsulate casting of pointers for MISRA deviations
//!
//! @details
//! This macro is specifically and exclusively used for casting pointers
//! that are never de-referenced, but only used for internal bookkeeping and
//! checking (via assertions) the correct operation of the QXK kernel.
//! Such pointer casting is not compliant with MISRA C++ Rule 5-2-7
//! as well as other messages (e.g., PC-Lint-Plus warning 826).
//! Defining this specific macro for this purpose allows to selectively
//! disable the warnings for this particular case.</documentation>
<!--${QXK-extern-C::QXK_PTR_CAST_::type_}-->
<parameter name="type_" type="&lt;QXK obj&gt;"/>
<!--${QXK-extern-C::QXK_PTR_CAST_::ptr_}-->
<parameter name="ptr_" type="QP::QActive *"/>
<code>(reinterpret_cast&lt;type_&gt;(ptr_))</code>
</operation>
<!--${QXK-extern-C::QXTHREAD_CAST_}-->
<operation name="QXTHREAD_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
<documentation>//! internal macro to encapsulate casting of pointers for MISRA deviations
//!
//! @details
//! This macro is specifically and exclusively used for downcasting pointers
//! to QActive to pointers to QXThread in situations when it is known
//! that such downcasting is correct.&lt;br&gt;
//!
//! However, such pointer casting is not compliant with MISRA C++
//! Rule 5-2-7 as well as other messages (e.g., PC-Lint-Plus warning 826).
//! Defining this specific macro for this purpose allows to selectively
//! disable the warnings for this particular case.</documentation>
<!--${QXK-extern-C::QXTHREAD_CAST_::ptr_}-->
<parameter name="ptr_" type="QP::QActive *"/>
<code>(static_cast&lt;QP::QXThread *&gt;(ptr_))</code>
</operation>
</package>
<!--${QXK-impl}-->
<package name="QXK-impl" stereotype="0x02">
<!--${QXK-impl::QXK_ISR_CONTEXT_}-->
<operation name="QXK_ISR_CONTEXT_?ndef QXK_ISR_CONTEXT_" type="" visibility="0x03" properties="0x00">
<documentation>//! Internal port-specific macro that checks the execution context
//! (ISR vs. thread). Might be overridden in qxk_port.hpp.
//!
//! @returns
//! 'true' if the code executes in the ISR context and 'false' otherwise.</documentation>
<code>(QF::intNest_ != 0U)</code>
</operation>
<!--${QXK-impl::QF_SCHED_STAT_}-->
<attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
<documentation>//! QXK scheduler lock status</documentation>
<code>QSchedStatus lockStat_;</code>
</attribute>
<!--${QXK-impl::QF_SCHED_LOCK_}-->
<operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
<documentation>//! QXK selective scheduler locking</documentation>
<!--${QXK-impl::QF_SCHED_LOCK_::ceil_}-->
<parameter name="ceil_" type="std::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">
<documentation>//! QXK selective scheduler unlocking</documentation>
<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">
<documentation>// QXK native event queue waiting</documentation>
<!--${QXK-impl::QACTIVE_EQUEUE_W~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>\
Q_ASSERT_ID(110, (me_)-&gt;m_eQueue.m_frontEvt != nullptr)</code>
</operation>
<!--${QXK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
<operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
<documentation>// QXK native event queue signalling</documentation>
<!--${QXK-impl::QACTIVE_EQUEUE_S~::me_}-->
<parameter name="me_" type="QP::QActive *"/>
<code>do { \
QF::readySet_.insert( \
static_cast&lt;std::uint_fast8_t&gt;((me_)-&gt;m_prio)); \
if (!QXK_ISR_CONTEXT_()) { \
if (QXK_sched_() != 0U) { \
QXK_activate_(); \
} \
} \
} while (false)</code>
</operation>
</package>
<!--${include}-->
<directory name="include">
<!--${include::qep.hpp}-->
<file name="qep.hpp">
<text>//! @file
//! @brief QEP/C++ platform-independent public interface.
//!
//! @tr{RQP001} @tr{RQP101}
#ifndef QP_INC_QEP_HPP_
#define QP_INC_QEP_HPP_
//============================================================================
//! The current QP version as an unsigned number
//
// @details
// ::QP_VERSION is a decimal constant, where XX is a 1-digit or 2-digit
// major version number, Y is a 1-digit minor version number, and Z is
// a 1-digit release number.
//
#define QP_VERSION 720U
//! The current QP version as a zero terminated string literal.
//
// @details
// ::QP_VERSION_STR is of the form &quot;XX.Y.Z&quot;, where XX is a 1-or 2-digit
// major version number, Y is a 1-digit minor version number, and Z is
// a 1-digit release number.
//
#define QP_VERSION_STR &quot;7.2.0&quot;
//! Encrypted current QP release (7.2.0) and date (2023-01-06)
#define QP_RELEASE 0x76D8998FU
//============================================================================
// Global namespace...
$declare ${glob-types}
$declare ${QEP-config}
//============================================================================
$declare ${QEP}
//============================================================================
$declare ${QEP-macros}
#endif // QP_INC_QEP_HPP_</text>
</file>
<!--${include::qf.hpp}-->
<file name="qf.hpp">
<text>//! @file
//! @brief QF/C++ platform-independent public interface.
#ifndef QP_INC_QF_HPP_
#define QP_INC_QF_HPP_
#ifdef Q_EVT_CTOR
#include &lt;new&gt; // for placement new
#include &lt;cstdarg&gt; // for va_list
#endif // Q_EVT_CTOR
//============================================================================
// Global namespace...
$declare ${QF-config}
//============================================================================
$declare ${QF-types}
$declare ${QF::QActive}
$declare ${QF::QMActive}
$declare ${QF::QTimeEvt}
$declare ${QF::QTicker}
$declare ${QF::QF-base}
$declare ${QF::QF-dyn}
//============================================================================
extern &quot;C&quot; {
$declare ${QF-extern-C}
} // extern &quot;C&quot;
//============================================================================
// Global namespace...
$declare ${QF-macros}
#endif // QP_INC_QF_HPP_</text>
</file>
<!--${include::qf_pkg.hpp}-->
<file name="qf_pkg.hpp">
<text>//! @file
//! @brief Internal (package scope) QF/C++ interface.
#ifndef QP_INC_QF_PKG_HPP_
#define QP_INC_QF_PKG_HPP_
//============================================================================
//! helper macro to cast const away from an event pointer
#define QF_CONST_CAST_(type_, ptr_) const_cast&lt;type_&gt;(ptr_)
$declare ${QF::QF-pkg}
//============================================================================
namespace QP {
//............................................................................
//! Structure representing a free block in the Native QF Memory Pool
//! @sa QP::QMPool
struct QFreeBlock {
QFreeBlock * volatile m_next; //!&lt; link to the next free block
};
//............................................................................
// The following flags and flags and bitmasks are for the fields of the
// `QEvt.refCtr_` attribute of the QP::QTimeEvt class (subclass of QP::QEvt).
// This attribute is NOT used for reference counting in time events
// because the `QEvt.poolId_` attribute is zero (&quot;static event&quot;).
//
constexpr std::uint8_t TE_IS_LINKED = 1U &lt;&lt; 7U; // flag
constexpr std::uint8_t TE_WAS_DISARMED = 1U &lt;&lt; 6U; // flag
constexpr std::uint8_t TE_TICK_RATE = 0x0FU; // bitmask
// internal helper inline functions
//! increment the refCtr_ of an event `e`
inline void QEvt_refCtr_inc_(QEvt const * const e) noexcept {
(QF_CONST_CAST_(QEvt*, e))-&gt;refCtr_ = e-&gt;refCtr_ + 1U;
}
//! decrement the refCtr_ of an event `e`
inline void QEvt_refCtr_dec_(QEvt const * const e) noexcept {
(QF_CONST_CAST_(QEvt*, e))-&gt;refCtr_ = e-&gt;refCtr_ - 1U;
}
} // namespace QP
//============================================================================
// QF-specific critical section...
#ifndef QF_CRIT_STAT_TYPE
//! This is an internal macro for defining the critical section
//! status type.
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! provides the definition of the critical section status variable.
//! Otherwise this macro is empty.
//! @sa #QF_CRIT_STAT_TYPE
#define QF_CRIT_STAT_
//! This is an internal macro for entering a critical section.
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! invokes QF_CRIT_ENTRY() passing the key variable as the parameter.
//! Otherwise QF_CRIT_ENTRY() is invoked with a dummy parameter.
//! @sa QF_CRIT_ENTRY()
#define QF_CRIT_E_() QF_CRIT_ENTRY(dummy)
//! This is an internal macro for exiting a critical section.
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! invokes QF_CRIT_EXIT() passing the key variable as the parameter.
//! Otherwise QF_CRIT_EXIT() is invoked with a dummy parameter.
//! @sa QF_CRIT_EXIT()
//!
#define QF_CRIT_X_() QF_CRIT_EXIT(dummy)
#elif (!defined QF_CRIT_STAT_)
#define QF_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_;
#define QF_CRIT_E_() QF_CRIT_ENTRY(critStat_)
#define QF_CRIT_X_() QF_CRIT_EXIT(critStat_)
#endif // QF_CRIT_STAT_TYPE
// Assertions inside the critical section ------------------------------------
#ifdef Q_NASSERT // Q_NASSERT defined--assertion checking disabled
#define Q_ASSERT_CRIT_(id_, test_) static_cast&lt;void&gt;(0)
#define Q_REQUIRE_CRIT_(id_, test_) static_cast&lt;void&gt;(0)
#define Q_ERROR_CRIT_(id_) static_cast&lt;void&gt;(0)
#else // Q_NASSERT not defined--assertion checking enabled
#define Q_ASSERT_CRIT_(id_, test_) do { \
if ((test_)) {} else { \
QF_CRIT_X_(); \
Q_onAssert(&amp;Q_this_module_[0], static_cast&lt;int_t&gt;(id_)); \
} \
} while (false)
#define Q_REQUIRE_CRIT_(id_, test_) Q_ASSERT_CRIT_((id_), (test_))
#define Q_ERROR_CRIT_(id_) do { \
QF_CRIT_X_(); \
Q_onAssert(&amp;Q_this_module_[0], static_cast&lt;int_t&gt;(id_)); \
} while (false)
#endif // Q_NASSERT
//! helper macro to test that a pointer `x_` is in range between
//! `min_` and `max_`
//!
//! @details
//! This macro is specifically and exclusively used for checking the range
//! of a block pointer returned to the pool. Such a check must rely on the
//! pointer arithmetic not compliant with the [AUTOSAR Rule M5-0-18].
//! Defining a specific macro for this purpose allows to selectively
//! disable the warnings for this particular case.
#define QF_PTR_RANGE_(x_, min_, max_) (((min_) &lt;= (x_)) &amp;&amp; ((x_) &lt;= (max_)))
#endif // QP_INC_QF_PKG_HPP_</text>
</file>
<!--${include::qequeue.hpp}-->
<file name="qequeue.hpp">
<text>//! @file
//! @brief platform-independent fast &quot;raw&quot; thread-safe event queue interface
//!
//! @details
//! This header file must be included in all QF ports that use native QF
//! event queue for active objects. Also, this file needs to be included
//! in the QP/C++ library when the application uses QActive::defer() /
//! QActive::recall(). Finally, this file is also needed when the &quot;raw&quot;
//! thread-safe queues are used for communication between active objects
//! and non-framework entities, such as ISRs, device drivers, or legacy
//! code.
#ifndef QP_INC_QEQUEUE_HPP_
#define QP_INC_QEQUEUE_HPP_
#ifndef QF_EQUEUE_CTR_SIZE
//! The size (in bytes) of the ring-buffer counters used in the
//! native QF event queue implementation. Valid values: 1U, 2U, or 4U;
//! default 1U.
//! @details
//! This macro can be defined in the QF port file (qf_port.hpp) to
//! configure the QP::QEQueueCtr type. Here the macro is not defined
//! so the default of 1 byte is chosen.
#define QF_EQUEUE_CTR_SIZE 1U
#endif
namespace QP {
#if (QF_EQUEUE_CTR_SIZE == 1U)
//! The data type to store the ring-buffer counters based on
//! the macro #QF_EQUEUE_CTR_SIZE.
//! @details
//! The dynamic range of this data type determines the maximum length
//! of the ring buffer managed by the native QF event queue.
using QEQueueCtr = std::uint8_t;
#elif (QF_EQUEUE_CTR_SIZE == 2U)
using QEQueueCtr = std::uint16_t;
#elif (QF_EQUEUE_CTR_SIZE == 4U)
using QEQueueCtr = std::uint32_t;
#else
#error &quot;QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U&quot;
#endif
} // namespace QP
//============================================================================
$declare ${QF::QEQueue}
#endif // QP_INC_QEQUEUE_HPP_</text>
</file>
<!--${include::qmpool.hpp}-->
<file name="qmpool.hpp">
<text>//! @file
//! @brief platform-independent memory pool QP::QMPool interface.
#ifndef QP_INC_QMPOOL_HPP_
#define QP_INC_QMPOOL_HPP_
#ifndef QF_MPOOL_SIZ_SIZE
//! macro to override the default QP::QMPoolSize size.
//! Valid values 1U, 2U, or 4U; default 2U
#define QF_MPOOL_SIZ_SIZE 2U
#endif
#ifndef QF_MPOOL_CTR_SIZE
//! macro to override the default QMPoolCtr size.
//! Valid values 1U, 2U, or 4U; default 2U
#define QF_MPOOL_CTR_SIZE 2
#endif
//! Memory pool element to allocate correctly aligned storage for QP::QMPool
#define QF_MPOOL_EL(type_) \
struct { void *sto_[((sizeof(type_) - 1U)/sizeof(void*)) + 1U]; }
//============================================================================
namespace QP {
#if (QF_MPOOL_SIZ_SIZE == 1U)
using QMPoolSize = std::uint8_t;
#elif (QF_MPOOL_SIZ_SIZE == 2U)
//! The data type to store the block-size based on the macro
//! #QF_MPOOL_SIZ_SIZE
//!
//! @details
//! The dynamic range of this data type determines the maximum size
//! of blocks that can be managed by the native QF event pool.
using QMPoolSize = std::uint16_t;
#elif (QF_MPOOL_SIZ_SIZE == 4U)
using QMPoolSize = std::uint32_t;
#else
#error &quot;QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U&quot;
#endif
#if (QF_MPOOL_CTR_SIZE == 1U)
using QMPoolCtr = std::uint8_t;
#elif (QF_MPOOL_CTR_SIZE == 2U)
//! The data type to store the block-counter based on the macro
//! #QF_MPOOL_CTR_SIZE
//!
//! @details
//! The dynamic range of this data type determines the maximum number
//! of blocks that can be stored in the pool.
using QMPoolCtr = std::uint16_t;
#elif (QF_MPOOL_CTR_SIZE == 4U)
using QMPoolCtr = std::uint32_t;
#else
#error &quot;QF_MPOOL_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U&quot;
#endif
} // namespace QP
//============================================================================
$declare ${QF::QMPool}
#endif // QP_INC_QMPOOL_HPP_</text>
</file>
<!--${include::qv.hpp}-->
<file name="qv.hpp">
<text>//! @file
//! @brief QV/C++ platform-independent public interface.
#ifndef QP_INC_QV_HPP_
#define QP_INC_QV_HPP_
//============================================================================
// QF customization for QV -- data members of the QActive class...
// QV event-queue used for AOs
#define QF_EQUEUE_TYPE QEQueue
//============================================================================
#include &quot;qequeue.hpp&quot; // QV kernel uses the native QF event queue
#include &quot;qmpool.hpp&quot; // QV kernel uses the native QF memory pool
#include &quot;qf.hpp&quot; // QF framework integrates directly with QV
//============================================================================
$declare ${QV::QV-base}
//============================================================================
// interface used only inside QF, but not in applications
#ifdef QP_IMPL
// QV-specific scheduler locking and event queue...
$declare ${QV-impl}
// Native QF event pool operations...
$declare ${QF-QMPool-impl}
#endif // QP_IMPL
#endif // QP_INC_QV_HPP_</text>
</file>
<!--${include::qk.hpp}-->
<file name="qk.hpp">
<text>//! @file
//! @brief QK/C++ platform-independent public interface.
#ifndef QP_INC_QK_HPP_
#define QP_INC_QK_HPP_
//============================================================================
// QF customization for QK -- data members of the QActive class...
// QK event-queue used for AOs
#define QF_EQUEUE_TYPE QEQueue
// QK thread type used for AOs
// QK uses this member to store the private Thread-Local Storage pointer.
#define QF_THREAD_TYPE void*
//============================================================================
#include &quot;qequeue.hpp&quot; // QK kernel uses the native QF event queue
#include &quot;qmpool.hpp&quot; // QK kernel uses the native QF memory pool
#include &quot;qf.hpp&quot; // QF framework integrates directly with QK
//============================================================================
$declare ${QK::QK-base}
//============================================================================
extern &quot;C&quot; {
$declare ${QK-extern-C}
} // extern &quot;C&quot;
//============================================================================
// interface used only inside QF, but not in applications
#ifdef QP_IMPL
// QK-specific scheduler locking and event queue...
$declare ${QK-impl}
// Native QF event pool operations...
$declare ${QF-QMPool-impl}
#endif // QP_IMPL
#endif // QP_INC_QK_HPP_</text>
</file>
<!--${include::qxk.hpp}-->
<file name="qxk.hpp">
<text>//! @file
//! @brief QXK/C++ preemptive extended (blocking) kernel, platform-independent
//! public interface.
#ifndef QP_INC_QXK_HPP_
#define QP_INC_QXK_HPP_
//============================================================================
// QF customization for QXK -- data members of the QActive class...
// QXK event-queue used for AOs
#define QF_EQUEUE_TYPE QEQueue
// QXK OS-object used to store the private stack pointer for extended threads.
// (The private stack pointer is NULL for basic-threads).
#define QF_OS_OBJECT_TYPE void*
// QXK thread type used to store the private Thread-Local Storage pointer.
#define QF_THREAD_TYPE void*
//! Access Thread-Local Storage (TLS) and cast it on the given `type_`
#define QXK_TLS(type_) (static_cast&lt;type_&gt;(QXK_current()-&gt;m_thread))
//============================================================================
#include &quot;qequeue.hpp&quot; // QXK kernel uses the native QF event queue
#include &quot;qmpool.hpp&quot; // QXK kernel uses the native QF memory pool
#include &quot;qf.hpp&quot; // QF framework integrates directly with QXK
//============================================================================
$declare ${QXK::QXTHREAD_NO_TIMEOUT}
$declare ${QXK::QXK-base}
$declare ${QXK::QXThread}
$declare ${QXK::QXSemaphore}
$declare ${QXK::QXMutex}
//============================================================================
extern &quot;C&quot; {
$declare ${QXK-extern-C}
} // extern &quot;C&quot;
//============================================================================
// interface used only inside QF, but not in applications
#ifdef QP_IMPL
// QXK implementation...
$declare ${QXK-impl}
// Native QF event pool operations...
$declare ${QF-QMPool-impl}
#endif // QP_IMPL
#endif // QP_INC_QXK_HPP_</text>
</file>
<!--${include::qs.hpp}-->
<file name="qs.hpp">
<text>//! @file
//! @brief QS/C++ platform-independent public interface.
#ifndef QP_INC_QS_HPP_
#define QP_INC_QS_HPP_
#ifndef Q_SPY
#error &quot;Q_SPY must be defined to include qs.hpp&quot;
#endif
//============================================================================
// Global namespace...
$declare ${QS-config}
//============================================================================
$declare ${QS}
//============================================================================
// Global namespace...
$declare ${QS-macros}
//============================================================================
// Facilities for QS critical section
// QS-specific critical section
#ifdef QS_CRIT_ENTRY // separate QS critical section defined?
#ifndef QS_CRIT_STAT_TYPE
#define QS_CRIT_STAT_
#define QS_CRIT_E_() QS_CRIT_ENTRY(dummy)
#define QS_CRIT_X_() QS_CRIT_EXIT(dummy); QS_REC_DONE()
#else
#define QS_CRIT_STAT_ QS_CRIT_STAT_TYPE critStat_;
#define QS_CRIT_E_() QS_CRIT_ENTRY(critStat_)
#define QS_CRIT_X_() QS_CRIT_EXIT(critStat_); QS_REC_DONE()
#endif // QS_CRIT_STAT_TYPE
#else // separate QS critical section not defined--use the QF definition
#ifndef QF_CRIT_STAT_TYPE
//! This is an internal macro for defining the critical section
//! status type
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! provides the definition of the critical section status variable.
//! Otherwise this macro is empty.
//! @sa #QF_CRIT_STAT_TYPE
#define QS_CRIT_STAT_
//! This is an internal macro for entering a critical section
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! invokes #QF_CRIT_ENTRY passing the key variable as the parameter.
//! Otherwise #QF_CRIT_ENTRY is invoked with a dummy parameter.
//! @sa #QF_CRIT_ENTRY
#define QS_CRIT_E_() QF_CRIT_ENTRY(dummy)
//! This is an internal macro for exiting a critical section
//!
//! @details
//! The purpose of this macro is to enable writing the same code for the
//! case when critical section status type is defined and when it is not.
//! If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
//! invokes #QF_CRIT_EXIT passing the key variable as the parameter.
//! Otherwise #QF_CRIT_EXIT is invoked with a dummy parameter.
//! @sa #QF_CRIT_EXIT
#define QS_CRIT_X_() QF_CRIT_EXIT(dummy); QS_REC_DONE()
#elif (!defined QS_CRIT_STAT_)
#define QS_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_;
#define QS_CRIT_E_() QF_CRIT_ENTRY(critStat_)
#define QS_CRIT_X_() QF_CRIT_EXIT(critStat_); QS_REC_DONE()
#endif // simple unconditional interrupt disabling used
#endif // separate QS critical section not defined
//============================================================================
// Macros for use in QUTest only
#ifdef Q_UTEST
$declare ${QUTest}
//----------------------------------------------------------------------------
// 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 ${QUTest-stub::QS}
$declare ${QUTest-stub::QHsmDummy}
$declare ${QUTest-stub::QActiveDummy}
#endif // Q_UTEST != 0
//! QS macro to define the Test-Probe for a given `fun_`
#define QS_TEST_PROBE_DEF(fun_) \
std::uint32_t const qs_tp_ = \
QP::QS::getTestProbe_(QP::QS::force_cast&lt;void (*)(void)&gt;(fun_));
//! QS macro to apply a Test-Probe
#define QS_TEST_PROBE(code_) \
if (qs_tp_ != 0U) { code_ }
//! QS macro to apply a Test-Probe
#define QS_TEST_PROBE_ID(id_, code_) \
if (qs_tp_ == static_cast&lt;std::uint32_t&gt;(id_)) { code_ }
//! QS macro to pause test execution and enter the test event loop
#define QS_TEST_PAUSE() (QP::QS::test_pause_())
#else
// 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 // QP_INC_QS_HPP_</text>
</file>
<!--${include::qs_dummy.hpp}-->
<file name="qs_dummy.hpp">
<text>//! @file
//! @brief Dummy definitions of the QS macros that avoid code generation from
//! the QS instrumentation.
#ifndef QP_INC_QS_DUMMY_HPP_
#define QP_INC_QS_DUMMY_HPP_
#ifdef Q_SPY
#error &quot;Q_SPY must NOT be defined to include qs_dummy.hpp&quot;
#endif
#define QS_INIT(arg_) (true)
#define QS_EXIT() static_cast&lt;void&gt;(0)
#define QS_DUMP() static_cast&lt;void&gt;(0)
#define QS_GLB_FILTER(rec_) static_cast&lt;void&gt;(0)
#define QS_LOC_FILTER(qs_id_) static_cast&lt;void&gt;(0)
#define QS_GET_BYTE(pByte_) (0xFFFFU)
#define QS_GET_BLOCK(pSize_) (nullptr)
#define QS_BEGIN_ID(rec_, qs_id_) if (false) {
#define QS_END() }
#define QS_BEGIN_NOCRIT(rec_, qs_id_) if (false) {
#define QS_END_NOCRIT() }
#define QS_I8(width_, data_) static_cast&lt;void&gt;(0)
#define QS_U8(width_, data_) static_cast&lt;void&gt;(0)
#define QS_I16(width_, data_) static_cast&lt;void&gt;(0)
#define QS_U16(width_, data_) static_cast&lt;void&gt;(0)
#define QS_I32(width_, data_) static_cast&lt;void&gt;(0)
#define QS_U32(width_, data_) static_cast&lt;void&gt;(0)
#define QS_F32(width_, data_) static_cast&lt;void&gt;(0)
#define QS_F64(width_, data_) static_cast&lt;void&gt;(0)
#define QS_I64(width_, data_) static_cast&lt;void&gt;(0)
#define QS_U64(width_, data_) static_cast&lt;void&gt;(0)
#define QS_ENUM(group_, value_) static_cast&lt;void&gt;(0)
#define QS_STR(str_) static_cast&lt;void&gt;(0)
#define QS_MEM(mem_, size_) static_cast&lt;void&gt;(0)
#define QS_SIG(sig_, obj_) static_cast&lt;void&gt;(0)
#define QS_OBJ(obj_) static_cast&lt;void&gt;(0)
#define QS_FUN(fun_) static_cast&lt;void&gt;(0)
#define QS_SIG_DICTIONARY(sig_, obj_) static_cast&lt;void&gt;(0)
#define QS_OBJ_DICTIONARY(obj_) static_cast&lt;void&gt;(0)
#define QS_OBJ_ARR_DICTIONARY(obj_, idx_) static_cast&lt;void&gt;(0)
#define QS_FUN_DICTIONARY(fun_) static_cast&lt;void&gt;(0)
#define QS_USR_DICTIONARY(rec_) static_cast&lt;void&gt;(0)
#define QS_ENUM_DICTIONARY(value_, group_) static_cast&lt;void&gt;(0)
#define QS_ASSERTION(module_, loc_, delay_) static_cast&lt;void&gt;(0)
#define QS_FLUSH() static_cast&lt;void&gt;(0)
#define QS_TEST_PROBE_DEF(fun_)
#define QS_TEST_PROBE(code_)
#define QS_TEST_PROBE_ID(id_, code_)
#define QS_TEST_PAUSE() static_cast&lt;void&gt;(0)
#define QS_OUTPUT() static_cast&lt;void&gt;(0)
#define QS_RX_INPUT() static_cast&lt;void&gt;(0)
//============================================================================
$declare ${QS::QSpyIdOffsets}
$declare ${QS::QSpyIdGroups}
$declare ${QS::QSpyId}
//============================================================================
// internal QS macros used only in the QP components
#ifdef QP_IMPL
// predefined QS trace records
#define QS_BEGIN_PRE_(rec_, qs_id_) if (false) {
#define QS_END_PRE_() }
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_) if (false) {
#define QS_END_NOCRIT_PRE_() }
#define QS_U8_PRE_(data_) static_cast&lt;void&gt;(0)
#define QS_2U8_PRE_(data1_, data2_) static_cast&lt;void&gt;(0)
#define QS_U16_PRE_(data_) static_cast&lt;void&gt;(0)
#define QS_U32_PRE_(data_) static_cast&lt;void&gt;(0)
#define QS_TIME_PRE_() static_cast&lt;void&gt;(0)
#define QS_SIG_PRE_(sig_) static_cast&lt;void&gt;(0)
#define QS_EVS_PRE_(size_) static_cast&lt;void&gt;(0)
#define QS_OBJ_PRE_(obj_) static_cast&lt;void&gt;(0)
#define QS_FUN_PRE_(fun_) static_cast&lt;void&gt;(0)
#define QS_EQC_PRE_(ctr_) static_cast&lt;void&gt;(0)
#define QS_MPC_PRE_(ctr_) static_cast&lt;void&gt;(0)
#define QS_MPS_PRE_(size_) static_cast&lt;void&gt;(0)
#define QS_TEC_PRE_(ctr_) static_cast&lt;void&gt;(0)
#define QS_CRIT_STAT_
#define QF_QS_CRIT_ENTRY() static_cast&lt;void&gt;(0)
#define QF_QS_CRIT_EXIT() static_cast&lt;void&gt;(0)
#define QF_QS_ISR_ENTRY(isrnest_, prio_) static_cast&lt;void&gt;(0)
#define QF_QS_ISR_EXIT(isrnest_, prio_) static_cast&lt;void&gt;(0)
#define QF_QS_ACTION(act_) static_cast&lt;void&gt;(0)
#endif // QP_IMPL
#endif // QP_INC_QS_DUMMY_HPP_</text>
</file>
<!--${include::qs_pkg.hpp}-->
<file name="qs_pkg.hpp">
<text>//! @file
//! @brief Internal (package scope) QS/C++ interface.
#ifndef QP_INC_QS_PKG_HPP_
#define QP_INC_QS_PKG_HPP_
//============================================================================
namespace QP {
//! QS received record types (RX channel)
//!
//! @details
//! This enumeration specifies the record types for the QS receive channel
enum QSpyRxRecords : std::uint8_t {
QS_RX_INFO, //!&lt; query Target info (ver, config, tstamp)
QS_RX_COMMAND, //!&lt; execute a user-defined command in the Target
QS_RX_RESET, //!&lt; reset the Target
QS_RX_TICK, //!&lt; call QF_tick()
QS_RX_PEEK, //!&lt; peek Target memory
QS_RX_POKE, //!&lt; poke Target memory
QS_RX_FILL, //!&lt; fill Target memory
QS_RX_TEST_SETUP, //!&lt; test setup
QS_RX_TEST_TEARDOWN, //!&lt; test teardown
QS_RX_TEST_PROBE, //!&lt; set a Test-Probe in the Target
QS_RX_GLB_FILTER, //!&lt; set global filters in the Target
QS_RX_LOC_FILTER, //!&lt; set local filters in the Target
QS_RX_AO_FILTER, //!&lt; set local AO filter in the Target
QS_RX_CURR_OBJ, //!&lt; set the &quot;current-object&quot; in the Target
QS_RX_TEST_CONTINUE, //!&lt; continue a test after QS_RX_TEST_WAIT()
QS_RX_QUERY_CURR, //!&lt; query the &quot;current object&quot; in the Target
QS_RX_EVENT //!&lt; inject an event to the Target (post/publish)
};
//! @brief Frame character of the QS output protocol
constexpr std::uint8_t QS_FRAME = 0x7EU;
//! @brief Escape character of the QS output protocol
constexpr std::uint8_t QS_ESC = 0x7DU;
//! @brief Escape modifier of the QS output protocol
//!
//! @details
//! The escaped byte is XOR-ed with the escape modifier before it is inserted
//! into the QS buffer.
constexpr std::uint8_t QS_ESC_XOR = 0x20U;
//! @brief Escape character of the QS output protocol
constexpr std::uint8_t QS_GOOD_CHKSUM = 0xFFU;
} // namespace QP
//============================================================================
// Macros for use inside other macros or internally in the QP code
//! Internal QS macro to insert an un-escaped byte into the QS buffer
#define QS_INSERT_BYTE_(b_) \
buf_[head_] = (b_); \
++head_; \
if (head_ == end_) { \
head_ = 0U; \
}
//! Internal QS macro to insert an escaped byte into the QS buffer
#define QS_INSERT_ESC_BYTE_(b_) \
chksum_ += (b_); \
if (((b_) != QS_FRAME) &amp;&amp; ((b_) != QS_ESC)) { \
QS_INSERT_BYTE_(b_) \
} \
else { \
QS_INSERT_BYTE_(QS_ESC) \
QS_INSERT_BYTE_(static_cast&lt;std::uint8_t&gt;((b_) ^ QS_ESC_XOR)) \
priv_.used = (priv_.used + 1U); \
}
//! Internal QS macro to begin a predefined QS record with critical section.
//! @note
//! This macro is intended to use only inside QP components and NOT
//! at the application level.
//! @sa QS_BEGIN_ID()
//!
#define QS_BEGIN_PRE_(rec_, qs_id_) \
if (QS_GLB_CHECK_(rec_) &amp;&amp; QS_LOC_CHECK_(qs_id_)) { \
QS_CRIT_E_(); \
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(rec_));
//! Internal QS macro to end a predefined QS record with critical section.
//! @note
//! This macro is intended to use only inside QP components and NOT
//! at the application level.
//! @sa QS_END()
//!
#define QS_END_PRE_() \
QP::QS::endRec_(); \
QS_CRIT_X_(); \
}
//! Internal QS macro to begin a predefined QS record without critical section
//!
//! @note
//! This macro is intended to use only inside QP components and NOT
//! at the application level.
//! @sa QS_BEGIN_NOCRIT_PRE_()
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_) \
if (QS_GLB_CHECK_(rec_) &amp;&amp; QS_LOC_CHECK_(qs_id_)) { \
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(rec_));
//! Internal QS macro to end a predefiend QS record without critical section
//!
//! @note
//! This macro is intended to use only inside QP components and NOT
//! at the application level. @sa #QS_END_NOCRIT
#define QS_END_NOCRIT_PRE_() \
QP::QS::endRec_(); \
}
#if (Q_SIGNAL_SIZE == 1U)
//! Internal QS macro to output an unformatted event signal data element
//! @note
//! The size of the pointer depends on the macro #Q_SIGNAL_SIZE.
#define QS_SIG_PRE_(sig_) \
(QP::QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(sig_)))
#elif (Q_SIGNAL_SIZE == 2U)
#define QS_SIG_PRE_(sig_) \
(QP::QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(sig_)))
#elif (Q_SIGNAL_SIZE == 4U)
#define QS_SIG_PRE_(sig_) \
(QP::QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(sig_)))
#endif
//! Internal QS macro to output an unformatted uint8_t data element
#define QS_U8_PRE_(data_) \
(QP::QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(data_)))
//! Internal QS macro to output 2 unformatted uint8_t data elements
#define QS_2U8_PRE_(data1_, data2_) \
(QP::QS::u8u8_raw_(static_cast&lt;std::uint8_t&gt;(data1_), \
static_cast&lt;std::uint8_t&gt;(data2_)))
//! Internal QS macro to output an unformatted uint16_t data element
#define QS_U16_PRE_(data_) \
(QP::QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(data_)))
//! Internal QS macro to output an unformatted uint32_t data element
#define QS_U32_PRE_(data_) \
(QP::QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(data_)))
//! Internal QS macro to output a zero-terminated ASCII string
//! data element
#define QS_STR_PRE_(msg_) (QP::QS::str_raw_(msg_))
//! Internal QS macro to output object pointer data element
#define QS_OBJ_PRE_(obj_) (QP::QS::obj_raw_(obj_))
#if (QS_FUN_PTR_SIZE == 1U)
#define QS_FUN_PRE_(fun_) \
(QP::QS::u8_raw_(reinterpret_cast&lt;std::uint8_t&gt;(fun_)))
#elif (QS_FUN_PTR_SIZE == 2U)
#define QS_FUN_PRE_(fun_) \
(QP::QS::u16_raw_(reinterpret_cast&lt;std::uint16_t&gt;(fun_)))
#elif (QS_FUN_PTR_SIZE == 4U)
#define QS_FUN_PRE_(fun_) \
(QP::QS::u32_raw_(reinterpret_cast&lt;std::uint32_t&gt;(fun_)))
#elif (QS_FUN_PTR_SIZE == 8U)
#define QS_FUN_PRE_(fun_) \
(QP::QS::u64_raw_(reinterpret_cast&lt;std::uint64_t&gt;(fun_)))
#else
//! Internal QS macro to output an unformatted function pointer
//! data element
//!
//! @note
//! The size of the pointer depends on the macro #QS_FUN_PTR_SIZE.
//! If the size is not defined the size of pointer is assumed 4-bytes.
#define QS_FUN_PRE_(fun_) \
(QP::QS::u32_raw_(reinterpret_cast&lt;std::uint32_t&gt;(fun_)))
#endif
#if (QF_EQUEUE_CTR_SIZE == 1U)
//! Internal QS macro to output an unformatted event queue
//! counter data element
//! @note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE.
#define QS_EQC_PRE_(ctr_) \
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(ctr_))
#elif (QF_EQUEUE_CTR_SIZE == 2U)
#define QS_EQC_PRE_(ctr_) \
QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(ctr_))
#elif (QF_EQUEUE_CTR_SIZE == 4U)
#define QS_EQC_PRE_(ctr_) \
QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(ctr_))
#else
#error &quot;QF_EQUEUE_CTR_SIZE not defined&quot;
#endif
#if (QF_EVENT_SIZ_SIZE == 1U)
//! Internal QS macro to output an unformatted event size
//! data element
//!
//! @note the event size depends on the macro #QF_EVENT_SIZ_SIZE.
#define QS_EVS_PRE_(size_) \
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(size_))
#elif (QF_EVENT_SIZ_SIZE == 2U)
#define QS_EVS_PRE_(size_) \
QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(size_))
#elif (QF_EVENT_SIZ_SIZE == 4U)
#define QS_EVS_PRE_(size_) \
QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(size_))
#endif
#if (QF_MPOOL_SIZ_SIZE == 1U)
//! Internal QS macro to output an unformatted memory pool
//! block-size data element
//! @note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE.
#define QS_MPS_PRE_(size_) \
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(size_))
#elif (QF_MPOOL_SIZ_SIZE == 2U)
#define QS_MPS_PRE_(size_) \
QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(size_))
#elif (QF_MPOOL_SIZ_SIZE == 4U)
#define QS_MPS_PRE_(size_) \
QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(size_))
#endif
#if (QF_MPOOL_CTR_SIZE == 1U)
//! Internal QS macro to output an unformatted memory pool
//! block-counter data element
//! @note the counter size depends on the macro #QF_MPOOL_CTR_SIZE.
#define QS_MPC_PRE_(ctr_) \
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(ctr_))
#elif (QF_MPOOL_CTR_SIZE == 2U)
#define QS_MPC_PRE_(ctr_) \
QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(ctr_))
#elif (QF_MPOOL_CTR_SIZE == 4U)
#define QS_MPC_PRE_(ctr_) \
QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(ctr_))
#endif
#if (QF_TIMEEVT_CTR_SIZE == 1U)
//! Internal QS macro to output an unformatted time event
//! tick-counter data element
//! @note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE.
#define QS_TEC_PRE_(ctr_) \
QS::u8_raw_(static_cast&lt;std::uint8_t&gt;(ctr_))
#elif (QF_TIMEEVT_CTR_SIZE == 2U)
#define QS_TEC_PRE_(ctr_) \
QS::u16_raw_(static_cast&lt;std::uint16_t&gt;(ctr_))
#elif (QF_TIMEEVT_CTR_SIZE == 4U)
#define QS_TEC_PRE_(ctr_) \
QS::u32_raw_(static_cast&lt;std::uint32_t&gt;(ctr_))
#endif
//! Internal QS macro to cast enumerated QS record number to uint8_t
//!
//! @note Casting from enum to unsigned char violates the MISRA-C++ 2008 rules
//! 5-2-7, 5-2-8 and 5-2-9. Encapsulating this violation in a macro allows to
//! selectively suppress this specific deviation.
#define QS_REC_NUM_(enum_) (static_cast&lt;std::uint_fast8_t&gt;(enum_))
#endif // QP_INC_QS_PKG_HPP_</text>
</file>
<!--${include::qpcpp.hpp}-->
<file name="qpcpp.hpp">
<text>//! @file
//! @brief QP/C++ public interface including backwards-compatibility layer
//!
//! @details
//! This header file must be included directly or indirectly
//! in all application modules (*.cpp files) that use QP/C++.
#ifndef QP_INC_QPCPP_HPP_
#define QP_INC_QPCPP_HPP_
//============================================================================
#include &quot;qf_port.hpp&quot; // QF/C++ port from the port directory
#include &quot;qassert.h&quot; // QP assertions
#ifdef Q_SPY // software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS/C++ port from the port directory
#else
#include &quot;qs_dummy.hpp&quot; // QS/C++ dummy (inactive) interface
#endif
//============================================================================
#ifndef QP_API_VERSION
//! Macro that specifies the backwards compatibility with the
//! QP/C++ API version.
//!
//! @details
//! For example, QP_API_VERSION=540 will cause generating the compatibility
//! layer with QP/C++ version 5.4.0 and newer, but not older than 5.4.0.
//! QP_API_VERSION=0 causes generation of the compatibility layer &quot;from the
//! begining of time&quot;, which is the maximum backwards compatibilty. This is
//! the default.&lt;br&gt;
//!
//! Conversely, QP_API_VERSION=9999 means that no compatibility layer should
//! be generated. This setting is useful for checking if an application
//! complies with the latest QP/C++ API.
#define QP_API_VERSION 0
#endif // QP_API_VERSION
// QP/C++ API compatibility layer...
#if (QP_API_VERSION &lt; 700)
//! @deprecated use QP::QF::NO_MARGIN instead
#define QF_NO_MARGIN QP::QF::NO_MARGIN
//! @deprecated plain 'char' is no longer forbidden in MISRA/AUTOSAR-C++
using char_t = char;
//============================================================================
#if (QP_API_VERSION &lt; 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_) (static_cast&lt;void&gt;(0))
//! @deprecated enable the QS local filter for AO (active objects)
#define QS_FILTER_AO_OBJ(obj_) (static_cast&lt;void&gt;(0))
//! @deprecated enable the QS local filter for MP (memory pool) object
#define QS_FILTER_MP_OBJ(obj_) (static_cast&lt;void&gt;(0))
//! @deprecated enable the QS local filter for EQ (event queue) object
#define QS_FILTER_EQ_OBJ(obj_) (static_cast&lt;void&gt;(0))
//! @deprecated enable the QS local filter for TE (time event) object
#define QS_FILTER_TE_OBJ(obj_) (static_cast&lt;void&gt;(0))
#ifdef Q_SPY
//! @deprecated local Filter for a generic application object `obj_`.
#define QS_FILTER_AP_OBJ(obj_) \
(QP::QS::priv_.locFilter_AP = (obj_))
//! @deprecated begin of a user QS record, instead use QS_BEGIN_ID()
#define QS_BEGIN(rec_, obj_) \
if (QS_GLB_FILTER_(rec_) &amp;&amp; \
((QP::QS::priv_.locFilter[QP::QS::AP_OBJ] == nullptr) \
|| (QP::QS::priv_.locFilter_AP == (obj_)))) \
{ \
QS_CRIT_STAT_ \
QS_CRIT_E_(); \
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(rec_)); \
QS_TIME_PRE_();
//! @deprecated output hex-formatted std::uint32_t to the QS record
#define QS_U32_HEX(width_, data_) \
(QP::QS::u32_fmt_(static_cast&lt;std::uint8_t&gt;( \
(static_cast&lt;std::uint8_t&gt;((width_) &lt;&lt; 4)) | QS_HEX_FMT), (data_)))
#else
#define QS_FILTER_AP_OBJ(obj_) (static_cast&lt;void&gt;(0))
#define QS_BEGIN(rec_, obj_) if (false) {
#define QS_U32_HEX(width_, data_) (Q_UNUSED_PAR(0))
#endif // def Q_SPY
//============================================================================
#if (QP_API_VERSION &lt; 680)
//! @deprecated
//! Macro to specify a transition in the &quot;me-&gt;&quot; impl-strategy.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! you call tran(Q_STATE_CAST(target_)).
#define Q_TRAN(target_) (me-&gt;tran(Q_STATE_CAST(target_)))
//! @deprecated
//! Macro to specify a tran-to-history in the &quot;me-&gt;&quot; impl-strategy.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! you call tran_hist(Q_STATE_CAST(hist_)).
#define Q_TRAN_HIST(hist_) (me-&gt;tran_hist((hist_)))
//! @deprecated
//! Macro to specify the superstate in the &quot;me-&gt;&quot; impl-strategy.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! you call super(state_)).
#define Q_SUPER(state_) (me-&gt;super(Q_STATE_CAST(state_)))
//! @deprecated
//! Macro to call in a QM state entry-handler. Applicable only to QMSMs.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_entry(Q_STATE_CAST(state_)).
#define QM_ENTRY(state_) (me-&gt;qm_entry((state_)))
//! @deprecated
//! Macro to call in a QM state exit-handler. Applicable only to QMSMs.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_exit(Q_STATE_CAST(state_)).
#define QM_EXIT(state_) (me-&gt;qm_exit((state_)))
//! @deprecated
//! Macro to call in a QM submachine exit-handler. Applicable only to QMSMs.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_sm_exit(Q_STATE_CAST(state_)).
#define QM_SM_EXIT(state_) (me-&gt;qm_sm_exit((state_)))
//! @deprecated
//! Macro to call in a QM state-handler when it executes a transition.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_tran((tatbl_)).
#define QM_TRAN(tatbl_) (me-&gt;qm_tran((tatbl_)))
//! @deprecated
//! Macro to call in a QM state-handler when it executes an initial tran.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_tran_init((tatbl_)).
#define QM_TRAN_INIT(tatbl_) (me-&gt;qm_tran_init((tatbl_)))
//! @deprecated
//! Macro to call in a QM state-handler when it executes a tran-to-history.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_tran_hist((history_), (tatbl_)).
#define QM_TRAN_HIST(history_, tatbl_) \
(me-&gt;qm_tran_hist((history_), (tatbl_)))
//! @deprecated
//! Macro to call in a QM state-handler when it executes an initial tran.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_tran_ep((tatbl_)).
#define QM_TRAN_EP(tatbl_) (me-&gt;qm_tran_ep((tatbl_)))
//! @deprecated
//! Macro to call in a QM state-handler when it executes a tran-to-exit-point.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_tran_xp((xp_), (tatbl_)).
#define QM_TRAN_XP(xp_, tatbl_) (me-&gt;qm_tran_xp((xp_), (tatbl_)))
//! @deprecated
//! Designates the superstate of a given state in a subclass of QP::QMsm.
//! Instead use the new impl-strategy without the &quot;me-&gt;&quot; pointer, where
//! the QM-generated code calls qm_super_sub((state_)).
#define QM_SUPER_SUB(state_) (me-&gt;qm_super_sub((state_)))
#endif // QP_API_VERSION &lt; 680
#endif // QP_API_VERSION &lt; 691
#endif // QP_API_VERSION &lt; 700
#endif // QP_INC_QPCPP_HPP_</text>
</file>
<!--${include::qstamp.hpp}-->
<file name="qstamp.hpp">
<text>//! @file
//! @brief Application build time-stamp interface
#ifndef QP_INC_QSTAMP_HPP_
#define QP_INC_QSTAMP_HPP_
namespace QP {
extern char const BUILD_DATE[12];
extern char const BUILD_TIME[9];
} // namespace QP
#endif // QP_INC_QSTAMP_HPP_</text>
</file>
</directory>
<!--${src}-->
<directory name="src">
<!--${src::qf}-->
<directory name="qf">
<!--${src::qf::qep_hsm.cpp}-->
<file name="qep_hsm.cpp">
<text>//! @file
//! @brief QP::QHsm implementation
//!
//! @tr{RQP103} @tr{RQP104} @tr{RQP120} @tr{RQP130}
#define QP_IMPL // this is QP implementation
#include &quot;qep_port.hpp&quot; // QEP port
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
//============================================================================
$define ${QEP::versionStr[]}
//============================================================================
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qep_hsm&quot;)
//----------------------------------------------------------------------------
//! Immutable events corresponding to the reserved signals.
//!
//! @details
//! Static, immutable reserved events that the QEP event processor sends
//! to state handler functions of QHsm-style state machine to execute entry
//! actions, exit actions, and initial transitions.
//!
static QP::QEvt const l_reservedEvt_[4] {
#ifdef Q_EVT_CTOR // Is the QEvt constructor provided?
QP::QEvt(static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_EMPTY_SIG), 0U),
QP::QEvt(static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_ENTRY_SIG), 0U),
QP::QEvt(static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_EXIT_SIG), 0U),
QP::QEvt(static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_INIT_SIG), 0U)
#else // QEvt is a POD (Plain Old Datatype)
{ static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_EMPTY_SIG), 0U, 0U },
{ static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_ENTRY_SIG), 0U, 0U },
{ static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_EXIT_SIG), 0U, 0U },
{ static_cast&lt;QP::QSignal&gt;(QP::QHsm::Q_INIT_SIG), 0U, 0U }
#endif
};
//----------------------------------------------------------------------------
// inline helper functions
//............................................................................
//! helper function to trigger reserved event in an QHsm
//!
//! @param[in] state state handler function
//! @param[in] sig reserved signal to trigger
static inline QP::QState hsm_reservedEvt_(
QP::QHsm * const me,
QP::QStateHandler const state,
enum QP::QHsm::ReservedSig const sig)
{
return (*state)(me, &amp;l_reservedEvt_[sig]);
}
//............................................................................
//! Helper function to execute entry into a given state in a
//! hierarchical state machine (HSM).
//!
//! @param[in] state state handler function
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
static inline void hsm_state_entry_(
QP::QHsm * const me,
QP::QStateHandler const state,
std::uint_fast8_t const qs_id)
{
#ifdef Q_SPY
if ((*state)(me, &amp;l_reservedEvt_[QP::QHsm::Q_ENTRY_SIG])
== QP::QHsm::Q_RET_HANDLED)
{
QS_CRIT_STAT_
QS_BEGIN_PRE_(QP::QS_QEP_STATE_ENTRY, qs_id)
QS_OBJ_PRE_(me);
QS_FUN_PRE_(state);
QS_END_PRE_()
}
#else
Q_UNUSED_PAR(qs_id);
static_cast&lt;void&gt;((*state)(me, &amp;l_reservedEvt_[QP::QHsm::Q_ENTRY_SIG]));
#endif // Q_SPY
}
//............................................................................
//! Helper function to execute exit from a given state in a
//! hierarchical state machine (HSM).
//!
//! @param[in] state state handler function
//! @param[in] qs_id QS-id of this state machine (for QS local filter)
//!
//! @returns
//! 'true' if the exit action has been found in the state and
//! 'flase' otherwise.
static inline bool hsm_state_exit_(
QP::QHsm * const me,
QP::QStateHandler const state,
std::uint_fast8_t const qs_id)
{
#ifdef Q_SPY
bool isHandled;
if ((*state)(me, &amp;l_reservedEvt_[QP::QHsm::Q_EXIT_SIG])
== QP::QHsm::Q_RET_HANDLED)
{
QS_CRIT_STAT_
QS_BEGIN_PRE_(QP::QS_QEP_STATE_EXIT, qs_id)
QS_OBJ_PRE_(me);
QS_FUN_PRE_(state);
QS_END_PRE_()
isHandled = true;
}
else {
isHandled = false;
}
return isHandled;
#else
Q_UNUSED_PAR(qs_id);
return (*state)(me, &amp;l_reservedEvt_[QP::QHsm::Q_EXIT_SIG]);
#endif // Q_SPY
}
} // unnamed namespace
$define ${QEP::QHsm}</text>
</file>
<!--${src::qf::qep_msm.cpp}-->
<file name="qep_msm.cpp">
<text>//! @file
//! @brief QP::QMsm implementation
#define QP_IMPL // this is QP implementation
#include &quot;qep_port.hpp&quot; // QEP port
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qep_msm&quot;)
} // unnamed namespace
//============================================================================
$define ${QEP::QMsm}</text>
</file>
<!--${src::qf::qf_act.cpp}-->
<file name="qf_act.cpp">
<text>//! @file
//! @deprecated
//! Empty file kept only for backwards compatibility.
//! @sa qf_qact.cpp
extern char const dummy; // declaration
char const dummy = '\0'; // definition</text>
</file>
<!--${src::qf::qf_actq.cpp}-->
<file name="qf_actq.cpp">
<text>//! @file
//! @brief QP::QActive native queue operations (based on QP::QEQueue)
//!
//! @attention
//! This qf_actq.cpp source file is only included in the build when the
//! macro #QF_EQUEUE_TYPE is defined as QEQueue. This means that the QP
//! port uses the QP::QEQueue for active objects and so this implementation
//! applies to the QP port.
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
//============================================================================
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_actq&quot;)
} // unnamed namespace
//============================================================================
$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.cpp}-->
<file name="qf_defer.cpp">
<text>//! @file
//! @brief QActive::defer(), QActive::recall(), and
//! QActive::flushDeferred() definitions.
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_defer&quot;)
} // unnamed namespace
$define ${QF::QActive::defer}
$define ${QF::QActive::recall}
$define ${QF::QActive::flushDeferred}</text>
</file>
<!--${src::qf::qf_dyn.cpp}-->
<file name="qf_dyn.cpp">
<text>//! @file
//! @brief QF/C++ dynamic event management
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
#if (QF_MAX_EPOOL &gt; 0U) // dynamic events configured?
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_dyn&quot;)
} // unnamed namespace
//============================================================================
$define ${QF::QF-pkg::maxPool_}
$define ${QF::QF-pkg::ePool_[QF_MAX_EPOOL]}
//============================================================================
$define ${QF::QF-dyn}
#endif // (QF_MAX_EPOOL &gt; 0U) dynamic events configured</text>
</file>
<!--${src::qf::qf_mem.cpp}-->
<file name="qf_mem.cpp">
<text>//! @file
//! @brief QF/C++ memory management services
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_mem&quot;)
} // unnamed namespace
$define ${QF::QMPool}</text>
</file>
<!--${src::qf::qf_qact.cpp}-->
<file name="qf_qact.cpp">
<text>//! @file
//! @brief QP::QActive services and QF support code
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qf_qact&quot;)
} // unnamed namespace
//============================================================================
$define ${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}
$define ${QF::QF-base::intLock_}
$define ${QF::QF-base::intNest_}
$define ${QF::QF-pkg::readySet_}
$define ${QF::QF-pkg::bzero}
//============================================================================
$define ${QF::QActive::QActive}
$define ${QF::QActive::register_}
$define ${QF::QActive::unregister_}
//============================================================================
$define ${QF-types::QPSet::QF_LOG2}</text>
</file>
<!--${src::qf::qf_qmact.cpp}-->
<file name="qf_qmact.cpp">
<text>//! @file
//! @brief QMActive::QMActive() and virtual functions
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
//! Internal macro to cast a QP::QMActive pointer `qact_` to QP::QMsm*
//! @note
//! Casting pointer to pointer pointer violates the MISRA-C++ 2008 Rule 5-2-7,
//! cast from pointer to pointer. Additionally this cast violates the MISRA-
//! C++ 2008 Rule 5-2-8 Unusual pointer cast (incompatible indirect types).
//! Encapsulating these violations in a macro allows to selectively suppress
//! this specific deviation.
#define QF_QMACTIVE_TO_QMSM_CAST_(qact_) \
reinterpret_cast&lt;QMsm *&gt;((qact_))
//! Internal macro to cast a QP::QMActive pointer `qact_` to QP::QMsm const *
#define QF_QMACTIVE_TO_QMSM_CONST_CAST_(qact_) \
reinterpret_cast&lt;QMsm const *&gt;((qact_))
// unnamed namespace for local definitions with internal linkage
namespace {
//Q_DEFINE_THIS_MODULE(&quot;qf_qmact&quot;)
} // unnamed namespace
$define ${QF::QMActive}</text>
</file>
<!--${src::qf::qf_qeq.cpp}-->
<file name="qf_qeq.cpp">
<text>//! @file
//! @brief QP::QEQueue implementation
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_qeq&quot;)
} // unnamed namespace
$define ${QF::QEQueue}</text>
</file>
<!--${src::qf::qf_ps.cpp}-->
<file name="qf_ps.cpp">
<text>//! @file
//! @brief QF/C++ Publish-Subscribe services
//! definitions.
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_ps&quot;)
} // unnamed namespace
$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.cpp}-->
<file name="qf_time.cpp">
<text>//! @file
//! @brief QF/C++ time events and time management services
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qf_time&quot;)
} // unnamed namespace
$define ${QF::QTimeEvt}</text>
</file>
</directory>
<!--${src::qv}-->
<directory name="qv">
<!--${src::qv::qv.cpp}-->
<file name="qv.cpp">
<text>//! @file
//! @brief Cooperative QV kernel implementation.
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QV_HPP_
#error &quot;Source file included in a project NOT based on the QV kernel&quot;
#endif // QP_INC_QV_HPP_
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qv&quot;)
} // unnamed namespace
//============================================================================
$define ${QV::QV-base}
$define ${QV::QF-cust}
$define ${QV::QActive}</text>
</file>
</directory>
<!--${src::qk}-->
<directory name="qk">
<!--${src::qk::qk.cpp}-->
<file name="qk.cpp">
<text>//! @file
//! @brief QK/C++ preemptive kernel core functions
#define QP_IMPL // this is QF/QK implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QK_HPP_
#error &quot;Source file included in a project NOT based on the QK kernel&quot;
#endif // QP_INC_QK_HPP_
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qk&quot;)
} // unnamed namespace
//============================================================================
$define ${QK::QK-base}
$define ${QK::QF-cust}
$define ${QK::QActive}
//============================================================================
extern &quot;C&quot; {
$define ${QK-extern-C}
} // extern &quot;C&quot;</text>
</file>
</directory>
<!--${src::qxk}-->
<directory name="qxk">
<!--${src::qxk::qxk.cpp}-->
<file name="qxk.cpp">
<text>//! @file
//! @brief QXK/C++ preemptive kernel core functions
//! public interface.
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QXK_HPP_
#error &quot;Source file included in a project NOT based on the QXK kernel&quot;
#endif // QP_INC_QXK_HPP_
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qxk&quot;)
} // unnamed namespace
//============================================================================
$define ${QXK::QXK-base}
$define ${QXK::QF-cust}
$define ${QXK::QActive}
//============================================================================
extern &quot;C&quot; {
$define ${QXK-extern-C}
} // extern &quot;C&quot;</text>
</file>
<!--${src::qxk::qxk_mutex.cpp}-->
<file name="qxk_mutex.cpp">
<text>//! @file
//! @brief Priority-ceiling blocking mutex QP::QXMutex class definition
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QXK_HPP_
#error &quot;Source file included in a project NOT based on the QXK kernel&quot;
#endif // QP_INC_QXK_HPP_
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qxk_mutex&quot;)
} // unnamed namespace
$define ${QXK::QXMutex}</text>
</file>
<!--${src::qxk::qxk_sema.cpp}-->
<file name="qxk_sema.cpp">
<text>//! @file
//! @brief QXK/C++ preemptive kernel counting semaphore implementation
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QXK_HPP_
#error &quot;Source file included in a project NOT based on the QXK kernel&quot;
#endif // QP_INC_QXK_HPP_
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qxk_sema&quot;)
} // unnamed namespace
//============================================================================
$define ${QXK::QXSemaphore}</text>
</file>
<!--${src::qxk::qxk_xthr.cpp}-->
<file name="qxk_xthr.cpp">
<text>//! @file
//! @brief QXK/C++ preemptive kernel extended (blocking) thread implementation
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#ifdef Q_SPY // QS software tracing enabled?
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS facilities for pre-defined trace records
#else
#include &quot;qs_dummy.hpp&quot; // disable the QS software tracing
#endif // Q_SPY
// protection against including this source file in a wrong project
#ifndef QP_INC_QXK_HPP_
#error &quot;Source file included in a project NOT based on the QXK kernel&quot;
#endif // QP_INC_QXK_HPP_
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qxk_xthr&quot;)
} // unnamed namespace
//============================================================================
$define ${QXK::QXThread}</text>
</file>
</directory>
<!--${src::qs}-->
<directory name="qs">
<!--${src::qs::qs.cpp}-->
<file name="qs.cpp">
<text>//! @file
//! @brief QS software tracing services
#define QP_IMPL // this is QP implementation
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS package-scope internal interface
#include &quot;qstamp.hpp&quot; // QP time-stamp
#include &quot;qassert.h&quot; // QP assertions
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qs&quot;)
} // unnamed namespace
$define ${QS::QS-tx}</text>
</file>
<!--${src::qs::qs_64bit.cpp}-->
<file name="qs_64bit.cpp">
<text>//! @file
//! @brief QS long-long (64-bit) output
#define QP_IMPL // this is QF/QK implementation
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS package-scope internal interface
$define ${QS::QS-tx-64bit}</text>
</file>
<!--${src::qs::qs_fp.cpp}-->
<file name="qs_fp.cpp">
<text>//! @file
//! @brief QS floating point output implementation
#define QP_IMPL // this is QF/QK implementation
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS package-scope internal interface
$define ${QS::QS-tx-fp}</text>
</file>
<!--${src::qs::qs_rx.cpp}-->
<file name="qs_rx.cpp">
<text>//! @file
//! @brief QS receive channel services
#define QP_IMPL // this is QP implementation
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS package-scope internal interface
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP assertions
static_assert(QP::QS::MAX_OBJ &lt;= 8U, &quot;QS::MAX_OBJECT below the limit&quot;);
//============================================================================
namespace { // unnamed local namespace
Q_DEFINE_THIS_MODULE(&quot;qs_rx&quot;)
//............................................................................
#if (QS_OBJ_PTR_SIZE == 1U)
using QSObj = std::uint8_t;
#elif (QS_OBJ_PTR_SIZE == 2U)
using QSObj = std::uint16_t;
#elif (QS_OBJ_PTR_SIZE == 4U)
using QSObj = std::uint32_t;
#elif (QS_OBJ_PTR_SIZE == 8U)
using QSObj = std::uint64_t;
#endif
//! @cond
//! Exclude the following internals from the Doxygen documentation
//! Extended-state variables used for parsing various QS-RX Records
struct CmdVar {
std::uint32_t param1;
std::uint32_t param2;
std::uint32_t param3;
std::uint8_t idx;
std::uint8_t cmdId;
};
struct TickVar {
std::uint_fast8_t rate;
};
struct PeekVar {
std::uint16_t offs;
std::uint8_t size;
std::uint8_t num;
std::uint8_t idx;
};
struct PokeVar {
std::uint32_t data;
std::uint16_t offs;
std::uint8_t size;
std::uint8_t num;
std::uint8_t idx;
std::uint8_t fill;
};
struct FltVar {
std::uint8_t data[16];
std::uint8_t idx;
std::uint8_t recId; // global/local
};
struct ObjVar {
QSObj addr;
std::uint8_t idx;
std::uint8_t kind; // see qs.hpp, enum QSpyObjKind
std::uint8_t recId;
};
struct EvtVar {
QP::QEvt *e;
std::uint8_t *p;
QP::QSignal sig;
std::uint16_t len;
std::uint8_t prio;
std::uint8_t idx;
};
// extended-state variables for the current QS-RX state
static struct ExtState {
union Variant {
CmdVar cmd;
TickVar tick;
PeekVar peek;
PokeVar poke;
FltVar flt;
ObjVar obj;
EvtVar evt;
#ifdef Q_UTEST
QP::QS::TProbe tp;
#endif // Q_UTEST
} var;
std::uint8_t state;
std::uint8_t esc;
std::uint8_t seq;
std::uint8_t chksum;
} l_rx;
enum RxStateEnum : std::uint8_t {
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
};
// internal helper functions...
static void rxParseData_(std::uint8_t const b) noexcept;
static void rxHandleBadFrame_(std::uint8_t const state) noexcept;
static void rxReportAck_(enum QP::QSpyRxRecords const recId) noexcept;
static void rxReportError_(std::uint8_t const code) noexcept;
static void rxReportDone_(enum QP::QSpyRxRecords const recId) noexcept;
static void rxPoke_(void) noexcept;
//! Internal QS-RX function to take a transition in the QS-RX FSM
static inline void tran_(RxStateEnum const target) noexcept {
l_rx.state = static_cast&lt;std::uint8_t&gt;(target);
}
//! @endcond
} // unnamed namespace
//============================================================================
$define ${QS::QS-rx}
//============================================================================
namespace { // unnamed local namespace
//............................................................................
static void rxParseData_(std::uint8_t const b) noexcept {
switch (l_rx.state) {
case WAIT4_SEQ: {
++l_rx.seq;
if (l_rx.seq != b) { // not the expected sequence?
rxReportError_(0x42U);
l_rx.seq = b; // update the sequence
}
tran_(WAIT4_REC);
break;
}
case WAIT4_REC: {
switch (b) {
case QP::QS_RX_INFO:
tran_(WAIT4_INFO_FRAME);
break;
case QP::QS_RX_COMMAND:
tran_(WAIT4_CMD_ID);
break;
case QP::QS_RX_RESET:
tran_(WAIT4_RESET_FRAME);
break;
case QP::QS_RX_TICK:
tran_(WAIT4_TICK_RATE);
break;
case QP::QS_RX_PEEK:
if (QP::QS::rxPriv_.currObj[QP::QS::AP_OBJ] != nullptr) {
l_rx.var.peek.offs = 0U;
l_rx.var.peek.idx = 0U;
tran_(WAIT4_PEEK_OFFS);
}
else {
rxReportError_(
static_cast&lt;std::uint8_t&gt;(QP::QS_RX_PEEK));
tran_(ERROR_STATE);
}
break;
case QP::QS_RX_POKE:
case QP::QS_RX_FILL:
l_rx.var.poke.fill =
(b == static_cast&lt;std::uint8_t&gt;(QP::QS_RX_FILL))
? 1U
: 0U;
if (QP::QS::rxPriv_.currObj[QP::QS::AP_OBJ] != nullptr) {
l_rx.var.poke.offs = 0U;
l_rx.var.poke.idx = 0U;
tran_(WAIT4_POKE_OFFS);
}
else {
rxReportError_(
(l_rx.var.poke.fill != 0U)
? static_cast&lt;std::uint8_t&gt;(QP::QS_RX_FILL)
: static_cast&lt;std::uint8_t&gt;(QP::QS_RX_POKE));
tran_(ERROR_STATE);
}
break;
case QP::QS_RX_GLB_FILTER: // intentionally fall-through
case QP::QS_RX_LOC_FILTER:
l_rx.var.flt.recId = b;
tran_(WAIT4_FILTER_LEN);
break;
case QP::QS_RX_AO_FILTER: // intentionally fall-through
case QP::QS_RX_CURR_OBJ:
l_rx.var.obj.recId = b;
tran_(WAIT4_OBJ_KIND);
break;
case QP::QS_RX_QUERY_CURR:
l_rx.var.obj.recId =
static_cast&lt;std::uint8_t&gt;(QP::QS_RX_QUERY_CURR);
tran_(WAIT4_QUERY_KIND);
break;
case QP::QS_RX_EVENT:
tran_(WAIT4_EVT_PRIO);
break;
#ifdef Q_UTEST
case QP::QS_RX_TEST_SETUP:
tran_(WAIT4_TEST_SETUP_FRAME);
break;
case QP::QS_RX_TEST_TEARDOWN:
tran_(WAIT4_TEST_TEARDOWN_FRAME);
break;
case QP::QS_RX_TEST_CONTINUE:
tran_(WAIT4_TEST_CONTINUE_FRAME);
break;
case QP::QS_RX_TEST_PROBE:
if (QP::QS::testData.tpNum
&lt; static_cast&lt;std::uint8_t&gt;(
(sizeof(QP::QS::testData.tpBuf)
/ sizeof(QP::QS::testData.tpBuf[0]))))
{
l_rx.var.tp.data = 0U;
l_rx.var.tp.idx = 0U;
tran_(WAIT4_TEST_PROBE_DATA);
}
else { // the number of Test-Probes exceeded
rxReportError_(
static_cast&lt;std::uint8_t&gt;(QP::QS_RX_TEST_PROBE));
tran_(ERROR_STATE);
}
break;
#endif // Q_UTEST
default:
rxReportError_(0x43U);
tran_(ERROR_STATE);
break;
}
break;
}
case WAIT4_INFO_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case 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;
tran_(WAIT4_CMD_PARAM1);
break;
}
case WAIT4_CMD_PARAM1: {
l_rx.var.cmd.param1 |=
(static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; 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;
tran_(WAIT4_CMD_PARAM2);
}
break;
}
case WAIT4_CMD_PARAM2: {
l_rx.var.cmd.param2 |=
static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; 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;
tran_(WAIT4_CMD_PARAM3);
}
break;
}
case WAIT4_CMD_PARAM3: {
l_rx.var.cmd.param3 |=
static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; 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;
tran_(WAIT4_CMD_FRAME);
}
break;
}
case WAIT4_CMD_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_RESET_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_TICK_RATE: {
l_rx.var.tick.rate = static_cast&lt;std::uint_fast8_t&gt;(b);
tran_(WAIT4_TICK_FRAME);
break;
}
case WAIT4_TICK_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_PEEK_OFFS: {
if (l_rx.var.peek.idx == 0U) {
l_rx.var.peek.offs = static_cast&lt;std::uint16_t&gt;(b);
l_rx.var.peek.idx += 8U;
}
else {
l_rx.var.peek.offs |= static_cast&lt;std::uint16_t&gt;(
static_cast&lt;std::uint16_t&gt;(b) &lt;&lt; 8U);
tran_(WAIT4_PEEK_SIZE);
}
break;
}
case WAIT4_PEEK_SIZE: {
if ((b == 1U) || (b == 2U) || (b == 4U)) {
l_rx.var.peek.size = b;
tran_(WAIT4_PEEK_NUM);
}
else {
rxReportError_(static_cast&lt;std::uint8_t&gt;(QP::QS_RX_PEEK));
tran_(ERROR_STATE);
}
break;
}
case WAIT4_PEEK_NUM: {
l_rx.var.peek.num = b;
tran_(WAIT4_PEEK_FRAME);
break;
}
case WAIT4_PEEK_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_POKE_OFFS: {
if (l_rx.var.poke.idx == 0U) {
l_rx.var.poke.offs = static_cast&lt;std::uint16_t&gt;(b);
l_rx.var.poke.idx = 1U;
}
else {
l_rx.var.poke.offs |= static_cast&lt;std::uint16_t&gt;(
static_cast&lt;std::uint16_t&gt;(b) &lt;&lt; 8U);
tran_(WAIT4_POKE_SIZE);
}
break;
}
case WAIT4_POKE_SIZE: {
if ((b == 1U)
|| (b == 2U)
|| (b == 4U))
{
l_rx.var.poke.size = b;
tran_(WAIT4_POKE_NUM);
}
else {
rxReportError_((l_rx.var.poke.fill != 0U)
? static_cast&lt;std::uint8_t&gt;(QP::QS_RX_FILL)
: static_cast&lt;std::uint8_t&gt;(QP::QS_RX_POKE));
tran_(ERROR_STATE);
}
break;
}
case WAIT4_POKE_NUM: {
if (b &gt; 0U) {
l_rx.var.poke.num = b;
l_rx.var.poke.data = 0U;
l_rx.var.poke.idx = 0U;
tran_((l_rx.var.poke.fill != 0U)
? WAIT4_FILL_DATA
: WAIT4_POKE_DATA);
}
else {
rxReportError_((l_rx.var.poke.fill != 0U)
? static_cast&lt;std::uint8_t&gt;(QP::QS_RX_FILL)
: static_cast&lt;std::uint8_t&gt;(QP::QS_RX_POKE));
tran_(ERROR_STATE);
}
break;
}
case WAIT4_FILL_DATA: {
l_rx.var.poke.data |=
static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; l_rx.var.poke.idx;
l_rx.var.poke.idx += 8U;
if ((l_rx.var.poke.idx &gt;&gt; 3U) == l_rx.var.poke.size) {
tran_(WAIT4_FILL_FRAME);
}
break;
}
case WAIT4_POKE_DATA: {
l_rx.var.poke.data |=
static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; l_rx.var.poke.idx;
l_rx.var.poke.idx += 8U;
if ((l_rx.var.poke.idx &gt;&gt; 3U) == l_rx.var.poke.size) {
rxPoke_();
--l_rx.var.poke.num;
if (l_rx.var.poke.num == 0U) {
tran_(WAIT4_POKE_FRAME);
}
}
break;
}
case 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 WAIT4_FILTER_LEN: {
if (b == static_cast&lt;std::uint8_t&gt;(sizeof(l_rx.var.flt.data))) {
l_rx.var.flt.idx = 0U;
tran_(WAIT4_FILTER_DATA);
}
else {
rxReportError_(l_rx.var.flt.recId);
tran_(ERROR_STATE);
}
break;
}
case 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)) {
tran_(WAIT4_FILTER_FRAME);
}
break;
}
case WAIT4_FILTER_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_OBJ_KIND: {
if (b &lt;= static_cast&lt;std::uint8_t&gt;(QP::QS::SM_AO_OBJ)) {
l_rx.var.obj.kind = b;
l_rx.var.obj.addr = 0U;
l_rx.var.obj.idx = 0U;
tran_(WAIT4_OBJ_ADDR);
}
else {
rxReportError_(l_rx.var.obj.recId);
tran_(ERROR_STATE);
}
break;
}
case WAIT4_OBJ_ADDR: {
l_rx.var.obj.addr |=
static_cast&lt;QSObj&gt;(b) &lt;&lt; l_rx.var.obj.idx;
l_rx.var.obj.idx += 8U;
if (l_rx.var.obj.idx
== (8U * static_cast&lt;unsigned&gt;(QS_OBJ_PTR_SIZE)))
{
tran_(WAIT4_OBJ_FRAME);
}
break;
}
case WAIT4_OBJ_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_QUERY_KIND: {
if (b &lt; static_cast&lt;std::uint8_t&gt;(QP::QS::MAX_OBJ)) {
l_rx.var.obj.kind = b;
tran_(WAIT4_QUERY_FRAME);
}
else {
rxReportError_(l_rx.var.obj.recId);
tran_(ERROR_STATE);
}
break;
}
case WAIT4_QUERY_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_EVT_PRIO: {
l_rx.var.evt.prio = b;
l_rx.var.evt.sig = 0U;
l_rx.var.evt.idx = 0U;
tran_(WAIT4_EVT_SIG);
break;
}
case WAIT4_EVT_SIG: {
l_rx.var.evt.sig |= static_cast&lt;QP::QSignal&gt;(
static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; l_rx.var.evt.idx);
l_rx.var.evt.idx += 8U;
if (l_rx.var.evt.idx
== (8U *static_cast&lt;unsigned&gt;(Q_SIGNAL_SIZE)))
{
l_rx.var.evt.len = 0U;
l_rx.var.evt.idx = 0U;
tran_(WAIT4_EVT_LEN);
}
break;
}
case WAIT4_EVT_LEN: {
l_rx.var.evt.len |= static_cast&lt;std::uint16_t&gt;(
static_cast&lt;unsigned&gt;(b) &lt;&lt; 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(QP::QEvt))
&lt;= static_cast&lt;std::uint16_t&gt;(
QP::QF::poolGetMaxBlockSize()))
{
// report Ack before generating any other QS records
rxReportAck_(QP::QS_RX_EVENT);
l_rx.var.evt.e = QP::QF::newX_(
(static_cast&lt;std::uint_fast16_t&gt;(l_rx.var.evt.len)
+ sizeof(QP::QEvt)),
0U, // margin
static_cast&lt;enum_t&gt;(l_rx.var.evt.sig));
// event allocated?
if (l_rx.var.evt.e != nullptr) {
l_rx.var.evt.p =
reinterpret_cast&lt;std::uint8_t *&gt;(l_rx.var.evt.e);
l_rx.var.evt.p = &amp;l_rx.var.evt.p[sizeof(QP::QEvt)];
if (l_rx.var.evt.len &gt; 0U) {
tran_(WAIT4_EVT_PAR);
}
else {
tran_(WAIT4_EVT_FRAME);
}
}
else {
rxReportError_(
static_cast&lt;std::uint8_t&gt;(QP::QS_RX_EVENT));
tran_(ERROR_STATE);
}
}
else {
rxReportError_(
static_cast&lt;std::uint8_t&gt;(QP::QS_RX_EVENT));
tran_(ERROR_STATE);
}
}
break;
}
case 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) {
tran_(WAIT4_EVT_FRAME);
}
break;
}
case WAIT4_EVT_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
#ifdef Q_UTEST
case WAIT4_TEST_SETUP_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_TEST_TEARDOWN_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_TEST_CONTINUE_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
case WAIT4_TEST_PROBE_DATA: {
l_rx.var.tp.data |=
(static_cast&lt;QP::QSFun&gt;(b) &lt;&lt; l_rx.var.tp.idx);
l_rx.var.tp.idx += 8U;
if (l_rx.var.tp.idx == (8U * sizeof(std::uint32_t))) {
l_rx.var.tp.addr = 0U;
l_rx.var.tp.idx = 0U;
tran_(WAIT4_TEST_PROBE_ADDR);
}
break;
}
case WAIT4_TEST_PROBE_ADDR: {
l_rx.var.tp.addr |=
(static_cast&lt;std::uint32_t&gt;(b) &lt;&lt; l_rx.var.tp.idx);
l_rx.var.tp.idx += 8U;
if (l_rx.var.tp.idx
== (8U * static_cast&lt;unsigned&gt;(QS_FUN_PTR_SIZE)))
{
tran_(WAIT4_TEST_PROBE_FRAME);
}
break;
}
case WAIT4_TEST_PROBE_FRAME: {
// keep ignoring the data until a frame is collected
break;
}
#endif // Q_UTEST
case ERROR_STATE: {
// keep ignoring the data until a good frame is collected
break;
}
default: { // unexpected or unimplemented state
rxReportError_(0x45U);
tran_(ERROR_STATE);
break;
}
}
}
//............................................................................
static void rxHandleBadFrame_(std::uint8_t const state) noexcept {
rxReportError_(0x50U); // error for all bad frames
switch (state) {
case WAIT4_EVT_FRAME: {
Q_ASSERT_ID(910, l_rx.var.evt.e != nullptr);
#if (QF_MAX_EPOOL &gt; 0U)
QP::QF::gc(l_rx.var.evt.e); // don't leak an allocated event
#endif
break;
}
default: {
break;
}
}
}
//............................................................................
static void rxReportAck_(enum QP::QSpyRxRecords const recId) noexcept {
QS_CRIT_STAT_
QS_CRIT_E_();
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QP::QS_RX_STATUS));
QS_U8_PRE_(recId); // record ID
QP::QS::endRec_();
QS_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
}
//............................................................................
static void rxReportError_(std::uint8_t const code) noexcept {
QS_CRIT_STAT_
QS_CRIT_E_();
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QP::QS_RX_STATUS));
QS_U8_PRE_(0x80U | code); // error code
QP::QS::endRec_();
QS_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
}
//............................................................................
static void rxReportDone_(enum QP::QSpyRxRecords const recId) noexcept {
QS_CRIT_STAT_
QS_CRIT_E_();
QP::QS::beginRec_(static_cast&lt;std::uint_fast8_t&gt;(QP::QS_TARGET_DONE));
QS_TIME_PRE_(); // timestamp
QS_U8_PRE_(recId); // record ID
QP::QS::endRec_();
QS_CRIT_X_();
QS_REC_DONE(); // user callback (if defined)
}
//............................................................................
static void rxPoke_(void) noexcept {
std::uint8_t * ptr =
static_cast&lt;std::uint8_t *&gt;(QP::QS::rxPriv_.currObj[QP::QS::AP_OBJ]);
ptr = &amp;ptr[l_rx.var.poke.offs];
switch (l_rx.var.poke.size) {
case 1:
*ptr = static_cast&lt;std::uint8_t&gt;(l_rx.var.poke.data);
break;
case 2:
*reinterpret_cast&lt;std::uint16_t *&gt;(ptr)
= static_cast&lt;std::uint16_t&gt;(l_rx.var.poke.data);
break;
case 4:
*reinterpret_cast&lt;std::uint32_t *&gt;(ptr) = l_rx.var.poke.data;
break;
default:
Q_ERROR_ID(900);
break;
}
l_rx.var.poke.data = 0U;
l_rx.var.poke.idx = 0U;
l_rx.var.poke.offs += static_cast&lt;std::uint16_t&gt;(l_rx.var.poke.size);
}
} // unnamed namespace</text>
</file>
<!--${src::qs::qutest.cpp}-->
<file name="qutest.cpp">
<text>//! @file
//! @brief QUTest unit testing harness + QF/++ stub for QUTest
// only build when Q_UTEST is defined
#ifdef Q_UTEST
#define QP_IMPL // this is QP implementation
#include &quot;qf_port.hpp&quot; // QF port
#include &quot;qf_pkg.hpp&quot; // QF package-scope internal interface
#include &quot;qassert.h&quot; // QP embedded systems-friendly assertions
#include &quot;qs_port.hpp&quot; // QS port
#include &quot;qs_pkg.hpp&quot; // QS package-scope internal interface
// unnamed namespace for local definitions with internal linkage
namespace {
Q_DEFINE_THIS_MODULE(&quot;qutest&quot;)
} // unnamed namespace
//============================================================================
// QUTest unit testing harness
$define ${QUTest}
//============================================================================
namespace QP {
QSTimeCtr QS::onGetTime() {
return (++testData.testTime);
}
} // namespace QP
//============================================================================
extern &quot;C&quot; {
Q_NORETURN Q_onAssert(char const * const module, int_t const location) {
QS_BEGIN_NOCRIT_PRE_(QP::QS_ASSERT_FAIL, 0U)
QS_TIME_PRE_();
QS_U16_PRE_(location);
QS_STR_PRE_((module != nullptr) ? module : &quot;?&quot;);
QS_END_NOCRIT_PRE_()
QP::QS::onFlush(); // flush the assertion record to the host
QP::QS::onCleanup(); // cleanup after the failure
QP::QS::onReset(); // reset the target to prevent the code from continuing
for (;;) { // onReset() should not return, but to ensure no-return...
}
}
} // extern &quot;C&quot;
//============================================================================
// 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
$define ${QUTest-stub}
#endif // Q_UTEST != 0
#endif // def Q_UTEST</text>
</file>
<!--${src::qs::qstamp.cpp}-->
<file name="qstamp.cpp">
<text>//! @file
//! @brief Application build time-stamp
//! @note
//! This module needs to be re-compiled in every new software build. To achive
//! this, it is recommended to delete the object file (qstamp.o or qstamp.obj)
//! in the build directory before each build. (Most development tools allow
//! you to specify a pre-build action, which is the ideal place to delete
//! the qstamp object file.)
#include &quot;qstamp.hpp&quot;
namespace QP {
//! the calendar date of the last translation of the form: &quot;Mmm dd yyyy&quot;
char const BUILD_DATE[12] = __DATE__;
//! the time of the last translation of the form: &quot;hh:mm:ss&quot;
char const BUILD_TIME[9] = __TIME__;
} // namespace QP</text>
</file>
</directory>
</directory>
</model>