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.

Files at this revision

API Documentation at this revision

Comitter:
QL
Date:
Wed Feb 09 14:46:03 2011 +0000
Child:
1:379cf3202ba2
Commit message:
4.1.06a

Changed in this revision

qk_port.s Show annotated file Show diff for this revision Revisions of this file
qp.cpp Show annotated file Show diff for this revision Revisions of this file
qp.h Show annotated file Show diff for this revision Revisions of this file
qp_port.cpp Show annotated file Show diff for this revision Revisions of this file
qp_port.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qk_port.s	Wed Feb 09 14:46:03 2011 +0000
@@ -0,0 +1,126 @@
+;*****************************************************************************
+; Product: QK port to ARM Cortex-M0/M3, mbed ARM assembler, CMSIS-compliant
+; Last Updated for Version: 4.1.06
+; Date of the Last Update:  Feb 07, 2011
+;
+;                    Q u a n t u m     L e a P s
+;                    ---------------------------
+;                    innovating embedded systems
+;
+; Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+;
+; This software may be distributed and modified under the terms of the GNU
+; General Public License version 2 (GPL) as published by the Free Software
+; Foundation and appearing in the file GPL.TXT included in the packaging of
+; this file. Please note that GPL Section 2[b] requires that all works based
+; on this software must also be made publicly available under the terms of
+; the GPL ("Copyleft").
+;
+; Alternatively, this software may be distributed and modified under the
+; terms of Quantum Leaps commercial licenses, which expressly supersede
+; the GPL and are specifically designed for licensees interested in
+; retaining the proprietary status of their code.
+;
+; Contact information:
+; Quantum Leaps Web site:  http://www.quantum-leaps.com
+; e-mail:                  info@quantum-leaps.com
+;*****************************************************************************
+    AREA QK, CODE, READONLY
+
+    EXPORT  QK_init
+    EXPORT  PendSV_Handler    ; CMSIS-compliant PendSV exception name
+    EXPORT  SVC_Handler       ; CMSIS-compliant SVC exception name
+
+    EXTERN  QK_schedule_      ; external references
+    EXTERN  QK_readySet_      ; external references
+
+
+;*****************************************************************************
+;
+; The QK_init function sets the priorities of SVCall and PendSV exceptions
+; to the lowest level possible (0xFF). The function internally disables
+; interrupts, but restores the original interrupt lock before exit.
+;
+;*****************************************************************************
+QK_init
+    MRS     r0,PRIMASK        ; store the state of the PRIMASK in r0
+    CPSID   i                 ; disable interrupts (set PRIMASK)
+
+    LDR     r1,=0xE000ED18    ; System Handler Priority Register
+    LDR     r2,[r1,#8]        ; load the System 12-15 Priority Register
+    MOVS    r3,#0xFF
+    LSLS    r3,r3,#16
+    ORRS    r2,r3             ; set PRI_14 (PendSV) to 0xFF
+    STR     r2,[r1,#8]        ; write the System 12-15 Priority Register
+    LDR     r2,[r1,#4]        ; load the System 8-11 Priority Register
+    LSLS    r3,r3,#8
+    ORRS    r2,r3             ; set PRI_11 (SVCall) to 0xFF
+    STR     r2,[r1,#4]        ; write the System 8-11 Priority Register
+
+    MSR     PRIMASK,r0        ; restore the original PRIMASK
+    BX      lr                ; return to the caller
+
+
+;*****************************************************************************
+;
+; The PendSV_Handler exception hanlder is used for handling asynchronous
+; preemptions in QK. The use of the PendSV exception is the recommended
+; and most efficient method for performing context switches with ARM Cortex.
+;
+; The PendSV exception should have the lowest priority in the whole system
+; (0xFF, see QK_init). All other exeptions and interrupts should have higher
+; priority. For example, for NVIC with 2 priority bits all interrupts and
+; exceptions must have numerical value of priority lower than 0xC0. In this
+; case the interrupt priority levels available to your applications are (in
+; the order from the lowest urgency to the highest urgency): 0x80, 0x40, 0x00.
+;
+; Also, *all* ISRs in the QK application must trigger the PendSV exception
+; by calling the QK_ISR_EXIT() macro.
+;
+; Due to tail-chaining and its lowest priority, the PendSV exception will be
+; entered immediately after the exit from the *last* nested interrupt (or
+; exception). In QK, this is exactly the time when the QK scheduler needs to
+; check for the asynchronous preemptions.
+;
+;*****************************************************************************
+PendSV_Handler
+    CPSID   i                 ; disable interrupts at processor level
+    LDR     r0,=QK_readySet_  ; load the address of QK_readySet_
+    LDRB    r0,[r0]           ; load the first byte of QK_readySet_
+    CMP     r0,#0             ; is QK_readySet_ == 0 ?
+    BEQ.N   iret              ; if QK_readySet_ == 0, branch to iret
+
+    MOVS    r1,#0x01
+    LSLS    r1,r1,#24         ; make up a task xPSR with only the T bit set
+    LDR     r0,=schedule      ; load the address of sched wrapper (new PC)
+    PUSH    {r0-r1}           ; push xPSR,PC
+    SUB     sp,sp,#(6*4)      ; don't care for lr,r12,r3,r2,r1,r0
+    BX      lr                ; interrupt return to the scheduler
+
+iret
+    CPSIE   i                 ; enable interrupts at processor level
+    BX      lr                ; interrupt return to the task
+
+schedule
+    BL      QK_schedule_      ; call the QK scheduler
+    CPSIE   i                 ; enable interrupts to allow SVCall exception
+    SVC     0                 ; SV exception returns to the preempted task
+
+
+;*****************************************************************************
+;
+; The SVC_Handler exception handler is used for returning back to the
+; interrupted context (task or interrupt). The SVC exception should have
+; the lowest priority in the whole system (see QK_init). The SVCall
+; exception simply removes its own interrupt stack frame from the stack and
+; returns to the preempted task using the interrupt stack frame that must be
+; at the top of the stack.
+;
+;*****************************************************************************
+SVC_Handler
+    ADD     sp,sp,#(8*4)      ; remove one interrupt frame from the stack
+    BX      lr                ; return to the preempted task
+
+    ALIGN                     ; make sure proper alignment
+    END
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qp.cpp	Wed Feb 09 14:46:03 2011 +0000
@@ -0,0 +1,2067 @@
+//////////////////////////////////////////////////////////////////////////////
+// Product: QP/C++, selectabel Vanilla/QK kernels
+// Last Updated for QP ver: 4.1.06 (modified to fit in one file)
+// Date of the Last Update: Feb 08, 2011
+//
+//                    Q u a n t u m     L e a P s
+//                    ---------------------------
+//                    innovating embedded systems
+//
+// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+//
+// This software may be distributed and modified under the terms of the GNU
+// General Public License version 2 (GPL) as published by the Free Software
+// Foundation and appearing in the file GPL.TXT included in the packaging of
+// this file. Please note that GPL Section 2[b] requires that all works based
+// on this software must also be made publicly available under the terms of
+// the GPL ("Copyleft").
+//
+// Alternatively, this software may be distributed and modified under the
+// terms of Quantum Leaps commercial licenses, which expressly supersede
+// the GPL and are specifically designed for licensees interested in
+// retaining the proprietary status of their code.
+//
+// Contact information:
+// Quantum Leaps Web site:  http://www.quantum-leaps.com
+// e-mail:                  info@quantum-leaps.com
+//////////////////////////////////////////////////////////////////////////////
+#include "qp_port.h"                                                // QP port
+
+Q_DEFINE_THIS_MODULE(qp)
+
+// "qep_pkg.h" ===============================================================
+/// internal QEP constants
+enum QEPConst {
+    QEP_EMPTY_SIG_ = 0,                ///< empty signal for internal use only
+
+    /// maximum depth of state nesting (including the top level), must be >= 3
+    QEP_MAX_NEST_DEPTH_ = 6
+};
+
+/// helper macro to trigger internal event in an HSM
+#define QEP_TRIG_(state_, sig_) \
+    ((*(state_))(this, &QEP_reservedEvt_[sig_]))
+
+/// helper macro to trigger entry action in an HSM
+#define QEP_EXIT_(state_) \
+    if (QEP_TRIG_(state_, Q_EXIT_SIG) == Q_RET_HANDLED) { \
+        QS_BEGIN_(QS_QEP_STATE_EXIT, QS::smObj_, this) \
+            QS_OBJ_(this); \
+            QS_FUN_(state_); \
+        QS_END_() \
+    }
+
+/// helper macro to trigger exit action in an HSM
+#define QEP_ENTER_(state_) \
+    if (QEP_TRIG_(state_, Q_ENTRY_SIG) == Q_RET_HANDLED) { \
+        QS_BEGIN_(QS_QEP_STATE_ENTRY, QS::smObj_, this) \
+            QS_OBJ_(this); \
+            QS_FUN_(state_); \
+        QS_END_() \
+    }
+
+// "qep.cpp" =================================================================
+// Package-scope objects -----------------------------------------------------
+QEvent const QEP_reservedEvt_[] = {
+    { (QSignal)QEP_EMPTY_SIG_, (uint8_t)0 },
+    { (QSignal)Q_ENTRY_SIG,    (uint8_t)0 },
+    { (QSignal)Q_EXIT_SIG,     (uint8_t)0 },
+    { (QSignal)Q_INIT_SIG,     (uint8_t)0 }
+};
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+char const Q_ROM * Q_ROM_VAR QEP::getVersion(void) {
+    static char const Q_ROM Q_ROM_VAR version[] = {
+        ((QP_VERSION >> 12) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  8) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  4) & 0xF) + '0',
+        (QP_VERSION         & 0xF) + '0',
+        '\0'
+    };
+    return version;
+}
+
+// "qhsm_top.cpp" ============================================================
+QState QHsm::top(QHsm *, QEvent const *) {
+    return Q_IGNORED();                    // the top state ignores all events
+}
+
+// "qhsm_ini.cpp" ============================================================
+QHsm::~QHsm() {
+}
+//............................................................................
+void QHsm::init(QEvent const *e) {
+    QStateHandler t;
+    QS_INT_LOCK_KEY_
+
+                              // the top-most initial transition must be taken
+    Q_ALLEGE((*m_state)(this, e) == Q_RET_TRAN);
+
+    t = (QStateHandler)&QHsm::top;              // HSM starts in the top state
+    do {                                           // drill into the target...
+        QStateHandler path[QEP_MAX_NEST_DEPTH_];
+        int8_t ip = (int8_t)0;                  // transition entry path index
+
+
+        QS_BEGIN_(QS_QEP_STATE_INIT, QS::smObj_, this)
+            QS_OBJ_(this);                        // this state machine object
+            QS_FUN_(t);                                    // the source state
+            QS_FUN_(m_state);          // the target of the initial transition
+        QS_END_()
+
+        path[0] = m_state;
+        (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);
+        while (m_state != t) {
+            ++ip;
+            path[ip] = m_state;
+            (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);
+        }
+        m_state = path[0];
+                                               // entry path must not overflow
+        Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
+
+        do {           // retrace the entry path in reverse (desired) order...
+            QEP_ENTER_(path[ip]);                            // enter path[ip]
+            --ip;
+        } while (ip >= (int8_t)0);
+
+        t = path[0];                   // current state becomes the new source
+    } while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN);
+    m_state = t;
+
+    QS_BEGIN_(QS_QEP_INIT_TRAN, QS::smObj_, this)
+        QS_TIME_();                                              // time stamp
+        QS_OBJ_(this);                            // this state machine object
+        QS_FUN_(m_state);                              // the new active state
+    QS_END_()
+}
+
+// "qhsm_dis.cpp" ============================================================
+void QHsm::dispatch(QEvent const *e) {
+    QStateHandler path[QEP_MAX_NEST_DEPTH_];
+    QStateHandler s;
+    QStateHandler t;
+    QState r;
+    QS_INT_LOCK_KEY_
+
+    t = m_state;                                     // save the current state
+
+    QS_BEGIN_(QS_QEP_DISPATCH, QS::smObj_, this)
+        QS_TIME_();                                              // time stamp
+        QS_SIG_(e->sig);                            // the signal of the event
+        QS_OBJ_(this);                            // this state machine object
+        QS_FUN_(t);                                       // the current state
+    QS_END_()
+
+    do {                                // process the event hierarchically...
+        s = m_state;
+        r = (*s)(this, e);                           // invoke state handler s
+    } while (r == Q_RET_SUPER);
+
+    if (r == Q_RET_TRAN) {                                // transition taken?
+#ifdef Q_SPY
+        QStateHandler src = s;       // save the transition source for tracing
+#endif
+        int8_t ip = (int8_t)(-1);               // transition entry path index
+        int8_t iq;                       // helper transition entry path index
+
+        path[0] = m_state;                // save the target of the transition
+        path[1] = t;
+
+        while (t != s) {       // exit current state to transition source s...
+            if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {   //exit handled?
+                QS_BEGIN_(QS_QEP_STATE_EXIT, QS::smObj_, this)
+                    QS_OBJ_(this);                // this state machine object
+                    QS_FUN_(t);                            // the exited state
+                QS_END_()
+
+                (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);    // find superstate of t
+            }
+            t = m_state;                       // m_state holds the superstate
+        }
+
+        t = path[0];                               // target of the transition
+
+        if (s == t) {         // (a) check source==target (transition to self)
+            QEP_EXIT_(s)                                    // exit the source
+            ip = (int8_t)0;                                // enter the target
+        }
+        else {
+            (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);        // superstate of target
+            t = m_state;
+            if (s == t) {                   // (b) check source==target->super
+                ip = (int8_t)0;                            // enter the target
+            }
+            else {
+                (void)QEP_TRIG_(s, QEP_EMPTY_SIG_);       // superstate of src
+                                     // (c) check source->super==target->super
+                if (m_state == t) {
+                    QEP_EXIT_(s)                            // exit the source
+                    ip = (int8_t)0;                        // enter the target
+                }
+                else {
+                                            // (d) check source->super==target
+                    if (m_state == path[0]) {
+                        QEP_EXIT_(s)                        // exit the source
+                    }
+                    else { // (e) check rest of source==target->super->super..
+                           // and store the entry path along the way
+                           //
+                        iq = (int8_t)0;         // indicate that LCA not found
+                        ip = (int8_t)1;     // enter target and its superstate
+                        path[1] = t;          // save the superstate of target
+                        t = m_state;                     // save source->super
+                                                  // find target->super->super
+                        r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_);
+                        while (r == Q_RET_SUPER) {
+                            ++ip;
+                            path[ip] = m_state;        // store the entry path
+                            if (m_state == s) {           // is it the source?
+                                iq = (int8_t)1;     // indicate that LCA found
+                                               // entry path must not overflow
+                                Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
+                                --ip;               // do not enter the source
+                                r = Q_RET_HANDLED;       // terminate the loop
+                            }
+                            else {      // it is not the source, keep going up
+                                r = QEP_TRIG_(m_state, QEP_EMPTY_SIG_);
+                            }
+                        }
+                        if (iq == (int8_t)0) {       // the LCA not found yet?
+
+                                               // entry path must not overflow
+                            Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
+
+                            QEP_EXIT_(s)                   // exit the source
+
+                            // (f) check the rest of source->super
+                            //                  == target->super->super...
+                            //
+                            iq = ip;
+                            r = Q_RET_IGNORED;       // indicate LCA NOT found
+                            do {
+                                if (t == path[iq]) {       // is this the LCA?
+                                    r = Q_RET_HANDLED;   // indicate LCA found
+                                    ip = (int8_t)(iq - 1); // do not enter LCA
+                                    iq = (int8_t)(-1);   // terminate the loop
+                                }
+                                else {
+                                    --iq;    // try lower superstate of target
+                                }
+                            } while (iq >= (int8_t)0);
+
+                            if (r != Q_RET_HANDLED) {    // LCA not found yet?
+                                // (g) check each source->super->...
+                                // for each target->super...
+                                //
+                                r = Q_RET_IGNORED;             // keep looping
+                                do {
+                                                          // exit t unhandled?
+                                    if (QEP_TRIG_(t, Q_EXIT_SIG)
+                                        == Q_RET_HANDLED)
+                                    {
+                                        QS_BEGIN_(QS_QEP_STATE_EXIT,
+                                                  QS::smObj_, this)
+                                            QS_OBJ_(this);
+                                            QS_FUN_(t);
+                                        QS_END_()
+
+                                        (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);
+                                    }
+                                    t = m_state;         //  set to super of t
+                                    iq = ip;
+                                    do {
+                                        if (t == path[iq]) {   // is this LCA?
+                                                           // do not enter LCA
+                                            ip = (int8_t)(iq - 1);
+                                            iq = (int8_t)(-1);   //break inner
+                                            r = Q_RET_HANDLED;   //break outer
+                                        }
+                                        else {
+                                            --iq;
+                                        }
+                                    } while (iq >= (int8_t)0);
+                                } while (r != Q_RET_HANDLED);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+                       // retrace the entry path in reverse (desired) order...
+        for (; ip >= (int8_t)0; --ip) {
+            QEP_ENTER_(path[ip])                             // enter path[ip]
+        }
+        t = path[0];                         // stick the target into register
+        m_state = t;                               // update the current state
+
+                                         // drill into the target hierarchy...
+        while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN) {
+
+            QS_BEGIN_(QS_QEP_STATE_INIT, QS::smObj_, this)
+                QS_OBJ_(this);                    // this state machine object
+                QS_FUN_(t);                        // the source (pseudo)state
+                QS_FUN_(m_state);              // the target of the transition
+            QS_END_()
+
+            ip = (int8_t)0;
+            path[0] = m_state;
+            (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);       // find superstate
+            while (m_state != t) {
+                ++ip;
+                path[ip] = m_state;
+                (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);   // find superstate
+            }
+            m_state = path[0];
+                                               // entry path must not overflow
+            Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
+
+            do {       // retrace the entry path in reverse (correct) order...
+                QEP_ENTER_(path[ip])                         // enter path[ip]
+                --ip;
+            } while (ip >= (int8_t)0);
+
+            t = path[0];
+        }
+
+        QS_BEGIN_(QS_QEP_TRAN, QS::smObj_, this)
+            QS_TIME_();                                          // time stamp
+            QS_SIG_(e->sig);                        // the signal of the event
+            QS_OBJ_(this);                        // this state machine object
+            QS_FUN_(src);                      // the source of the transition
+            QS_FUN_(t);                                // the new active state
+        QS_END_()
+
+    }
+    else {                                             // transition not taken
+#ifdef Q_SPY
+        if (r == Q_RET_IGNORED) {                            // event ignored?
+
+            QS_BEGIN_(QS_QEP_IGNORED, QS::smObj_, this)
+                QS_TIME_();                                      // time stamp
+                QS_SIG_(e->sig);                    // the signal of the event
+                QS_OBJ_(this);                    // this state machine object
+                QS_FUN_(t);                               // the current state
+            QS_END_()
+
+        }
+        else {                                                // event handled
+
+            QS_BEGIN_(QS_QEP_INTERN_TRAN, QS::smObj_, this)
+                QS_TIME_();                                      // time stamp
+                QS_SIG_(e->sig);                    // the signal of the event
+                QS_OBJ_(this);                    // this state machine object
+                QS_FUN_(s);                // the state that handled the event
+            QS_END_()
+
+        }
+#endif
+    }
+    m_state = t;                 // set new state or restore the current state
+}
+
+// "qf_pkg.h" ================================================================
+                                    // QF-specific interrupt locking/unlocking
+#ifndef QF_INT_KEY_TYPE
+
+    /// \brief This is an internal macro for defining the interrupt lock key.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro provides the
+    /// definition of the lock key variable. Otherwise this macro is empty.
+    /// \sa #QF_INT_KEY_TYPE
+    #define QF_INT_LOCK_KEY_
+
+    /// \brief This is an internal macro for locking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro invokes #QF_INT_LOCK
+    /// passing the key variable as the parameter. Otherwise #QF_INT_LOCK
+    /// is invoked with a dummy parameter.
+    /// \sa #QF_INT_LOCK, #QK_INT_LOCK
+    #define QF_INT_LOCK_()      QF_INT_LOCK(dummy)
+
+    /// \brief This is an internal macro for unlocking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro invokes
+    /// #QF_INT_UNLOCK passing the key variable as the parameter.
+    /// Otherwise #QF_INT_UNLOCK is invoked with a dummy parameter.
+    /// \sa #QF_INT_UNLOCK, #QK_INT_UNLOCK
+    #define QF_INT_UNLOCK_()    QF_INT_UNLOCK(dummy)
+#else
+    #define QF_INT_LOCK_KEY_    QF_INT_KEY_TYPE intLockKey_;
+    #define QF_INT_LOCK_()      QF_INT_LOCK(intLockKey_)
+    #define QF_INT_UNLOCK_()    QF_INT_UNLOCK(intLockKey_)
+#endif
+
+// package-scope objects -----------------------------------------------------
+extern QTimeEvt *QF_timeEvtListHead_;  ///< head of linked list of time events
+extern QF_EPOOL_TYPE_ QF_pool_[3];                 ///< allocate 3 event pools
+extern uint8_t QF_maxPool_;                  ///< # of initialized event pools
+extern QSubscrList *QF_subscrList_;             ///< the subscriber list array
+extern QSignal QF_maxSignal_;                ///< the maximum published signal
+
+//............................................................................
+/// \brief Structure representing a free block in the Native QF Memory Pool
+/// \sa ::QMPool
+struct QFreeBlock {
+    QFreeBlock *m_next;
+};
+
+// "qa_defer.cpp" ============================================================
+void QActive::defer(QEQueue *eq, QEvent const *e) {
+    eq->postFIFO(e);
+}
+//............................................................................
+QEvent const *QActive::recall(QEQueue *eq) {
+    QEvent const *e = eq->get();    // try to get an event from deferred queue
+    if (e != (QEvent *)0) {                                // event available?
+
+        postLIFO(e);      // post it to the front of the Active Object's queue
+
+        QF_INT_LOCK_KEY_
+        QF_INT_LOCK_();
+
+        if (e->dynamic_ != (uint8_t)0) {             // is it a dynamic event?
+
+            // after posting to the AO's queue the event must be referenced
+            // at least twice: once in the deferred event queue (eq->get()
+            // did NOT decrement the reference counter) and once in the
+            // AO's event queue.
+            Q_ASSERT((e->dynamic_ & 0x3F) > 1);
+
+            // we need to decrement the reference counter once, to account
+            // for removing the event from the deferred event queue.
+            //
+            //lint -e1773                           Attempt to cast away const
+            --((QEvent *)e)->dynamic_;      // decrement the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+        }
+
+        QF_INT_UNLOCK_();
+
+    }
+    return e;  // pass the recalled event to the caller (NULL if not recalled)
+}
+
+// "qa_fifo.cpp" =============================================================
+void QActive::postFIFO(QEvent const *e) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_FIFO, QS::aoObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(e->sig);                            // the signal of the event
+        QS_OBJ_(this);                                   // this active object
+        QS_U8_(e->dynamic_);                  // the QF attribute of the event
+        QS_EQC_(m_eQueue.m_nFree);                   // number of free entries
+        QS_EQC_(m_eQueue.m_nMin);                // min number of free entries
+    QS_END_NOLOCK_()
+
+    if (e->dynamic_ != (uint8_t)0) {                 // is it a dynamic event?
+        //lint -e1773                               Attempt to cast away const
+        ++((QEvent *)e)->dynamic_;          // increment the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+    }
+
+    if (m_eQueue.m_frontEvt == (QEvent *)0) {           // is the queue empty?
+        m_eQueue.m_frontEvt = e;                     // deliver event directly
+        QACTIVE_EQUEUE_SIGNAL_(this);                // signal the event queue
+    }
+    else {               // queue is not empty, leave event in the ring-buffer
+                                        // queue must accept all posted events
+        Q_ASSERT(m_eQueue.m_nFree != (QEQueueCtr)0);
+        m_eQueue.m_ring[m_eQueue.m_head] = e;//insert e into the buffer (FIFO)
+        if (m_eQueue.m_head == (QEQueueCtr)0) {      // need to wrap the head?
+            m_eQueue.m_head = m_eQueue.m_end;                   // wrap around
+        }
+        --m_eQueue.m_head;
+
+        --m_eQueue.m_nFree;                    // update number of free events
+        if (m_eQueue.m_nMin > m_eQueue.m_nFree) {
+            m_eQueue.m_nMin = m_eQueue.m_nFree;       // update minimum so far
+        }
+    }
+    QF_INT_UNLOCK_();
+}
+
+// "qa_get_.cpp" =============================================================
+QEvent const *QActive::get_(void) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QACTIVE_EQUEUE_WAIT_(this);           // wait for event to arrive directly
+
+    QEvent const *e = m_eQueue.m_frontEvt;
+
+    if (m_eQueue.m_nFree != m_eQueue.m_end) { //any events in the ring buffer?
+                                                 // remove event from the tail
+        m_eQueue.m_frontEvt = m_eQueue.m_ring[m_eQueue.m_tail];
+        if (m_eQueue.m_tail == (QEQueueCtr)0) {      // need to wrap the tail?
+            m_eQueue.m_tail = m_eQueue.m_end;                   // wrap around
+        }
+        --m_eQueue.m_tail;
+
+        ++m_eQueue.m_nFree;          // one more free event in the ring buffer
+
+        QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_GET, QS::aoObj_, this)
+            QS_TIME_();                                           // timestamp
+            QS_SIG_(e->sig);                       // the signal of this event
+            QS_OBJ_(this);                               // this active object
+            QS_U8_(e->dynamic_);        // the dynamic attributes of the event
+            QS_EQC_(m_eQueue.m_nFree);               // number of free entries
+        QS_END_NOLOCK_()
+    }
+    else {
+        m_eQueue.m_frontEvt = (QEvent *)0;          // the queue becomes empty
+        QACTIVE_EQUEUE_ONEMPTY_(this);
+
+        QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_GET_LAST, QS::aoObj_, this)
+            QS_TIME_();                                           // timestamp
+            QS_SIG_(e->sig);                       // the signal of this event
+            QS_OBJ_(this);                               // this active object
+            QS_U8_(e->dynamic_);        // the dynamic attributes of the event
+        QS_END_NOLOCK_()
+    }
+    QF_INT_UNLOCK_();
+    return e;
+}
+//............................................................................
+uint32_t QF::getQueueMargin(uint8_t prio) {
+    Q_REQUIRE((prio <= (uint8_t)QF_MAX_ACTIVE)
+              && (active_[prio] != (QActive *)0));
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+    uint32_t margin = (uint32_t)(active_[prio]->m_eQueue.m_nMin);
+    QF_INT_UNLOCK_();
+
+    return margin;
+}
+
+// "qa_lifo.cpp" =============================================================
+void QActive::postLIFO(QEvent const *e) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_POST_LIFO, QS::aoObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(e->sig);                           // the signal of this event
+        QS_OBJ_(this);                                   // this active object
+        QS_U8_(e->dynamic_);            // the dynamic attributes of the event
+        QS_EQC_(m_eQueue.m_nFree);                   // number of free entries
+        QS_EQC_(m_eQueue.m_nMin);                // min number of free entries
+    QS_END_NOLOCK_()
+
+    if (e->dynamic_ != (uint8_t)0) {                    // is it a pool event?
+        //lint -e1773                               Attempt to cast away const
+        ++((QEvent *)e)->dynamic_;          // increment the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+    }
+
+    if (m_eQueue.m_frontEvt == (QEvent *)0) {           // is the queue empty?
+        m_eQueue.m_frontEvt = e;                     // deliver event directly
+        QACTIVE_EQUEUE_SIGNAL_(this);                // signal the event queue
+    }
+    else {               // queue is not empty, leave event in the ring-buffer
+                                        // queue must accept all posted events
+        Q_ASSERT(m_eQueue.m_nFree != (QEQueueCtr)0);
+
+        ++m_eQueue.m_tail;
+        if (m_eQueue.m_tail == m_eQueue.m_end) {     // need to wrap the tail?
+            m_eQueue.m_tail = (QEQueueCtr)0;                    // wrap around
+        }
+
+        m_eQueue.m_ring[m_eQueue.m_tail] = m_eQueue.m_frontEvt;
+        m_eQueue.m_frontEvt = e;                         // put event to front
+
+        --m_eQueue.m_nFree;                    // update number of free events
+        if (m_eQueue.m_nMin > m_eQueue.m_nFree) {
+            m_eQueue.m_nMin = m_eQueue.m_nFree;       // update minimum so far
+        }
+    }
+    QF_INT_UNLOCK_();
+}
+
+// "qa_sub.cpp" ==============================================================
+void QActive::subscribe(QSignal sig) const {
+    uint8_t p = m_prio;
+    Q_REQUIRE(((QSignal)Q_USER_SIG <= sig)
+              && (sig < QF_maxSignal_)
+              && ((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE)
+              && (QF::active_[p] == this));
+
+    uint8_t i = Q_ROM_BYTE(QF_div8Lkup[p]);
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_SUBSCRIBE, QS::aoObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(sig);                              // the signal of this event
+        QS_OBJ_(this);                                   // this active object
+    QS_END_NOLOCK_()
+                                                       // set the priority bit
+    QF_subscrList_[sig].m_bits[i] |= Q_ROM_BYTE(QF_pwr2Lkup[p]);
+    QF_INT_UNLOCK_();
+}
+
+// "qa_usub.cpp" =============================================================
+void QActive::unsubscribe(QSignal sig) const {
+    uint8_t p = m_prio;
+    Q_REQUIRE(((QSignal)Q_USER_SIG <= sig)
+              && (sig < QF_maxSignal_)
+              && ((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE)
+              && (QF::active_[p] == this));
+
+    uint8_t i = Q_ROM_BYTE(QF_div8Lkup[p]);
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_UNSUBSCRIBE, QS::aoObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(sig);                              // the signal of this event
+        QS_OBJ_(this);                                   // this active object
+    QS_END_NOLOCK_()
+                                                     // clear the priority bit
+    QF_subscrList_[sig].m_bits[i] &= Q_ROM_BYTE(QF_invPwr2Lkup[p]);
+    QF_INT_UNLOCK_();
+}
+
+// "qa_usuba.cpp" ============================================================
+void QActive::unsubscribeAll(void) const {
+    uint8_t p = m_prio;
+    Q_REQUIRE(((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE)
+              && (QF::active_[p] == this));
+
+    uint8_t i = Q_ROM_BYTE(QF_div8Lkup[p]);
+
+    QSignal sig;
+    for (sig = (QSignal)Q_USER_SIG; sig < QF_maxSignal_; ++sig) {
+        QF_INT_LOCK_KEY_
+        QF_INT_LOCK_();
+        if ((QF_subscrList_[sig].m_bits[i] & Q_ROM_BYTE(QF_pwr2Lkup[p]))
+             != 0)
+        {
+
+            QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_UNSUBSCRIBE, QS::aoObj_, this)
+                QS_TIME_();                                       // timestamp
+                QS_SIG_(sig);                      // the signal of this event
+                QS_OBJ_(this);                           // this active object
+            QS_END_NOLOCK_()
+                                                     // clear the priority bit
+            QF_subscrList_[sig].m_bits[i] &= Q_ROM_BYTE(QF_invPwr2Lkup[p]);
+        }
+        QF_INT_UNLOCK_();
+    }
+}
+
+// "qeq_fifo.cpp" ============================================================
+void QEQueue::postFIFO(QEvent const *e) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_POST_FIFO, QS::eqObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(e->sig);                           // the signal of this event
+        QS_OBJ_(this);                                    // this queue object
+        QS_U8_(e->dynamic_);            // the dynamic attributes of the event
+        QS_EQC_(m_nFree);                            // number of free entries
+        QS_EQC_(m_nMin);                         // min number of free entries
+    QS_END_NOLOCK_()
+
+    if (e->dynamic_ != (uint8_t)0) {                    // is it a pool event?
+        //lint -e1773                               Attempt to cast away const
+        ++((QEvent *)e)->dynamic_;          // increment the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+    }
+
+    if (m_frontEvt == (QEvent *)0) {                    // is the queue empty?
+        m_frontEvt = e;                              // deliver event directly
+    }
+    else {               // queue is not empty, leave event in the ring-buffer
+               // the queue must be able to accept the event (cannot overflow)
+        Q_ASSERT(m_nFree != (QEQueueCtr)0);
+
+        m_ring[m_head] = e;             // insert event into the buffer (FIFO)
+        if (m_head == (QEQueueCtr)0) {               // need to wrap the head?
+            m_head = m_end;                                     // wrap around
+        }
+        --m_head;
+
+        --m_nFree;                             // update number of free events
+        if (m_nMin > m_nFree) {
+            m_nMin = m_nFree;                         // update minimum so far
+        }
+    }
+    QF_INT_UNLOCK_();
+}
+
+// "qeq_get.cpp" =============================================================
+QEvent const *QEQueue::get(void) {
+    QEvent const *e;
+    QF_INT_LOCK_KEY_
+
+    QF_INT_LOCK_();
+    if (m_frontEvt == (QEvent *)0) {                    // is the queue empty?
+        e = (QEvent *)0;                    // no event available at this time
+    }
+    else {
+        e = m_frontEvt;
+
+        if (m_nFree != m_end) {          // any events in the the ring buffer?
+            m_frontEvt = m_ring[m_tail];         // remove event from the tail
+            if (m_tail == (QEQueueCtr)0) {           // need to wrap the tail?
+                m_tail = m_end;                                 // wrap around
+            }
+            --m_tail;
+
+            ++m_nFree;               // one more free event in the ring buffer
+
+            QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_GET, QS::eqObj_, this)
+                QS_TIME_();                                       // timestamp
+                QS_SIG_(e->sig);                   // the signal of this event
+                QS_OBJ_(this);                            // this queue object
+                QS_U8_(e->dynamic_);    // the dynamic attributes of the event
+                QS_EQC_(m_nFree);                    // number of free entries
+            QS_END_NOLOCK_()
+        }
+        else {
+            m_frontEvt = (QEvent *)0;               // the queue becomes empty
+
+            QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_GET_LAST, QS::eqObj_, this)
+                QS_TIME_();                                       // timestamp
+                QS_SIG_(e->sig);                   // the signal of this event
+                QS_OBJ_(this);                            // this queue object
+                QS_U8_(e->dynamic_);     // the dynamic attribute of the event
+            QS_END_NOLOCK_()
+        }
+    }
+    QF_INT_UNLOCK_();
+    return e;
+}
+
+// "qeq_init.cpp" ============================================================
+void QEQueue::init(QEvent const *qSto[], QEQueueCtr qLen) {
+    m_frontEvt = (QEvent *)0;                        // no events in the queue
+    m_ring     = &qSto[0];
+    m_end      = qLen;
+    m_head     = (QEQueueCtr)0;
+    m_tail     = (QEQueueCtr)0;
+    m_nFree    = qLen;
+    m_nMin     = qLen;
+
+    QS_INT_LOCK_KEY_
+    QS_BEGIN_(QS_QF_EQUEUE_INIT, QS::eqObj_, this)
+        QS_OBJ_(qSto);                                  // this QEQueue object
+        QS_EQC_(qLen);                              // the length of the queue
+    QS_END_()
+}
+
+// "qeq_lifo.cpp" ============================================================
+void QEQueue::postLIFO(QEvent const *e) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_EQUEUE_POST_LIFO, QS::eqObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_SIG_(e->sig);                           // the signal of this event
+        QS_OBJ_(this);                                    // this queue object
+        QS_U8_(e->dynamic_);             // the dynamic attribute of the event
+        QS_EQC_(m_nFree);                            // number of free entries
+        QS_EQC_(m_nMin);                         // min number of free entries
+    QS_END_NOLOCK_()
+
+    if (e->dynamic_ != (uint8_t)0) {                 // is it a dynamic event?
+        //lint -e1773                               Attempt to cast away const
+        ++((QEvent *)e)->dynamic_;          // increment the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+    }
+
+    if (m_frontEvt != (QEvent *)0) {                // is the queue not empty?
+               // the queue must be able to accept the event (cannot overflow)
+        Q_ASSERT(m_nFree != (QEQueueCtr)0);
+
+        ++m_tail;
+        if (m_tail == m_end) {                       // need to wrap the tail?
+            m_tail = (QEQueueCtr)0;                             // wrap around
+        }
+
+        m_ring[m_tail] = m_frontEvt;               // buffer the old front evt
+
+        --m_nFree;                             // update number of free events
+        if (m_nMin > m_nFree) {
+            m_nMin = m_nFree;                         // update minimum so far
+        }
+    }
+
+    m_frontEvt = e;                        // stick the new event to the front
+
+    QF_INT_UNLOCK_();
+}
+
+// "qf_act.cpp" ==============================================================
+// public objects ------------------------------------------------------------
+QActive *QF::active_[QF_MAX_ACTIVE + 1];        // to be used by QF ports only
+uint8_t QF_intLockNest_;                       // interrupt-lock nesting level
+
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+const char Q_ROM * Q_ROM_VAR QF::getVersion(void) {
+    static char const Q_ROM Q_ROM_VAR version[] = {
+        ((QP_VERSION >> 12) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  8) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  4) & 0xF) + '0',
+        (QP_VERSION         & 0xF) + '0',
+        '\0'
+    };
+    return version;
+}
+//............................................................................
+void QF::add_(QActive *a) {
+    uint8_t p = a->m_prio;
+
+    Q_REQUIRE(((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE)
+              && (active_[p] == (QActive *)0));
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    active_[p] = a;            // registger the active object at this priority
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_ADD, QS::aoObj_, a)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(a);                                       // the active object
+        QS_U8_(p);                        // the priority of the active object
+    QS_END_NOLOCK_()
+
+    QF_INT_UNLOCK_();
+}
+//............................................................................
+void QF::remove_(QActive const *a) {
+    uint8_t p = a->m_prio;
+
+    Q_REQUIRE(((uint8_t)0 < p) && (p <= (uint8_t)QF_MAX_ACTIVE)
+              && (active_[p] == a));
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    active_[p] = (QActive *)0;                   // free-up the priority level
+
+    QS_BEGIN_NOLOCK_(QS_QF_ACTIVE_REMOVE, QS::aoObj_, a)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(a);                                       // the active object
+        QS_U8_(p);                        // the priority of the active object
+    QS_END_NOLOCK_()
+
+    QF_INT_UNLOCK_();
+}
+
+// "qf_gc.cpp" ===============================================================
+void QF::gc(QEvent const *e) {
+    if (e->dynamic_ != (uint8_t)0) {                 // is it a dynamic event?
+        QF_INT_LOCK_KEY_
+        QF_INT_LOCK_();
+
+        if ((e->dynamic_ & 0x3F) > 1) {      // isn't this the last reference?
+
+            //lint -e1773                           Attempt to cast away const
+            --((QEvent *)e)->dynamic_;      // decrement the reference counter
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event
+
+            QS_BEGIN_NOLOCK_(QS_QF_GC_ATTEMPT, (void *)0, (void *)0)
+                QS_TIME_();                                       // timestamp
+                QS_SIG_(e->sig);                    // the signal of the event
+                QS_U8_(e->dynamic_);    // the dynamic attributes of the event
+            QS_END_NOLOCK_()
+
+            QF_INT_UNLOCK_();
+        }
+        else {         // this is the last reference to this event, recycle it
+            uint8_t idx = (uint8_t)((e->dynamic_ >> 6) - 1);
+
+            QS_BEGIN_NOLOCK_(QS_QF_GC, (void *)0, (void *)0)
+                QS_TIME_();                                       // timestamp
+                QS_SIG_(e->sig);                    // the signal of the event
+                QS_U8_(e->dynamic_);    // the dynamic attributes of the event
+            QS_END_NOLOCK_()
+
+            QF_INT_UNLOCK_();
+
+            Q_ASSERT(idx < QF_maxPool_);
+
+            //lint -e1773                           Attempt to cast away const
+            QF_EPOOL_PUT_(QF_pool_[idx], (QEvent *)e);   // cast 'const' away,
+                             // which is legitimate, because it's a pool event
+        }
+    }
+}
+
+// "qf_log2.cpp" =============================================================
+uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256] = {
+    0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U, 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U,
+    5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U,
+    6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U,
+    6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U,
+    7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U,
+    7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U,
+    7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U,
+    7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U,
+    8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U, 8U
+};
+
+// "qf_new.cpp" ==============================================================
+QEvent *QF::new_(uint16_t evtSize, QSignal sig) {
+                    // find the pool id that fits the requested event size ...
+    uint8_t id = (uint8_t)0;
+    while (evtSize > QF_EPOOL_EVENT_SIZE_(QF_pool_[id])) {
+        ++id;
+        Q_ASSERT(id < QF_maxPool_);      // cannot run out of registered pools
+    }
+
+    QS_INT_LOCK_KEY_
+    QS_BEGIN_(QS_QF_NEW, (void *)0, (void *)0)
+        QS_TIME_();                                               // timestamp
+        QS_EVS_(evtSize);                             // the size of the event
+        QS_SIG_(sig);                               // the signal of the event
+    QS_END_()
+
+    QEvent *e;
+    QF_EPOOL_GET_(QF_pool_[id], e);
+    Q_ASSERT(e != (QEvent *)0);             // pool must not run out of events
+
+    e->sig = sig;                                 // set signal for this event
+
+                                 // store the dynamic attributes of the event:
+                                 // the pool ID and the reference counter == 0
+    e->dynamic_ = (uint8_t)((id + 1) << 6);
+    return e;
+}
+
+// "qf_pool.cpp" =============================================================
+// Package-scope objects -----------------------------------------------------
+QF_EPOOL_TYPE_ QF_pool_[3];                          // allocate 3 event pools
+uint8_t QF_maxPool_;                      // number of initialized event pools
+
+//............................................................................
+void QF::poolInit(void *poolSto, uint32_t poolSize, QEventSize evtSize) {
+                         // cannot exceed the number of available memory pools
+    Q_REQUIRE(QF_maxPool_ < (uint8_t)Q_DIM(QF_pool_));
+               // please initialize event pools in ascending order of evtSize:
+    Q_REQUIRE((QF_maxPool_ == (uint8_t)0)
+              || (QF_EPOOL_EVENT_SIZE_(QF_pool_[QF_maxPool_ - 1]) < evtSize));
+    QF_EPOOL_INIT_(QF_pool_[QF_maxPool_], poolSto, poolSize, evtSize);
+    ++QF_maxPool_;                                            // one more pool
+}
+
+// "qf_psini.cpp" ============================================================
+// Package-scope objects -----------------------------------------------------
+QSubscrList *QF_subscrList_;
+QSignal QF_maxSignal_;
+
+//............................................................................
+void QF::psInit(QSubscrList *subscrSto, QSignal maxSignal) {
+    QF_subscrList_ = subscrSto;
+    QF_maxSignal_ = maxSignal;
+}
+
+// "qf_pspub.cpp" ============================================================
+void QF::publish(QEvent const *e) {
+         // make sure that the published signal is within the configured range
+    Q_REQUIRE(e->sig < QF_maxSignal_);
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_PUBLISH, (void *)0, (void *)0)
+        QS_TIME_();                                           // the timestamp
+        QS_SIG_(e->sig);                            // the signal of the event
+        QS_U8_(e->dynamic_);            // the dynamic attributes of the event
+    QS_END_NOLOCK_()
+
+    if (e->dynamic_ != (uint8_t)0) {                 // is it a dynamic event?
+        //lint -e1773                               Attempt to cast away const
+        ++((QEvent *)e)->dynamic_;      // increment reference counter, NOTE01
+                   // NOTE: cast the 'const' away, which is legitimate because
+                   // it's a dynamic event */
+    }
+    QF_INT_UNLOCK_();
+
+#if (QF_MAX_ACTIVE <= 8)
+    uint8_t tmp = QF_subscrList_[e->sig].m_bits[0];
+    while (tmp != (uint8_t)0) {
+        uint8_t p = Q_ROM_BYTE(QF_log2Lkup[tmp]);
+        tmp &= Q_ROM_BYTE(QF_invPwr2Lkup[p]);      // clear the subscriber bit
+        Q_ASSERT(active_[p] != (QActive *)0);            // must be registered
+
+        active_[p]->postFIFO(e);  // internally asserts if the queue overflows
+    }
+#else
+    uint8_t i = Q_DIM(QF_subscrList_[0].m_bits);// number of bytes in the list
+    do {                       // go through all bytes in the subsciption list
+        --i;
+        uint8_t tmp = QF_subscrList_[e->sig].m_bits[i];
+        while (tmp != (uint8_t)0) {
+            uint8_t p = Q_ROM_BYTE(QF_log2Lkup[tmp]);
+            tmp &= Q_ROM_BYTE(QF_invPwr2Lkup[p]);  // clear the subscriber bit
+            p = (uint8_t)(p + (i << 3));                // adjust the priority
+            Q_ASSERT(active_[p] != (QActive *)0);        // must be registered
+
+                       // postFIFO() internally asserts if the queue overflows
+            active_[p]->postFIFO(e);
+        }
+    } while (i != (uint8_t)0);
+#endif
+
+    gc(e);                            // run the garbage collector, see NOTE01
+}
+
+// "qf_pwr2.cpp" =============================================================
+// Global objects ------------------------------------------------------------
+uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65] = {
+    0x00U,                                                  // unused location
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U,
+    0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U
+};
+
+uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65] = {
+    0xFFU,                                                  // unused location
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU,
+    0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU
+};
+
+uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65] = {
+    0U,                                                     // unused location
+    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
+    1U, 1U, 1U, 1U, 1U, 1U, 1U, 1U,
+    2U, 2U, 2U, 2U, 2U, 2U, 2U, 2U,
+    3U, 3U, 3U, 3U, 3U, 3U, 3U, 3U,
+    4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U,
+    5U, 5U, 5U, 5U, 5U, 5U, 5U, 5U,
+    6U, 6U, 6U, 6U, 6U, 6U, 6U, 6U,
+    7U, 7U, 7U, 7U, 7U, 7U, 7U, 7U
+};
+
+// "qf_tick.cpp" =============================================================
+void QF::tick(void) {                                            // see NOTE01
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_TICK, (void *)0, (void *)0)
+        QS_TEC_(++QS::tickCtr_);                           // the tick counter
+    QS_END_NOLOCK_()
+
+    QTimeEvt *t = QF_timeEvtListHead_;
+    while (t != (QTimeEvt *)0) {
+        --t->m_ctr;
+        if (t->m_ctr == (QTimeEvtCtr)0) {  // is the time evt about to expire?
+            if (t->m_interval != (QTimeEvtCtr)0) {//is it a periodic time evt?
+                t->m_ctr = t->m_interval;                // rearm the time evt
+            }
+            else {   // one-shot time evt, disarm by removing it from the list
+                if (t == QF_timeEvtListHead_) {
+                    QF_timeEvtListHead_ = t->m_next;
+                }
+                else {
+                    if (t->m_next != (QTimeEvt *)0) {// not the last time evt?
+                        t->m_next->m_prev = t->m_prev;
+                    }
+                    t->m_prev->m_next = t->m_next;
+                }
+                t->m_prev = (QTimeEvt *)0;     // mark the time event disarmed
+
+                QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_AUTO_DISARM, QS::teObj_, t)
+                    QS_OBJ_(t);                      // this time event object
+                    QS_OBJ_(t->m_act);                     // the active object
+                QS_END_NOLOCK_()
+            }
+
+            QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_POST, QS::teObj_, t)
+                QS_TIME_();                                       // timestamp
+                QS_OBJ_(t);                           // the time event object
+                QS_SIG_(t->sig);              // the signal of this time event
+                QS_OBJ_(t->m_act);                        // the active object
+            QS_END_NOLOCK_()
+
+            QF_INT_UNLOCK_();   // unlock interrupts before calling QF service
+
+                  // postFIFO() asserts internally that the event was accepted
+            t->m_act->postFIFO(t);
+        }
+        else {
+            QF_INT_UNLOCK_();
+            static uint8_t volatile dummy;
+            dummy = (uint8_t)0;      // execute a few instructions, see NOTE02
+        }
+
+        QF_INT_LOCK_();           // lock interrupts again to advance the link
+        t = t->m_next;
+    }
+    QF_INT_UNLOCK_();
+}
+
+// "qmp_get.cpp" =============================================================
+void *QMPool::get(void) {
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QFreeBlock *fb = (QFreeBlock *)m_free;         // get a free block or NULL
+    if (fb != (QFreeBlock *)0) {                      // free block available?
+        m_free = fb->m_next;        // adjust list head to the next free block
+        --m_nFree;                                      // one free block less
+        if (m_nMin > m_nFree) {
+            m_nMin = m_nFree;                   // remember the minimum so far
+        }
+    }
+
+    QS_BEGIN_NOLOCK_(QS_QF_MPOOL_GET, QS::mpObj_, m_start)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(m_start);                   // the memory managed by this pool
+        QS_MPC_(m_nFree);             // the number of free blocks in the pool
+        QS_MPC_(m_nMin);     // the mninimum number of free blocks in the pool
+    QS_END_NOLOCK_()
+
+    QF_INT_UNLOCK_();
+    return fb;               // return the block or NULL pointer to the caller
+}
+//............................................................................
+uint32_t QF::getPoolMargin(uint8_t poolId) {
+    Q_REQUIRE(((uint8_t)1 <= poolId) && (poolId <= QF_maxPool_));
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+    uint32_t margin = (uint32_t)QF_pool_[poolId - (uint8_t)1].m_nMin;
+    QF_INT_UNLOCK_();
+
+    return margin;
+}
+
+// "qmp_init.cpp" ============================================================
+void QMPool::init(void *poolSto, uint32_t poolSize, QMPoolSize blockSize) {
+    // The memory block must be valid
+    // and the poolSize must fit at least one free block
+    // and the blockSize must not be too close to the top of the dynamic range
+    Q_REQUIRE((poolSto != (void *)0)
+              && (poolSize >= (uint32_t)sizeof(QFreeBlock))
+              && ((QMPoolSize)(blockSize + (QMPoolSize)sizeof(QFreeBlock))
+                    > blockSize));
+
+    //lint -e923                       ignore MISRA Rule 45 in this expression
+    uint32_t corr = ((uint32_t)poolSto
+                      & ((uint32_t)sizeof(QFreeBlock) - (uint32_t)1));
+    if (corr != (uint32_t)0) {                            // alignment needed?
+        corr = (uint32_t)sizeof(QFreeBlock) - corr; // amount to align poolSto
+        poolSize -= corr;                    // reduce the available pool size
+    }
+    //lint -e826   align the head of free list at the free block-size boundary
+    m_free = (void *)((uint8_t *)poolSto + corr);
+
+                // round up the blockSize to fit an integer number of pointers
+    m_blockSize = (QMPoolSize)sizeof(QFreeBlock);       // start with just one
+    uint32_t nblocks = (uint32_t)1;// # free blocks that fit in a memory block
+    while (m_blockSize < blockSize) {
+        m_blockSize += (QMPoolSize)sizeof(QFreeBlock);
+        ++nblocks;
+    }
+    blockSize = m_blockSize;          // use the rounded-up value from here on
+
+               // the whole pool buffer must fit at least one rounded-up block
+    Q_ASSERT(poolSize >= (uint32_t)blockSize);
+
+                                // chain all blocks together in a free-list...
+    poolSize -= (uint32_t)blockSize;             // don't chain the last block
+    m_nTot     = (QMPoolCtr)1;             // one (the last) block in the pool
+    QFreeBlock *fb = (QFreeBlock *)m_free;//start at the head of the free list
+    while (poolSize >= (uint32_t)blockSize) {
+        fb->m_next = &fb[nblocks];                      // setup the next link
+        fb = fb->m_next;                              // advance to next block
+        poolSize -= (uint32_t)blockSize;     // reduce the available pool size
+        ++m_nTot;                     // increment the number of blocks so far
+    }
+
+    fb->m_next = (QFreeBlock *)0;              // the last link points to NULL
+    m_nFree    = m_nTot;                                // all blocks are free
+    m_nMin     = m_nTot;                  // the minimum number of free blocks
+    m_start    = poolSto;               // the original start this pool buffer
+    m_end      = fb;                            // the last block in this pool
+
+    QS_INT_LOCK_KEY_
+    QS_BEGIN_(QS_QF_MPOOL_INIT, QS::mpObj_, m_start)
+        QS_OBJ_(m_start);                   // the memory managed by this pool
+        QS_MPC_(m_nTot);                         // the total number of blocks
+    QS_END_()
+}
+
+// "qmp_put.cpp" =============================================================
+void QMPool::put(void *b) {
+    //lint -e946 -e1904             ignore MISRA Rule 103 in this precondition
+    Q_REQUIRE((m_start <= b) && (b <= m_end)           /*  must be in range */
+              && (m_nFree <= m_nTot));        // # free blocks must be < total
+
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    ((QFreeBlock *)b)->m_next = (QFreeBlock *)m_free;//link into the free list
+    m_free = b;                            // set as new head of the free list
+    ++m_nFree;                             // one more free block in this pool
+
+    QS_BEGIN_NOLOCK_(QS_QF_MPOOL_PUT, QS::mpObj_, m_start)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(m_start);                   // the memory managed by this pool
+        QS_MPC_(m_nFree);             // the number of free blocks in the pool
+    QS_END_NOLOCK_()
+
+    QF_INT_UNLOCK_();
+}
+
+// "qte_arm.cpp" =============================================================
+// Package-scope objects -----------------------------------------------------
+QTimeEvt *QF_timeEvtListHead_;           // head of linked list of time events
+
+//............................................................................
+void QTimeEvt::arm_(QActive *act, QTimeEvtCtr nTicks) {
+    Q_REQUIRE((nTicks > (QTimeEvtCtr)0)          /* cannot arm with 0 ticks */
+              && (sig >= (QSignal)Q_USER_SIG)               /* valid signal */
+              && (m_prev == (QTimeEvt *)0)   /* time event must NOT be used */
+              && (act != (QActive *)0));  /* active object must be provided */
+    m_ctr = nTicks;
+    m_prev = this;                                    // mark the timer in use
+    m_act = act;
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_ARM, QS::teObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(this);                               // this time event object
+        QS_OBJ_(act);                                     // the active object
+        QS_TEC_(nTicks);                                // the number of ticks
+        QS_TEC_(m_interval);                                   // the interval
+    QS_END_NOLOCK_()
+
+    m_next = QF_timeEvtListHead_;
+    if (QF_timeEvtListHead_ != (QTimeEvt *)0) {
+        QF_timeEvtListHead_->m_prev = this;
+    }
+    QF_timeEvtListHead_ = this;
+    QF_INT_UNLOCK_();
+}
+
+// "qte_ctor.cpp" ============================================================
+QTimeEvt::QTimeEvt(QSignal s)
+    : m_prev((QTimeEvt *)0),
+      m_next((QTimeEvt *)0),
+      m_act((QActive *)0),
+      m_ctr((QTimeEvtCtr)0),
+      m_interval((QTimeEvtCtr)0)
+{
+    Q_REQUIRE(s >= (QSignal)Q_USER_SIG);                       // valid signal
+    sig = s;
+    dynamic_ = (uint8_t)0;            // time event must be static, see NOTE01
+}
+
+// "qte_darm.cpp" ============================================================
+// NOTE: disarm a time evt (no harm in disarming an already disarmed time evt)
+uint8_t QTimeEvt::disarm(void) {
+    uint8_t wasArmed;
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+    if (m_prev != (QTimeEvt *)0) {        // is the time event actually armed?
+        wasArmed = (uint8_t)1;
+        if (this == QF_timeEvtListHead_) {
+            QF_timeEvtListHead_ = m_next;
+        }
+        else {
+            if (m_next != (QTimeEvt *)0) {        // not the last in the list?
+                m_next->m_prev = m_prev;
+            }
+            m_prev->m_next = m_next;
+        }
+        m_prev = (QTimeEvt *)0;             // mark the time event as disarmed
+
+        QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM, QS::teObj_, this)
+            QS_TIME_();                                           // timestamp
+            QS_OBJ_(this);                           // this time event object
+            QS_OBJ_(m_act);                               // the active object
+            QS_TEC_(m_ctr);                             // the number of ticks
+            QS_TEC_(m_interval);                               // the interval
+        QS_END_NOLOCK_()
+    }
+    else {                                     // the time event was not armed
+        wasArmed = (uint8_t)0;
+
+        QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_DISARM_ATTEMPT, QS::teObj_, this)
+            QS_TIME_();                                           // timestamp
+            QS_OBJ_(this);                           // this time event object
+            QS_OBJ_(m_act);                               // the active object
+        QS_END_NOLOCK_()
+    }
+    QF_INT_UNLOCK_();
+    return wasArmed;
+}
+
+// "qte_rarm.cpp" ============================================================
+uint8_t QTimeEvt::rearm(QTimeEvtCtr nTicks) {
+    Q_REQUIRE((nTicks > (QTimeEvtCtr)0)        /* cannot rearm with 0 ticks */
+              && (sig >= (QSignal)Q_USER_SIG)               /* valid signal */
+              && (m_act != (QActive *)0));              // valid active object
+    uint8_t isArmed;
+    QF_INT_LOCK_KEY_
+    QF_INT_LOCK_();
+    m_ctr = nTicks;
+    if (m_prev == (QTimeEvt *)0) {             // is this time event disarmed?
+        isArmed = (uint8_t)0;
+        m_next = QF_timeEvtListHead_;
+        if (QF_timeEvtListHead_ != (QTimeEvt *)0) {
+            QF_timeEvtListHead_->m_prev = this;
+        }
+        QF_timeEvtListHead_ = this;
+        m_prev = this;                             // mark the time evt in use
+    }
+    else {                                          // the time event is armed
+        isArmed = (uint8_t)1;
+    }
+
+    QS_BEGIN_NOLOCK_(QS_QF_TIMEEVT_REARM, QS::teObj_, this)
+        QS_TIME_();                                               // timestamp
+        QS_OBJ_(this);                               // this time event object
+        QS_OBJ_(m_act);                                   // the active object
+        QS_TEC_(m_ctr);                                 // the number of ticks
+        QS_TEC_(m_interval);                                   // the interval
+        QS_U8_(isArmed);                               // was the timer armed?
+    QS_END_NOLOCK_()
+
+    QF_INT_UNLOCK_();
+    return isArmed;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Kernel selection based on QK_PREEMPTIVE
+//
+#ifdef QK_PREEMPTIVE
+
+// "qk_pkg.h" ================================================================
+                                    // QK internal interrupt locking/unlocking
+#ifndef QF_INT_KEY_TYPE
+    #define QK_INT_LOCK_KEY_
+    #define QK_INT_LOCK_()      QF_INT_LOCK(dummy)
+    #define QK_INT_UNLOCK_()    QF_INT_UNLOCK(dummy)
+#else
+
+    /// \brief This is an internal macro for defining the interrupt lock key.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro provides the
+    /// definition of the lock key variable. Otherwise this macro is empty.
+    /// \sa #QF_INT_KEY_TYPE, #QF_INT_LOCK_, #QF_INT_UNLOCK_
+    #define QK_INT_LOCK_KEY_    QF_INT_KEY_TYPE intLockKey_;
+
+    /// \brief This is an internal macro for locking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro invokes #QF_INT_LOCK
+    /// passing the key variable as the parameter. Otherwise #QF_INT_LOCK
+    /// is invoked with a dummy parameter.
+    /// \sa #QK_INT_LOCK_KEY_, #QK_INT_UNLOCK_
+    #define QK_INT_LOCK_()      QF_INT_LOCK(intLockKey_)
+
+    /// \brief This is an internal macro for unlocking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QF_INT_KEY_TYPE is defined, this internal macro invokes
+    /// #QF_INT_UNLOCK passing the key variable as the parameter. Otherwise
+    /// #QF_INT_UNLOCK is invoked with a dummy parameter.
+    /// \sa #QK_INT_LOCK_KEY_, #QK_INT_LOCK_
+    #define QK_INT_UNLOCK_()    QF_INT_UNLOCK(intLockKey_)
+#endif
+
+                                                   // package-scope objects...
+#ifndef QK_NO_MUTEX
+    extern uint8_t volatile QK_ceilingPrio_;    ///< QK mutex priority ceiling
+#endif
+
+// "qk.cpp" ==================================================================
+// Public-scope objects ------------------------------------------------------
+#if (QF_MAX_ACTIVE <= 8)
+    QPSet8  volatile QK_readySet_;                          // ready set of QK
+#else
+    QPSet64 volatile QK_readySet_;                          // ready set of QK
+#endif
+                                         // start with the QK scheduler locked
+uint8_t volatile QK_currPrio_ = (uint8_t)(QF_MAX_ACTIVE + 1);
+uint8_t volatile QK_intNest_;                 // start with nesting level of 0
+
+
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+char const Q_ROM * Q_ROM_VAR QK::getVersion(void) {
+    static char const Q_ROM Q_ROM_VAR version[] = {
+        ((QP_VERSION >> 12) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  8) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  4) & 0xF) + '0',
+        (QP_VERSION         & 0xF) + '0',
+        '\0'
+    };
+    return version;
+}
+//............................................................................
+void QF::init(void) {
+    QK_init();           // QK initialization ("C" linkage, might be assembly)
+}
+//............................................................................
+void QF::stop(void) {
+    QF::onCleanup();                                       // cleanup callback
+    // nothing else to do for the QK preemptive kernel
+}
+//............................................................................
+void QF::run(void) {
+    QK_INT_LOCK_KEY_
+
+    QK_INT_LOCK_();
+    QK_currPrio_ = (uint8_t)0;        // set the priority for the QK idle loop
+    QK_SCHEDULE_();                      // process all events produced so far
+    QK_INT_UNLOCK_();
+
+    QF::onStartup();                                       // startup callback
+
+    for (;;) {                                             // the QK idle loop
+        QK::onIdle();                        // invoke the QK on-idle callback
+    }
+}
+//............................................................................
+void QActive::start(uint8_t prio,
+                    QEvent const *qSto[], uint32_t qLen,
+                    void *tls, uint32_t flags,
+                    QEvent const *ie)
+{
+    Q_REQUIRE(((uint8_t)0 < prio) && (prio <= (uint8_t)QF_MAX_ACTIVE));
+
+    m_eQueue.init(qSto, (QEQueueCtr)qLen);       // initialize the event queue
+    m_prio = prio;
+    QF::add_(this);                     // make QF aware of this active object
+
+#if defined(QK_TLS) || defined(QK_EXT_SAVE)
+    m_osObject = (uint8_t)flags;       // m_osObject contains the thread flags
+    m_thread   = tls;      // contains the pointer to the thread-local-storage
+#else
+    Q_ASSERT((tls == (void *)0) && (flags == (uint32_t)0));
+#endif
+
+    init(ie);                                    // execute initial transition
+
+    QS_FLUSH();                          // flush the trace buffer to the host
+}
+//............................................................................
+void QActive::stop(void) {
+    QF::remove_(this);                // remove this active object from the QF
+}
+
+// "qk_sched" ================================================================
+//............................................................................
+// NOTE: the QK scheduler is entered and exited with interrupts LOCKED
+#ifndef QF_INT_KEY_TYPE
+void QK_schedule_(void) {
+#else
+void QK_schedule_(QF_INT_KEY_TYPE intLockKey_) {
+#endif
+                         // the QK scheduler must be called at task level only
+    Q_REQUIRE(QK_intNest_ == (uint8_t)0);
+
+           // determine the priority of the highest-priority task ready to run
+    uint8_t p = QK_readySet_.findMax();
+
+#ifdef QK_NO_MUTEX
+    if (p > QK_currPrio_) {                        // do we have a preemption?
+#else                                   // QK priority-ceiling mutexes allowed
+    if ((p > QK_currPrio_) && (p > QK_ceilingPrio_)) {
+#endif
+        uint8_t pin = QK_currPrio_;               // save the initial priority
+        QActive *a;
+#ifdef QK_TLS                                    // thread-local storage used?
+        uint8_t pprev = pin;
+#endif
+        do {
+            QEvent const *e;
+            a = QF::active_[p];                // obtain the pointer to the AO
+            QK_currPrio_ = p;        // this becomes the current task priority
+
+#ifdef QK_TLS                                    // thread-local storage used?
+            if (p != pprev) {                      // are we changing threads?
+                QK_TLS(a);                  // switch new thread-local storage
+                pprev = p;
+            }
+#endif
+            QS_BEGIN_NOLOCK_(QS_QK_SCHEDULE, QS::aoObj_, a)
+                QS_TIME_();                                       // timestamp
+                QS_U8_(p);                // the priority of the active object
+                QS_U8_(pin);                         // the preempted priority
+            QS_END_NOLOCK_()
+
+            QK_INT_UNLOCK_();                         // unlock the interrupts
+
+            e = a->get_();        // get the next event for this active object
+            a->dispatch(e);                 // dispatch e to the active object
+            QF::gc(e);              // garbage collect the event, if necessary
+
+            QK_INT_LOCK_();
+                             // determine the highest-priority AO ready to run
+            if (QK_readySet_.notEmpty()) {
+                p = QK_readySet_.findMax();
+            }
+            else {
+                p = (uint8_t)0;
+            }
+#ifdef QK_NO_MUTEX
+        } while (p > pin);         // is the new priority higher than initial?
+#else                                   // QK priority-ceiling mutexes allowed
+        } while ((p > pin) && (p > QK_ceilingPrio_));
+#endif
+        QK_currPrio_ = pin;                    // restore the initial priority
+
+#ifdef QK_TLS                                    // thread-local storage used?
+        if (pin != (uint8_t)0) {      // no extended context for the idle loop
+            a = QF::active_[pin];           // the pointer to the preempted AO
+            QK_TLS(a);                             // restore the original TLS
+        }
+#endif
+    }
+}
+
+// "qk_mutex.cpp" ============================================================
+#ifndef QK_NO_MUTEX
+
+// package-scope objects -----------------------------------------------------
+uint8_t volatile QK_ceilingPrio_;               // ceiling priority of a mutex
+
+//............................................................................
+QMutex QK::mutexLock(uint8_t prioCeiling) {
+    QK_INT_LOCK_KEY_
+    QK_INT_LOCK_();
+    uint8_t mutex = QK_ceilingPrio_; // original QK priority ceiling to return
+    if (QK_ceilingPrio_ < prioCeiling) {
+        QK_ceilingPrio_ = prioCeiling;        // raise the QK priority ceiling
+    }
+
+    QS_BEGIN_NOLOCK_(QS_QK_MUTEX_LOCK, (void *)0, (void *)0)
+        QS_TIME_();                                               // timestamp
+        QS_U8_(mutex);                                // the original priority
+        QS_U8_(QK_ceilingPrio_);               // the current priority ceiling
+    QS_END_NOLOCK_()
+
+    QK_INT_UNLOCK_();
+    return mutex;
+}
+//............................................................................
+void QK::mutexUnlock(QMutex mutex) {
+    QK_INT_LOCK_KEY_
+    QK_INT_LOCK_();
+
+    QS_BEGIN_NOLOCK_(QS_QK_MUTEX_UNLOCK, (void *)0, (void *)0)
+        QS_TIME_();                                               // timestamp
+        QS_U8_(mutex);                                // the original priority
+        QS_U8_(QK_ceilingPrio_);               // the current priority ceiling
+    QS_END_NOLOCK_()
+
+    if (QK_ceilingPrio_ > mutex) {
+        QK_ceilingPrio_ = mutex;         // restore the saved priority ceiling
+        QK_SCHEDULE_();
+    }
+    QK_INT_UNLOCK_();
+}
+#endif                                                          // QK_NO_MUTEX
+
+#else                                                         // QK_PREEMPTIVE
+
+// "qvanilla.cpp" ============================================================
+// Package-scope objects -----------------------------------------------------
+#if (QF_MAX_ACTIVE <= 8)
+    QPSet8  volatile QF_readySet_;           // QF-ready set of active objects
+#else
+    QPSet64 volatile QF_readySet_;           // QF-ready set of active objects
+#endif
+
+//............................................................................
+char const Q_ROM * Q_ROM_VAR QF::getPortVersion(void) {
+    static const char Q_ROM version[] = "4.0.00";
+    return version;
+}
+//............................................................................
+void QF::init(void) {
+    // nothing to do for the "vanilla" kernel
+}
+//............................................................................
+void QActive::start(uint8_t prio,
+                    QEvent const *qSto[], uint32_t qLen,
+                    void *stkSto, uint32_t /*lint -e1904 stkSize */,
+                    QEvent const *ie)
+{
+    Q_REQUIRE(((uint8_t)0 < prio) && (prio <= (uint8_t)QF_MAX_ACTIVE)
+              && (stkSto == (void *)0));      // does not need per-actor stack
+
+    m_eQueue.init(qSto, (QEQueueCtr)qLen);               // initialize QEQueue
+    m_prio = prio;                // set the QF priority of this active object
+    QF::add_(this);                     // make QF aware of this active object
+    init(ie);                                    // execute initial transition
+
+    QS_FLUSH();                          // flush the trace buffer to the host
+}
+//............................................................................
+void QActive::stop(void) {
+    QF::remove_(this);
+}
+
+//............................................................................
+void QF::stop(void) {
+    QF::onCleanup();                                       // cleanup callback
+    // nothing else to do for the "vanilla" kernel
+}
+//............................................................................
+void QF::run(void) {
+    QF::onStartup();                                       // startup callback
+
+    for (;;) {                                           // the bacground loop
+        QF_INT_LOCK_KEY_
+        QF_INT_LOCK_();
+        if (QF_readySet_.notEmpty()) {
+            uint8_t p = QF_readySet_.findMax();
+            QActive *a = active_[p];
+            QF_INT_UNLOCK_();
+
+            QEvent const *e = a->get_();     // get the next event for this AO
+            a->dispatch(e);                         // dispatch evt to the HSM
+            gc(e);       // determine if event is garbage and collect it if so
+        }
+        else {
+#ifndef QF_INT_KEY_TYPE
+            onIdle();                                            // see NOTE01
+#else
+            onIdle(intLockKey_);                                 // see NOTE01
+#endif                                                      // QF_INT_KEY_TYPE
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// NOTE01:
+// QF::onIdle() must be called with interrupts LOCKED because the
+// determination of the idle condition (no events in the queues) can change
+// at any time by an interrupt posting events to a queue. The QF::onIdle()
+// MUST enable interrups internally, perhaps at the same time as putting the
+// CPU into a power-saving mode.
+//
+
+#endif                                                        // QK_PREEMPTIVE
+
+//////////////////////////////////////////////////////////////////////////////
+#ifdef Q_SPY
+
+// "qs_pkg.h" ================================================================
+/// \brief QS ring buffer counter and offset type
+typedef uint16_t QSCtr;
+
+/// \brief Internal QS macro to insert an un-escaped byte into
+/// the QS buffer
+////
+#define QS_INSERT_BYTE(b_) \
+    QS_ring_[QS_head_] = (b_); \
+    ++QS_head_; \
+    if (QS_head_ == QS_end_) { \
+        QS_head_ = (QSCtr)0; \
+    } \
+    ++QS_used_;
+
+/// \brief Internal QS macro to insert an escaped byte into the QS buffer
+#define QS_INSERT_ESC_BYTE(b_) \
+    QS_chksum_ = (uint8_t)(QS_chksum_ + (b_)); \
+    if (((b_) == QS_FRAME) || ((b_) == QS_ESC)) { \
+        QS_INSERT_BYTE(QS_ESC) \
+        QS_INSERT_BYTE((uint8_t)((b_) ^ QS_ESC_XOR)) \
+    } \
+    else { \
+        QS_INSERT_BYTE(b_) \
+    }
+
+/// \brief Internal QS macro to insert a escaped checksum byte into
+/// the QS buffer
+#define QS_INSERT_CHKSUM_BYTE() \
+    QS_chksum_ = (uint8_t)~QS_chksum_; \
+    if ((QS_chksum_ == QS_FRAME) || (QS_chksum_ == QS_ESC)) { \
+        QS_INSERT_BYTE(QS_ESC) \
+        QS_INSERT_BYTE((uint8_t)(QS_chksum_ ^ QS_ESC_XOR)) \
+    } \
+    else { \
+        QS_INSERT_BYTE(QS_chksum_) \
+    }
+
+
+/// \brief Frame character of the QS output protocol
+#define QS_FRAME    ((uint8_t)0x7E)
+
+/// \brief Escape character of the QS output protocol
+#define QS_ESC      ((uint8_t)0x7D)
+
+/// \brief Escape modifier of the QS output protocol
+///
+/// The escaped byte is XOR-ed with the escape modifier before it is inserted
+/// into the QS buffer.
+#define QS_ESC_XOR  0x20
+
+#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
+
+//............................................................................
+extern uint8_t *QS_ring_;         ///< pointer to the start of the ring buffer
+extern QSCtr QS_end_;                ///< offset of the end of the ring buffer
+extern QSCtr QS_head_;         ///< offset to where next byte will be inserted
+extern QSCtr QS_tail_;       ///< offset of where next event will be extracted
+extern QSCtr QS_used_;       ///< number of bytes currently in the ring buffer
+extern uint8_t QS_seq_;                        ///< the record sequence number
+extern uint8_t QS_chksum_;             ///< the checksum of the current record
+extern uint8_t QS_full_;              ///< the ring buffer is temporarily full
+
+// "qs.cpp" ==================================================================
+//............................................................................
+uint8_t QS::glbFilter_[32];                                // global QS filter
+
+//............................................................................
+uint8_t *QS_ring_;                  // pointer to the start of the ring buffer
+QSCtr QS_end_;                         // offset of the end of the ring buffer
+QSCtr QS_head_;                  // offset to where next byte will be inserted
+QSCtr QS_tail_;                 // offset of where next byte will be extracted
+QSCtr QS_used_;                // number of bytes currently in the ring buffer
+uint8_t QS_seq_;                                 // the record sequence number
+uint8_t QS_chksum_;                      // the checksum of the current record
+uint8_t QS_full_;                       // the ring buffer is temporarily full
+
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+char const Q_ROM * Q_ROM_VAR QS::getVersion(void) {
+    static char const Q_ROM Q_ROM_VAR version[] = {
+        ((QP_VERSION >> 12) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  8) & 0xF) + '0',
+        '.',
+        ((QP_VERSION >>  4) & 0xF) + '0',
+        (QP_VERSION         & 0xF) + '0',
+        '\0'
+    };
+    return version;
+}
+//............................................................................
+void QS::initBuf(uint8_t sto[], uint32_t stoSize) {
+    QS_ring_ = &sto[0];
+    QS_end_  = (QSCtr)stoSize;
+}
+//............................................................................
+void QS::filterOn(uint8_t rec) {
+    if (rec == QS_ALL_RECORDS) {
+        uint8_t i;
+        for (i = (uint8_t)0; i < (uint8_t)sizeof(glbFilter_); ++i) {
+            glbFilter_[i] = (uint8_t)0xFF;
+        }
+    }
+    else {
+        glbFilter_[rec >> 3] |= (uint8_t)(1U << (rec & 0x07));
+    }
+}
+//............................................................................
+void QS::filterOff(uint8_t rec) {
+    if (rec == QS_ALL_RECORDS) {
+        uint8_t i;
+        for (i = (uint8_t)0; i < (uint8_t)sizeof(glbFilter_); ++i) {
+            glbFilter_[i] = (uint8_t)0;
+        }
+    }
+    else {
+        glbFilter_[rec >> 3] &= (uint8_t)(~(1U << (rec & 0x07)));
+    }
+}
+//............................................................................
+void QS::begin(uint8_t rec) {
+    QS_chksum_ = (uint8_t)0;                             // clear the checksum
+    ++QS_seq_;                         // always increment the sequence number
+    QS_INSERT_ESC_BYTE(QS_seq_)                   // store the sequence number
+    QS_INSERT_ESC_BYTE(rec)                             // store the record ID
+}
+//............................................................................
+void QS::end(void) {
+    QS_INSERT_CHKSUM_BYTE()
+    QS_INSERT_BYTE(QS_FRAME)
+    if (QS_used_ > QS_end_) {                    // overrun over the old data?
+        QS_tail_ = QS_head_;                 // shift the tail to the old data
+        QS_used_ = QS_end_;                        // the whole buffer is used
+    }
+}
+//............................................................................
+void QS::u8(uint8_t format, uint8_t d) {
+    QS_INSERT_ESC_BYTE(format)
+    QS_INSERT_ESC_BYTE(d)
+}
+//............................................................................
+void QS::u16(uint8_t format, uint16_t d) {
+    QS_INSERT_ESC_BYTE(format)
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+}
+//............................................................................
+void QS::u32(uint8_t format, uint32_t d) {
+    QS_INSERT_ESC_BYTE(format)
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+}
+
+// "qs_.cpp" =================================================================
+//............................................................................
+void const *QS::smObj_;                  // local state machine for QEP filter
+void const *QS::aoObj_;                   // local active object for QF filter
+void const *QS::mpObj_;                     //  local event pool for QF filter
+void const *QS::eqObj_;                      //  local raw queue for QF filter
+void const *QS::teObj_;                     //  local time event for QF filter
+void const *QS::apObj_;                    //  local object Application filter
+
+QSTimeCtr volatile QS::tickCtr_;     // tick counter for the QS_QF_TICK record
+
+//............................................................................
+void QS::u8_(uint8_t d) {
+    QS_INSERT_ESC_BYTE(d)
+}
+//............................................................................
+void QS::u16_(uint16_t d) {
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+}
+//............................................................................
+void QS::u32_(uint32_t d) {
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+    d >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)d)
+}
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+void QS::str_(char const *s) {
+    while (*s != '\0') {
+                                       // ASCII characters don't need escaping
+        QS_chksum_ = (uint8_t)(QS_chksum_ + (uint8_t)(*s));
+        QS_INSERT_BYTE((uint8_t)(*s))
+        ++s;
+    }
+    QS_INSERT_BYTE((uint8_t)0)
+}
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+void QS::str_ROM_(char const Q_ROM * Q_ROM_VAR s) {
+    uint8_t b;
+    while ((b = (uint8_t)Q_ROM_BYTE(*s)) != (uint8_t)0) {
+                                       // ASCII characters don't need escaping
+        QS_chksum_ = (uint8_t)(QS_chksum_ + b);
+        QS_INSERT_BYTE(b)
+        ++s;
+    }
+    QS_INSERT_BYTE((uint8_t)0)
+}
+
+// "qs_blk.cpp" ==============================================================
+//............................................................................
+// get up to *pn bytes of contiguous memory
+uint8_t const *QS::getBlock(uint16_t *pNbytes) {
+    uint8_t *block;
+    if (QS_used_ == (QSCtr)0) {
+        *pNbytes = (uint16_t)0;
+        block = (uint8_t *)0;                  // no bytes to return right now
+    }
+    else {
+        QSCtr n = (QSCtr)(QS_end_ - QS_tail_);
+        if (n > QS_used_) {
+            n = QS_used_;
+        }
+        if (n > (QSCtr)(*pNbytes)) {
+            n = (QSCtr)(*pNbytes);
+        }
+        *pNbytes = (uint16_t)n;
+        QS_used_ = (QSCtr)(QS_used_ - n);
+        QSCtr t  = QS_tail_;
+        QS_tail_ = (QSCtr)(QS_tail_ + n);
+        if (QS_tail_ == QS_end_) {
+            QS_tail_ = (QSCtr)0;
+        }
+        block = &QS_ring_[t];
+    }
+    return block;
+}
+
+// "qs_byte.cpp" =============================================================
+//............................................................................
+uint16_t QS::getByte(void) {
+    uint16_t ret;
+    if (QS_used_ == (QSCtr)0) {
+        ret = QS_EOD;                                       // set End-Of-Data
+    }
+    else {
+        ret = QS_ring_[QS_tail_];                    // set the byte to return
+        ++QS_tail_;                                        // advance the tail
+        if (QS_tail_ == QS_end_) {                        // tail wrap around?
+            QS_tail_ = (QSCtr)0;
+        }
+        --QS_used_;                                      // one less byte used
+    }
+    return ret;                                      // return the byte or EOD
+}
+
+// "qs_f32.cpp" ==============================================================
+//............................................................................
+void QS::f32(uint8_t format, float f) {
+    union F32Rep {
+        float f;
+        uint32_t u;
+    } fu32;
+    fu32.f = f;
+
+    QS_INSERT_ESC_BYTE(format)
+    QS_INSERT_ESC_BYTE((uint8_t)fu32.u)
+    fu32.u >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu32.u)
+    fu32.u >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu32.u)
+    fu32.u >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu32.u)
+}
+
+// "qs_f64.cpp" ==============================================================
+//............................................................................
+void QS::f64(uint8_t format, double d) {
+    union F64Rep {
+        double d;
+        struct UInt2 {
+            uint32_t u1, u2;
+        } i;
+    } fu64;
+    fu64.d = d;
+
+    QS_INSERT_ESC_BYTE(format)
+
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u1)
+    fu64.i.u1 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u1)
+    fu64.i.u1 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u1)
+    fu64.i.u1 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u1)
+
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u2)
+    fu64.i.u2 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u2)
+    fu64.i.u2 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u2)
+    fu64.i.u2 >>= 8;
+    QS_INSERT_ESC_BYTE((uint8_t)fu64.i.u2)
+}
+
+// "qs_mem.cpp" ==============================================================
+//............................................................................
+void QS::mem(uint8_t const *blk, uint8_t size) {
+    QS_INSERT_BYTE((uint8_t)QS_MEM_T)
+    QS_chksum_ = (uint8_t)(QS_chksum_ + (uint8_t)QS_MEM_T);
+    QS_INSERT_ESC_BYTE(size)
+    while (size != (uint8_t)0) {
+        QS_INSERT_ESC_BYTE(*blk)
+        ++blk;
+        --size;
+    }
+}
+
+// "qs_str.cpp" ==============================================================
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+void QS::str(char const *s) {
+    QS_INSERT_BYTE((uint8_t)QS_STR_T)
+    QS_chksum_ = (uint8_t)(QS_chksum_ + (uint8_t)QS_STR_T);
+    while ((*s) != '\0') {
+                                       // ASCII characters don't need escaping
+        QS_INSERT_BYTE((uint8_t)(*s))
+        QS_chksum_ = (uint8_t)(QS_chksum_ + (uint8_t)(*s));
+        ++s;
+    }
+    QS_INSERT_BYTE((uint8_t)0)
+}
+//............................................................................
+//lint -e970 -e971               ignore MISRA rules 13 and 14 in this function
+void QS::str_ROM(char const Q_ROM * Q_ROM_VAR s) {
+    QS_INSERT_BYTE((uint8_t)QS_STR_T)
+    QS_chksum_ = (uint8_t)(QS_chksum_ + (uint8_t)QS_STR_T);
+    uint8_t b;
+    while ((b = (uint8_t)Q_ROM_BYTE(*s)) != (uint8_t)0) {
+                                       // ASCII characters don't need escaping
+        QS_INSERT_BYTE(b)
+        QS_chksum_ = (uint8_t)(QS_chksum_ + b);
+        ++s;
+    }
+    QS_INSERT_BYTE((uint8_t)0)
+}
+
+#endif                                                                // Q_SPY
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qp.h	Wed Feb 09 14:46:03 2011 +0000
@@ -0,0 +1,3314 @@
+//////////////////////////////////////////////////////////////////////////////
+// Product: QP/C++
+// Last Updated for QP ver: 4.1.06 (modified to fit in one file)
+// Date of the Last Update: Jan 26, 2011
+//
+//                    Q u a n t u m     L e a P s
+//                    ---------------------------
+//                    innovating embedded systems
+//
+// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+//
+// This software may be distributed and modified under the terms of the GNU
+// General Public License version 2 (GPL) as published by the Free Software
+// Foundation and appearing in the file GPL.TXT included in the packaging of
+// this file. Please note that GPL Section 2[b] requires that all works based
+// on this software must also be made publicly available under the terms of
+// the GPL ("Copyleft").
+//
+// Alternatively, this software may be distributed and modified under the
+// terms of Quantum Leaps commercial licenses, which expressly supersede
+// the GPL and are specifically designed for licensees interested in
+// retaining the proprietary status of their code.
+//
+// Contact information:
+// Quantum Leaps Web site:  http://www.quantum-leaps.com
+// e-mail:                  info@quantum-leaps.com
+//////////////////////////////////////////////////////////////////////////////
+#ifndef qp_h
+#define qp_h
+
+// "qevent.h" ================================================================
+/// \brief QEvent 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      0x4106
+
+#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 1
+#endif
+#if (Q_SIGNAL_SIZE == 1)
+    /// \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
+    /// document
+    /// <A HREF="http://www.quantum-leaps.com/devzone/Recipe_IntroHSM.pdf">
+    /// Brief Introduction to UML State Machines</A>) for more information
+    /// about state machine concepts.
+    typedef uint8_t QSignal;
+#elif (Q_SIGNAL_SIZE == 2)
+    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
+
+//////////////////////////////////////////////////////////////////////////////
+/// \brief QEvent base class.
+///
+/// QEvent represents events without parameters and serves as the base class
+/// for derivation of events with parameters.
+///
+/// \note All data members of the QEvent class must remain public to keep it
+/// an AGGREGATE. Therefore, the attribute QEvent::dynamic_ cannot be
+/// declared private.
+///
+/// The following example illustrates how to add an event parameter by
+/// inheriting from the QEvent class.
+/// \include qep_qevent.cpp
+struct QEvent {
+    QSignal sig;                             ///< signal of the event instance
+    uint8_t dynamic_;  ///< attributes of a dynamic event (0 for static event)
+};
+
+//////////////////////////////////////////////////////////////////////////////
+/// helper macro to calculate static dimension of a 1-dim array \a array_
+#define Q_DIM(array_) (sizeof(array_) / sizeof(array_[0]))
+
+// "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 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 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 *me, QEvent const *e);
+
+
+//////////////////////////////////////////////////////////////////////////////
+/// \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 {
+protected:
+    QStateHandler m_state;          ///< current active state (state-variable)
+
+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 ::QEvent or a class
+    /// derived from ::QEvent.
+    ///
+    /// \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(QEvent const *e = (QEvent *)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 ::QEvent or a
+    /// class derived from ::QEvent.
+    ///
+    /// \note Must be called after QFsm::init().
+    ///
+    /// \sa example for QFsm::init()
+    void dispatch(QEvent 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 initial) : m_state(initial) {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+/// \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 {
+protected:
+    QStateHandler m_state;          ///< current active state (state-variable)
+
+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 ::QEvent or a class derived from ::QEvent
+    /// \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(QEvent const *e = (QEvent *)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 ::QEvent or a
+    /// class derived from ::QEvent.
+    ///
+    /// \note Must be called after QHsm::init().
+    ///
+    /// \sa example for QHsm::init()
+    void dispatch(QEvent 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.
+    uint8_t isIn(QStateHandler state);
+
+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 initial) : m_state(initial) {}
+
+    /// \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(QHsm *me, QEvent const *e);
+};
+
+/// \brief Value returned by a non-hierarchical state-handler function when
+/// it ignores (does not handle) the event.
+#define Q_RET_IGNORED       ((QState)1)
+
+/// \brief The macro returned from a non-hierarchical state-handler function
+/// when it ignores (does not handle) the event.
+///
+/// You call that macro after the return statement (return Q_IGNORED();)
+///
+/// \include qepn_qfsm.cpp
+#define Q_IGNORED()         (Q_RET_IGNORED)
+
+/// \brief Value returned by a state-handler function when it handles
+/// the event.
+#define Q_RET_HANDLED       ((QState)0)
+
+/// \brief Value returned by a state-handler function when it handles
+/// the event.
+///
+/// You call that macro after the return statement (return Q_HANDLED();)
+/// Q_HANDLED() can be used both in the FSMs and HSMs.
+///
+/// \include qepn_qfsm.cpp
+#define Q_HANDLED()         (Q_RET_HANDLED)
+
+/// \brief Value returned by a state-handler function when it takes a
+/// regular state transition.
+#define Q_RET_TRAN          ((QState)2)
+
+/// \brief Designates a target for an initial or regular transition.
+/// Q_TRAN() can be used both in the FSMs and HSMs.
+///
+/// \include qepn_qtran.cpp
+//lint -e960 -e1924 ignore MISRA Rule 42 (comma operator) and C-style cast
+#define Q_TRAN(target_)  \
+    (me->m_state = (QStateHandler)(target_), Q_RET_TRAN)
+
+/// \brief Value returned by a state-handler function when it cannot
+/// handle the event.
+#define Q_RET_SUPER         ((QState)3)
+
+/// \brief Designates the superstate of a given state in an HSM.
+///
+/// \include qep_qhsm.cpp
+//lint -e960 -e1924 ignore MISRA Rule 42 (comma operator) and C-style cast
+#define Q_SUPER(super_)  \
+    (me->m_state = (QStateHandler)(super_),  Q_RET_SUPER)
+
+//////////////////////////////////////////////////////////////////////////////
+/// \brief QEP reserved signals.
+enum QReservedSignals {
+    Q_ENTRY_SIG = 1,                             ///< signal for entry actions
+    Q_EXIT_SIG,                                   ///< signal for exit actions
+    Q_INIT_SIG,                     ///< signal for nested initial transitions
+    Q_USER_SIG                              ///< signal to offset user signals
+};
+
+// "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
+#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.
+    QEvent const *m_frontEvt;
+
+    /// \brief pointer to the start of the ring buffer
+    QEvent 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(QEvent const *qSto[], QEQueueCtr 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(QEvent 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(QEvent 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()
+    QEvent 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;
+};
+
+// "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
+#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
+
+//////////////////////////////////////////////////////////////////////////////
+#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
+#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 *poolSto, uint32_t poolSize, QMPoolSize 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 *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;
+};
+
+// "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.
+
+                      // external declarations of QF lookup tables used inline
+extern uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256];
+extern uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65];
+extern uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65];
+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 {
+protected:
+    //////////////////////////////////////////////////////////////////////////
+    /// \brief bimask representing elements of the set
+    uint8_t m_bits;
+
+public:
+
+    /// \brief the function evaluates to TRUE if the priority set is empty,
+    /// which means that no active objects are ready to run.
+    uint8_t isEmpty(void) volatile {
+        return (uint8_t)(m_bits == (uint8_t)0);
+    }
+
+    /// \brief the function evaluates to TRUE if the priority set has elements,
+    /// which means that some active objects are ready to run.
+    uint8_t notEmpty(void) volatile {
+        return (uint8_t)(m_bits != (uint8_t)0);
+    }
+
+    /// \brief the function evaluates to TRUE if the priority set has the
+    /// element \a n.
+    uint8_t hasElement(uint8_t n) volatile {
+        return (uint8_t)((m_bits & Q_ROM_BYTE(QF_pwr2Lkup[n])) != 0);
+    }
+
+    /// \brief insert element \a n into the set, n = 1..8
+    void insert(uint8_t n) volatile {
+        m_bits |= Q_ROM_BYTE(QF_pwr2Lkup[n]);
+    }
+
+    /// \brief remove element \a n from the set, n = 1..8
+    void remove(uint8_t n) volatile {
+        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) volatile {
+        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 : public QPSet8 {
+
+    /// \brief subsets representing elements in the set as follows: \n
+    /// m_subset[0] represent elements  1..8  \n
+    /// m_subset[1] represent elements  9..16 \n
+    /// m_subset[2] represent elements 17..24 \n
+    /// m_subset[3] represent elements 25..32 \n
+    /// m_subset[4] represent elements 33..40 \n
+    /// m_subset[5] represent elements 41..48 \n
+    /// m_subset[6] represent elements 49..56 \n
+    /// m_subset[7] represent elements 57..64 \n
+    QPSet8 m_subset[8];
+
+public:
+
+    /// \brief the function evaluates to TRUE if the priority set has the
+    /// element \a n.
+    uint8_t hasElement(uint8_t n) volatile {
+         return m_subset[Q_ROM_BYTE(QF_div8Lkup[n])].QPSet8::hasElement(n);
+    }
+
+    /// \brief insert element \a n into the set, n = 1..64
+    void insert(uint8_t n) volatile {
+        QPSet8::insert(Q_ROM_BYTE(QF_div8Lkup[n]) + 1);
+        m_subset[Q_ROM_BYTE(QF_div8Lkup[n])].QPSet8::insert(n);
+    }
+
+    /// \brief remove element \a n from the set, n = 1..64
+    void remove(uint8_t n) volatile {
+        if ((m_subset[Q_ROM_BYTE(QF_div8Lkup[n])].m_bits
+                 &= Q_ROM_BYTE(QF_invPwr2Lkup[n])) == (uint8_t)0)
+        {
+            QPSet8::remove(Q_ROM_BYTE(QF_div8Lkup[n]) + 1);
+        }
+    }
+
+    /// \brief find the maximum element in the set,
+    /// \note returns zero if the set is empty
+    uint8_t findMax(void) volatile {
+        if (m_bits != (uint8_t)0) {
+            uint8_t n = (uint8_t)(Q_ROM_BYTE(QF_log2Lkup[m_bits]) - 1);
+            return (uint8_t)(Q_ROM_BYTE(QF_log2Lkup[m_subset[n].m_bits])
+                             + (n << 3));
+        }
+        else {
+            return (uint8_t)0;
+        }
+    }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Kernel selection based on QK_PREEMPTIVE
+//
+#ifdef QK_PREEMPTIVE
+
+/// \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 QPSet8  volatile QK_readySet_;                 ///< ready set of QK
+#else
+    extern QPSet64 volatile QK_readySet_;                 ///< ready set of QK
+#endif
+
+extern uint8_t volatile QK_currPrio_;     ///< current task/interrupt priority
+extern uint8_t volatile 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 != (QEvent *)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_) \
+    QK_readySet_.insert((me_)->m_prio); \
+    if (QK_intNest_ == (uint8_t)0) { \
+        QK_SCHEDULE_(); \
+    } else ((void)0)
+
+/// \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 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 memory pool, this macro is defined
+/// at the level of the platform-independent interface qk.h.
+#define QF_EPOOL_TYPE_              QMPool
+
+/// \brief Platform-dependent macro defining the event pool initialization
+///
+/// \note This is just an example of #QF_EPOOL_INIT_ 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_, evtSize_)
+
+/// \brief Platform-dependent macro defining how QF should obtain the
+/// event pool block-size
+///
+/// \note This is just an example of #QF_EPOOL_EVENT_SIZE_ 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_)    ((p_).getBlockSize())
+
+/// \brief Platform-dependent macro defining how QF should obtain an event
+/// \a e_ from the event pool \a p_
+///
+/// \note This is just an example of #QF_EPOOL_GET_ 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_) = (QEvent *)(p_).get())
+
+/// \brief Platform-dependent macro defining how QF should return an event
+/// \a e_ to the event pool \a p_
+///
+/// \note This is just an example of #QF_EPOOL_PUT_ 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_))
+
+#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.
+    ///
+    /// \sa QK::getPortVersion()
+    static char const Q_ROM * Q_ROM_VAR getVersion(void);
+
+    /// \brief Returns the QK-port 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 QK-port version string is "1.1.03".
+    ///
+    /// \sa QK::getVersion()
+    static char const Q_ROM * Q_ROM_VAR getPortVersion(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 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 mutex);
+
+#endif                                                          // QK_NO_MUTEX
+
+};
+
+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);
+
+// QK scheduler and extended scheduler
+#ifndef QF_INT_KEY_TYPE
+    void QK_schedule_(void);                                   // QK scheduler
+    void QK_scheduleExt_(void);                       // QK extended scheduler
+
+    #define QK_SCHEDULE_()    QK_schedule_()
+#else
+
+    /// \brief The QK scheduler
+    ///
+    /// \note The QK scheduler must be always called with the interrupts
+    /// locked and unlocks interrupts internally.
+    ///
+    /// The signature of QK_schedule_() depends on the policy of locking and
+    /// unlocking interrupts. When the interrupt lock key is not used
+    /// (#QF_INT_KEY_TYPE undefined), the signature is as follows: \n
+    /// void QK_schedule_(void); \n
+    ///
+    /// However, when the interrupt key lock is used (#QF_INT_KEY_TYPE
+    /// defined), the signature is different: \n
+    /// void QK_schedule_(QF_INT_KEY_TYPE intLockKey); \n
+    ///
+    /// For the internal use, these differences are hidden by the macro
+    /// #QK_SCHEDULE_.
+    void QK_schedule_(QF_INT_KEY_TYPE intLockKey);
+
+    /// \brief The QK extended scheduler for interrupt context
+    ///
+    /// \note The QK extended exscheduler must be always called with the
+    /// interrupts locked and unlocks interrupts internally.
+    ///
+    /// The signature of QK_scheduleExt_() depends on the policy of locking
+    /// and unlocking interrupts. When the interrupt lock key is not used
+    /// (#QF_INT_KEY_TYPE undefined), the signature is as follows: \n
+    /// void QK_scheduleExt_(void); \n
+    ///
+    /// However, when the interrupt key lock is used (#QF_INT_KEY_TYPE
+    /// defined), the signature is different: \n
+    /// void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey); \n
+    void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey); // QK extended scheduler
+
+    /// #QF_INT_KEY_TYPE is defined, this internal macro invokes
+    /// QK_schedule_() passing the key variable as the parameter. Otherwise
+    /// QK_schedule_() is invoked without parameters.
+    /// \sa #QK_INT_LOCK, #QK_INT_UNLOCK
+    #define QK_SCHEDULE_()    QK_schedule_(intLockKey_)
+
+#endif
+}                                                                // extern "C"
+
+#else                                                         // QK_PREEMPTIVE
+
+// "qvanilla.h" ==============================================================
+#define QF_EQUEUE_TYPE              QEQueue
+                                              // native event queue operations
+#define QACTIVE_EQUEUE_WAIT_(me_) \
+    Q_ASSERT((me_)->m_eQueue.m_frontEvt != (QEvent *)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_, evtSize_)
+#define QF_EPOOL_EVENT_SIZE_(p_)    ((p_).getBlockSize())
+#define QF_EPOOL_GET_(p_, e_)       ((e_) = (QEvent *)(p_).get())
+#define QF_EPOOL_PUT_(p_, e_)       ((p_).put(e_))
+
+#if (QF_MAX_ACTIVE <= 8)
+    extern QPSet8  volatile QF_readySet_;  ///< QF-ready set of active objects
+#else
+    extern QPSet64 volatile QF_readySet_;  ///< QF-ready set of active objects
+#endif
+
+#endif                                                        // QK_PREEMPTIVE
+
+
+// qf.h (QF platform-independent public interface) ===========================
+//////////////////////////////////////////////////////////////////////////////
+#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_EVENT_SIZ_SIZE
+
+    /// \brief Default value of the macro configurable value in qf_port.h
+    #define QF_EVENT_SIZ_SIZE 2
+#endif
+#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 QEventSize;
+#elif (QF_EVENT_SIZ_SIZE == 2)
+    typedef uint16_t QEventSize;
+#elif (QF_EVENT_SIZ_SIZE == 4)
+    typedef uint32_t QEventSize;
+#else
+    #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
+#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
+
+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_ {
+private:
+
+    /// \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;
+
+public:
+#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 the 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;
+
+    /// \brief The Boolean loop variable determining if the thread routine
+    /// of the active object is running.
+    ///
+    /// This flag is only used with the traditional loop-structured thread
+    /// routines. Clearing this flag breaks out of the thread loop, which is
+    /// often the cleanest way to terminate the thread. The following example
+    /// illustrates the thread routine for Win32:
+    /// \include qf_run.cpp
+    uint8_t m_running;
+
+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 prio,
+               QEvent const *qSto[], uint32_t qLen,
+               void *stkSto = (void *)0, uint32_t stkSize = 0,
+               QEvent const *ie = (QEvent *)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.
+    void postFIFO(QEvent const *e);
+
+    /// \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 with great caution because
+    /// it alters order of events in the queue.
+    /// \sa QActive::postFIFO()
+    void postLIFO(QEvent const *e);
+
+    /// \brief Traditional loop-structured thread routine for an active object
+    ///
+    /// This function is only used when QF is ported to a traditional
+    /// RTOS/Kernel. QActive::run() is structured as a typical endless loop,
+    /// which blocks on the event queue get() operation of an active object.
+    /// When an event becomes available, it's dispatched to the active
+    /// object's state machine and after this recycled with QF::gc().
+    /// The loop might optionally use the QActive::m_running flag to terminate
+    /// and cause QActive::run() to return which is often the cleanest way to
+    /// terminate the thread.
+    void run(void);
+
+    /// \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()
+    QEvent const *get_(void);
+
+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_ initial) : QF_ACTIVE_SUPER_(initial) {
+    }
+
+    /// \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(QSignal 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(QSignal 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 *eq, QEvent const *e);
+
+    /// \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 the pointer to the recalled event to the
+    /// caller. The function returns NULL if no event has been recalled.
+    ///
+    /// An active object can use multiple event queues to defer events of
+    /// different kinds.
+    ///
+    /// \sa QActive::defer(), QEQueue, QActive::postLIFO()
+    QEvent const *recall(QEQueue *eq);
+
+public:
+    /// \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;
+
+private:
+
+    friend class QF;
+    friend class QTimeEvt;
+    #ifndef QF_INT_KEY_TYPE
+        friend void QK_schedule_(void);
+        friend void QK_scheduleExt_(void);
+    #else
+        friend void QK_schedule_(QF_INT_KEY_TYPE intLockKey);
+        friend void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey);
+    #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_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
+
+//////////////////////////////////////////////////////////////////////////////
+/// \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 ::QEvent 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 QEvent {
+private:
+
+    //// link to the previous time event in the list
+    QTimeEvt *m_prev;
+
+    /// 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(QSignal 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 *act, QTimeEvtCtr nTicks) {
+        m_interval = (uint16_t)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 *act, QTimeEvtCtr nTicks) {
+        m_interval = nTicks;
+        arm_(act, nTicks);
+    }
+
+    /// \brief Disarm a time event.
+    ///
+    /// The time event gets disarmed and can be reused. The function
+    /// returns 1 (TRUE) if the time event was truly disarmed, that is, it
+    /// was running. The return of 0 (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.
+    uint8_t 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 1 (TRUE) if the time event was running as it
+    /// was re-armed. The return of 0 (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.
+    uint8_t rearm(QTimeEvtCtr nTicks);
+
+    // for backwards compatibility
+
+    /// \brief Arm a one-shot time event for direct event posting (obsolete).
+    ///
+    /// This facility is now obsolete, please use \sa QTimeEvt::postIn().
+    void fireIn(QActive *act, QTimeEvtCtr nTicks) {
+        postIn(act, nTicks);
+    }
+
+    /// \brief Arm a periodic time event for direct event posting (obsolete).
+    ///
+    /// This facility is now obsolete, please use \sa QTimeEvt::postEvery().
+    void fireEvery(QActive *act, QTimeEvtCtr nTicks) {
+        postEvery(act, nTicks);
+    }
+
+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 *act, QTimeEvtCtr nTicks);
+
+    friend class QF;
+};
+
+
+#if (QF_MAX_ACTIVE > 63)
+    #error "QF_MAX_ACTIVE exceeds 63"
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+/// \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_MAX_ACTIVE - 1) / 8) + 1];
+
+    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 *subscrSto, QSignal 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 *poolSto, uint32_t poolSize,
+                         QEventSize 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.
+    ///
+    /// \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 void 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);
+
+#ifndef QF_INT_KEY_TYPE
+    static void onIdle(void);                // interrupt lock key NOT defined
+
+#else
+
+    /// \brief QF idle callback (customized in BSPs for QF)
+    ///
+    /// QF::onIdle() is called by the non-preemptive 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 LOCKED because the idle
+    /// condition can be asynchronously changed at any time by an interrupt.
+    /// QF::onIdle() MUST unlock the interrupts internally, but not before
+    /// putting the CPU into the low-power mode. (Ideally, unlocking
+    /// interrupts and low-power mode should happen atomically). At the very
+    /// least, the function MUST unlock interrupts, otherwise interrups will
+    /// be locked permanently.
+    ///
+    /// \note QF::onIdle() is only used by the non-preemptive scheduler built
+    /// into QF in the "bare metal" port, and is NOT used in any other 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(QF_INT_KEY_TYPE intLockKey);   // int. lock key defined
+
+#endif                                                      // QF_INT_KEY_TYPE
+
+    /// \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.)
+    static void publish(QEvent const *e);
+
+    /// \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
+    static void tick(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 const Q_ROM * Q_ROM_VAR getVersion(void);
+
+    /// \brief Returns the QF-port 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 QF-port version string is "1.1.03".
+    ///
+    /// \sa QF::getVersion()
+    static char const Q_ROM * Q_ROM_VAR getPortVersion(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 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 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 QEvent *new_(uint16_t evtSize, QSignal sig);
+
+    /// \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_) ((evtT_ *)QF::new_(sizeof(evtT_), (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(QEvent const *e);
+
+    /// \brief array of registered active objects
+    ///
+    /// \note Not to be used by Clients directly, only in ports of QF
+    static QActive *active_[];
+
+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 *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 *a);
+
+    friend class QActive;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// 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];
+
+//////////////////////////////////////////////////////////////////////////////
+// QS software tracing
+#ifdef Q_SPY
+
+// qs.h ======================================================================
+//////////////////////////////////////////////////////////////////////////////
+
+/// \brief Quantum Spy record types.
+///
+/// This enumeration specifies the record types used in the QP components.
+/// You can specify your own record types starting from ::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 {
+    // QEP records
+    QS_QEP_STATE_EMPTY,
+    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_RESERVED0,
+
+    // 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_RESERVED7,
+    QS_QF_INT_LOCK,                                ///< interrupts were locked
+    QS_QF_INT_UNLOCK,                            ///< interrupts were unlocked
+    QS_QF_ISR_ENTRY,                                   ///< an ISR was entered
+    QS_QF_ISR_EXIT,                                     ///< an ISR was exited
+    QS_QF_RESERVED6,
+    QS_QF_RESERVED5,
+    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_DICTIONARY,                            ///< signal dictionary entry
+    QS_OBJ_DICTIONARY,                            ///< object dictionary entry
+    QS_FUN_DICTIONARY,                          ///< function dictionary entry
+    QS_ASSERT,                                ///< assertion fired in the code
+    QS_RESERVED5,
+    QS_RESERVED4,
+    QS_RESERVED3,
+    QS_RESERVED2,
+    QS_RESERVED1,
+    QS_RESERVED0,
+
+    // 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()
+#define QS_ALL_RECORDS          ((uint8_t)0xFF)
+
+/// \brief Constant representing End-Of-Data condition returned from the
+/// QS::getByte() function.
+#define QS_EOD                  ((uint16_t)0xFFFF)
+
+
+#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
+#if (QS_TIME_SIZE == 1)
+    typedef uint8_t QSTimeCtr;
+    #define QS_TIME_()   QS::u8_(QS::onGetTime())
+#elif (QS_TIME_SIZE == 2)
+    typedef uint16_t QSTimeCtr;
+    #define QS_TIME_()   QS::u16_(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_()   QS::u32_(QS::onGetTime())
+#else
+    #error "QS_TIME_SIZE defined incorrectly, expected 1, 2, or 4"
+#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
+
+
+/// \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 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 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 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 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_NOLOCK, depending if it's called in a normal code or from
+    /// a critical section.
+    static void begin(uint8_t 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_NOLOCK, 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 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 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 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 format, uint8_t 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 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 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 format, float 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 format, double 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 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 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);
+
+    // 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 *pNbytes);
+
+// platform-dependent callback functions, need to be implemented by clients
+public:
+
+    // 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 (1) if the QS initialization was successful,
+    /// or FALSE (0) if it failed.
+    ///
+    /// The following example illustrates an implementation of QS_onStartup():
+    /// \include qs_startup.cpp
+    static uint8_t 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
+    /// unlock interrupts.
+    ///
+    /// 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 ...............................................
+public:
+    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 .............................................................
+public:
+                                    /// tick counter for the QS_QF_TICK record
+    static QSTimeCtr volatile tickCtr_;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+// 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_)           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()               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_)      QS::filterOn(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_)     QS::filterOff(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_)  (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_)  (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_)  (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_)  (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_)  (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_)  (QS_apObj_ = (obj_))
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros to generate user QS records
+
+/// \brief Begin a QS user record without locking interrupts.
+#define QS_BEGIN_NOLOCK(rec_, obj_) \
+    if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
+          & (1U << ((uint8_t)(rec_) & 7U))) != 0) \
+        && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
+    { \
+        QS::begin((uint8_t)(rec_)); \
+        QS_TIME_();
+
+/// \brief End a QS user record without locking interrupts.
+#define QS_END_NOLOCK() \
+    QS_END_NOLOCK_()
+
+                                    // QS-specific interrupt locking/unlocking
+#ifndef QF_INT_KEY_TYPE
+    /// \brief This is an internal macro for defining the interrupt lock key.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QS_INT_KEY_TYPE is defined, this internal macro provides the
+    /// definition of the lock key variable. Otherwise this macro is empty.
+    /// \sa #QS_INT_KEY_TYPE, #QF_INT_KEY_TYPE
+    #define QS_INT_LOCK_KEY_
+
+    /// \brief This is an internal macro for locking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QS_INT_KEY_TYPE is defined, this internal macro invokes #QS_INT_LOCK
+    /// passing the key variable as the parameter. Otherwise #QS_INT_LOCK
+    /// is invoked with a dummy parameter.
+    /// \sa #QS_INT_LOCK, #QF_INT_LOCK, #QK_INT_LOCK
+    #define QS_INT_LOCK_()      QF_INT_LOCK(ignore_)
+
+    /// \brief This is an internal macro for unlocking interrupts.
+    ///
+    /// The purpose of this macro is to enable writing the same code for the
+    /// case when interrupt key is defined and when it is not. If the macro
+    /// #QS_INT_KEY_TYPE is defined, this internal macro invokes
+    /// #QS_INT_UNLOCK passing the key variable as the parameter. Otherwise
+    /// #QS_INT_UNLOCK is invoked with a dummy parameter.
+    /// \sa #QS_INT_UNLOCK, #QF_INT_UNLOCK, #QK_INT_UNLOCK
+    #define QS_INT_UNLOCK_()    QF_INT_UNLOCK(ignore_)
+#else
+    #define QS_INT_LOCK_KEY_    QF_INT_KEY_TYPE intLockKey_;
+    #define QS_INT_LOCK_()      QF_INT_LOCK(intLockKey_)
+    #define QS_INT_UNLOCK_()    QF_INT_UNLOCK(intLockKey_)
+#endif
+
+/// \brief Begin a user QS record with locking interrupts.
+///
+/// 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::glbFilter_[(uint8_t)(rec_) >> 3U] \
+          & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
+        && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
+    { \
+        QS_INT_LOCK_KEY_ \
+        QS_INT_LOCK_(); \
+        QS::begin((uint8_t)(rec_)); \
+        QS_TIME_();
+
+/// \brief End a QS record with locking interrupts.
+/// \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 locking the interrupts.
+/// \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::glbFilter_[(uint8_t)(rec_) >> 3U] \
+          & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
+        && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \
+    { \
+        QS_INT_LOCK_(); \
+        QS::begin((uint8_t)(rec_));
+
+/// \brief  Internal QS macro to end a QS record with locking the interrupts.
+/// \note This macro is intended to use only inside QP components and NOT
+/// at the application level. \sa #QS_END
+#define QS_END_() \
+        QS::end(); \
+        QS_INT_UNLOCK_(); \
+    }
+
+/// \brief Internal QS macro to begin a QS record without locking the
+/// interrupts.
+/// \note This macro is intended to use only inside QP components and NOT
+/// at the application level. \sa #QS_BEGIN_NOLOCK
+#define QS_BEGIN_NOLOCK_(rec_, objFilter_, obj_) \
+    if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
+          & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
+        && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \
+    { \
+        QS::begin((uint8_t)(rec_));
+
+/// \brief Internal QS macro to end a QS record without locking
+/// the interrupts.
+/// \note This macro is intended to use only inside QP components and NOT
+/// at the application level. \sa #QS_END_NOLOCK
+#define QS_END_NOLOCK_() \
+        QS::end(); \
+    }
+
+/// \brief Internal QS macro to output an unformatted uint8_t data element
+#define QS_U8_(data_)           QS::u8_(data_)
+
+/// \brief Internal QS macro to output an unformatted uint16_t data element
+#define QS_U16_(data_)          QS::u16_(data_)
+
+/// \brief Internal QS macro to output an unformatted uint32_t data element
+#define QS_U32_(data_)          QS::u32_(data_)
+
+
+#if (QS_OBJ_PTR_SIZE == 1)
+    #define QS_OBJ_(obj_)       QS::u8_((uint8_t)(obj_))
+#elif (QS_OBJ_PTR_SIZE == 2)
+    #define QS_OBJ_(obj_)       QS::u16_((uint16_t)(obj_))
+#elif (QS_OBJ_PTR_SIZE == 4)
+    #define QS_OBJ_(obj_)       QS::u32_((uint32_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_)       QS::u32_((uint32_t)(obj_))
+#endif
+
+
+#if (QS_FUN_PTR_SIZE == 1)
+    #define QS_FUN_(fun_)       QS::u8_((uint8_t)(fun_))
+#elif (QS_FUN_PTR_SIZE == 2)
+    #define QS_FUN_(fun_)       QS::u16_((uint16_t)(fun_))
+#elif (QS_FUN_PTR_SIZE == 4)
+    #define QS_FUN_(fun_)       QS::u32_((uint32_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_)       QS::u32_((uint32_t)(fun_))
+#endif
+
+/// \brief Internal QS macro to output a zero-terminated ASCII string
+/// data element
+#define QS_STR_(msg_)           QS::str_(msg_)
+
+/// \brief Internal QS macro to output a zero-terminated ASCII string
+/// allocated in ROM data element
+#define QS_STR_ROM_(msg_)       QS::str_ROM_(msg_)
+
+//////////////////////////////////////////////////////////////////////////////
+// Macros for use in the client code
+
+/// \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
+};
+
+/// \brief Output formatted int8_t to the QS record
+#define QS_I8(width_, data_) \
+    QS::u8((uint8_t)(((width_) << 4)) | QS_I8_T, (data_))
+
+/// \brief Output formatted uint8_t to the QS record
+#define QS_U8(width_, data_) \
+    QS::u8((uint8_t)(((width_) << 4)) | QS_U8_T, (data_))
+
+/// \brief Output formatted int16_t to the QS record
+#define QS_I16(width_, data_) \
+    QS::u16((uint8_t)(((width_) << 4)) | QS_I16_T, (data_))
+
+/// \brief Output formatted uint16_t to the QS record
+#define QS_U16(width_, data_) \
+    QS::u16((uint8_t)(((width_) << 4)) | QS_U16_T, (data_))
+
+/// \brief Output formatted int32_t to the QS record
+#define QS_I32(width_, data_) \
+    QS::u32((uint8_t)(((width_) << 4)) | QS_I32_T, (data_))
+
+/// \brief Output formatted uint32_t to the QS record
+#define QS_U32(width_, data_) \
+    QS::u32((uint8_t)(((width_) << 4)) | QS_U32_T, (data_))
+
+/// \brief Output formatted 32-bit floating point number to the QS record
+#define QS_F32(width_, data_) \
+    QS::f32((uint8_t)(((width_) << 4)) | QS_F32_T, (data_))
+
+/// \brief Output formatted 64-bit floating point number to the QS record
+#define QS_F64(width_, data_) \
+    QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_))
+
+/// \brief Output formatted zero-terminated ASCII string to the QS record
+#define QS_STR(str_)            QS::str(str_)
+
+/// \brief Output formatted zero-terminated ASCII string from ROM
+/// to the QS record
+#define QS_STR_ROM(str_)        QS::str_ROM(str_)
+
+/// \brief Output formatted memory block of up to 255 bytes to the QS
+/// record
+#define QS_MEM(mem_, size_)     QS::mem((mem_), (size_))
+
+
+#if (QS_OBJ_PTR_SIZE == 1)
+    #define QS_OBJ(obj_)        QS::u8(QS_OBJ_T, (uint8_t)(obj_))
+#elif (QS_OBJ_PTR_SIZE == 2)
+    #define QS_OBJ(obj_)        QS::u16(QS_OBJ_T, (uint16_t)(obj_))
+#elif (QS_OBJ_PTR_SIZE == 4)
+    #define QS_OBJ(obj_)        QS::u32(QS_OBJ_T, (uint32_t)(obj_))
+#else
+    /// \brief Output formatted object pointer to the QS record
+    #define QS_OBJ(obj_)        QS::u32(QS_OBJ_T, (uint32_t)(obj_))
+#endif
+
+
+#if (QS_FUN_PTR_SIZE == 1)
+    #define QS_FUN(fun_)        QS::u8(QS_FUN_T, (uint8_t)(fun_))
+#elif (QS_FUN_PTR_SIZE == 2)
+    #define QS_FUN(fun_)        QS::u16(QS_FUN_T, (uint16_t)(fun_))
+#elif (QS_FUN_PTR_SIZE == 4)
+    #define QS_FUN(fun_)        QS::u32(QS_FUN_T, (uint32_t)(fun_))
+#else
+    /// \brief Output formatted function pointer to the QS record
+    #define QS_FUN(fun_)        QS::u32(QS_FUN_T, (uint32_t)(fun_))
+#endif
+
+
+/// \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_) \
+    if (((QS::glbFilter_[(uint8_t)QS_SIG_DICTIONARY >> 3U] \
+          & (1U << ((uint8_t)QS_SIG_DICTIONARY & 7U))) != 0U)) \
+    { \
+        static char const Q_ROM Q_ROM_VAR sig_name__[] = #sig_; \
+        QS_INT_LOCK_KEY_ \
+        QS_INT_LOCK_(); \
+        QS::begin((uint8_t)QS_SIG_DICTIONARY); \
+        QS_SIG_(sig_); \
+        QS_OBJ_(obj_); \
+        QS_STR_ROM_(sig_name__); \
+        QS::end(); \
+        QS_INT_UNLOCK_(); \
+        QS::onFlush(); \
+    } else ((void)0)
+
+/// \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_) \
+    if (((QS::glbFilter_[(uint8_t)QS_OBJ_DICTIONARY >> 3U] \
+          & (1U << ((uint8_t)QS_OBJ_DICTIONARY & 7U))) != 0U)) \
+    { \
+        static char const Q_ROM Q_ROM_VAR obj_name__[] = #obj_; \
+        QS_INT_LOCK_KEY_ \
+        QS_INT_LOCK_(); \
+        QS::begin((uint8_t)QS_OBJ_DICTIONARY); \
+        QS_OBJ_(obj_); \
+        QS_STR_ROM_(obj_name__); \
+        QS::end(); \
+        QS_INT_UNLOCK_(); \
+        QS::onFlush(); \
+    } else ((void)0)
+
+/// \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_) \
+    if (((QS::glbFilter_[(uint8_t)QS_FUN_DICTIONARY >> 3U] \
+          & (1U << ((uint8_t)QS_FUN_DICTIONARY & 7U))) != 0U)) \
+    { \
+        static char const Q_ROM Q_ROM_VAR fun_name__[] = #fun_; \
+        QS_INT_LOCK_KEY_ \
+        QS_INT_LOCK_(); \
+        QS::begin((uint8_t)QS_FUN_DICTIONARY); \
+        QS_FUN_(fun_); \
+        QS_STR_ROM_(fun_name__); \
+        QS::end(); \
+        QS_INT_UNLOCK_(); \
+        QS::onFlush(); \
+    } else ((void)0)
+
+/// \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()   QS::onFlush()
+
+
+/// \brief Output the interrupt lock record
+#define QF_QS_INT_LOCK() \
+    QS_BEGIN_NOLOCK_(QS_QF_INT_LOCK, (void *)0, (void *)0); \
+        QS_TIME_(); \
+        QS_U8_((uint8_t)(++QF_intLockNest_)); \
+    QS_END_NOLOCK_()
+
+/// \brief Output the interrupt unlock record
+#define QF_QS_INT_UNLOCK() \
+    QS_BEGIN_NOLOCK_(QS_QF_INT_UNLOCK, (void *)0, (void *)0); \
+        QS_TIME_(); \
+        QS_U8_((uint8_t)(QF_intLockNest_--)); \
+    QS_END_NOLOCK_()
+
+/// \brief Output the interrupt entry record
+#define QF_QS_ISR_ENTRY(isrnest_, prio_) \
+    QS_BEGIN_NOLOCK_(QS_QF_ISR_ENTRY, (void *)0, (void *)0); \
+        QS_TIME_(); \
+        QS_U8_(isrnest_); \
+        QS_U8_(prio_); \
+    QS_END_NOLOCK_()
+
+/// \brief Output the interrupt exit record
+#define QF_QS_ISR_EXIT(isrnest_, prio_) \
+    QS_BEGIN_NOLOCK_(QS_QF_ISR_EXIT, (void *)0, (void *)0); \
+        QS_TIME_(); \
+        QS_U8_(isrnest_); \
+        QS_U8_(prio_); \
+    QS_END_NOLOCK_()
+
+/// \brief Execute an action that is only necessary for QS output
+#define QF_QS_ACTION(act_)      (act_)
+
+/// \brief interrupt-lock nesting level
+///
+/// \note Not to be used by Clients directly, only in ports of QF
+extern uint8_t QF_intLockNest_;
+
+// from "qep.h" --------------------------------------------------------------
+    #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_)       QS::u8_(sig_)
+    #elif (Q_SIGNAL_SIZE == 2)
+        #define QS_SIG_(sig_)       QS::u16_(sig_)
+    #elif (Q_SIGNAL_SIZE == 4)
+        #define QS_SIG_(sig_)       QS::u32_(sig_)
+    #endif
+
+// from "qf.h" ---------------------------------------------------------------
+    #if (QF_EQUEUE_CTR_SIZE == 1)
+
+        /// \brief Internal QS macro to output an unformatted event queue
+        /// counter data element
+        /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE.
+        #define QS_EQC_(ctr_)       QS::u8_(ctr_)
+    #elif (QF_EQUEUE_CTR_SIZE == 2)
+        #define QS_EQC_(ctr_)       QS::u16_(ctr_)
+    #elif (QF_EQUEUE_CTR_SIZE == 4)
+        #define QS_EQC_(ctr_)       QS::u32_(ctr_)
+    #else
+        #error "QF_EQUEUE_CTR_SIZE not defined"
+    #endif
+
+
+    #if (QF_EVENT_SIZ_SIZE == 1)
+
+        /// \brief Internal QS macro to output an unformatted event size
+        /// data element
+        /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE.
+        #define QS_EVS_(size_)      QS::u8_(size_)
+    #elif (QF_EVENT_SIZ_SIZE == 2)
+        #define QS_EVS_(size_)      QS::u16_(size_)
+    #elif (QF_EVENT_SIZ_SIZE == 4)
+        #define QS_EVS_(size_)      QS::u32_(size_)
+    #endif
+
+
+    #if (QF_MPOOL_SIZ_SIZE == 1)
+
+        /// \brief Internal QS macro to output an unformatted memory pool
+        /// block-size data element
+        /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE.
+        #define QS_MPS_(size_)      QS::u8_(size_)
+    #elif (QF_MPOOL_SIZ_SIZE == 2)
+        #define QS_MPS_(size_)      QS::u16_(size_)
+    #elif (QF_MPOOL_SIZ_SIZE == 4)
+        #define QS_MPS_(size_)      QS::u32_(size_)
+    #endif
+
+    #if (QF_MPOOL_CTR_SIZE == 1)
+
+        /// \brief Internal QS macro to output an unformatted memory pool
+        /// block-counter data element
+        /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE.
+        #define QS_MPC_(ctr_)       QS::u8_(ctr_)
+    #elif (QF_MPOOL_CTR_SIZE == 2)
+        #define QS_MPC_(ctr_)       QS::u16_(ctr_)
+    #elif (QF_MPOOL_CTR_SIZE == 4)
+        #define QS_MPC_(ctr_)       QS::u32_(ctr_)
+    #endif
+
+
+    #if (QF_TIMEEVT_CTR_SIZE == 1)
+
+        /// \brief Internal QS macro to output an unformatted time event
+        /// tick-counter data element
+        /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE.
+        #define QS_TEC_(ctr_)       QS::u8_(ctr_)
+    #elif (QF_TIMEEVT_CTR_SIZE == 2)
+        #define QS_TEC_(ctr_)       QS::u16_(ctr_)
+    #elif (QF_TIMEEVT_CTR_SIZE == 4)
+        #define QS_TEC_(ctr_)       QS::u32_(ctr_)
+    #endif
+
+#else                                                                 // Q_SPY
+
+// qs_dummy.h ================================================================
+
+#define QS_INIT(arg_)                   ((uint8_t)1)
+#define QS_EXIT()                       ((void)0)
+#define QS_DUMP()                       ((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_)             ((uint16_t)0xFFFF)
+#define QS_GET_BLOCK(pSize_)            ((uint8_t *)0)
+
+#define QS_BEGIN(rec_, obj_)            if (0) {
+#define QS_END()                        }
+#define QS_BEGIN_NOLOCK(rec_, obj_)     if (0) {
+#define QS_END_NOLOCK()                 }
+
+#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_STR(str_)                    ((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_FLUSH()                      ((void)0)
+
+// internal QS macros used only in the QP components .........................
+#define QS_INT_LOCK_KEY_
+#define QS_BEGIN_(rec_, refObj_, obj_)  if (0) {
+#define QS_END_()                       }
+#define QS_BEGIN_NOLOCK_(rec_, refObj_, obj_) if (0) {
+#define QS_END_NOLOCK_()                }
+#define QS_U8_(data_)                   ((void)0)
+#define QS_U16_(data_)                  ((void)0)
+#define QS_U32_(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_INT_LOCK()                ((void)0)
+#define QF_QS_INT_UNLOCK()              ((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
+
+//////////////////////////////////////////////////////////////////////////////
+/**
+* \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 \ref Q_ASSERT, \ref Q_REQUIRE, \ref Q_ENSURE,
+* \ref Q_INVARIANT, and \ref Q_ERROR do NOT evaluate the test condition
+* passed as the argument to these macros. One notable exception is the
+* macro \ref 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_ALLEGE(test_)    ((void)(test_))
+    #define Q_ERROR()          ((void)0)
+
+#else                  /* Q_NASSERT not defined--assertion checking enabled */
+
+    #ifdef __cplusplus
+        extern "C" {
+    #endif
+
+    /** callback invoked in case the condition passed to \ref Q_ASSERT,
+    * \ref Q_REQUIRE, \ref Q_ENSURE, \ref Q_ERROR, or \ref Q_ALLEGE
+    * evaluates to FALSE.
+    *
+    * \param file file name where the assertion failed
+    * \param line line number at which the assertion failed
+    */
+    /*lint -sem(Q_onAssert, r_no)                Q_onAssert() never returns */
+    void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int 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 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 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.
+    */
+    #define Q_ASSERT(test_) \
+        if (test_) { \
+        } \
+        else (Q_onAssert(l_this_file, __LINE__))
+
+    /** 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.
+    */
+    #define Q_ALLEGE(test_)    Q_ASSERT(test_)
+
+    /** Assertion that always calls the Q_onAssert() callback if
+    * ever executed.
+    * \note can be disabled with the Q_NASSERT switch.
+    */
+    #define Q_ERROR() \
+        (Q_onAssert(l_this_file, __LINE__))
+
+#endif                                                         /* Q_NASSERT */
+
+/** Assertion that checks for a precondition. This macro is equivalent to
+* \ref Q_ASSERT, except the name provides a better documentation of the
+* intention of this assertion.
+*/
+#define Q_REQUIRE(test_)   Q_ASSERT(test_)
+
+/** Assertion that checks for a postcondition. This macro is equivalent to
+* \ref Q_ASSERT, except the name provides a better documentation of the
+* intention of this assertion.
+*/
+#define Q_ENSURE(test_)    Q_ASSERT(test_)
+
+/** Assertion that checks for an invariant. This macro is equivalent to
+* \ref Q_ASSERT, except the name provides a better documentation of the
+* intention of this assertion.
+*/
+#define Q_INVARIANT(test_) Q_ASSERT(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 char Q_assert_compile[(test_) ? 1 : -1]
+
+#endif                                                                 // qp_h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qp_port.cpp	Wed Feb 09 14:46:03 2011 +0000
@@ -0,0 +1,47 @@
+//////////////////////////////////////////////////////////////////////////////
+// Product: QP/C++ port to Arduino, cooperative "vanilla" kernel, no Q-SPY
+// Last Updated for QP ver: 4.1.06 (modified to fit in one file)
+// Date of the Last Update: Jan 04, 2011
+//
+//                    Q u a n t u m     L e a P s
+//                    ---------------------------
+//                    innovating embedded systems
+//
+// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+//
+// This software may be distributed and modified under the terms of the GNU
+// General Public License version 2 (GPL) as published by the Free Software
+// Foundation and appearing in the file GPL.TXT included in the packaging of
+// this file. Please note that GPL Section 2[b] requires that all works based
+// on this software must also be made publicly available under the terms of
+// the GPL ("Copyleft").
+//
+// Alternatively, this software may be distributed and modified under the
+// terms of Quantum Leaps commercial licenses, which expressly supersede
+// the GPL and are specifically designed for licensees interested in
+// retaining the proprietary status of their code.
+//
+// Contact information:
+// Quantum Leaps Web site:  http://www.quantum-leaps.com
+// e-mail:                  info@quantum-leaps.com
+//////////////////////////////////////////////////////////////////////////////
+#include "qp_port.h"                                                // QP port
+
+Q_DEFINE_THIS_MODULE(qp_port)
+
+//............................................................................
+extern "C" void loop() {
+    QF::run();         // run the application, NOTE: QF::run() does not return
+}
+
+//............................................................................
+// This QP framework does NOT use new or delete, but the WinAVR/avr-g++
+// compiler generates somehow a reference to the operator delete for every
+// class with a virtual destructor. QP declares virtual destructors, so to
+// satisfy the linker the following dummy definition of the operator
+// delete is provided. This operator should never be actually called.
+//
+void operator delete(void *) {
+    Q_ERROR();               // this operator should never be actually called
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qp_port.h	Wed Feb 09 14:46:03 2011 +0000
@@ -0,0 +1,80 @@
+//////////////////////////////////////////////////////////////////////////////
+// Product: QP/C++ port to ARM Cortex, selectable Vanilla/QK, mbed compiler
+// Last Updated for QP ver: 4.1.06 (modified to fit in one file)
+// Date of the Last Update: Feb 08, 2011
+//
+//                    Q u a n t u m     L e a P s
+//                    ---------------------------
+//                    innovating embedded systems
+//
+// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+//
+// This software may be distributed and modified under the terms of the GNU
+// General Public License version 2 (GPL) as published by the Free Software
+// Foundation and appearing in the file GPL.TXT included in the packaging of
+// this file. Please note that GPL Section 2[b] requires that all works based
+// on this software must also be made publicly available under the terms of
+// the GPL ("Copyleft").
+//
+// Alternatively, this software may be distributed and modified under the
+// terms of Quantum Leaps commercial licenses, which expressly supersede
+// the GPL and are specifically designed for licensees interested in
+// retaining the proprietary status of their code.
+//
+// Contact information:
+// Quantum Leaps Web site:  http://www.quantum-leaps.com
+// e-mail:                  info@quantum-leaps.com
+//////////////////////////////////////////////////////////////////////////////
+#ifndef qp_port_h
+#define qp_port_h
+
+// enable the Q-SPY software tracing instrumentation
+#define Q_SPY
+
+// enable preemptive QK kernel
+#define QK_PREEMPTIVE
+
+// The maximum number of active objects in the application (could be up to 63)
+#define QF_MAX_ACTIVE      16
+
+// The signal size (1, 2, 4 bytes)
+#define Q_SIGNAL_SIZE      2
+
+//............................................................................
+                                             // QF critical section entry/exit
+// QF_INT_KEY_TYPE not defined
+#define QF_INT_LOCK(dummy)      __disable_irq()
+#define QF_INT_UNLOCK(dummy)    __enable_irq()
+
+#ifdef QK_PREEMPTIVE
+                                                // QK interrupt entry and exit
+    #define QK_ISR_ENTRY() do { \
+        __disable_irq(); \
+        ++QK_intNest_; \
+        QF_QS_ISR_ENTRY(QK_intNest_, QK_currPrio_); \
+        __enable_irq(); \
+    } while (0)
+
+    #define QK_ISR_EXIT()  do { \
+        __disable_irq(); \
+        QF_QS_ISR_EXIT(QK_intNest_, QK_currPrio_); \
+        --QK_intNest_; \
+        *((uint32_t volatile *)0xE000ED04) = 0x10000000; \
+        __enable_irq(); \
+    } while (0)
+#else
+    #define QK_ISR_ENTRY() ((void)0)
+    #define QK_ISR_EXIT()  ((void)0)
+#endif
+
+#ifdef Q_SPY
+    #define QS_TIME_SIZE        4
+    #define QS_OBJ_PTR_SIZE     4
+    #define QS_FUN_PTR_SIZE     4
+#endif
+
+#include <stdint.h>    // mbed compiler supports standard exact-width integers
+
+#include "qp.h"                           // QP platform-independent interface
+
+#endif                                                            // qp_port_h