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.

Revision:
0:064c79e7311a
Child:
6:01d57c81e96a
diff -r 000000000000 -r 064c79e7311a qp.cpp
--- /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
+
+