QP is an event-driven, RTOS-like, active object framework for microcontrollers, such as mbed. The QP framework provides thread-safe execution of active objects (concurrent state machines) and support both manual and automatic coding of UML statecharts in readable, production-quality C or C++. Automatic code generation of QP code is supported by the free QM modeling tool.

Dependents:   qp_hangman qp_dpp qp_blinky

QP/C++ (Quantum Platform in C++) is a lightweight, open source active object (actor) framework for building responsive and modular real-time embedded applications as systems of asynchronous event-driven active objects (actors). The QP/C++ framework is a member of a larger family consisting of QP/C++, QP/C, and QP-nano frameworks, which are all strictly quality controlled, thoroughly documented, and available under GPLv3 with a special Exception for mbed (see http://www.state-machine.com/licensing/QP-mbed_GPL_Exception.txt).

The behavior of active objects is specified in QP/C++ by means of hierarchical state machines (UML statecharts). The framework supports manual coding of UML state machines in C++ as well as automatic code generation by means of the free QM modeling tool (http://www.state-machine.com/qm).

Please see the "QP/C++ Reference Manual" (http://www.state-machine.com/qpcpp) for more information.

qp.h

Committer:
QL
Date:
2012-09-04
Revision:
9:ca2e6010d9e2
Parent:
8:934bb9eea80b

File content as of revision 9:ca2e6010d9e2:

//////////////////////////////////////////////////////////////////////////////
// Product: QP/C++ platform-independent interface
// Last Updated for QP ver: 4.5.02 (modified to fit in one file)
// Date of the Last Update: Aug 24, 2012
//
//                    Q u a n t u m     L e a P s
//                    ---------------------------
//                    innovating embedded systems
//
// Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved.
//
// This program is open source software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Alternatively, this program may be distributed and modified under the
// terms of Quantum Leaps commercial licenses, which expressly supersede
// the GNU General Public License and are specifically designed for
// licensees interested in retaining the proprietary status of their code.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Contact information:
// Quantum Leaps Web sites: http://www.quantum-leaps.com
//                          http://www.state-machine.com
// e-mail:                  info@quantum-leaps.com
//////////////////////////////////////////////////////////////////////////////
#ifndef qp_h
#define qp_h

// "qevt.h" ==================================================================
/// \brief QEvt class and basic macros used by all QP components.
///
/// This header file must be included, perhaps indirectly, in all modules
/// (*.cpp files) that use any component of QP/C++ (such as QEP, QF, or QK).

//////////////////////////////////////////////////////////////////////////////
/// \brief The current QP version number
///
/// \return version of the QP as a hex constant constant 0xXYZZ, where X is
/// a 1-digit major version number, Y is a 1-digit minor version number, and
/// ZZ is a 2-digit release number.
#define QP_VERSION      0x4502U

#ifndef Q_ROM
    /// \brief Macro to specify compiler-specific directive for placing a
    /// constant object in ROM.
    ///
    /// Many compilers for Harvard-architecture MCUs provide non-stanard
    /// extensions to support placement of objects in different memories.
    /// In order to conserve the precious RAM, QP uses the Q_ROM macro for
    /// all constant objects that can be allocated in ROM.
    ///
    /// To override the following empty definition, you need to define the
    /// Q_ROM macro in the qep_port.h header file. Some examples of valid
    /// Q_ROM macro definitions are: __code (IAR 8051 compiler), code (Keil
    /// Cx51 compiler), PROGMEM (gcc for AVR), __flash (IAR for AVR).
    #define Q_ROM
#endif
#ifndef Q_ROM_VAR            // if NOT defined, provide the default definition
    /// \brief Macro to specify compiler-specific directive for accessing a
    /// constant object in ROM.
    ///
    /// Many compilers for MCUs provide different size pointers for
    /// accessing objects in various memories. Constant objects allocated
    /// in ROM (see #Q_ROM macro) often mandate the use of specific-size
    /// pointers (e.g., far pointers) to get access to ROM objects. The
    /// macro Q_ROM_VAR specifies the kind of the pointer to be used to access
    /// the ROM objects.
    ///
    /// To override the following empty definition, you need to define the
    /// Q_ROM_VAR macro in the qep_port.h header file. An example of valid
    /// Q_ROM_VAR macro definition is: __far (Freescale HC(S)08 compiler).
    #define Q_ROM_VAR
#endif
#ifndef Q_ROM_BYTE
    /// \brief Macro to access a byte allocated in ROM
    ///
    /// Some compilers for Harvard-architecture MCUs, such as gcc for AVR, do
    /// not generate correct code for accessing data allocated in the program
    /// space (ROM). The workaround for such compilers is to explictly add
    /// assembly code to access each data element allocated in the program
    /// space. The macro Q_ROM_BYTE() retrieves a byte from the given ROM
    /// address.
    ///
    /// The Q_ROM_BYTE() macro should be defined for the compilers that
    /// cannot handle correctly data allocated in ROM (such as the gcc).
    /// If the macro is left undefined, the default definition simply returns
    /// the argument and lets the compiler generate the correct code.
    #define Q_ROM_BYTE(rom_var_)   (rom_var_)
#endif

#ifndef Q_SIGNAL_SIZE
    /// \brief The size (in bytes) of the signal of an event. Valid values:
    /// 1, 2, or 4; default 1
    ///
    /// This macro can be defined in the QEP port file (qep_port.h) to
    /// configure the ::QSignal type. When the macro is not defined, the
    /// default of 1 byte is chosen.
    #define Q_SIGNAL_SIZE 2
#endif

#ifndef Q_NNAMESPACE

    /// \brief begin of the namespace QP
    ///
    /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
    #define QP_BEGIN_  namespace QP {

    /// \brief end of the namespace QP
    ///
    /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
    #define QP_END_    }

    /// \brief namespace QP prefix
    ///
    /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
    #define QP_        QP::

#else

    #define QP_BEGIN_
    #define QP_END_
    #define QP_

#endif

QP_BEGIN_

#if (Q_SIGNAL_SIZE == 1)
    typedef uint8_t QSignal;
#elif (Q_SIGNAL_SIZE == 2)
    /// \brief QSignal represents the signal of an event.
    ///
    /// 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 [<A HREF="http://www.omg.org/docs/ptc/03-08-02.pdf">UML
    /// document ptc/03-08-02</A>], 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. Please refer to the
    typedef uint16_t QSignal;
#elif (Q_SIGNAL_SIZE == 4)
    typedef uint32_t QSignal;
#else
    #error "Q_SIGNAL_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

#ifdef Q_EVT_CTOR               // Provide the constructor for the QEvt class?

    //////////////////////////////////////////////////////////////////////////
    /// \brief QEvt base class.
    ///
    /// QEvt represents events without parameters and serves as the base class
    /// for derivation of events with parameters.
    ///
    /// The following example illustrates how to add an event parameter by
    /// inheriting from the QEvt class.
    /// \include qep_qevent.cpp
    class QEvt {
    public:
        QSignal sig;                         ///< signal of the event instance

        QEvt(QSignal const s)           // poolId_ intentionally uninitialized
          : sig(s) {}

#ifdef Q_EVT_VIRTUAL
        virtual ~QEvt() {}                               // virtual destructor
#endif

    private:
        uint8_t poolId_;                     ///< pool ID (0 for static event)
        uint8_t refCtr_;                                ///< reference counter

        friend class QF;
        friend class QTimeEvt;
        friend uint8_t QF_EVT_POOL_ID_ (QEvt const * const e);
        friend uint8_t QF_EVT_REF_CTR_ (QEvt const * const e);
        friend void QF_EVT_REF_CTR_INC_(QEvt const * const e);
        friend void QF_EVT_REF_CTR_DEC_(QEvt const * const e);
    };

#else                                    // QEvt is a POD (Plain Old Datatype)

    struct QEvt {
        QSignal sig;                         ///< signal of the event instance
        uint8_t poolId_;                     ///< pool ID (0 for static event)
        uint8_t refCtr_;                                ///< reference counter
    };

#endif                                                           // Q_EVT_CTOR

QP_END_

//////////////////////////////////////////////////////////////////////////////
/// helper macro to calculate static dimension of a 1-dim array \a array_
#define Q_DIM(array_) (sizeof(array_) / sizeof(array_[0]))

//////////////////////////////////////////////////////////////////////////////
// typedefs for basic numerical types; MISRA-C++ 2008 rule 3-9-2(req).

/// \brief typedef for character strings.
///
/// This typedef specifies character type for exclusive use in character
/// strings. Use of this type, rather than plain 'char', is in compliance
/// with the MISRA-C 2004 Rules 6.1(req), 6.3(adv).
///
typedef char char_t;

/// typedef for 32-bit IEEE 754 floating point numbers
typedef float float32_t;

/// typedef for 64-bit IEEE 754 floating point numbers
typedef double float64_t;

/// typedef for enumerations used for event signals
typedef int enum_t;

/// \brief Perform cast from unsigned integer \a uint_ to pointer
/// of type \a type_.
///
/// 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 "Note 923: cast from int to pointer"
/// and this macro helps to encapsulate this deviation.
///
#define Q_UINT2PTR_CAST(type_, uint_)  (reinterpret_cast<type_ *>(uint_))

/// \brief Initializer of static constant QEvt instances
///
/// This macro encapsulates the ugly casting of enumerated signals
/// to QSignal and constants for QEvt.poolID and QEvt.refCtr_.
///
#define QEVT_INITIALIZER(sig_) { static_cast<QP_ QSignal>(sig_), \
    static_cast<uint8_t>(0), static_cast<uint8_t>(0) }

//////////////////////////////////////////////////////////////////////////////
// facilities for backwards compatibility
//
#ifndef Q_NQEVENT
//    typedef struct QEvt QEvent;
    #define QEvent QEvt
#endif


// "qep.h" ===================================================================
/// \brief QEP/C++ platform-independent public interface.
///
/// This header file must be included directly or indirectly
/// in all modules (*.cpp files) that use QEP/C++.

/// \brief Designates a target for an initial or regular transition.
/// Q_TRAN() can be used both in the FSMs and HSMs.
///
/// \include qep_qtran.c
///
#define Q_TRAN(target_)     (me->tran(Q_STATE_CAST(target_)))

/// \brief Designates the superstate of a given state in an HSM.
///
/// \include qep_qhsm.c
///
#define Q_SUPER(super_)     (me->super(Q_STATE_CAST(super_)))

/// \brief Perform cast to QStateHandler.
///
/// 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.
///
#define Q_STATE_CAST(handler_) \
    (reinterpret_cast<QP_ QStateHandler>(handler_))

/// \brief Perform downcast of an event onto a subclass of QEvt \a class_
///
/// This macro encapsulates the downcast of QEvt pointers, which violates
/// MISRA-C 2004 rule 11.4(advisory). This macro helps to localize this
/// deviation.
///
#define Q_EVT_CAST(class_)   (static_cast<class_ const *>(e))

//////////////////////////////////////////////////////////////////////////////
QP_BEGIN_

/// \brief Provides miscellaneous QEP services.
class QEP {
public:
    /// \brief get the current QEP version number string
    ///
    /// \return version of the QEP as a constant 6-character string of the
    /// form x.y.zz, where x is a 1-digit major version number, y is a
    /// 1-digit minor version number, and zz is a 2-digit release number.
    static char_t const Q_ROM * Q_ROM_VAR getVersion(void);
};

//////////////////////////////////////////////////////////////////////////////

                       /// \brief Type returned from  a state-handler function
typedef uint8_t QState;
                                  /// \brief pointer to state-handler function
typedef QState (*QStateHandler)(void * const me, QEvt const * const e);

//////////////////////////////////////////////////////////////////////////////
/// \brief Value returned by a state-handler function when it handles
/// the event.
QState const Q_RET_HANDLED = static_cast<QState>(0);

/// \brief Value returned by a non-hierarchical state-handler function when
/// it ignores (does not handle) the event.
QState const Q_RET_IGNORED = static_cast<QState>(1);

/// \brief Value returned by a state-handler function when it takes a
/// regular state transition.
QState const Q_RET_TRAN    = static_cast<QState>(2);

/// \brief Value returned by a state-handler function when it forwards
/// the event to the superstate to handle.
QState const Q_RET_SUPER   = static_cast<QState>(3);

/// \brief Value returned by a state-handler function when a guard
/// condition prevents it from handling the event.
///
QState const Q_RET_UNHANDLED = static_cast<QState>(4);


/// Offset or the user signals
enum_t const Q_USER_SIG    = static_cast<enum_t>(4);


//////////////////////////////////////////////////////////////////////////////
/// \brief Finite State Machine base class
///
/// QFsm represents a traditional non-hierarchical Finite State Machine (FSM)
/// without state hierarchy, but with entry/exit actions.
///
/// QFsm is also a base structure for the ::QHsm class.
///
/// \note QFsm is not intended to be instantiated directly, but rather serves
/// as the base class for derivation of state machines in the application
/// code.
///
/// The following example illustrates how to derive a state machine class
/// from QFsm.
/// \include qep_qfsm.cpp
class QFsm {
private:
    QStateHandler m_state;          ///< current active state (state-variable)
    QStateHandler m_temp;  ///< temporary state: target of tran. or superstate

public:
    /// \brief virtual destructor
    virtual ~QFsm();

    /// \brief Performs the second step of FSM initialization by triggering
    /// the top-most initial transition.
    ///
    /// The argument \a e is constant pointer to ::QEvt or a class
    /// derived from ::QEvt.
    ///
    /// \note Must be called only ONCE before QFsm::dispatch()
    ///
    /// The following example illustrates how to initialize a FSM, and
    /// dispatch events to it:
    /// \include qep_qfsm_use.cpp
    void init(QEvt const * const e = static_cast<QEvt const *>(0));

    /// \brief Dispatches an event to a FSM
    ///
    /// Processes one event at a time in Run-to-Completion (RTC) fashion.
    /// The argument \a e is a constant pointer the ::QEvt or a
    /// class derived from ::QEvt.
    ///
    /// \note Must be called after QFsm::init().
    ///
    /// \sa example for QFsm::init()
    void dispatch(QEvt const * const e);

protected:
    /// \brief Protected constructor of a FSM.
    ///
    /// Performs the first step of FSM initialization by assigning the
    /// initial pseudostate to the currently active state of the state
    /// machine.
    ///
    /// \note The constructor is protected to prevent direct instantiating
    /// of QFsm objects. This class is intended for subclassing only.
    ///
    /// \sa The ::QFsm example illustrates how to use the QHsm constructor
    /// in the constructor initializer list of the derived state machines.
    QFsm(QStateHandler const initial)
      : m_state(Q_STATE_CAST(0)),
        m_temp(initial)
    {}

    /// \brief Return the current active state.
    QStateHandler state(void) const {
        return m_state;
    }

    /// \brief Inline function to specify the return of a state-handler
    /// when it igonres (does not handle in any way) the event.
    static QState Q_IGNORED(void) { return Q_RET_IGNORED; }

    /// \brief Inline function to specify the return of a state-handler
    /// when it handles the event.
    ///
    /// \include qep_qhsm.cpp
    static QState Q_HANDLED(void) { return Q_RET_HANDLED; }

    /// \brief Macro to specify the return of a state-handler function when
    /// it attempts to handle the event but a guard condition evaluates to
    /// false and there is no other explicit way of handling the event.
    static QState Q_UNHANDLED(void) { return Q_RET_UNHANDLED; }

    /// \brief internal helper function to record a state transition
    QState tran(QStateHandler const target) {
        m_temp = target;
        return Q_RET_TRAN;
    }

    enum ReservedFsmSignals {
        Q_ENTRY_SIG = 1,                         ///< signal for entry actions
        Q_EXIT_SIG                                ///< signal for exit actions
    };
};

//////////////////////////////////////////////////////////////////////////////
/// \brief Hierarchical State Machine base class
///
/// QHsm represents a Hierarchical Finite State Machine (HSM). QHsm derives
/// from the ::QFsm class and extends the capabilities of a basic FSM
/// with state hierarchy.
///
/// \note QHsm is not intended to be instantiated directly, but rather serves
/// as the base structure for derivation of state machines in the application
/// code.
///
/// The following example illustrates how to derive a state machine class
/// from QHsm.
/// \include qep_qhsm.cpp
class QHsm {
private:
    QStateHandler m_state;          ///< current active state (state-variable)
    QStateHandler m_temp;  ///< temporary state: target of tran. or superstate

public:
    /// \brief virtual destructor
    virtual ~QHsm();

    /// \brief Performs the second step of HSM initialization by triggering
    /// the top-most initial transition.
    ///
    /// \param e constant pointer ::QEvt or a class derived from ::QEvt
    /// \note Must be called only ONCE before QHsm::dispatch()
    ///
    /// The following example illustrates how to initialize a HSM, and
    /// dispatch events to it:
    /// \include qep_qhsm_use.cpp
    void init(QEvt const * const e = static_cast<QEvt const *>(0));

    /// \brief Dispatches an event to a HSM
    ///
    /// Processes one event at a time in Run-to-Completion (RTC) fashion.
    /// The argument \a e is a constant pointer the ::QEvt or a
    /// class derived from ::QEvt.
    ///
    /// \note Must be called after QHsm::init().
    ///
    /// \sa example for QHsm::init()
    void dispatch(QEvt const * const e);

    /// \brief Tests if a given state is part of the current active state
    /// configuratioin
    ///
    /// \param state is a pointer to the state handler function, e.g.,
    /// &QCalc::on.
    bool isIn(QStateHandler const s);

protected:
    /// \brief Protected constructor of a HSM.
    ///
    /// Performs the first step of HSM initialization by assigning the
    /// initial pseudostate to the currently active state of the state
    /// machine.
    ///
    /// \note The constructor is protected to prevent direct instantiating
    /// of QHsm objects. This class is intended for subclassing only.
    ///
    /// \sa The ::QHsm example illustrates how to use the QHsm constructor
    /// in the constructor initializer list of the derived state machines.
    /// \sa QFsm::QFsm()
    QHsm(QStateHandler const initial)
      : m_state(Q_STATE_CAST(&QHsm::top)),
        m_temp(initial)
    {}

    /// \brief Return the current active state.
    QStateHandler state(void) const {
        return m_state;
    }

    /// \brief the top-state.
    ///
    /// QHsm::top() is the ultimate root of state hierarchy in all HSMs
    /// derived from ::QHsm. This state handler always returns (QSTATE)0,
    /// which means that it "handles" all events.
    ///
    /// \sa Example of the QCalc::on() state handler.
    static QState top(void * const me, QEvt const * const e);

    /// \brief Inline function to specify the return of a state-handler
    /// when it handles the event.
    ///
    /// \include qep_qhsm.cpp
    static QState Q_HANDLED(void) { return Q_RET_HANDLED; }

    /// \brief Macro to specify the return of a state-handler function when
    /// it attempts to handle the event but a guard condition evaluates to
    /// false and there is no other explicit way of handling the event.
    static QState Q_UNHANDLED(void) { return Q_RET_UNHANDLED; }

    /// \brief internal helper function to record a state transition
    QState tran(QStateHandler const target) {
        m_temp = target;
        return Q_RET_TRAN;
    }

    /// \brief internal helper function to record the superstate
    QState super(QStateHandler const superstate) {
        m_temp = superstate;
        return Q_RET_SUPER;
    }

    enum ReservedHsmSignals {
        Q_ENTRY_SIG = 1,                         ///< signal for entry actions
        Q_EXIT_SIG,                               ///< signal for exit actions
        Q_INIT_SIG                  ///< signal for nested initial transitions
    };
};

//////////////////////////////////////////////////////////////////////////////

QP_END_

// "qequeue.h" ===============================================================
/// \brief platform-independent event queue interface.
///
/// This header file must be included in all QF ports that use native QF
/// event queue implementation. Also, this file is needed when the "raw"
/// thread-safe queues are used for communication between active objects
/// and non-framework entities, such as ISRs, device drivers, or legacy
/// code.

#ifndef QF_EQUEUE_CTR_SIZE

    /// \brief The size (in bytes) of the ring-buffer counters used in the
    /// native QF event queue implementation. Valid values: 1, 2, or 4;
    /// default 1.
    ///
    /// This macro can be defined in the QF port file (qf_port.h) to
    /// configure the ::QEQueueCtr type. Here the macro is not defined so the
    /// default of 1 byte is chosen.
    #define QF_EQUEUE_CTR_SIZE 1
#endif

QP_BEGIN_

#if (QF_EQUEUE_CTR_SIZE == 1)
    /// \brief The data type to store the ring-buffer counters based on
    /// the macro #QF_EQUEUE_CTR_SIZE.
    ///
    /// The dynamic range of this data type determines the maximum length
    /// of the ring buffer managed by the native QF event queue.
    typedef uint8_t QEQueueCtr;
#elif (QF_EQUEUE_CTR_SIZE == 2)
    typedef uint16_t QEQueueCtr;
#elif (QF_EQUEUE_CTR_SIZE == 4)
    typedef uint32_t QEQueueCtr;
#else
    #error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
#endif


//////////////////////////////////////////////////////////////////////////////
/// \brief Native QF Event Queue class
///
/// This structure describes the native QF event queue, which can be used as
/// the event queue for active objects, or as a simple "raw" event queue for
/// thread-safe event passing among non-framework entities, such as ISRs,
/// device drivers, or other third-party components.
///
/// The native QF event queue is configured by defining the macro
/// #QF_EQUEUE_TYPE as ::QEQueue in the specific QF port header file.
///
/// The ::QEQueue structure 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.
///
/// 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.
///
/// The ::QEQueue structure 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::postFIFO_(),
/// QActive::postLIFO_(), and QActive::get_(). Additionally the function
/// QEQueue_init() is used to initialize the queue.
///
/// The other set of functions, uses this structure as a simple "raw" event
/// queue to pass events between entities other than active objects, such as
/// ISRs. The "raw" 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 "raw" thread-safe queue
/// consists of the following functions: QEQueue::postFIFO(),
/// QEQueue::postLIFO(), and QEQueue::get(). Additionally the function
/// QEQueue::init() is used to initialize the queue.
///
/// \note Most event queue operations (both the active object queues and
/// the "raw" 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.
class QEQueue {
private:

    /// \brief pointer to event at the front of the queue
    ///
    /// 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.
    ///
    /// 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 NULL.
    QEvt const *m_frontEvt;

    /// \brief pointer to the start of the ring buffer
    QEvt const **m_ring;

    /// \brief offset of the end of the ring buffer from the start of the
    /// buffer m_ring
    QEQueueCtr m_end;

    /// \brief offset to where next event will be inserted into the buffer
    QEQueueCtr m_head;

    /// \brief offset of where next event will be extracted from the buffer
    QEQueueCtr m_tail;

    /// \brief number of free events in the ring buffer
    QEQueueCtr m_nFree;

    /// \brief 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 QF::getQueueMargin().
    QEQueueCtr m_nMin;

public:

    /// \brief Initializes the native QF event queue
    ///
    /// The parameters are as follows: \a qSto[] is the ring buffer storage,
    /// \a qLen is the length of the ring buffer in the units of event-
    /// pointers.
    ///
    /// \note The actual capacity of the queue is qLen + 1, because of the
    /// extra location fornEvt_.
    void init(QEvt const *qSto[], QEQueueCtr const qLen);

    /// \brief "raw" thread-safe QF event queue implementation for the
    /// First-In-First-Out (FIFO) event posting. You can call this function
    /// from any task context or ISR context. Please note that this function
    /// uses internally a critical section.
    ///
    /// \note The function raises an assertion if the native QF queue becomes
    /// full and cannot accept the event.
    ///
    /// \sa QEQueue::postLIFO(), QEQueue::get()
    void postFIFO(QEvt const * const e);

    /// \brief "raw" thread-safe QF event queue implementation for the
    /// First-In-First-Out (FIFO) event posting. You can call this function
    /// from any task context or ISR context. Please note that this function
    ///  uses internally a critical section.
    ///
    /// \note The function raises an assertion if the native QF queue becomes
    /// full and cannot accept the event.
    ///
    /// \sa QEQueue::postLIFO(), QEQueue::get()
    void postLIFO(QEvt const * const e);

    /// \brief "raw" thread-safe QF event queue implementation for the
    /// Last-In-First-Out (LIFO) event posting.
    ///
    /// \note The LIFO policy should be used only with great caution because
    /// it alters order of events in the queue.
    /// \note The function raises an assertion if the native QF queue becomes
    /// full and cannot accept the event. You can call this function from
    /// any task context or ISR context. Please note that this function uses
    /// internally a critical section.
    ///
    /// \sa QEQueue::postFIFO(), QEQueue::get()
    QEvt const *get(void);

    /// \brief "raw" thread-safe QF event queue operation for
    /// obtaining the number of free entries still available in the 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 QActive::defer(), QActive::recall()
    QEQueueCtr getNFree(void) const {
        return m_nFree;
    }

private:
    friend class QF;
    friend class QActive;
};

QP_END_

// "qmpool.h" ================================================================
/// \brief platform-independent memory pool interface.
///
/// This header file must be included in all QF ports that use native QF
/// memory pool implementation.

#ifndef QF_MPOOL_SIZ_SIZE
    /// \brief macro to override the default ::QMPoolSize size.
    /// Valid values 1, 2, or 4; default 2
    #define QF_MPOOL_SIZ_SIZE 2
#endif

#ifndef QF_MPOOL_CTR_SIZE

    /// \brief macro to override the default QMPoolCtr size.
    /// Valid values 1, 2, or 4; default 2
    #define QF_MPOOL_CTR_SIZE 2
#endif

//////////////////////////////////////////////////////////////////////////////
QP_BEGIN_

#if (QF_MPOOL_SIZ_SIZE == 1)
    /// \brief The data type to store the block-size based on the macro
    /// #QF_MPOOL_SIZ_SIZE.
    ///
    /// The dynamic range of this data type determines the maximum size
    /// of blocks that can be managed by the native QF event pool.
    typedef uint8_t QMPoolSize;
#elif (QF_MPOOL_SIZ_SIZE == 2)

    typedef uint16_t QMPoolSize;
#elif (QF_MPOOL_SIZ_SIZE == 4)
    typedef uint32_t QMPoolSize;
#else
    #error "QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

#if (QF_MPOOL_CTR_SIZE == 1)
    /// \brief The data type to store the block-counter based on the macro
    /// #QF_MPOOL_CTR_SIZE.
    ///
    /// The dynamic range of this data type determines the maximum number
    /// of blocks that can be stored in the pool.
    typedef uint8_t QMPoolCtr;
#elif (QF_MPOOL_CTR_SIZE == 2)
    typedef uint16_t QMPoolCtr;
#elif (QF_MPOOL_CTR_SIZE == 4)
    typedef uint32_t QMPoolCtr;
#else
    #error "QF_MPOOL_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

//////////////////////////////////////////////////////////////////////////////
/// \brief Native QF memory pool class
///
/// This 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.
///
/// The ::QMPool structure 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.
///
/// The native QF event pool is configured by defining the macro
/// #QF_EPOOL_TYPE_ as QEQueue in the specific QF port header file.
class QMPool {
private:

    /// start of the memory managed by this memory pool
    void *m_start;

    /// end of the memory managed by this memory pool
    void *m_end;

    /// linked list of free blocks
    void *m_free;

    ///  maximum block size (in bytes)
    QMPoolSize m_blockSize;

    /// total number of blocks
    QMPoolCtr m_nTot;

    /// number of free blocks remaining
    QMPoolCtr m_nFree;

    /// 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::getPoolMargin().
    QMPoolCtr m_nMin;

public:

    /// \brief Initializes the native QF event pool
    ///
    /// The parameters are as follows: \a poolSto is the pool storage,
    /// \a poolSize is the size of the pool storage in bytes, and
    /// \a blockSize is the block size of this pool.
    ///
    /// The caller of this method must make sure that the \a poolSto pointer
    /// is properly aligned. In particular, it must be possible to efficiently
    /// store a pointer at the location pointed to by \a poolSto.
    /// Internally, the QMPool::init() function rounds up the block size
    /// \a 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 (\a poolSize / \a blockSize). You can check
    ///  the capacity of the pool by calling the QF::getPoolMargin() function.
    void init(void * const poolSto, uint32_t const poolSize,
              QMPoolSize const blockSize);

    /// \brief Obtains a memory block from a memory pool.
    ///
    /// The only parameter \a me is a pointer to the ::QMPool from which the
    /// block is requested. The function returns a pointer to the allocated
    /// memory block or NULL if no free blocks are available.
    ///
    /// A allocated block must be returned to the same pool from which it has
    /// been allocated.
    ///
    /// This function can be called from any task level or ISR level.
    ///
    /// \note The memory pool \a me must be initialized before any events can
    /// be requested from it. Also, the 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.
    ///
    /// \sa QMPool::put()
    void *get(void);

    /// \brief Returns a memory block back to a memory pool.
    ///
    ///
    /// This function can be called from any task level or ISR level.
    ///
    /// \note The block must be allocated from the same memory pool to which
    /// it is returned. The QMPool::put() function raises an assertion if the
    /// returned pointer to the block points outside of the original memory
    /// buffer managed by the memory pool. Also, the QMPool::put() 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.
    ///
    /// \sa QMPool::get()
    void put(void * const b);

    /// \brief return the fixed block-size of the blocks managed by this pool
    QMPoolSize getBlockSize(void) const {
        return m_blockSize;
    }

private:
    friend class QF;
};

QP_END_

/// \brief Memory pool element to allocate correctly aligned storage
/// for QMPool class.
///
#define QF_MPOOL_EL(type_) \
    struct { void *sto_[((sizeof(type_) - 1U)/sizeof(void*)) + 1U]; }

// "qpset.h" =================================================================
/// \brief platform-independent priority sets of 8 or 64 elements.
///
/// This header file must be included in those QF ports that use the
/// cooperative multitasking QF scheduler or the QK.

QP_BEGIN_

//////////////////////////////////////////////////////////////////////////////
// useful lookup tables

/// \brief Lookup table for (log2(n) + 1), where n is the index
/// into the table.
///
/// This lookup delivers the 1-based number of the most significant 1-bit
/// of a byte.
///
/// \note Index range n = 0..255. The first index (n == 0) should never
/// be used.
///
extern uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256];

/// \brief Lookup table for (1 << ((n-1) % 8)), where n is the index
/// into the table.
///
/// \note Index range n = 0..64. The first index (n == 0) should never
/// be used.
extern uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65];

/// \brief Lookup table for ~(1 << ((n-1) % 8)), where n is the index
/// into the table.
///
/// \note Index range n = 0..64. The first index (n == 0) should never
/// be used.
extern uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65];

/// \brief Lookup table for (n-1)/8
///
/// \note Index range n = 0..64. The first index (n == 0) should never
/// be used.
extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65];


//////////////////////////////////////////////////////////////////////////////
/// \brief Priority Set of up to 8 elements for building various schedulers,
/// but also useful as a general set of up to 8 elements of any kind.
///
/// The priority set represents the set of active objects that are ready to
/// run and need to be considered by scheduling processing. The set is capable
/// of storing up to 8 priority levels.
class QPSet8 {

    //////////////////////////////////////////////////////////////////////////
    /// \brief bimask representing elements of the set
    uint8_t m_bits;

public:

    /// \brief the function evaluates to TRUE if the set is empty,
    /// which means that no active objects are ready to run.
    bool isEmpty(void) const {
        return (m_bits == static_cast<uint8_t>(0));
    }

    /// \brief the function evaluates to TRUE if the set has elements,
    /// which means that some active objects are ready to run.
    bool notEmpty(void) const {
        return (m_bits != static_cast<uint8_t>(0));
    }

    /// \brief the function evaluates to TRUE if the priority set has the
    /// element \a n.
    bool hasElement(uint8_t const n) const {
        return ((m_bits & Q_ROM_BYTE(QF_pwr2Lkup[n]))
                != static_cast<uint8_t>(0));
    }

    /// \brief insert element \a n into the set, n = 1..8
    void insert(uint8_t const n) {
        m_bits |= Q_ROM_BYTE(QF_pwr2Lkup[n]);
    }

    /// \brief remove element \a n from the set, n = 1..8
    void remove(uint8_t const n) {
        m_bits &= Q_ROM_BYTE(QF_invPwr2Lkup[n]);
    }

    /// \brief find the maximum element in the set,
    /// \note returns zero if the set is empty
    uint8_t findMax(void) const {
        return Q_ROM_BYTE(QF_log2Lkup[m_bits]);
    }

    friend class QPSet64;
};

//////////////////////////////////////////////////////////////////////////////
/// \brief Priority Set of up to 64 elements for building various schedulers,
/// but also useful as a general set of up to 64 elements of any kind.
///
/// The priority set represents the set of active objects that are ready to
/// run and need to be considered by scheduling processing. The set is capable
/// of storing up to 64 priority levels.
///
/// The priority set allows to build cooperative multitasking schedulers
/// to manage up to 64 tasks. It is also used in the Quantum Kernel (QK)
/// preemptive scheduler.
///
/// The inherited 8-bit set is used as the 8-elemtn set of of 8-bit subsets
/// Each bit in the super.bits set represents a subset (8-elements)
/// as follows: \n
/// bit 0 in this->m_bits is 1 when subset[0] is not empty \n
/// bit 1 in this->m_bits is 1 when subset[1] is not empty \n
/// bit 2 in this->m_bits is 1 when subset[2] is not empty \n
/// bit 3 in this->m_bits is 1 when subset[3] is not empty \n
/// bit 4 in this->m_bits is 1 when subset[4] is not empty \n
/// bit 5 in this->m_bits is 1 when subset[5] is not empty \n
/// bit 6 in this->m_bits is 1 when subset[6] is not empty \n
/// bit 7 in this->m_bits is 1 when subset[7] is not empty \n
class QPSet64 {

    //////////////////////////////////////////////////////////////////////////
    /// \brief bimask representing 8-element subsets of the set
    uint8_t m_bytes;

    /// \brief bits representing elements in the set as follows: \n
    /// m_bits[0] represent elements  1..8  \n
    /// m_bits[1] represent elements  9..16 \n
    /// m_bits[2] represent elements 17..24 \n
    /// m_bits[3] represent elements 25..32 \n
    /// m_bits[4] represent elements 33..40 \n
    /// m_bits[5] represent elements 41..48 \n
    /// m_bits[6] represent elements 49..56 \n
    /// m_bits[7] represent elements 57..64 \n
    uint8_t m_bits[8];

public:

    /// \brief the function evaluates to TRUE if the set is empty,
    /// which means that no active objects are ready to run.
    bool isEmpty(void) const {
        return (m_bytes == static_cast<uint8_t>(0));
    }

    /// \brief the function evaluates to TRUE if the set has elements,
    /// which means that some active objects are ready to run.
    bool notEmpty(void) const {
        return (m_bytes != static_cast<uint8_t>(0));
    }

    /// \brief the function evaluates to TRUE if the priority set has the
    /// element \a n.
    bool hasElement(uint8_t const n) const {
        uint8_t const m = Q_ROM_BYTE(QF_div8Lkup[n]);
        return ((m_bits[m] & Q_ROM_BYTE(QF_pwr2Lkup[n]))
                != static_cast<uint8_t>(0));
    }

    /// \brief insert element \a n into the set, n = 1..64
    void insert(uint8_t const n) {
        uint8_t m = Q_ROM_BYTE(QF_div8Lkup[n]);
        m_bits[m] |= Q_ROM_BYTE(QF_pwr2Lkup[n]);
        m_bytes |= Q_ROM_BYTE(QF_pwr2Lkup[m + static_cast<uint8_t>(1)]);
    }

    /// \brief remove element \a n from the set, n = 1..64
    void remove(uint8_t const n) {
        uint8_t m = Q_ROM_BYTE(QF_div8Lkup[n]);
        if ((m_bits[m] &= Q_ROM_BYTE(QF_invPwr2Lkup[n]))
             == static_cast<uint8_t>(0))
        {
            m_bytes &=Q_ROM_BYTE(QF_invPwr2Lkup[m + static_cast<uint8_t>(1)]);
        }
    }

    /// \brief find the maximum element in the set,
    /// \note returns zero if the set is empty
    uint8_t findMax(void) const {
        uint8_t n;
        if (m_bytes != static_cast<uint8_t>(0)) {
            n = static_cast<uint8_t>(Q_ROM_BYTE(QF_log2Lkup[m_bytes])
                                     - static_cast<uint8_t>(1));
            n = static_cast<uint8_t>(
                    Q_ROM_BYTE(QF_log2Lkup[m_bits[n]])
                               + static_cast<uint8_t>(n << 3));
        }
        else {
            n = static_cast<uint8_t>(0);
        }
        return n;
    }
};

QP_END_


//////////////////////////////////////////////////////////////////////////////
// Kernel selection based on QK_PREEMPTIVE
//
#ifdef QK_PREEMPTIVE

// "qk.h" ====================================================================
/// \brief This macro defines the type of the event queue used for the
/// active objects.
///
/// \note This is just an example of the macro definition. Typically, you need
/// to define it in the specific QF port file (qf_port.h). In case of QK,
/// which always depends on the native QF queue, this macro is defined at the
/// level of the platform-independent interface qk.h.
#define QF_EQUEUE_TYPE             QEQueue

#if defined(QK_TLS) || defined(QK_EXT_SAVE)
    /// \brief This macro defines the type of the OS-Object used for blocking
    /// the native QF event queue when the queue is empty
    ///
    /// In QK, the OS object is used to hold the per-thread flags, which might
    /// be used, for example, to rembember the thread attributes (e.g.,
    /// if the thread uses a floating point co-processor). The OS object value
    /// is set on per-thread basis in QActive::start(). Later, the extended
    /// context switch macros (QK_EXT_SAVE() and QK_EXT_RESTORE()) might use
    /// the per-thread flags to determine what kind of extended context switch
    /// this particular thread needs (e.g., the thread might not be using the
    /// coprocessor or might be using a different one).
    #define QF_OS_OBJECT_TYPE      uint8_t

    /// \brief This macro defines the type of the thread handle used for the
    /// active objects.
    ///
    /// The thread type in QK is the pointer to the thread-local storage (TLS)
    /// This thread-local storage can be set on per-thread basis in
    /// QActive::start(). Later, the QK scheduler, passes the pointer to the
    /// thread-local storage to the macro #QK_TLS.
    #define QF_THREAD_TYPE         void *
#endif                                                // QK_TLS || QK_EXT_SAVE

#if (QF_MAX_ACTIVE <= 8)
    extern "C" QP_ QPSet8  QK_readySet_;                  ///< ready set of QK
#else
    extern "C" QP_ QPSet64 QK_readySet_;                  ///< ready set of QK
#endif

extern "C" uint8_t QK_currPrio_;          ///< current task/interrupt priority
extern "C" uint8_t QK_intNest_;                   ///< interrupt nesting level

// QK active object queue implementation .....................................

/// \brief Platform-dependent macro defining how QF should block the calling
/// task when the QF native queue is empty
///
/// \note This is just an example of #QACTIVE_EQUEUE_WAIT_ for the QK-port
/// of QF. QK never activates a task that has no events to process, so in this
/// case the macro asserts that the queue is not empty. In other QF ports you
// need to define the macro appropriately for the underlying kernel/OS you're
/// using.
#define QACTIVE_EQUEUE_WAIT_(me_) \
    Q_ASSERT((me_)->m_eQueue.m_frontEvt != static_cast<QEvt const *>(0))

/// \brief Platform-dependent macro defining how QF should signal the
/// active object task that an event has just arrived.
///
/// The macro is necessary only when the native QF event queue is used.
/// The signaling of task involves unblocking the task if it is blocked.
///
/// \note #QACTIVE_EQUEUE_SIGNAL_ is called from a critical section.
/// It might leave the critical section internally, but must restore
/// the critical section before exiting to the caller.
///
/// \note This is just an example of #QACTIVE_EQUEUE_SIGNAL_ for the QK-port
/// of QF. In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QACTIVE_EQUEUE_SIGNAL_(me_) do { \
    QK_readySet_.insert((me_)->m_prio); \
    if (QK_intNest_ == static_cast<uint8_t>(0)) { \
        uint8_t p = QK_schedPrio_(); \
        if (p != static_cast<uint8_t>(0)) { \
            QK_sched_(p); \
        } \
    } \
} while (false)

/// \brief Platform-dependent macro defining the action QF should take
/// when the native QF event queue becomes empty.
///
/// \note #QACTIVE_EQUEUE_ONEMPTY_ is called from a critical section.
/// It should not leave the critical section.
///
/// \note This is just an example of #QACTIVE_EQUEUE_ONEMPTY_ for the QK-port
/// of QF. In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QACTIVE_EQUEUE_ONEMPTY_(me_) \
    QK_readySet_.remove((me_)->m_prio)

// QK event pool operations ..................................................

/// \brief This macro defines the type of the event pool used in this QF port.
///
/// \note This is a specific implementation for the QK-port of QF.
/// In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QF_EPOOL_TYPE_              QMPool

/// \brief Platform-dependent macro defining the event pool initialization
///
/// \note This is a specific implementation for the QK-port of QF.
/// In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
    (p_).init((poolSto_), (poolSize_), \
        static_cast<QMPoolSize>(evtSize_))

/// \brief Platform-dependent macro defining how QF should obtain the
/// event pool block-size
///
/// \note This is a specific implementation for the QK-port of QF.
/// In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QF_EPOOL_EVENT_SIZE_(p_)    \
    static_cast<uint32_t>((p_).getBlockSize())

/// \brief Platform-dependent macro defining how QF should obtain an event
/// \a e_ from the event pool \a p_
///
/// \note This is a specific implementation for the QK-port of QF.
/// In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QF_EPOOL_GET_(p_, e_)       ((e_) = static_cast<QEvt *>((p_).get()))

/// \brief Platform-dependent macro defining how QF should return an event
/// \a e_ to the event pool \a p_
///
/// \note This is a specific implementation for the QK-port of QF.
/// In other QF ports you need to define the macro appropriately for
/// the underlying kernel/OS you're using.
#define QF_EPOOL_PUT_(p_, e_)       ((p_).put(e_))

//////////////////////////////////////////////////////////////////////////////
QP_BEGIN_

#ifndef QK_NO_MUTEX
    //////////////////////////////////////////////////////////////////////////
    /// \brief QK Mutex type.
    ///
    /// QMutex represents the priority-ceiling mutex available in QK.
    /// \sa QK::mutexLock()
    /// \sa QK::mutexUnlock()
    typedef uint8_t QMutex;
#endif                                                          // QK_NO_MUTEX

//////////////////////////////////////////////////////////////////////////////
/// \brief QK services.
///
/// This class groups together QK services. It has only static members and
/// should not be instantiated.
///
// \note The QK scheduler, QK priority, QK ready set, etc. belong conceptually
/// to the QK class (as static class members). However, to avoid C++ potential
/// name-mangling problems in assembly language, these elements are defined
/// outside of the QK class and use the extern "C" linkage specification.
///
class QK {
public:

    /// \brief get the current QK version number string
    ///
    /// \return version of the QK as a constant 6-character string of the
    /// form x.y.zz, where x is a 1-digit major version number, y is a
    /// 1-digit minor version number, and zz is a 2-digit release number.
    static char_t const Q_ROM * Q_ROM_VAR getVersion(void);

    /// \brief QK idle callback (customized in BSPs for QK)
    ///
    /// QK::onIdle() is called continously 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 unlocked and must also
    /// return with interrupts unlocked.
    ///
    /// \sa QF::onIdle()
    static void onIdle(void);

#ifndef QK_NO_MUTEX

    /// \brief QK priority-ceiling mutex lock
    ///
    /// Lock the QK scheduler up to the priority level \a prioCeiling.
    ///
    // \note This function should be always paired with QK::mutexUnlock().
    /// The code between QK::mutexLock() and QK::mutexUnlock() should be
    /// kept to the minimum.
    ///
    /// \include qk_mux.cpp
    static QMutex mutexLock(uint8_t const prioCeiling);

    /// \brief QK priority-ceiling mutex unlock
    ///
    /// \note This function should be always paired with QK::mutexLock().
    /// The code between QK::mutexLock() and QK::mutexUnlock() should be
    /// kept to the minimum.
    ///
    /// \include qk_mux.cpp
    static void mutexUnlock(QMutex const mutex);

#endif                                                          // QK_NO_MUTEX

};

QP_END_

//////////////////////////////////////////////////////////////////////////////
extern "C" {

/// \brief QK initialization
///
/// QK_init() is called from QF_init() in qk.cpp. This function is
/// defined in the QK ports.
void QK_init(void);

/// \brief The QK scheduler
///
/// \note The QK scheduler must be always called with the interrupts
/// disabled and enables interrupts internally.
///
/// \sa QK_schedPrio_()
void QK_sched_(uint8_t p);

/// \brief The QK extended scheduler for interrupt context
///
/// \note The QK extended exscheduler must be always called with the
/// interrupts disabled and enables interrupts internally.
///
/// \sa QK_schedPrio_()
void QK_schedExt_(uint8_t p);

/// \brief Find the highest-priority task ready to run
///
/// \note QK_schedPrio_() must be always called with interrupts disabled
/// and returns with interrupts disabled.
uint8_t QK_schedPrio_(void);

}                                                                // extern "C"

#else                                                         // QK_PREEMPTIVE

// "qvanilla.h" ==============================================================
/// \brief platform-independent interface to the cooperative "vanilla" kernel.

QP_BEGIN_
                              // the event queue type for the "Vanilla" kernel
#define QF_EQUEUE_TYPE     QEQueue
                                              // native event queue operations
#define QACTIVE_EQUEUE_WAIT_(me_) \
    Q_ASSERT((me_)->m_eQueue.m_frontEvt != static_cast<QEvt const *>(0))

#define QACTIVE_EQUEUE_SIGNAL_(me_) \
    (QF_readySet_.insert((me_)->m_prio))

#define QACTIVE_EQUEUE_ONEMPTY_(me_) \
    (QF_readySet_.remove((me_)->m_prio))

                                            // native QF event pool operations
#define QF_EPOOL_TYPE_           QMPool
#define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
    (p_).init((poolSto_), (poolSize_), static_cast<QMPoolSize>(evtSize_))
#define QF_EPOOL_EVENT_SIZE_(p_) \
    static_cast<uint32_t>((p_).getBlockSize())
#define QF_EPOOL_GET_(p_, e_)    ((e_) = static_cast<QEvt *>((p_).get()))
#define QF_EPOOL_PUT_(p_, e_)    ((p_).put(e_))

QP_END_

#if (QF_MAX_ACTIVE <= 8)
    extern "C" QP_ QPSet8  QF_readySet_;      ///< ready set of active objects
#else
    extern "C" QP_ QPSet64 QF_readySet_;      ///< ready set of active objects
#endif

extern "C" uint8_t QF_currPrio_;          ///< current task/interrupt priority
extern "C" uint8_t QF_intNest_;                   ///< interrupt nesting level

#endif                                                        // QK_PREEMPTIVE


// qf.h (QF platform-independent public interface) ===========================

/// \brief QF/C++ platform-independent public interface.
///
/// This header file must be included directly or indirectly
/// in all modules (*.cpp files) that use QF/C++.

//////////////////////////////////////////////////////////////////////////////
#ifdef Q_EVT_CTOR
#include <new>                                            // for placement new
#endif

//////////////////////////////////////////////////////////////////////////////
// apply defaults for all undefined configuration parameters
//
#ifndef QF_EVENT_SIZ_SIZE
    /// \brief Default value of the macro configurable value in qf_port.h
    #define QF_EVENT_SIZ_SIZE    2
#endif

#ifndef QF_MAX_EPOOL
    /// \brief Default value of the macro configurable value in qf_port.h
    #define QF_MAX_EPOOL         3
#endif

#ifndef QF_TIMEEVT_CTR_SIZE
    /// \brief macro to override the default QTimeEvtCtr size.
    /// Valid values 1, 2, or 4; default 2
    #define QF_TIMEEVT_CTR_SIZE  2
#endif

#if (QF_MAX_ACTIVE < 1) || (63 < QF_MAX_ACTIVE)
    #error "QF_MAX_ACTIVE not defined or out of range. Valid range is 1..63"
#endif

#ifndef QF_ACTIVE_SUPER_

    //////////////////////////////////////////////////////////////////////////
    /// \brief The macro defining the base class for QActive.
    ///
    /// By default, the ::QActive class is derived from ::QHsm. However,
    /// if the macro QF_ACTIVE_SUPER_ is defined, QActive is derived from
    /// QF_ACTIVE_SUPER_.
    ///
    /// Clients might choose, for example, to define QF_ACTIVE_SUPER_ as QFsm
    /// to avoid the 1-2KB overhead of the hierarchical event processor.
    ///
    /// Clients might also choose to define QF_ACTIVE_SUPER_ as their own
    /// completely customized class that has nothing to do with QHsm or QFsm.
    /// The QF_ACTIVE_SUPER_ class must provide member functions init() and
    /// dispatch(), consistent with the signatures of QHsm and QFsm. But
    /// the implementatin of these functions is completely open.
    #define QF_ACTIVE_SUPER_  QHsm

    /// \brief The argument of the base class' constructor.
    #define QF_ACTIVE_STATE_  QStateHandler

#endif

//////////////////////////////////////////////////////////////////////////////
QP_BEGIN_

//////////////////////////////////////////////////////////////////////////////
#if (QF_EVENT_SIZ_SIZE == 1)

    /// \brief The data type to store the block-size defined based on
    /// the macro #QF_EVENT_SIZ_SIZE.
    ///
    /// The dynamic range of this data type determines the maximum block
    /// size that can be managed by the pool.
    typedef uint8_t QEvtSize;
#elif (QF_EVENT_SIZ_SIZE == 2)
    typedef uint16_t QEvtSize;
#elif (QF_EVENT_SIZ_SIZE == 4)
    typedef uint32_t QEvtSize;
#else
    #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

//////////////////////////////////////////////////////////////////////////////
#if (QF_TIMEEVT_CTR_SIZE == 1)
    /// \brief type of the Time Event counter, which determines the dynamic
    /// range of the time delays measured in clock ticks.
    ///
    /// This typedef is configurable via the preprocessor switch
    /// #QF_TIMEEVT_CTR_SIZE. The other possible values of this type are
    /// as follows: \n
    /// uint8_t when (QF_TIMEEVT_CTR_SIZE == 1), and \n
    /// uint32_t when (QF_TIMEEVT_CTR_SIZE == 4).
    typedef uint8_t QTimeEvtCtr;
#elif (QF_TIMEEVT_CTR_SIZE == 2)
    typedef uint16_t QTimeEvtCtr;
#elif (QF_TIMEEVT_CTR_SIZE == 4)
    typedef uint32_t QTimeEvtCtr;
#else
    #error "QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

class QEQueue;                                          // forward declaration

//////////////////////////////////////////////////////////////////////////////
/// \brief Base class for derivation of application-level active object
/// classes.
///
/// QActive is the base class for derivation of active objects. Active objects
/// in QF are encapsulated tasks (each embedding a state machine and an event
/// queue) that communicate with one another asynchronously by sending and
/// receiving events. Within an active object, events are processed
/// sequentially in a run-to-completion (RTC) fashion, while QF encapsulates
/// all the details of thread-safe event exchange and queuing.
///
/// \note QActive is not intended to be instantiated directly, but rather
/// serves as the base class for derivation of active objects in the
/// application code.
///
/// The following example illustrates how to derive an active object from
/// QActive.
/// \include qf_qactive.cpp
///
/// \sa #QF_ACTIVE_SUPER_ defines the base class for QActive
class QActive : public QF_ACTIVE_SUPER_ {

#ifdef QF_EQUEUE_TYPE
    /// \brief OS-dependent event-queue type.
    ///
    /// The type of the queue depends on the underlying operating system or
    /// a kernel. Many kernels support "message queues" 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.
    ///
    /// The native QF event queue is configured by defining the macro
    /// #QF_EQUEUE_TYPE as ::QEQueue.
    QF_EQUEUE_TYPE m_eQueue;
#endif

#ifdef QF_OS_OBJECT_TYPE
    /// \brief OS-dependent per-thread object.
    ///
    /// 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.
    QF_OS_OBJECT_TYPE m_osObject;
#endif

#ifdef QF_THREAD_TYPE
    /// \brief OS-dependent representation of the thread of the active
    /// object.
    ///
    /// 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).
    QF_THREAD_TYPE m_thread;
#endif

    /// \brief QF priority associated with the active object.
    /// \sa QActive::start()
    uint8_t m_prio;

public:
    /// \brief Starts execution of an active object and registers the object
    /// with the framework.
    ///
    /// The function takes six arguments.
    /// \a prio is the priority of the active object. QF allows you to start
    /// up to 63 active objects, each one having a unique priority number
    /// between 1 and 63 inclusive, where higher numerical values correspond
    /// to higher priority (urgency) of the active object relative to the
    /// others.
    /// \a qSto[] and \a qLen arguments are the storage and size of the event
    /// queue used by this active object.
    /// \a stkSto and \a stkSize are the stack storage and size in bytes.
    /// Please note that a per-active object stack is used only when the
    /// underlying OS requies it. If the stack is not required, or the
    /// underlying OS allocates the stack internally, the \a stkSto should be
    /// NULL and/or \a stkSize should be 0.
    /// \a ie is an optional initialization event that can be used to pass
    /// additional startup data to the active object. (Pass NULL if your
    /// active object does not expect the initialization event).
    ///
    /// \note This function is strongly OS-dependent and must be defined in
    /// the QF port to a particular platform.
    ///
    /// The following example shows starting of the Philosopher object when a
    /// per-task stack is required:
    /// \include qf_start.cpp
    void start(uint8_t const prio,
               QEvt const *qSto[], uint32_t const qLen,
               void * const stkSto, uint32_t const stkSize,
               QEvt const * const ie = static_cast<QEvt *>(0));

    /// \brief Posts an event \a e directly to the event queue of the acitve
    /// object \a me using the First-In-First-Out (FIFO) policy.
    ///
    /// Direct event posting is the simplest asynchronous communication method
    /// available in QF. The following example illustrates how the Philosopher
    /// active obejct posts directly the HUNGRY event to the Table active
    /// object. \include qf_post.cpp
    ///
    /// \note The producer of the event (Philosopher in this case) must only
    /// "know" the recipient (Table) by a generic (QActive *QDPP_table)
    /// pointer, but the specific definition of the Table class is not
    /// required.
    ///
    /// \note Direct event posting should not be confused with direct event
    /// dispatching. In contrast to asynchronous event posting through event
    /// queues, direct event dispatching is synchronous. Direct event
    /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch()
    /// function.
#ifndef Q_SPY
    void postFIFO(QEvt const * const e);
#else
    void postFIFO(QEvt const * const e, void const * const sender);
#endif

    /// \brief Un-subscribes from the delivery of all signals to the active
    /// object.
    ///
    /// 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 QF::publish(), QActive::subscribe(), and QActive::unsubscribe()
    void unsubscribeAll(void) const;

protected:
    /// \brief protected constructor
    ///
    /// Performs the first step of active object initialization by assigning
    /// the initial pseudostate to the currently active state of the state
    /// machine.
    ///
    /// \note The constructor is protected to prevent direct instantiation
    /// of QActive objects. This class is intended only for derivation
    /// (abstract class).
    QActive(QF_ACTIVE_STATE_ const initial) : QF_ACTIVE_SUPER_(initial) {
    }

    /// \brief Posts an event directly to the event queue of the active object
    /// \a me using the Last-In-First-Out (LIFO) policy.
    ///
    /// \note The LIFO policy should be used only for self-posting and with
    /// great caution because it alters order of events in the queue.
    ///
    /// \sa QActive::postFIFO()
    void postLIFO(QEvt const * const e);

    /// \brief Stops execution of an active object and removes it from the
    /// framework's supervision.
    ///
    /// The preferred way of calling this function is from within the active
    /// object that needs to stop (that's why this function is protected).
    /// In other words, an active object should stop itself rather than being
    /// stopped by some other entity. This policy works best, because only
    /// the active object itself "knows" when it has reached the appropriate
    /// state for the shutdown.
    ///
    /// \note This function is strongly OS-dependent and should be defined in
    /// the QF port to a particular platform. This function is optional in
    /// embedded systems where active objects never need to be stopped.
    void stop(void);

    /// \brief Subscribes for delivery of signal \a sig to the active object
    ///
    /// 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
    /// \a sig to the event queue of the active object.
    ///
    /// The following example shows how the Table active object subscribes
    /// to three signals in the initial transition:
    /// \include qf_subscribe.cpp
    ///
    /// \sa QF::publish(), QActive::unsubscribe(), and
    /// QActive::unsubscribeAll()
    void subscribe(enum_t const sig) const;

    /// \brief Un-subscribes from the delivery of signal \a sig to the
    /// active object.
    ///
    /// 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
    /// \a sig to the event queue of the active object.
    ///
    /// \note Due to the latency of event queues, an active object should NOT
    /// assume that a given signal \a 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 rise an assertion.
    ///
    /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribeAll()
    void unsubscribe(enum_t const sig) const;

    /// \brief Defer an event to a given separate event queue.
    ///
    /// This function is part of the event deferral support. An active object
    /// uses this function to defer an event \a e to the QF-supported native
    /// event queue \a 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.
    ///
    /// An active object can use multiple event queues to defer events of
    /// different kinds.
    ///
    /// \sa QActive::recall(), QEQueue
    void defer(QEQueue * const eq, QEvt const * const e) const;

    /// \brief Recall a deferred event from a given event queue.
    ///
    /// 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 \a eq and posted (LIFO) to the event queue of
    /// the active object.
    ///
    /// QActive::recall() returns true if an event has been recalled.
    /// Otherwise the function returns false.
    ///
    /// An active object can use multiple event queues to defer events of
    /// different kinds.
    ///
    /// \sa QActive::defer(), QEQueue, QActive::postLIFO()
    bool recall(QEQueue * const eq);

private:

    /// \brief Get an event from the event queue of an active object.
    ///
    /// This function is used internally by a QF port to extract events from
    /// the event queue of an active object. This function depends on the
    /// event queue implementation and is sometimes implemented in the QF port
    /// (qf_port.cpp file). Depending on the underlying OS or kernel, the
    /// function might block the calling thread when no events are available.
    ///
    /// \note QActive::get_() is public because it often needs to be called
    /// from thread-run routines with difficult to foresee signature (so
    /// declaring friendship with such function(s) is not possible.)
    ///
    /// \sa QActive::postFIFO(), QActive::postLIFO()
    QEvt const *get_(void);

    friend class QF;
    friend class QTimeEvt;

#ifdef QK_PREEMPTIVE                                       // is this QK port?
    friend void ::QK_schedExt_(uint8_t p);
    friend void ::QK_sched_(uint8_t p);
#endif

};

//////////////////////////////////////////////////////////////////////////////
/// \brief Time Event class
///
/// 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.
///
/// Time events, as any other QF events derive from the ::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.
///
/// Internally, the armed time events are organized into a bi-directional
/// linked list. This linked list is scanned in every invocation of the
/// QF::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 function QF::tick(), which
/// must be called periodically, preferably from the clock tick ISR.
/// \note In this version of QF QTimeEvt objects should be allocated
/// statically rather than dynamically from event pools. Currently, QF will
/// not correctly recycle the dynamically allocated Time Events.
class QTimeEvt : public QEvt {
private:

    /// link to the next time event in the list
    QTimeEvt *m_next;

    /// the active object that receives the time events.
    QActive *m_act;

    /// the internal down-counter of the time event. The down-counter
    /// is decremented by 1 in every QF_tick() invocation. The time event
    /// fires (gets posted or published) when the down-counter reaches zero.
    QTimeEvtCtr m_ctr;

    /// the interval for the periodic time event (zero for the one-shot
    /// time event). 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.
    QTimeEvtCtr m_interval;

public:

    /// \brief The Time Event constructor.
    ///
    /// The most important initialization performed in  the constructor is
    /// assigning a signal to the Time Event. You can reuse the Time Event
    /// any number of times, but you cannot change the signal.
    /// This is because pointers to Time Events might still be held in event
    /// queues and changing signal could to hard-to-detect errors.
    ///
    /// The following example shows the use of QTimeEvt::QTimeEvt()
    /// constructor in the constructor initializer list of the Philosopher
    /// active object constructor that owns the time event
    /// \include qf_ctor.cpp
    QTimeEvt(enum_t const s);

    /// \brief Arm a one-shot time event for direct event posting.
    ///
    /// Arms a time event to fire in \a nTicks clock ticks (one-shot time
    /// event). The time event gets directly posted (using the FIFO policy)
    /// into the event queue of the active object \a act.
    ///
    /// After posting, the time event gets automatically disarmed and can be
    /// reused for a one-shot or periodic timeout requests.
    ///
    /// A one-shot time event can be disarmed at any time by calling the
    /// QTimeEvt::disarm() function. Also, a one-shot time event can be
    /// re-armed to fire in a different number of clock ticks by calling the
    /// QTimeEvt::rearm() function.
    ///
    /// The following example shows how to arm a one-shot time event from a
    /// state machine of an active object:
    /// \include qf_state.cpp
    void postIn(QActive * const act, QTimeEvtCtr const nTicks) {
        m_interval = static_cast<QTimeEvtCtr>(0);
        arm_(act, nTicks);
    }

    /// \brief Arm a periodic time event for direct event posting.
    ///
    /// Arms a time event to fire every \a nTicks clock ticks (periodic time
    /// event). The time event gets directly posted (using the FIFO policy)
    /// into the event queue of the active object \a act.
    ///
    /// After posting, the time event gets automatically re-armed to fire
    /// again in the specified \a nTicks clock ticks.
    ///
    /// A periodic time event can be disarmed only by calling the
    /// QTimeEvt::disarm() function. After disarming, the time event can be
    /// reused for a one-shot or periodic timeout requests.
    ///
    /// \note An attempt to reuse (arm again) a running periodic time event
    /// raises an assertion.
    ///
    /// Also, a periodic time event can be re-armed to shorten or extend the
    /// current period by calling the QTimeEvt_rearm() function. After
    /// adjusting the current period, the periodic time event goes back
    /// timing out at the original rate.
    void postEvery(QActive * const act, QTimeEvtCtr const nTicks) {
        m_interval = nTicks;
        arm_(act, nTicks);
    }

    /// \brief Disarm a time event.
    ///
    /// The time event gets disarmed and can be reused. The function
    /// 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 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 state machine.
    bool disarm(void);

    /// \brief Rearm a time event.
    ///
    /// The time event gets rearmed with a new number of clock ticks
    /// \a nTicks. This facility can be used to prevent a one-shot time event
    /// from expiring (e.g., a watchdog time event), or to adjusts the
    /// current period of a periodic time event. Rearming a periodic timer
    /// leaves the interval unchanged and is a convenient method to adjust
    /// the phasing of the periodic time event.
    ///
    /// The function returns true if the time event was running as it
    /// was re-armed. The return of false 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 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 state machine.
    bool rearm(QTimeEvtCtr const nTicks);

    /// \brief Get the current value of the down-counter of a time event.
    ///
    /// If the time event is armed, the function returns the current value of
    /// the down-counter of the given time event. If the time event is not
    /// armed, the function returns 0.
    ///
    /// /note The function is thread-safe.
    QTimeEvtCtr ctr(void) const;

private:

    /// \brief Arm a time event (internal function to be used through macros
    /// only).
    ///
    /// \sa QTimeEvt::postIn(), QTimeEvt::postEvery(),
    /// \sa QTimeEvt::publishIn(), QTimeEvt::publishEvery()
    void arm_(QActive * const act, QTimeEvtCtr const nTicks);

    friend class QF;
};


//////////////////////////////////////////////////////////////////////////////
/// \brief The size of the Subscriber list bit array
///
/// The size is determined of the maximum number of active objects in the
/// application configured by the #QF_MAX_ACTIVE macro.
uint8_t const QF_SUBSCR_LIST_SIZE =
    static_cast<uint8_t>(((QF_MAX_ACTIVE - 1) / 8) + 1);

/// \brief Subscriber List class
///
/// This data type represents a set of active objects that subscribe to
/// a given signal. The set is represented as an array of bits, where each
/// bit corresponds to the unique priority of an active object.
class QSubscrList {
private:

    /// An array of bits representing subscriber active objects. Each bit
    /// in the array corresponds to the unique priority of the active object.
    /// The size of the array is determined of the maximum number of active
    /// objects in the application configured by the #QF_MAX_ACTIVE macro.
    /// For example, an active object of priority p is a subscriber if the
    /// following is true: ((m_bits[QF_div8Lkup[p]] & QF_pwr2Lkup[p]) != 0)
    ///
    /// \sa QF::psInit(), QF_div8Lkup, QF_pwr2Lkup, #QF_MAX_ACTIVE
    uint8_t m_bits[QF_SUBSCR_LIST_SIZE];

    friend class QF;
    friend class QActive;
};

//////////////////////////////////////////////////////////////////////////////
/// \brief QF services.
///
/// This class groups together QF services. It has only static members and
/// should not be instantiated.
class QF {
public:

    /// \brief QF initialization.
    ///
    /// This function initializes QF and must be called exactly once before
    /// any other QF function.
    static void init(void);

    /// \brief Publish-subscribe initialization.
    ///
    /// This function initializes the publish-subscribe facilities of QF and
    /// must be called exactly once before any subscriptions/publications
    /// occur in the application. The arguments are as follows: \a subscrSto
    /// is a pointer to the array of subscriber-lists. \a maxSignal is the
    /// dimension of this 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
    /// mapping between the signals and subscirber-lists. The subscriber-
    /// lists are bitmasks of type ::QSubscrList, each bit in the bitmask
    /// corresponding to the unique priority of an active object. The size
    /// of the ::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 ::QSubscrList
    ///
    /// The following example shows the typical initialization sequence of
    /// QF: \include qf_main.cpp
    static void psInit(QSubscrList * const subscrSto,
                       uint32_t const maxSignal);

    /// \brief Event pool initialization for dynamic allocation of events.
    ///
    /// 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.
    /// The arguments are as follows: \a poolSto is a pointer to the memory
    /// block for the events. \a poolSize is the size of the memory block in
    /// bytes. \a evtSize is the block-size of the pool in bytes, which
    /// determines the maximum size of events that can be allocated from the
    /// pool.
    ///
    /// You might initialize one, two, and up to three event pools by making
    /// one, two, or three 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.
    ///
    /// Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that
    /// can be used for QF event pools. In case such support is missing, QF
    /// provides a native QF event pool implementation. The macro
    /// #QF_EPOOL_TYPE_ determines the type of event pool used by a
    /// particular QF port. See class ::QMPool for more information.
    ///
    /// \note The actual number of events available in the pool might be
    /// actually less than (\a poolSize / \a 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::getPoolMargin().
    ///
    /// \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()
    static void poolInit(void * const poolSto, uint32_t const poolSize,
                         uint32_t const evtSize);

    /// \brief Transfers control to QF to run the application.
    ///
    /// QF::run() is typically called from your startup code after you
    /// initialize the QF and start at least one active object with
    /// QActive::start(). Also, QF::start() call must precede the transfer
    /// of control to QF::run(), but some QF ports might call QF::start()
    /// from QF::run(). QF::run() typically never returns to the caller,
    /// but when it does, it returns the error code (0 for success)
    ///
    /// \note This function is strongly platform-dependent and is not
    /// implemented in the QF, but either in the QF port or in the
    /// Board Support Package (BSP) for the given application. All QF ports
    /// must implement QF::run().
    ///
    /// \note When the Quantum Kernel (QK) is used as the underlying real-time
    /// kernel for the QF, all platfrom dependencies are handled in the QK, so
    /// no porting of QF is necessary. In other words, you only need to
    /// recompile the QF platform-independent code with the compiler for your
    /// platform, but you don't need to provide any platform-specific
    /// implementation (so, no qf_port.cpp file is necessary). Moreover, QK
    /// implements the function QF::run() in a platform-independent way,
    /// in the modile qk.cpp.
    static int16_t run(void);

    /// \brief Startup QF callback.
    ///
    /// The timeline for calling QF::onStartup() depends on the particular
    /// QF port. In most cases, QF::onStartup() is called from QF::run(),
    /// right before starting any multitasking kernel or the background loop.
    static void onStartup(void);

    /// \brief Cleanup QF callback.
    ///
    /// QF::onCleanup() is called in some QF ports before QF returns to the
    /// underlying operating system or RTOS.
    ///
    /// This function is strongly platform-specific and is not implemented in
    /// the QF but either in the QF port or in the Board Support Package (BSP)
    /// for the given application. Some QF ports might not require
    /// implementing QF::onCleanup() at all, because many embedded
    /// applications don't have anything to exit to.
    ///
    /// \sa QF::init() and QF::stop()
    static void onCleanup(void);

    /// \brief QF idle callback (customized in BSPs for QF)
    ///
    /// QF::onIdle() is called by the non-preemptive "Vanilla" scheduler built
    /// into QF when the framework detects that no events are available for
    /// active objects (the idle condition). This callback gives the
    /// application an opportunity to enter a power-saving CPU mode, or
    /// perform some other idle processing (such as Q-Spy output).
    ///
    /// \note QF_onIdle() is invoked with interrupts DISABLED because the idle
    /// condition can be asynchronously changed at any time by an interrupt.
    /// QF_onIdle() MUST enable the interrupts internally, but not before
    /// putting the CPU into the low-power mode. (Ideally, enabling interrupts
    /// and low-power mode should happen atomically). At the very least, the
    /// function MUST enable interrupts, otherwise interrups will remain
    /// disabled permanently.
    ///
    /// \note QF::onIdle() is only used by the non-preemptive "Vanilla"
    /// scheduler in the "bare metal" QF port, and is NOT used in any other
    /// QF ports. When QF is combined with QK, the QK idle loop calls a
    /// different function QK::onIdle(), with different semantics than
    /// QF::onIdle(). When QF is combined with a 3rd-party RTOS or kernel, the
    /// idle processing mechanism of the RTOS or kernal is used instead of
    /// QF::onIdle().
    ///
    static void onIdle(void);

    /// \brief Function invoked by the application layer to stop the QF
    /// application and return control to the OS/Kernel.
    ///
    /// 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
    /// funcition 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.
    ///
    /// This function is strongly platform-specific and is not implemented in
    /// the QF but either in the QF port or in the Board Support Package (BSP)
    /// for the given application. Some QF ports might not require
    /// implementing QF::stop() at all, because many embedded application
    /// don't have anything to exit to.
    ///
    /// \sa QF::stop() and QF::onCleanup()
    static void stop(void);

    /// \brief Publish event to the framework.
    ///
    /// This function posts (using the FIFO policy) the event \a e it to ALL
    /// active object that have subscribed to the signal \a e->sig.
    /// This function is designed to be callable from any part of the system,
    /// including ISRs, device drivers, and active objects.
    ///
    /// In the general case, event publishing requires multi-casting the
    /// event to multiple subscribers. This happens in the caller's thread
    /// with the scheduler locked to prevent preemptions during the multi-
    /// casting process. (Please note that the interrupts are not locked.)
#ifndef Q_SPY
    static void publish(QEvt const *e);
#else
    static void publish(QEvt const *e, void const *sender);
#endif

    /// \brief Processes all armed time events at every clock tick.
    ///
    /// This function must be called periodically from a time-tick ISR or from
    /// the highest-priority task so that QF can manage the timeout events.
    ///
    /// \note The QF::tick() function is not reentrant meaning that it must
    /// run to completion before it is called again. Also, QF::tick() assumes
    /// that it never will get preempted by a task, which is always the case
    /// when it is called from an ISR or the highest-priority task.
    ///
    /// \sa ::QTimeEvt.
    ///
    /// The following example illustrates the call to QF::tick():
    /// \include qf_tick.cpp
#ifndef Q_SPY
    static void tick(void);
#else
    static void tick(void const * const sender);
#endif

    /// \brief Returns true if all time events are inactive and false
    /// any time event is active.
    ///
    /// \note This function should be called in critical section.
    static bool noTimeEvtsActive(void);

    /// \brief Returns the QF version.
    ///
    /// This function returns constant version string in the format x.y.zz,
    /// where x (one digit) is the major version, y (one digit) is the minor
    /// version, and zz (two digits) is the maintenance release version.
    /// An example of the version string is "3.1.03".
    ///
    /// The following example illustrates the usage of this function:
    /// \include qf_version.cpp
    static char_t const Q_ROM * Q_ROM_VAR getVersion(void);

    /// \brief This function returns the margin of the given event pool.
    ///
    /// This function returns the margin of the given event pool \a poolId,
    /// where poolId is the ID of the pool initialized by the call to
    /// QF::poolInit(). The poolId of the first initialized pool is 1, the
    /// second 2, and so on.
    ///
    /// The returned pool margin is the minimal number of free blocks
    /// encountered in the given pool since system startup.
    ///
    /// \note Requesting the margin of an un-initialized pool raises an
    /// assertion in the QF.
    static uint32_t getPoolMargin(uint8_t const poolId);

    /// \brief This function returns the margin of the given event queue.
    ///
    /// This function returns the margin of the given event queue of an active
    /// object with priority \a prio. (QF priorities start with 1 and go up to
    /// #QF_MAX_ACTIVE.) The margin is the minimal number of free events
    /// encountered in the given queue since system startup.
    ///
    /// \note QF::getQueueMargin() is available only when the native QF event
    /// queue implementation is used. Requesting the queue margin of an unused
    /// priority level raises an assertion in the QF. (A priority level
    /// becomes used in QF after the call to the QF::add_() function.)
    static uint32_t getQueueMargin(uint8_t const prio);

    /// \brief Internal QF implementation of the dynamic event allocator.
    ///
    /// \note The application code should not call this function directly.
    /// Please use the macro #Q_NEW.
    static QEvt *new_(QEvtSize const evtSize, enum_t const sig);

    /// \brief Recycle a dynamic event.
    ///
    /// This function implements a simple garbage collector for the 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->attrQF__ attribute.) Next, the function
    /// decrements the reference counter of the event, 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.
    /// The pool-of-origin information is stored in the upper 2-MSBs of the
    /// e->attrQF__ attribute.)
    ///
    /// \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 "raw" thread-safe queues
    /// (see ::QEQueue). Such queues are processed outside of QF and the
    /// automatic garbage collection CANNOT be performed for these events.
    /// In this case you need to call QF::gc() explicitly.
    static void gc(QEvt const *e);

private:                              // functions to be used in QF ports only

    /// \brief Register an active object to be managed by the framework
    ///
    /// This function should not be called by the application directly, only
    /// through the function QActive::start(). The priority of the active
    /// object \a a should be set before calling this function.
    ///
    /// \note This function raises an assertion if the priority of the active
    /// object exceeds the maximum value #QF_MAX_ACTIVE. Also, this function
    /// raises an assertion if the priority of the active object is already in
    /// use. (QF requires each active object to have a UNIQUE priority.)
    static void add_(QActive * const a);

public:
    /// \brief Remove the active object from the framework.
    ///
    /// This function should not be called by the application directly, only
    /// inside the QF port. The priority level occupied by the active object
    /// is freed-up and can be reused for another active object.
    ///
    /// The active object that is removed from the framework can no longer
    /// participate in the publish-subscribe event exchange.
    ///
    /// \note This function raises an assertion if the priority of the active
    /// object exceeds the maximum value #QF_MAX_ACTIVE or is not used.
    static void remove_(QActive const * const a);

    /// \brief array of registered active objects
    ///
    /// \note Not to be used by Clients directly, only in ports of QF
    static QActive *active_[];

    /// \brief Thread routine for executing an active object \a act.
    ///
    /// This function is actually implemented internally by certain QF ports
    /// to be called by the active object thread routine.
    static void thread_(QActive *act);

    friend class QActive;
};

QP_END_

//////////////////////////////////////////////////////////////////////////////
#ifdef Q_EVT_CTOR               // Provide the constructor for the QEvt class?

    /// \brief Allocate a dynamic event.
    ///
    /// This macro returns an event pointer cast to the type \a evtT_. The
    /// event is initialized with the signal \a sig. Internally, the macro
    /// calls the internal QF function QF::new_(), which always returns a
    /// valid event pointer.
    ///
    /// \note The internal QF function QF::new_() raises an assertion when
    /// the allocation of the event turns out to be impossible due to
    /// event pool depletion, or incorrect (too big) size of the requested
    /// event.
    ///
    /// The following example illustrates dynamic allocation of an event:
    /// \include qf_post.cpp
    #define Q_NEW(evtT_, sig_, ...) \
        (new(QP_ QF::new_( \
            static_cast<QP_ QEvtSize>(sizeof(evtT_)), (sig_))) \
            evtT_((sig_),  ##__VA_ARGS__))
#else                                    // QEvt is a POD (Plain Old Datatype)

    #define Q_NEW(evtT_, sig_) \
        (static_cast<evtT_ *>( \
            QP_ QF::new_(static_cast<QP_ QEvtSize>(sizeof(evtT_)), (sig_))))
#endif

//////////////////////////////////////////////////////////////////////////////
// QS software tracing integration, only if enabled
#ifdef Q_SPY                                   // QS software tracing enabled?

    /// \brief Invoke the system clock tick processing QF::tick(). 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.
    ///
    /// This macro takes the argument \a sender_, which is a pointer to the
    /// sender object. This argument is actually only used when QS software
    /// tracing is enabled (macro #Q_SPY is defined). When QS software
    /// tracing is disabled, the macro calls QF::tick() without any
    /// arguments, so the overhead of passing this extra argument is
    /// entirely avoided.
    ///
    /// \note the pointer to the sender object is not necessarily a poiner
    /// to an active object. In fact, typically QF::TICK() will be called from
    /// an interrupt, in which case you would create a unique object just to
    /// unambiguously identify the ISR as the sender of the time events.
    ///
    /// \sa QF::tick()
    #define TICK(sender_)                  tick(sender_)

    /// \brief Invoke the event publishing facility QF::publish(). 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.
    ///
    ///
    /// This macro takes the last argument \a sender_, which is a pointer to
    /// the sender object. This argument is actually only used when QS
    /// tracing is enabled (macro #Q_SPY is defined). When QS software
    /// tracing is disabled, the macro calls QF::publish() without the
    /// \a sender_ argument, so the overhead of passing this extra argument
    /// is entirely avoided.
    ///
    /// \note the pointer to the sender object is not necessarily a poiner
    /// to an active object. In fact, if QF::PUBLISH() is called from an
    /// interrupt or other context, you can create a unique object just to
    /// unambiguously identify the publisher of the event.
    ///
    /// \sa QF::publish()
    #define PUBLISH(e_, sender_)           publish((e_), (sender_))

    /// \brief Invoke the direct event posting facility QActive::postFIFO().
    /// This macro is the recommended way of posting events, because it
    /// provides the vital information for software tracing and avoids any
    /// overhead when the tracing is disabled.
    ///
    ///
    /// This macro takes the last argument \a sender_, which is a pointer to
    /// the sender object. This argument is actually only used when QS
    /// tracing is disabled (macro #Q_SPY is defined). When QS software
    /// tracing is not enabled, the macro calls QF_publish() without the
    /// \a sender_ argument, so the overhead of passing this extra argument
    /// is entirely avoided.
    ///
    /// \note the pointer to the sender object is not necessarily a poiner
    /// to an active object. In fact, if ao->POST() is called from an
    /// interrupt or other context, you can create a unique object just to
    /// unambiguously identify the publisher of the event.
    ///
    /// \sa QActive::postFIFO()
    #define POST(e_, sender_)              postFIFO((e_), (sender_))

#else

    #define TICK(dummy_)                   tick()
    #define PUBLISH(e_, dummy_)            publish(e_)
    #define POST(e_, dummy_)               postFIFO(e_)

#endif                                                                // Q_SPY

//////////////////////////////////////////////////////////////////////////////
// QS software tracing
#ifdef Q_SPY

// qs.h ======================================================================
/// \brief QS/C++ platform-independent public interface.
/// This header file must be included directly or indirectly
/// in all modules (*.cpp files) that use QS/C++.

#ifndef Q_SPY
    #error "Q_SPY must be defined to include qs.h"
#endif

#ifndef Q_ROM                      // provide the default if Q_ROM NOT defined
    #define Q_ROM
#endif
#ifndef Q_ROM_VAR              // provide the default if Q_ROM_VAR NOT defined
    #define Q_ROM_VAR
#endif
#ifndef Q_ROM_BYTE            // provide the default if Q_ROM_BYTE NOT defined
    #define Q_ROM_BYTE(rom_var_)   (rom_var_)
#endif

#ifndef QS_TIME_SIZE

    /// \brief The size (in bytes) of the QS time stamp. Valid values: 1, 2,
    /// or 4; default 4.
    ///
    /// This macro can be defined in the QS port file (qs_port.h) to
    /// configure the ::QSTimeCtr type. Here the macro is not defined so the
    /// default of 4 byte is chosen.
    #define QS_TIME_SIZE 4
#endif

//////////////////////////////////////////////////////////////////////////////
QP_BEGIN_

/// \brief Quantum Spy record types.
///
/// The following constants specify the QS record types used in QP components.
/// You can specify your own record types starting from the ::QS_USER offset.
/// Currently, the maximum of all records cannot exceed 256.
/// \sa QS::filterOn()/#QS_FILTER_ON and QS::filterOff()/#QS_FILTER_OFF

enum QSpyRecords {
    QS_QP_RESET,                 ///< reset the QP (start of a new QS session)

    // QEP records
    QS_QEP_STATE_ENTRY,                               ///< a state was entered
    QS_QEP_STATE_EXIT,                                 ///< a state was exited
    QS_QEP_STATE_INIT,          ///< an intial transition was taken in a state
    QS_QEP_INIT_TRAN,           ///< the top-most initial transition was taken
    QS_QEP_INTERN_TRAN,                  ///< an internal transition was taken
    QS_QEP_TRAN,                           ///< a regular transition was taken
    QS_QEP_IGNORED,             ///< an event was ignored (silently discarded)
    QS_QEP_DISPATCH,          ///< an event was dispatched (begin of RTC step)
    QS_QEP_UNHANDLED,               ///< an event was unhandled due to a guard

    // QF records
    QS_QF_ACTIVE_ADD,                ///< an AO has been added to QF (started)
    QS_QF_ACTIVE_REMOVE,         ///< an AO has been removed from QF (stopped)
    QS_QF_ACTIVE_SUBSCRIBE,                  ///< an AO subscribed to an event
    QS_QF_ACTIVE_UNSUBSCRIBE,              ///< an AO unsubscribed to an event
    QS_QF_ACTIVE_POST_FIFO,  ///< an event was posted (FIFO) directly to an AO
    QS_QF_ACTIVE_POST_LIFO,  ///< an event was posted (LIFO) directly to an AO
    QS_QF_ACTIVE_GET, ///< an AO got an event and its queue is still not empty
    QS_QF_ACTIVE_GET_LAST,      ///< an AO got an event and its queue is empty
    QS_QF_EQUEUE_INIT,                     ///< an event queue was initialized
    QS_QF_EQUEUE_POST_FIFO,     ///< an event was posted (FIFO) to a raw queue
    QS_QF_EQUEUE_POST_LIFO,     ///< an event was posted (LIFO) to a raw queue
    QS_QF_EQUEUE_GET,              ///< get an event and queue still not empty
    QS_QF_EQUEUE_GET_LAST,              ///< get the last event from the queue
    QS_QF_MPOOL_INIT,                       ///< a memory pool was initialized
    QS_QF_MPOOL_GET,        ///< a memory block was removed from a memory pool
    QS_QF_MPOOL_PUT,         ///< a memory block was returned to a memory pool
    QS_QF_PUBLISH,       ///< an event was truly published to some subscribers
    QS_QF_RESERVED8,
    QS_QF_NEW,                                         ///< new event creation
    QS_QF_GC_ATTEMPT,                          ///< garbage collection attempt
    QS_QF_GC,                                          ///< garbage collection
    QS_QF_TICK,                                     ///< QF::tick() was called
    QS_QF_TIMEEVT_ARM,                             ///< a time event was armed
    QS_QF_TIMEEVT_AUTO_DISARM,      ///< a time event expired and was disarmed
    QS_QF_TIMEEVT_DISARM_ATTEMPT,///< an attempt to disarmed a disarmed tevent
    QS_QF_TIMEEVT_DISARM,           ///< true disarming of an armed time event
    QS_QF_TIMEEVT_REARM,                         ///< rearming of a time event
    QS_QF_TIMEEVT_POST,      ///< a time event posted itself directly to an AO
    QS_QF_TIMEEVT_CTR,                 ///< a time event counter was requested
    QS_QF_CRIT_ENTRY,                        ///< critical section was entered
    QS_QF_CRIT_EXIT,                          ///< critical section was exited
    QS_QF_ISR_ENTRY,                                   ///< an ISR was entered
    QS_QF_ISR_EXIT,                                     ///< an ISR was exited
    QS_QF_INT_DISABLE,                           ///< interrupts were disabled
    QS_QF_INT_ENABLE,                             ///< interrupts were enabled
    QS_QF_RESERVED4,
    QS_QF_RESERVED3,
    QS_QF_RESERVED2,
    QS_QF_RESERVED1,
    QS_QF_RESERVED0,

    // QK records
    QS_QK_MUTEX_LOCK,                             ///< the QK mutex was locked
    QS_QK_MUTEX_UNLOCK,                         ///< the QK mutex was unlocked
    QS_QK_SCHEDULE,      ///< the QK scheduler scheduled a new task to execute
    QS_QK_RESERVED6,
    QS_QK_RESERVED5,
    QS_QK_RESERVED4,
    QS_QK_RESERVED3,
    QS_QK_RESERVED2,
    QS_QK_RESERVED1,
    QS_QK_RESERVED0,

    // Miscellaneous QS records
    QS_SIG_DIC,                                   ///< signal dictionary entry
    QS_OBJ_DIC,                                   ///< object dictionary entry
    QS_FUN_DIC,                                 ///< function dictionary entry
    QS_USR_DIC,                           ///< user QS record dictionary entry
    QS_RESERVED4,
    QS_RESERVED3,
    QS_RESERVED2,
    QS_RESERVED1,
    QS_RESERVED0,
    QS_ASSERT,                                ///< assertion fired in the code

    // User records
    QS_USER                ///< the first record available for user QS records
};

/// \brief Specification of all QS records for the QS::filterOn() and
/// QS::filterOff()
uint8_t const QS_ALL_RECORDS = static_cast<uint8_t>(0xFF);

/// \brief Constant representing End-Of-Data condition returned from the
/// QS::getByte() function.
uint16_t const QS_EOD  = static_cast<uint16_t>(0xFFFF);


#if (QS_TIME_SIZE == 1)
    typedef uint8_t QSTimeCtr;
    #define QS_TIME_()   (QP_ QS::u8_(QP_ QS::onGetTime()))
#elif (QS_TIME_SIZE == 2)
    typedef uint16_t QSTimeCtr;
    #define QS_TIME_()   (QP_ QS::u16_(QP_ QS::onGetTime()))
#elif (QS_TIME_SIZE == 4)

    /// \brief The type of the QS time stamp
    ///
    /// This type determines the dynamic range of QS time stamps
    typedef uint32_t QSTimeCtr;

    /// \brief Internal macro to output time stamp to the QS record
    #define QS_TIME_()   (QP_ QS::u32_(QP_ QS::onGetTime()))
#else
    #error "QS_TIME_SIZE defined incorrectly, expected 1, 2, or 4"
#endif

/// \brief Quantum Spy logging facilities
///
/// This class groups together QS services. It has only static members and
/// should not be instantiated.
class QS {
public:

    /// \brief Get the current version of QS
    ///
    /// \return version of the QS as a constant 6-character string of the form
    /// x.y.zz, where x is a 1-digit major version number, y is a 1-digit
    /// minor version number, and zz is a 2-digit release number.
    static char_t const Q_ROM * Q_ROM_VAR getVersion(void);

    /// \brief Initialize the QS data buffer.
    ///
    /// This function should be called from QS_init() to provide QS with the
    /// data buffer. The first argument \a sto[] is the address of the memory
    /// block, and the second argument \a stoSize is the size of this block
    /// in bytes. Currently the size of the QS buffer cannot exceed 64KB.
    ///
    /// QS can work with quite small data buffers, but you will start losing
    /// data if the buffer is too small for the bursts of logging 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 "last-is-best" QS policy. The record sequence
    ///  counters and checksums on each record allow to easily detect data
    /// loss.
    static void initBuf(uint8_t sto[], uint32_t const stoSize);

    /// \brief Turn the global Filter on for a given record type \a rec.
    ///
    /// This function sets up the QS filter to enable the record type \a rec.
    /// The argument #QS_ALL_RECORDS specifies to filter-on all records.
    /// This function should be called indirectly through the macro
    /// #QS_FILTER_ON.
    ///
    /// \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 into the QS
    /// buffer.
    /// \sa QS_filterOff(), #QS_FILTER_SM_OBJ, #QS_FILTER_AO_OBJ,
    /// #QS_FILTER_MP_OBJ, #QS_FILTER_EQ_OBJ, and #QS_FILTER_TE_OBJ.
    static void filterOn(uint8_t const rec);

    /// \brief Turn the global Filter off for a given record type \a rec.
    ///
    /// This function sets up the QS filter to disable the record type \a rec.
    /// The argument #QS_ALL_RECORDS specifies to suppress all records.
    /// This function should be called indirectly through the macro
    /// #QS_FILTER_OFF.
    ///
    /// \note Filtering records 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
    /// into the QS buffer.
    /// \sa
    static void filterOff(uint8_t const rec);

    /// \brief Mark the begin of a QS record \a rec
    ///
    /// This function must be called at the beginning of each QS record.
    /// This function should be called indirectly through the macro #QS_BEGIN,
    /// or #QS_BEGIN_NOCRIT, depending if it's called in a normal code or from
    /// a critical section.
    static void begin(uint8_t const rec);

    /// \brief Mark the end of a QS record \a rec
    ///
    /// 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.
    static void end(void);

    // unformatted data elements output ......................................

    /// \brief output uint8_t data element without format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u8_(uint8_t const d);

    /// \brief Output uint16_t data element without format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u16_(uint16_t d);

    /// \brief Output uint32_t data element without format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u32_(uint32_t d);

    /// \brief Output zero-terminated ASCII string element without format
    /// information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void str_(char_t const *s);

    /// \brief Output zero-terminated ASCII string element  allocated in ROM
    /// without format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void str_ROM_(char_t const Q_ROM * Q_ROM_VAR s);

    // formatted data elements output ........................................

    /// \brief Output uint8_t data element with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u8(uint8_t const format, uint8_t const d);

    /// \brief output uint16_t data element with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u16(uint8_t const format, uint16_t d);

    /// \brief Output uint32_t data element with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u32(uint8_t const format, uint32_t d);

    /// \brief Output 32-bit floating point data element with format
    /// information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void f32(uint8_t const format, float32_t const d);

    /// \brief Output 64-bit floating point data element with format
    /// information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void f64(uint8_t const format, float64_t const d);

    /// \brief Output zero-terminated ASCII string element with format
    /// information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void str(char_t const *s);

    /// \brief Output zero-terminated ASCII string element allocated in ROM
    /// with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void str_ROM(char_t const Q_ROM * Q_ROM_VAR s);

    /// \brief Output memory block of up to 255-bytes with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void mem(uint8_t const *blk, uint8_t size);

#if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8)
    /// \brief Output uint64_t data element without format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u64_(uint64_t d);

    /// \brief Output uint64_t data element with format information
    /// \note This function is only to be used through macros, never in the
    /// client code directly.
    static void u64(uint8_t format, uint64_t d);
#endif

    // QS buffer access ......................................................

    /// \brief Byte-oriented interface to the QS data buffer.
    ///
    /// This function delivers one byte at a time from the QS data buffer.
    /// The function 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.
    static uint16_t getByte(void);

    /// \brief Block-oriented interface to the QS data buffer.
    ///
    /// 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 \a pNbytes. The argument \a pNbytes is also used as
    /// input to provide the maximum size of the data block that the caller
    /// can accept.
    ///
    /// If no bytes are available in the QS buffer when the function is
    /// called, the function returns a NULL pointer and sets the value
    /// pointed to by \a pNbytes to zero.
    ///
    /// \note Only the NULL return from 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
    /// QS::getBlock() again to obtain the rest of the data that "wrapped
    /// around" to the beginning of the QS data buffer.
    ///
    /// \note QS::getBlock() is NOT protected with a critical section.
    static uint8_t const *getBlock(uint16_t * const pNbytes);

    //////////////////////////////////////////////////////////////////////////
    // platform-dependent callback functions to be implemented by clients

    // platform-specific callback functions, need to be implemented by clients
    /// \brief Callback to startup the QS facility
    ///
    /// This is a platform-dependent "callback" function invoked through the
    /// macro #QS_INIT. You need to implement this function in your
    /// application. At a minimum, the function must configure the QS buffer
    /// by calling QS::initBuf(). Typically, you will also want to open/
    /// configure the QS output channel, such as a serial port, or a file.
    /// The void* argument \a arg can be used to pass parameter(s) needed to
    /// configure the output channel.
    ///
    /// The function returns true if the QS initialization was successful,
    /// or false if it failed.
    ///
    /// The following example illustrates an implementation of QS_onStartup():
    /// \include qs_startup.cpp
    static bool onStartup(void const *arg);

    /// \brief Callback to cleanup the QS facility
    ///
    /// This is a platform-dependent "callback" function invoked through the
    /// macro #QS_EXIT. You need to implement this function in your
    /// application. The main purpose of this function is to close the QS
    /// output channel, if necessary.
    static void onCleanup(void);

    /// \brief Callback to flush the QS trace data to the host
    ///
    /// This is a 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.
    static void onFlush(void);

    /// \brief Callback to obtain a timestamp for a QS record.
    ///
    /// This is a platform-dependent "callback" function invoked from the
    /// macro #QS_TIME_ to add the time stamp to the QS record.
    ///
    /// \note Some of the pre-defined QS records from QP do not output the
    /// time stamp. However, ALL user records do output the time stamp.
    /// \note QS::onGetTime() is called in a critical section and should not
    /// exit critical section.
    ///
    /// The following example shows using a system call to implement QS
    /// time stamping:
    /// \include qs_onGetTime.cpp
    static QSTimeCtr onGetTime(void);

    //////////////////////////////////////////////////////////////////////////
    // Global and Local QS filters
    static uint8_t glbFilter_[32];                ///< global on/off QS filter
    static void const *smObj_;         ///< state machine for QEP local filter
    static void const *aoObj_;       ///< active object for QF/QK local filter
    static void const *mpObj_;            ///<  event pool for QF local filter
    static void const *eqObj_;             ///<  raw queue for QF local filter
    static void const *teObj_;            ///<  time event for QF local filter
    static void const *apObj_;///<  generic object Application QF local filter

    //////////////////////////////////////////////////////////////////////////
    // Miscallaneous
                                    /// tick counter for the QS_QF_TICK record
    static QSTimeCtr tickCtr_;
};

/// \brief Enumerates data formats recognized by QS
///
/// QS uses this enumeration is used only internally for the formatted user
/// data elements.
enum QSType {
    QS_I8_T,                                  ///< signed 8-bit integer format
    QS_U8_T,                                ///< unsigned 8-bit integer format
    QS_I16_T,                                ///< signed 16-bit integer format
    QS_U16_T,                              ///< unsigned 16-bit integer format
    QS_I32_T,                                ///< signed 32-bit integer format
    QS_U32_T,                              ///< unsigned 32-bit integer format
    QS_F32_T,                                ///< 32-bit floating point format
    QS_F64_T,                                ///< 64-bit floating point format
    QS_STR_T,                         ///< zero-terminated ASCII string format
    QS_MEM_T,                         ///< up to 255-bytes memory block format
    QS_SIG_T,                                         ///< event signal format
    QS_OBJ_T,                                       ///< object pointer format
    QS_FUN_T,                                     ///< function pointer format
    QS_I64_T,                                ///< signed 64-bit integer format
    QS_U64_T,                              ///< unsigned 64-bit integer format
    QS_U32_HEX_T                    ///< unsigned 32-bit integer in hex format
};

/// \brief critical section nesting level
///
/// \note Not to be used by Clients directly, only in ports of QF
extern uint8_t QF_critNest_;

QP_END_


//////////////////////////////////////////////////////////////////////////////
// Macros for adding QS instrumentation to the client code

/// \brief Initialize the QS facility.
///
/// 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 QS::onStartup(), example of setting up a QS filter in #QS_FILTER_IN
#define QS_INIT(arg_)           (QP_ QS::onStartup(arg_))

/// \brief Cleanup the QS facility.
///
/// 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 QS::onCleanup()
#define QS_EXIT()               (QP_ QS::onCleanup())

/// \brief Global Filter ON for a given record type \a rec.
///
/// This macro provides an indirection layer to call QS::filterOn() if #Q_SPY
/// is defined, or do nothing if #Q_SPY is not defined.
///
/// The following example shows how to use QS filters:
/// \include qs_filter.cpp
#define QS_FILTER_ON(rec_)      (QP_ QS::filterOn(static_cast<uint8_t>(rec_)))

/// \brief Global filter OFF for a given record type \a rec.
///
/// This macro provides an indirection layer to call QS::filterOff() if #Q_SPY
/// is defined, or do nothing if #Q_SPY is not defined.
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_OFF(rec_)    (QP_ QS::filterOff(static_cast<uint8_t>(rec_)))

/// \brief Local Filter for a given state machine object \a obj_.
///
/// This macro sets up the state machine object local filter if #Q_SPY is
/// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
/// is the pointer to the state machine object that you want to monitor.
///
/// The state machine object filter allows you to filter QS records pertaining
/// only to a given state machine object. With this filter disabled, QS will
/// output records from all state machines in your application. The object
/// filter is disabled by setting the state machine pointer to NULL.
///
/// The state machine filter affects the following QS records:
/// ::QS_QEP_STATE_ENTRY, ::QS_QEP_STATE_EXIT, ::QS_QEP_STATE_INIT,
/// ::QS_QEP_INIT_TRAN, ::QS_QEP_INTERN_TRAN, ::QS_QEP_TRAN,
/// and ::QS_QEP_IGNORED.
///
/// \note Because active objects are state machines at the same time,
/// the state machine filter (#QS_FILTER_SM_OBJ) pertains to active
/// objects as well. However, the state machine filter is more general,
/// because it can be used only for state machines that are not active
/// objects, such as "Orthogonal Components".
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_SM_OBJ(obj_)  (QP_ QS::smObj_ = (obj_))

/// \brief Local Filter for a given active object \a obj_.
///
/// This macro sets up the active object local filter if #Q_SPY is defined,
/// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
/// pointer to the active object that you want to monitor.
///
/// The active object filter allows you to filter QS records pertaining
/// only to a given active object. With this filter disabled, QS will
/// output records from all active objects in your application. The object
/// filter is disabled by setting the active object pointer \a obj_ to NULL.
///
/// The active object filter affects the following QS records:
/// ::QS_QF_ACTIVE_ADD, ::QS_QF_ACTIVE_REMOVE, ::QS_QF_ACTIVE_SUBSCRIBE,
/// ::QS_QF_ACTIVE_UNSUBSCRIBE, ::QS_QF_ACTIVE_POST_FIFO,
/// ::QS_QF_ACTIVE_POST_LIFO, ::QS_QF_ACTIVE_GET, and ::QS_QF_ACTIVE_GET_LAST.
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_AO_OBJ(obj_)  (QP_ QS::aoObj_ = (obj_))

/// \brief Local Filter for a given memory pool object \a obj_.
///
/// This macro sets up the memory pool object local filter if #Q_SPY is
/// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
/// is the pointer to the memory buffer used during the initialization of the
/// event pool with QF::poolInit().
///
/// The memory pool filter allows you to filter QS records pertaining
/// only to a given memory pool. With this filter disabled, QS will
/// output records from all memory pools in your application. The object
/// filter is disabled by setting the memory pool pointer \a obj_ to NULL.
///
/// The memory pool filter affects the following QS records:
/// ::QS_QF_MPOOL_INIT, ::QS_QF_MPOOL_GET, and ::QS_QF_MPOOL_PUT.
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_MP_OBJ(obj_)  (QP_ QS::mpObj_ = (obj_))

/// \brief Filter for a given event queue object \a obj_.
///
/// This macro sets up the event queue object filter if #Q_SPY is defined,
/// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
/// pointer to the "raw" thread-safe queue object you want to monitor.
///
/// The event queue filter allows you to filter QS records pertaining
/// only to a given event queue. With this filter disabled, QS will
/// output records from all event queues in your application. The object
/// filter is disabled by setting the event queue pointer \a obj_ to NULL.
///
/// The event queue filter affects the following QS records:
/// ::QS_QF_EQUEUE_INIT, ::QS_QF_EQUEUE_POST_FIFO, ::QS_QF_EQUEUE_POST_LIFO,
/// ::QS_QF_EQUEUE_GET, and ::QS_QF_EQUEUE_GET_LAST.
///
/// \sa Example of using QS filters in #QS_FILTER_IN documentation
#define QS_FILTER_EQ_OBJ(obj_)  (QP_ QS::eqObj_ = (obj_))

/// \brief Local Filter for a given time event object \a obj_.
///
/// This macro sets up the time event object local filter if #Q_SPY is
/// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
/// is the pointer to the time event object you want to monitor.
///
/// The time event filter allows you to filter QS records pertaining
/// only to a given time event. With this filter disabled, QS will
/// output records from all time events in your application. The object
/// filter is disabled by setting the time event pointer \a obj_ to NULL.
///
/// The time event filter affects the following QS records:
/// ::QS_QF_TIMEEVT_ARM, ::QS_QF_TIMEEVT_AUTO_DISARM,
/// ::QS_QF_TIMEEVT_DISARM_ATTEMPT, ::QS_QF_TIMEEVT_DISARM,
/// ::QS_QF_TIMEEVT_REARM, ::QS_QF_TIMEEVT_POST, and ::QS_QF_TIMEEVT_PUBLISH.
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_TE_OBJ(obj_)  (QP_ QS::teObj_ = (obj_))

/// \brief Local Filter for a generic application object \a obj_.
///
/// This macro sets up the local application object filter if #Q_SPY is
/// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
/// is the pointer to the application object you want to monitor.
///
/// The application object filter allows you to filter QS records pertaining
/// only to a given application object. With this filter disabled, QS will
/// output records from all application-records enabled by the global filter.
/// The local filter is disabled by setting the time event pointer \a obj_
/// to NULL.
///
/// \sa Example of using QS filters in #QS_FILTER_ON documentation
#define QS_FILTER_AP_OBJ(obj_)  (QP_ QS::apObj_ = (obj_))


//////////////////////////////////////////////////////////////////////////////
// Macros to generate user QS records

#define QS_GLB_FILTER_(rec_) \
    ((QP_ QS::glbFilter_[static_cast<uint8_t>(rec_) >> 3] \
      & (static_cast<uint8_t>(1U << (static_cast<uint8_t>(rec_) \
                                     & static_cast<uint8_t>(7))))) \
             != static_cast<uint8_t>(0))

/// \brief Begin a QS user record without entering critical section.
#define QS_BEGIN_NOCRIT(rec_, obj_) \
    if (QS_GLB_FILTER_(rec_) \
        && ((QP_ QS::apObj_ == static_cast<void *>(0)) \
            || (QP_ QS::apObj_ == (obj_)))) \
    { \
        QP_ QS::begin(static_cast<uint8_t>(rec_)); \
        QS_TIME_();

/// \brief End a QS user record without exiting critical section.
#define QS_END_NOCRIT() \
    QS_END_NOCRIT_()

                                               // QS-specific critical section
#ifndef QF_CRIT_STAT_TYPE
    /// \brief This is an internal macro for defining the critical section
    /// status type.
    ///
    /// The purpose of this macro is to enable writing the same code for the
    /// case when critical sectgion 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_

    /// \brief This is an internal macro for entering a critical section.
    ///
    /// The purpose of this macro is to enable writing the same code for the
    /// case when critical sectgion 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_ENTRY_()    QF_CRIT_ENTRY(dummy)

    /// \brief This is an internal macro for exiting a cricial section.
    ///
    /// The purpose of this macro is to enable writing the same code for the
    /// case when critical sectgion 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_EXIT_()     QF_CRIT_EXIT(dummy)

#else
    #define QS_CRIT_STAT_       QF_CRIT_STAT_TYPE critStat_;
    #define QS_CRIT_ENTRY_()    QF_CRIT_ENTRY(critStat_)
    #define QS_CRIT_EXIT_()     QF_CRIT_EXIT(critStat_)
#endif

/// \brief Begin a user QS record with entering critical section.
///
/// The following example shows how to build a user QS record using the
/// macros #QS_BEGIN, #QS_END, and the formatted output macros: #QS_U8 and
/// #QS_STR.
/// \include qs_user.cpp
/// \note Must always be used in pair with #QS_END
#define QS_BEGIN(rec_, obj_) \
    if (QS_GLB_FILTER_(rec_) \
        && ((QP_ QS::apObj_ == static_cast<void *>(0)) \
            || (QP_ QS::apObj_ == (obj_)))) \
    { \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(rec_)); \
        QS_TIME_();

/// \brief End a QS record with exiting critical section.
/// \sa example for #QS_BEGIN
/// \note Must always be used in pair with #QS_BEGIN
#define QS_END() \
    QS_END_()


//////////////////////////////////////////////////////////////////////////////
// Macros for use inside other macros or internally in the QP code

/// \brief Internal QS macro to begin a QS record with entering critical
/// section.
/// \note This macro is intended to use only inside QP components and NOT
/// at the application level. \sa #QS_BEGIN
#define QS_BEGIN_(rec_, objFilter_, obj_) \
    if (QS_GLB_FILTER_(rec_) \
        && (((objFilter_) == static_cast<void *>(0)) \
            || ((objFilter_) == (obj_)))) \
    { \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(rec_));

/// \brief  Internal QS macro to end a QS record with exiting 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_() \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
    }

/// \brief Internal QS macro to begin a QS record without entering critical
/// section.
/// \note This macro is intended to use only inside QP components and NOT
/// at the application level. \sa #QS_BEGIN_NOCRIT
#define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_) \
    if (QS_GLB_FILTER_(rec_) \
        && (((objFilter_) == static_cast<void *>(0)) \
            || ((objFilter_) == (obj_)))) \
    { \
        QP_ QS::begin(static_cast<uint8_t>(rec_));

/// \brief Internal QS macro to end a QS record without exiting 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_() \
        QP_ QS::end(); \
    }

#if (Q_SIGNAL_SIZE == 1)
    /// \brief 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_(sig_)    (QP_ QS::u8_(static_cast<uint8_t>(sig_))))
#elif (Q_SIGNAL_SIZE == 2)
    #define QS_SIG_(sig_)    (QP_ QS::u16_(static_cast<uint16_t>(sig_)))
#elif (Q_SIGNAL_SIZE == 4)
    #define QS_SIG_(sig_)    (QP_ QS::u32_(static_cast<uint32_t>(sig_)))
#endif

/// \brief Internal QS macro to output an unformatted uint8_t data element
#define QS_U8_(data_)        (QP_ QS::u8_(data_))

/// \brief Internal QS macro to output an unformatted uint16_t data element
#define QS_U16_(data_)       (QP_ QS::u16_(data_))

/// \brief Internal QS macro to output an unformatted uint32_t data element
#define QS_U32_(data_)       (QP_ QS::u32_(data_))


#if (QS_OBJ_PTR_SIZE == 1)
    #define QS_OBJ_(obj_)    (QP_ QS::u8_(reinterpret_cast<uint8_t>(obj_)))
#elif (QS_OBJ_PTR_SIZE == 2)
    #define QS_OBJ_(obj_)    (QP_ QS::u16_(reinterpret_cast<uint16_t>(obj_)))
#elif (QS_OBJ_PTR_SIZE == 4)
    #define QS_OBJ_(obj_)    (QP_ QS::u32_(reinterpret_cast<uint32_t>(obj_)))
#elif (QS_OBJ_PTR_SIZE == 8)
    #define QS_OBJ_(obj_)    (QP_ QS::u64_(reinterpret_cast<uint64_t>(obj_)))
#else

    /// \brief Internal QS macro to output an unformatted object pointer
    /// data element
    /// \note the size of the pointer depends on the macro #QS_OBJ_PTR_SIZE.
    /// If the size is not defined the size of pointer is assumed 4-bytes.
    #define QS_OBJ_(obj_)    (QP_ QS::u32_(reinterpret_cast<uint32_t>(obj_)))
#endif


#if (QS_FUN_PTR_SIZE == 1)
    #define QS_FUN_(fun_)    (QP_ QS::u8_(reinterpret_cast<uint8_t>(fun_)))
#elif (QS_FUN_PTR_SIZE == 2)
    #define QS_FUN_(fun_)    (QP_ QS::u16_(reinterpret_cast<uint16_t>(fun_)))
#elif (QS_FUN_PTR_SIZE == 4)
    #define QS_FUN_(fun_)    (QP_ QS::u32_(reinterpret_cast<uint32_t>(fun_)))
#elif (QS_FUN_PTR_SIZE == 8)
    #define QS_FUN_(fun_)    (QP_ QS::u64_(reinterpret_cast<uint64_t>(fun_)))
#else

    /// \brief 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_(fun_)    (QP_ QS::u32_(reinterpret_cast<uint32_t>(fun_)))
#endif

/// \brief Internal QS macro to output a zero-terminated ASCII string
/// data element
#define QS_STR_(msg_)        (QP_ QS::str_(msg_))

/// \brief Internal QS macro to output a zero-terminated ASCII string
/// allocated in ROM data element
#define QS_STR_ROM_(msg_)    (QP_ QS::str_ROM_(msg_))

//////////////////////////////////////////////////////////////////////////////
// Macros for use in the client code

/// \brief Output formatted int8_t to the QS record
#define QS_I8(width_, data_) \
    (QP_ QS::u8(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_I8_T)), (data_)))

/// \brief Output formatted uint8_t to the QS record
#define QS_U8(width_, data_) \
    (QP_ QS::u8(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_U8_T)), (data_)))

/// \brief Output formatted int16_t to the QS record
#define QS_I16(width_, data_) \
    (QP_ QS::u16(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_I16_T)), (data_)))

/// \brief Output formatted uint16_t to the QS record
#define QS_U16(width_, data_) \
    (QP_ QS::u16(static_cast<uint8_t>((((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_U16_T)), (data_)))

/// \brief Output formatted int32_t to the QS record
#define QS_I32(width_, data_) \
    (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_I32_T)), (data_)))

/// \brief Output formatted uint32_t to the QS record
#define QS_U32(width_, data_) \
    (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_U32_T)), (data_)))

/// \brief Output formatted 32-bit floating point number to the QS record
#define QS_F32(width_, data_) \
    QP_ QS::f32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_F32_T)), (data_)))

/// \brief Output formatted 64-bit floating point number to the QS record
#define QS_F64(width_, data_) \
    (QP_ QS::f64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_F64_T)), (data_)))

/// \brief Output formatted int64_t to the QS record
#define QS_I64(width_, data_) \
    (QP_ QS::u64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_I64_T)), (data_)))

/// \brief Output formatted uint64_t to the QS record
#define QS_U64(width_, data_) \
    (QP_ QS::u64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_U64_T)), (data_)))

/// \brief Output formatted uint32_t to the QS record
#define QS_U32_HEX(width_, data_) \
    (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
        | static_cast<uint8_t>(QP_ QS_U32_HEX_T)), (data_)))

/// \brief Output formatted zero-terminated ASCII string to the QS record
#define QS_STR(str_)            (QP_ QS::str(str_))

/// \brief Output formatted zero-terminated ASCII string from ROM
/// to the QS record
#define QS_STR_ROM(str_)        (QP_ QS::str_ROM(str_))

/// \brief Output formatted memory block of up to 255 bytes to the QS
/// record
#define QS_MEM(mem_, size_)     (QP_ QS::mem((mem_), (size_)))


#if (QS_OBJ_PTR_SIZE == 1)
    #define QS_OBJ(obj_)        (QP_ QS::u8(QS_OBJ_T, (uint8_t)(obj_)))
#elif (QS_OBJ_PTR_SIZE == 2)
    #define QS_OBJ(obj_)        (QP_ QS::u16(QS_OBJ_T, (uint16_t)(obj_)))
#elif (QS_OBJ_PTR_SIZE == 4)
    #define QS_OBJ(obj_)        (QP_ QS::u32(QS_OBJ_T, (uint32_t)(obj_)))
#elif (QS_OBJ_PTR_SIZE == 8)
    #define QS_OBJ(obj_)        (QP_ QS::u64(QS_OBJ_T, (uint64_t)(obj_)))
#else
    /// \brief Output formatted object pointer to the QS record
    #define QS_OBJ(obj_)        (QP_ QS::u32(QS_OBJ_T, (uint32_t)(obj_)))
#endif


#if (QS_FUN_PTR_SIZE == 1)
    #define QS_FUN(fun_)        (QP_ QS::u8(QS_FUN_T, (uint8_t)(fun_)))
#elif (QS_FUN_PTR_SIZE == 2)
    #define QS_FUN(fun_)        (QP_ QS::u16(QS_FUN_T, (uint16_t)(fun_)))
#elif (QS_FUN_PTR_SIZE == 4)
    #define QS_FUN(fun_)        (QP_ QS::u32(QS_FUN_T, (uint32_t)(fun_)))
#elif (QS_FUN_PTR_SIZE == 8)
    #define QS_FUN(fun_)        (QP_ QS::u64(QS_FUN_T, (uint64_t)(fun_)))
#else
    /// \brief Output formatted function pointer to the QS record
    #define QS_FUN(fun_)        (QP_ QS::u32(QS_FUN_T, (uint32_t)(fun_)))
#endif


/// \brief Reset the QS session.
///
/// This trace record should be generated at the beginning of the QS session.
/// It informs the QSPY host application that the new session has been started.
#define QS_RESET() do { \
    if (QS_GLB_FILTER_(QP_ QS_QP_RESET)) { \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(QP_ QS_QP_RESET)); \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
        QP_ QS::onFlush(); \
    } \
} while (false)

/// \brief Output signal dictionary record
///
/// 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.
///
/// Providing a signal 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 names.
///
/// A signal dictionary entry is associated with both the signal value \a sig_
/// and the state machine \a 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 "global" signals that have the same meaning in all state machines
/// (such as globally published signals), you can specify a signal dictionary
/// entry with the \a obj_ parameter set to NULL.
///
/// 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 ("me" \a obj_ pointer). The EAT_SIG signal, on the other
/// hand, is global (0 \a obj_ pointer):
/// \include qs_sigDic.cpp
///
/// \note The QSpy log utility must capture the signal dictionary record
/// in order to use the human-readable information. You need to connect to
/// the target before the dictionary entries have been transmitted.
///
/// 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
///
/// The following QSpy log example shows the same sequence of records, but
/// with dictionary records removed. The human-readable signal names are not
/// available.
/// \include qs_sigLog0.txt
#define QS_SIG_DICTIONARY(sig_, obj_) do { \
    if (QS_GLB_FILTER_(QP_ QS_SIG_DIC)) { \
        static char_t const Q_ROM Q_ROM_VAR sig_name_[] = #sig_; \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(QP_ QS_SIG_DIC)); \
        QS_SIG_(sig_); \
        QS_OBJ_(obj_); \
        QS_STR_ROM_(&sig_name_[0]); \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
        QP_ QS::onFlush(); \
    } \
} while (false)

/// \brief Output object dictionary record
///
/// An object dictionary record associates the binary address of an object
/// in the target's memory with the human-readable name of the object.
///
/// Providing an object 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 object names.
///
/// The following example shows the definition of object dictionary entry
/// for the Table active object:
/// \include qs_objDic.cpp
#define QS_OBJ_DICTIONARY(obj_) do { \
    if (QS_GLB_FILTER_(QP_ QS_OBJ_DIC)) { \
        static char_t const Q_ROM Q_ROM_VAR obj_name_[] = #obj_; \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(QP_ QS_OBJ_DIC)); \
        QS_OBJ_(obj_); \
        QS_STR_ROM_(&obj_name_[0]); \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
        QP_ QS::onFlush(); \
    } \
} while (false)

/// \brief Output function dictionary record
///
/// 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.
#define QS_FUN_DICTIONARY(fun_) do { \
    if (QS_GLB_FILTER_(QP_ QS_FUN_DIC)) { \
        static char_t const Q_ROM Q_ROM_VAR fun_name_[] = #fun_; \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(QP_ QS_FUN_DIC)); \
        QS_FUN_(fun_); \
        QS_STR_ROM_(&fun_name_[0]); \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
        QP_ QS::onFlush(); \
    } \
} while (false)

/// \brief Output user QS rectord dictionary record
///
/// A user QS record dictionary record associates the numerical value of a
/// user record with the human-readable identifier.
#define QS_USR_DICTIONARY(rec_) do { \
    if (QS_GLB_FILTER_(QP_ QS_USR_DIC)) { \
        static char_t const Q_ROM Q_ROM_VAR usr_name_[] = #rec_; \
        QS_CRIT_STAT_ \
        QS_CRIT_ENTRY_(); \
        QP_ QS::begin(static_cast<uint8_t>(QP_ QS_USR_DIC)); \
        QS_U8_(static_cast<uint8_t>(rec_)); \
        QS_STR_ROM_(&usr_name_[0]); \
        QP_ QS::end(); \
        QS_CRIT_EXIT_(); \
        QP_ QS::onFlush(); \
    } \
} while (false)

/// \brief Output the assertion violation
#define QS_ASSERTION(module_, loc_) do { \
    QS_BEGIN_NOCRIT_(QP_ QS_ASSERT, \
        static_cast<void *>(0), static_cast<void *>(0)) \
        QS_TIME_(); \
        QS_U16_(static_cast<uint16_t>(loc_)); \
        QS_STR_ROM_(module_); \
    QS_END_NOCRIT_() \
    QP_ QS::onFlush(); \
} while (false)

/// \brief Flush the QS trace data to the host
///
/// This macro invokes the 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.
#define QS_FLUSH()   (QP_ QS::onFlush())

/// \brief Output the critical section entry record
#define QF_QS_CRIT_ENTRY() \
    QS_BEGIN_NOCRIT_(QP_ QS_QF_CRIT_ENTRY, \
        static_cast<void *>(0), static_cast<void *>(0)) \
        QS_TIME_(); \
        QS_U8_((uint8_t)(++QF_critNest_)); \
    QS_END_NOCRIT_()

/// \brief Output the critical section exit record
#define QF_QS_CRIT_EXIT() \
    QS_BEGIN_NOCRIT_(QP_ QS_QF_CRIT_EXIT, \
        static_cast<void *>(0), static_cast<void *>(0)) \
        QS_TIME_(); \
        QS_U8_((uint8_t)(QF_critNest_--)); \
    QS_END_NOCRIT_()

/// \brief Output the interrupt entry record
#define QF_QS_ISR_ENTRY(isrnest_, prio_) \
    QS_BEGIN_NOCRIT_(QP_ QS_QF_ISR_ENTRY, \
        static_cast<void *>(0), static_cast<void *>(0)) \
        QS_TIME_(); \
        QS_U8_(isrnest_); \
        QS_U8_(prio_); \
    QS_END_NOCRIT_()

/// \brief Output the interrupt exit record
#define QF_QS_ISR_EXIT(isrnest_, prio_) \
    QS_BEGIN_NOCRIT_(QP_ QS_QF_ISR_EXIT,  \
        static_cast<void *>(0), static_cast<void *>(0)) \
        QS_TIME_(); \
        QS_U8_(isrnest_); \
        QS_U8_(prio_); \
    QS_END_NOCRIT_()

/// \brief Execute an action that is only necessary for QS output
#define QF_QS_ACTION(act_)      (act_)

#else                                                                 // Q_SPY

// qs_dummy.h ================================================================
/// \brief Dummy definitions of the QS macros that avoid code generation from
/// the QS instrumentation.

#define QS_INIT(arg_)                   (true)
#define QS_EXIT()                       ((void)0)
#define QS_DUMP()                       ((void)0)
#define QS_RESET()                      ((void)0)
#define QS_FILTER_ON(rec_)              ((void)0)
#define QS_FILTER_OFF(rec_)             ((void)0)
#define QS_FILTER_SM_OBJ(obj_)          ((void)0)
#define QS_FILTER_AO_OBJ(obj_)          ((void)0)
#define QS_FILTER_MP_OBJ(obj_)          ((void)0)
#define QS_FILTER_EQ_OBJ(obj_)          ((void)0)
#define QS_FILTER_TE_OBJ(obj_)          ((void)0)
#define QS_FILTER_AP_OBJ(obj_)          ((void)0)

#define QS_GET_BYTE(pByte_)             (static_cast<uint16_t>(0xFFFFU))
#define QS_GET_BLOCK(pSize_)            (static_cast<uint8_t *>(0))

#define QS_BEGIN(rec_, obj_)            if (false) {
#define QS_END()                        }
#define QS_BEGIN_NOCRIT(rec_, obj_)     if (false) {
#define QS_END_NOCRIT()                 }

#define QS_I8(width_, data_)            ((void)0)
#define QS_U8(width_, data_)            ((void)0)
#define QS_I16(width_, data_)           ((void)0)
#define QS_U16(width_, data_)           ((void)0)
#define QS_I32(width_, data_)           ((void)0)
#define QS_U32(width_, data_)           ((void)0)
#define QS_F32(width_, data_)           ((void)0)
#define QS_F64(width_, data_)           ((void)0)
#define QS_U64(width_, data_)           ((void)0)
#define QS_STR(str_)                    ((void)0)
#define QS_U32_HEX(width_, data_)       ((void)0)
#define QS_STR_ROM(str_)                ((void)0)
#define QS_MEM(mem_, size_)             ((void)0)
#define QS_SIG(sig_, obj_)              ((void)0)
#define QS_OBJ(obj_)                    ((void)0)
#define QS_FUN(fun_)                    ((void)0)

#define QS_SIG_DICTIONARY(sig_, obj_)   ((void)0)
#define QS_OBJ_DICTIONARY(obj_)         ((void)0)
#define QS_FUN_DICTIONARY(fun_)         ((void)0)
#define QS_USR_DICTIONARY(rec_)         ((void)0)
#define QS_ASSERTION(module_, loc_)     ((void)0)
#define QS_FLUSH()                      ((void)0)

// internal QS macros used only in the QP components .........................
#define QS_CRIT_STAT_
#define QS_BEGIN_(rec_, refObj_, obj_)  if (false) {
#define QS_END_()                       }
#define QS_BEGIN_NOCRIT_(rec_, refObj_, obj_) if (false) {
#define QS_END_NOCRIT_()                }
#define QS_U8_(data_)                   ((void)0)
#define QS_U16_(data_)                  ((void)0)
#define QS_U32_(data_)                  ((void)0)
#define QS_U64_(data_)                  ((void)0)
#define QS_TIME_()                      ((void)0)
#define QS_SIG_(sig_)                   ((void)0)
#define QS_EVS_(size_)                  ((void)0)
#define QS_OBJ_(obj_)                   ((void)0)
#define QS_FUN_(fun_)                   ((void)0)
#define QS_EQC_(ctr_)                   ((void)0)
#define QS_MPC_(ctr_)                   ((void)0)
#define QS_MPS_(size_)                  ((void)0)
#define QS_TEC_(ctr_)                   ((void)0)

#define QF_QS_CRIT_ENTRY()              ((void)0)
#define QF_QS_CRIT_EXIT()               ((void)0)
#define QF_QS_ISR_ENTRY(isrnest_, prio_) ((void)0)
#define QF_QS_ISR_EXIT(isrnest_, prio_) ((void)0)
#define QF_QS_ACTION(act_)              ((void)0)

#endif                                                                // Q_SPY

// qassert.h =================================================================
/* \brief Customizable QP assertions.
*
* Defines customizable and memory-efficient assertions applicable to
* embedded systems. This header file can be used in C, C++, and mixed C/C++
* programs.
*
* \note The preprocessor switch Q_NASSERT disables checking assertions.
* In particular macros #Q_ASSERT, #Q_REQUIRE, #Q_ENSURE, #Q_INVARIANT,
* #Q_ERROR as well as  #Q_ASSERT_ID, #Q_REQUIRE_ID, #Q_ENSURE_ID,
* #Q_INVARIANT_ID, and #Q_ERROR_ID do NOT evaluate the test condition
* passed as the argument to these macros. One notable exception is the
* macro #Q_ALLEGE, that still evaluates the test condition, but does
* not report assertion failures when the switch Q_NASSERT is defined.
*/
#ifdef Q_NASSERT          /* Q_NASSERT defined--assertion checking disabled */

    #define Q_DEFINE_THIS_FILE
    #define Q_DEFINE_THIS_MODULE(name_)
    #define Q_ASSERT(test_)             ((void)0)
    #define Q_ASSERT_ID(id_, test_)     ((void)0)
    #define Q_ALLEGE(test_)             ((void)(test_))
    #define Q_ALLEGE_ID(id_, test_)     ((void)(test_))
    #define Q_ERROR()                   ((void)0)
    #define Q_ERROR_ID(id_)             ((void)0)

#else                  /* Q_NASSERT not defined--assertion checking enabled */

    #ifdef __cplusplus
        extern "C" {
    #endif

    /** \brief Type for line numbers.
    *
    * This typedef specifies strong type for line numbers. The use of this
    * type, rather than plain 'int', is in compliance with the MISRA-C 2004
    * Rule 6.3(adv).
    */
    typedef int int_t;

    /** callback invoked in case the condition passed to #Q_ASSERT,
    * #Q_REQUIRE, #Q_ENSURE, #Q_ERROR, #Q_ALLEGE as well as #Q_ASSERT_ID,
    * #Q_REQUIRE_ID, #Q_ENSURE_ID, #Q_ERROR_ID, and #Q_ALLEGE_ID evaluates
    * to FALSE.
    *
    * \param file name where the assertion failed
    * \param line number at which the assertion failed
    */
    void Q_onAssert(char_t const Q_ROM * const Q_ROM_VAR file,
                    int_t const line);

    #ifdef __cplusplus
        }
    #endif

    /** Place this macro at the top of each C/C++ module to define the file
    * name string using __FILE__ (NOTE: __FILE__ might contain lengthy path
    * name). This file name will be used in reporting assertions in this file.
    */
    #define Q_DEFINE_THIS_FILE \
        static char_t const Q_ROM Q_ROM_VAR l_this_file[] = __FILE__;

    /** Place this macro at the top of each C/C++ module to define the module
    * name as the argument \a name_. This file name will be used in reporting
    * assertions in this file.
    */
    #define Q_DEFINE_THIS_MODULE(name_) \
        static char_t const Q_ROM Q_ROM_VAR l_this_file[] = name_;

    /** General purpose assertion that makes sure the \a test_ argument is
    * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
    * to FALSE.
    * \note the \a test_ is NOT evaluated if assertions are disabled with
    * the Q_NASSERT switch.
    * \sa #Q_ASSERT_ID
    */
    #define Q_ASSERT(test_) \
        ((test_) ? (void)0 : Q_onAssert(&l_this_file[0], (int_t)__LINE__))

    /** General purpose assertion that makes sure the \a test_ argument is
    * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
    * to FALSE. The argument \a id_ is the ID number (unique within
    * the file) of the assertion. This assertion style is better suited
    * for unit testig, because it avoids the volatility of line numbers
    * for indentifying assertions.
    * \note the \a test_ is NOT evaluated if assertions are disabled with
    * the Q_NASSERT switch.
    * \sa #Q_ASSERT
    */
    #define Q_ASSERT_ID(id_, test_) \
        ((test_) ? (void)0 : Q_onAssert(&l_this_file[0], (int_t)(id_))

    /** General purpose assertion that ALWAYS evaluates the \a test_
    * argument and calls the Q_onAssert() callback if the \a test_
    * evaluates to FALSE.
    * \note the \a test_ argument IS always evaluated even when assertions
    * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
    * defined, the Q_onAssert() callback is NOT called, even if the
    * \a test_ evaluates to FALSE.
    * \sa #Q_ALLEGE_ID
    */
    #define Q_ALLEGE(test_)    Q_ASSERT(test_)

    /** General purpose assertion that ALWAYS evaluates the \a test_
    * argument and calls the Q_onAssert() callback if the \a test_
    * evaluates to FALSE. This assertion style is better suited
    * for unit testig, because it avoids the volatility of line numbers
    * for indentifying assertions.
    * \note the \a test_ argument IS always evaluated even when assertions
    * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
    * defined, the Q_onAssert() callback is NOT called, even if the
    * \a test_ evaluates to FALSE.
    * \sa #Q_ALLEGE
    */
    #define Q_ALLEGE_ID(id_, test_) Q_ASSERT_ID(id_, test_)

    /** Assertion that always calls the Q_onAssert() callback if
    * ever executed.
    * \note can be disabled with the Q_NASSERT switch.
    * \sa #Q_ERROR_ID
    */
    #define Q_ERROR() \
        Q_onAssert(&l_this_file[0], (int_t)__LINE__)

    /** Assertion that always calls the Q_onAssert() callback if
    * ever executed. This assertion style is better suited for unit
    * testig, because it avoids the volatility of line numbers for
    * indentifying assertions.
    * \note can be disabled with the Q_NASSERT switch.
    * \sa #Q_ERROR
    */
    #define Q_ERROR_ID(id_) \
        Q_onAssert(l_this_file, (int_t)(id_))

#endif                                                         /* Q_NASSERT */

/** Assertion that checks for a precondition. This macro is equivalent to
* #Q_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_REQUIRE_ID
*/
#define Q_REQUIRE(test_)         Q_ASSERT(test_)

/** Assertion that checks for a precondition. This macro is equivalent to
* #Q_ASSERT_ID, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_REQUIRE
*/
#define Q_REQUIRE_ID(id_, test_) Q_ASSERT_ID(id_, test_)

/** Assertion that checks for a postcondition. This macro is equivalent to
* #Q_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_ENSURE_ID
*/
#define Q_ENSURE(test_)          Q_ASSERT(test_)

/** Assertion that checks for a postcondition. This macro is equivalent to
* #Q_ASSERT_ID, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_ENSURE
*/
#define Q_ENSURE_ID(id_, test_)  Q_ASSERT_ID(id_, test_)

/** Assertion that checks for an invariant. This macro is equivalent to
* #Q_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_INVARIANT_ID
*/
#define Q_INVARIANT(test_)       Q_ASSERT(test_)

/** Assertion that checks for an invariant. This macro is equivalent to
* #Q_ASSERT_ID, except the name provides a better documentation of the
* intention of this assertion.
* \sa #Q_INVARIANT
*/
#define Q_INVARIANT_ID(id_, test_) Q_ASSERT_ID(id_, test_)

/** Compile-time assertion exploits the fact that in C/C++ a dimension of
* an array cannot be negative. The following declaration causes a compilation
* error if the compile-time expression (\a test_) is not TRUE. The assertion
* has no runtime side effects.
*/
#define Q_ASSERT_COMPILE(test_) \
    extern int_t Q_assert_compile[(test_) ? 1 : -1]

#endif                                                                 // qp_h