QP is an event-driven, RTOS-like, active object framework for microcontrollers, such as mbed. The QP framework provides thread-safe execution of active objects (concurrent state machines) and support both manual and automatic coding of UML statecharts in readable, production-quality C or C++. Automatic code generation of QP code is supported by the free QM modeling tool.
Dependents: qp_hangman qp_dpp qp_blinky
QP/C++ (Quantum Platform in C++) is a lightweight, open source active object (actor) framework for building responsive and modular real-time embedded applications as systems of asynchronous event-driven active objects (actors). The QP/C++ framework is a member of a larger family consisting of QP/C++, QP/C, and QP-nano frameworks, which are all strictly quality controlled, thoroughly documented, and available under GPLv3 with a special Exception for mbed (see http://www.state-machine.com/licensing/QP-mbed_GPL_Exception.txt).
The behavior of active objects is specified in QP/C++ by means of hierarchical state machines (UML statecharts). The framework supports manual coding of UML state machines in C++ as well as automatic code generation by means of the free QM modeling tool (http://www.state-machine.com/qm).
Please see the "QP/C++ Reference Manual" (http://www.state-machine.com/qpcpp) for more information.
qp.cpp
- Committer:
- QL
- Date:
- 2012-09-04
- Revision:
- 9:ca2e6010d9e2
- Parent:
- 7:bf92d3a6625e
File content as of revision 9:ca2e6010d9e2:
////////////////////////////////////////////////////////////////////////////// // Product: QP/C++ // Last Updated for QP ver: 4.5.02 (modified to fit in one file) // Date of the Last Update: Aug 24, 2012 // // Q u a n t u m L e a P s // --------------------------- // innovating embedded systems // // Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved. // // This program is open source software: you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // Alternatively, this program may be distributed and modified under the // terms of Quantum Leaps commercial licenses, which expressly supersede // the GNU General Public License and are specifically designed for // licensees interested in retaining the proprietary status of their code. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // // Contact information: // Quantum Leaps Web sites: http://www.quantum-leaps.com // http://www.state-machine.com // e-mail: info@quantum-leaps.com ////////////////////////////////////////////////////////////////////////////// #include "qp_port.h" // QP port // "qep_pkg.h" =============================================================== QP_BEGIN_ Q_DEFINE_THIS_MODULE("qp") ////////////////////////////////////////////////////////////////////////////// /// preallocated reserved events extern QEvt const QEP_reservedEvt_[]; /// empty signal for internal use only QSignal const QEP_EMPTY_SIG_ = static_cast<QSignal>(0); /// maximum depth of state nesting (including the top level), must be >= 3 int8_t const QEP_MAX_NEST_DEPTH_ = static_cast<int8_t>(6); uint8_t const u8_0 = static_cast<uint8_t>(0); ///< \brief constant (uint8_t)0 uint8_t const u8_1 = static_cast<uint8_t>(1); ///< \brief constant (uint8_t)1 int8_t const s8_0 = static_cast<int8_t>(0); ///< \brief constant (int8_t)0 int8_t const s8_1 = static_cast<int8_t>(1); ///< \brief constant (int8_t)1 int8_t const s8_n1 = static_cast<int8_t>(-1); ///< \brief constant (int8_t)-1 QP_END_ /// helper macro to trigger internal event in an HSM #define QEP_TRIG_(state_, sig_) \ ((*(state_))(this, &QEP_reservedEvt_[sig_])) /// helper macro to trigger exit action in an HSM #define QEP_EXIT_(state_) do { \ 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_() \ } \ } while (false) /// helper macro to trigger entry action in an HSM #define QEP_ENTER_(state_) do { \ 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_() \ } \ } while (false) // "qep.cpp" ================================================================= /// \brief ::QEP_reservedEvt_ definition and QEP::getVersion() implementation. QP_BEGIN_ // Package-scope objects ----------------------------------------------------- QEvt const QEP_reservedEvt_[] = { #ifdef Q_EVT_CTOR // Is the QEvt constructor provided? static_cast<QSignal>(0), static_cast<QSignal>(1), static_cast<QSignal>(2), static_cast<QSignal>(3) #else // QEvt is a POD (Plain Old Datatype) { static_cast<QSignal>(0), u8_0, u8_0 }, { static_cast<QSignal>(1), u8_0, u8_0 }, { static_cast<QSignal>(2), u8_0, u8_0 }, { static_cast<QSignal>(3), u8_0, u8_0 } #endif }; //............................................................................ char_t const Q_ROM * Q_ROM_VAR QEP::getVersion(void) { uint8_t const u8_zero = static_cast<uint8_t>('0'); static char_t const Q_ROM Q_ROM_VAR version[] = { static_cast<char_t>(((QP_VERSION >> 12) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 8) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 4) & 0xFU) + u8_zero), static_cast<char_t>((QP_VERSION & 0xFU) + u8_zero), static_cast<char_t>('\0') }; return version; } QP_END_ // "qhsm_top.cpp" ============================================================ /// \brief QHsm::top() implementation. QP_BEGIN_ //............................................................................ QState QHsm::top(void * const, QEvt const * const) { return Q_RET_IGNORED; // the top state ignores all events } QP_END_ // "qhsm_ini.cpp" ============================================================ /// \brief QHsm::init() implementation. QP_BEGIN_ //............................................................................ QHsm::~QHsm() { } //............................................................................ void QHsm::init(QEvt const * const e) { QStateHandler t = m_state; Q_REQUIRE((m_temp != Q_STATE_CAST(0)) // ctor must be executed && (t == Q_STATE_CAST(&QHsm::top))); // initial tran. NOT taken // the top-most initial transition must be taken Q_ALLEGE((*m_temp)(this, e) == Q_RET_TRAN); QS_CRIT_STAT_ do { // drill into the target... QStateHandler path[QEP_MAX_NEST_DEPTH_]; int8_t ip = s8_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_temp); // the target of the initial transition QS_END_() path[0] = m_temp; (void)QEP_TRIG_(m_temp, QEP_EMPTY_SIG_); while (m_temp != t) { ++ip; path[ip] = m_temp; (void)QEP_TRIG_(m_temp, QEP_EMPTY_SIG_); } m_temp = path[0]; // entry path must not overflow Q_ASSERT(ip < QEP_MAX_NEST_DEPTH_); do { // retrace the entry path in reverse (desired) order... QEP_ENTER_(path[ip]); // enter path[ip] --ip; } while (ip >= s8_0); t = path[0]; // current state becomes the new source } while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN); QS_BEGIN_(QS_QEP_INIT_TRAN, QS::smObj_, this) QS_TIME_(); // time stamp QS_OBJ_(this); // this state machine object QS_FUN_(t); // the new active state QS_END_() m_state = t; // change the current active state m_temp = t; // mark the configuration as stable } QP_END_ // "qhsm_dis.cpp" ============================================================ /// \brief QHsm::dispatch() implementation. QP_BEGIN_ //............................................................................ void QHsm::dispatch(QEvt const * const e) { QStateHandler t = m_state; Q_REQUIRE(t == m_temp); // the state configuration must be stable QStateHandler s; QState r; QS_CRIT_STAT_ 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_temp; r = (*s)(this, e); // invoke state handler s if (r == Q_RET_UNHANDLED) { // unhandled due to a guard? QS_BEGIN_(QS_QEP_UNHANDLED, QS::smObj_, this) QS_SIG_(e->sig); // the signal of the event QS_OBJ_(this); // this state machine object QS_FUN_(s); // the current state QS_END_() r = QEP_TRIG_(s, QEP_EMPTY_SIG_); // find superstate of s } } while (r == Q_RET_SUPER); if (r == Q_RET_TRAN) { // transition taken? QStateHandler path[QEP_MAX_NEST_DEPTH_]; int8_t ip = s8_n1; // transition entry path index int8_t iq; // helper transition entry path index #ifdef Q_SPY QStateHandler src = s; // save the transition source for tracing #endif path[0] = m_temp; // 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_temp; // m_temp 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 = s8_0; // enter the target } else { (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); // superstate of target t = m_temp; if (s == t) { // (b) check source==target->super ip = s8_0; // enter the target } else { (void)QEP_TRIG_(s, QEP_EMPTY_SIG_); // superstate of src // (c) check source->super==target->super if (m_temp == t) { QEP_EXIT_(s); // exit the source ip = s8_0; // enter the target } else { // (d) check source->super==target if (m_temp == 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 = s8_0; // indicate LCA not found ip = s8_1; // enter target's superst path[1] = t; // save the superstate of target t = m_temp; // save source->super // find target->super->super r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_); while (r == Q_RET_SUPER) { ++ip; path[ip] = m_temp; // store the entry path if (m_temp == s) { // is it the source? // indicate that LCA found iq = s8_1; // entry path must not overflow Q_ASSERT(ip < 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_temp, QEP_EMPTY_SIG_); } } if (iq == s8_0) { // LCA found yet? // entry path must not overflow Q_ASSERT(ip < 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 // do not enter LCA ip = static_cast<int8_t>(iq - s8_1); // terminate the loop iq = s8_n1; } else { --iq; // try lower superstate of target } } while (iq >= s8_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_temp; // set to super of t iq = ip; do { if (t == path[iq]) { // is this LCA? // do not enter LCA ip = static_cast<int8_t>(iq-s8_1); // break out of the inner loop iq = s8_n1; r = Q_RET_HANDLED; // break outer } else { --iq; } } while (iq >= s8_0); } while (r != Q_RET_HANDLED); } } } } } } // retrace the entry path in reverse (desired) order... for (; ip >= s8_0; --ip) { QEP_ENTER_(path[ip]); // enter path[ip] } t = path[0]; // stick the target into register m_temp = t; // update the next 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_temp); // the target of the transition QS_END_() ip = s8_0; path[0] = m_temp; (void)QEP_TRIG_(m_temp, QEP_EMPTY_SIG_); // find superstate while (m_temp != t) { ++ip; path[ip] = m_temp; (void)QEP_TRIG_(m_temp, QEP_EMPTY_SIG_); // find superstate } m_temp = path[0]; // entry path must not overflow Q_ASSERT(ip < QEP_MAX_NEST_DEPTH_); do { // retrace the entry path in reverse (correct) order... QEP_ENTER_(path[ip]); // enter path[ip] --ip; } while (ip >= s8_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_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_(m_state); // the state that handled the event QS_END_() } else { 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_(m_state); // the current state QS_END_() } #endif } m_state = t; // change the current active state m_temp = t; // mark the configuration as stable } QP_END_ // "qf_pkg.h" ================================================================ /// \brief Internal (package scope) QF/C++ interface. /// \brief helper macro to cast const away from an event pointer \a e_ #define QF_EVT_CONST_CAST_(e_) const_cast<QEvt *>(e_) QP_BEGIN_ // QF-specific critical section #ifndef QF_CRIT_STAT_TYPE /// \brief This is an internal macro for defining the critical section /// status type. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// provides the definition of the critical section status varaible. /// Otherwise this macro is empty. /// \sa #QF_CRIT_STAT_TYPE /// #define QF_CRIT_STAT_ /// \brief This is an internal macro for entering a critical section. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// invokes #QF_CRIT_ENTRY passing the key variable as the parameter. /// Otherwise #QF_CRIT_ENTRY is invoked with a dummy parameter. /// \sa #QF_CRIT_ENTRY /// #define QF_CRIT_ENTRY_() QF_CRIT_ENTRY(dummy) /// \brief This is an internal macro for exiting a cricial section. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// invokes #QF_CRIT_EXIT passing the key variable as the parameter. /// Otherwise #QF_CRIT_EXIT is invoked with a dummy parameter. /// \sa #QF_CRIT_EXIT /// #define QF_CRIT_EXIT_() QF_CRIT_EXIT(dummy) #else #define QF_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_; #define QF_CRIT_ENTRY_() QF_CRIT_ENTRY(critStat_) #define QF_CRIT_EXIT_() QF_CRIT_EXIT(critStat_) #endif // package-scope objects ----------------------------------------------------- extern QTimeEvt *QF_timeEvtListHead_; ///< head of linked list of time events extern QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]; ///< allocate event pools extern uint8_t QF_maxPool_; ///< # of initialized event pools extern QSubscrList *QF_subscrList_; ///< the subscriber list array extern enum_t 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; }; ////////////////////////////////////////////////////////////////////////////// // internal helper inline functions /// \brief access to the poolId_ of an event \a e inline uint8_t QF_EVT_POOL_ID_(QEvt const * const e) { return e->poolId_; } /// \brief access to the refCtr_ of an event \a e inline uint8_t QF_EVT_REF_CTR_(QEvt const * const e) { return e->refCtr_; } /// \brief increment the refCtr_ of an event \a e inline void QF_EVT_REF_CTR_INC_(QEvt const * const e) { ++(QF_EVT_CONST_CAST_(e))->refCtr_; } /// \brief decrement the refCtr_ of an event \a e inline void QF_EVT_REF_CTR_DEC_(QEvt const * const e) { --(QF_EVT_CONST_CAST_(e))->refCtr_; } ////////////////////////////////////////////////////////////////////////////// // internal frequently used srongly-typed constants QTimeEvtCtr const tc_0 = static_cast<QTimeEvtCtr>(0); void * const null_void = static_cast<void *>(0); QEvt const * const null_evt = static_cast<QEvt const *>(0); QTimeEvt * const null_tevt = static_cast<QTimeEvt *>(0); QActive * const null_act = static_cast<QActive *>(0); QP_END_ /// \brief access element at index \a i_ from the base pointer \a base_ #define QF_PTR_AT_(base_, i_) (base_[i_]) ////////////////////////////////////////////////////////////////////////////// #ifdef Q_SPY // QS software tracing enabled? #if (QF_EQUEUE_CTR_SIZE == 1) /// \brief Internal QS macro to output an unformatted event queue /// counter data element /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE. #define QS_EQC_(ctr_) QS::u8_(ctr_) #elif (QF_EQUEUE_CTR_SIZE == 2) #define QS_EQC_(ctr_) QS::u16_(ctr_) #elif (QF_EQUEUE_CTR_SIZE == 4) #define QS_EQC_(ctr_) QS::u32_(ctr_) #else #error "QF_EQUEUE_CTR_SIZE not defined" #endif #if (QF_EVENT_SIZ_SIZE == 1) /// \brief Internal QS macro to output an unformatted event size /// data element /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE. #define QS_EVS_(size_) QS::u8_(size_) #elif (QF_EVENT_SIZ_SIZE == 2) #define QS_EVS_(size_) QS::u16_(size_) #elif (QF_EVENT_SIZ_SIZE == 4) #define QS_EVS_(size_) QS::u32_(size_) #endif #if (QF_MPOOL_SIZ_SIZE == 1) /// \brief Internal QS macro to output an unformatted memory pool /// block-size data element /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE. #define QS_MPS_(size_) QS::u8_(size_) #elif (QF_MPOOL_SIZ_SIZE == 2) #define QS_MPS_(size_) QS::u16_(size_) #elif (QF_MPOOL_SIZ_SIZE == 4) #define QS_MPS_(size_) QS::u32_(size_) #endif #if (QF_MPOOL_CTR_SIZE == 1) /// \brief Internal QS macro to output an unformatted memory pool /// block-counter data element /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE. #define QS_MPC_(ctr_) QS::u8_(ctr_) #elif (QF_MPOOL_CTR_SIZE == 2) #define QS_MPC_(ctr_) QS::u16_(ctr_) #elif (QF_MPOOL_CTR_SIZE == 4) #define QS_MPC_(ctr_) QS::u32_(ctr_) #endif #if (QF_TIMEEVT_CTR_SIZE == 1) /// \brief Internal QS macro to output an unformatted time event /// tick-counter data element /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE. #define QS_TEC_(ctr_) QS::u8_(ctr_) #elif (QF_TIMEEVT_CTR_SIZE == 2) #define QS_TEC_(ctr_) QS::u16_(ctr_) #elif (QF_TIMEEVT_CTR_SIZE == 4) #define QS_TEC_(ctr_) QS::u32_(ctr_) #endif #endif // Q_SPY // "qa_defer.cpp" ============================================================ /// \brief QActive::defer() and QActive::recall() implementation. /// QP_BEGIN_ //............................................................................ void QActive::defer(QEQueue * const eq, QEvt const * const e) const { eq->postFIFO(e); } //............................................................................ bool QActive::recall(QEQueue * const eq) { QEvt const * const e = eq->get(); // try to get evt from deferred queue bool const recalled = (e != null_evt); // event available? if (recalled) { postLIFO(e); // post it to the front of the Active Object's queue QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (QF_EVT_POOL_ID_(e) != u8_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(QF_EVT_REF_CTR_(e) > u8_1); // we need to decrement the reference counter once, to account // for removing the event from the deferred event queue. // QF_EVT_REF_CTR_DEC_(e); // decrement the reference counter } QF_CRIT_EXIT_(); } return recalled; // event not recalled } QP_END_ // "qa_fifo.cpp" ============================================================= /// \brief QActive::postFIFO() implementation. /// /// \note this source file is only included in the QF library when the native /// QF active object queue is used (instead of a message queue of an RTOS). QP_BEGIN_ //............................................................................ #ifndef Q_SPY void QActive::postFIFO(QEvt const * const e) { #else void QActive::postFIFO(QEvt const * const e, void const * const sender) { #endif QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_ACTIVE_POST_FIFO, QS::aoObj_, this) QS_TIME_(); // timestamp QS_OBJ_(sender); // the sender object QS_SIG_(e->sig); // the signal of the event QS_OBJ_(this); // this active object QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count 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_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter } if (m_eQueue.m_frontEvt == null_evt) { // 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 != static_cast<QEQueueCtr>(0)); // insert event pointer e into the buffer (FIFO) QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_head) = e; if (m_eQueue.m_head == static_cast<QEQueueCtr>(0)) { // need to wrap? 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_CRIT_EXIT_(); } QP_END_ // "qa_get_.cpp" ============================================================= /// \brief QActive::get_() and QF::getQueueMargin() definitions. /// /// \note this source file is only included in the QF library when the native /// QF active object queue is used (instead of a message queue of an RTOS). QP_BEGIN_ //............................................................................ QEvt const *QActive::get_(void) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly QEvt 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 = QF_PTR_AT_(m_eQueue.m_ring, m_eQueue.m_tail); if (m_eQueue.m_tail == static_cast<QEQueueCtr>(0)) { // need to wrap? 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_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_EQC_(m_eQueue.m_nFree); // number of free entries QS_END_NOCRIT_() } else { m_eQueue.m_frontEvt = null_evt; // the queue becomes empty QACTIVE_EQUEUE_ONEMPTY_(this); QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() } QF_CRIT_EXIT_(); return e; } //............................................................................ uint32_t QF::getQueueMargin(uint8_t const prio) { Q_REQUIRE((prio <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (active_[prio] != static_cast<QActive *>(0))); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); uint32_t margin = static_cast<uint32_t>(active_[prio]->m_eQueue.m_nMin); QF_CRIT_EXIT_(); return margin; } QP_END_ // "qa_lifo.cpp" ============================================================= /// \brief QActive::postLIFO() implementation. /// /// \note this source file is only included in the QF library when the native /// QF active object queue is used (instead of a message queue of an RTOS). QP_BEGIN_ //............................................................................ void QActive::postLIFO(QEvt const * const e) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count 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_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter } if (m_eQueue.m_frontEvt == null_evt) { // 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 != static_cast<QEQueueCtr>(0)); ++m_eQueue.m_tail; if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail? m_eQueue.m_tail = static_cast<QEQueueCtr>(0); // wrap around } QF_PTR_AT_(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_CRIT_EXIT_(); } QP_END_ // "qa_sub.cpp" ============================================================== /// \brief QActive::subscribe() implementation. QP_BEGIN_ //............................................................................ void QActive::subscribe(enum_t const sig) const { uint8_t p = m_prio; Q_REQUIRE((Q_USER_SIG <= sig) && (sig < QF_maxSignal_) && (u8_0 < p) && (p <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (QF::active_[p] == this)); uint8_t const i = Q_ROM_BYTE(QF_div8Lkup[p]); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(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_NOCRIT_() // set the priority bit QF_PTR_AT_(QF_subscrList_, sig).m_bits[i] |= Q_ROM_BYTE(QF_pwr2Lkup[p]); QF_CRIT_EXIT_(); } QP_END_ // "qa_usub.cpp" ============================================================= /// \brief QActive::unsubscribe() implementation. QP_BEGIN_ //............................................................................ void QActive::unsubscribe(enum_t const sig) const { uint8_t p = m_prio; Q_REQUIRE((Q_USER_SIG <= sig) && (sig < QF_maxSignal_) && (u8_0 < p) && (p <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (QF::active_[p] == this)); uint8_t const i = Q_ROM_BYTE(QF_div8Lkup[p]); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(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_NOCRIT_() // clear the priority bit QF_PTR_AT_(QF_subscrList_,sig).m_bits[i] &= Q_ROM_BYTE(QF_invPwr2Lkup[p]); QF_CRIT_EXIT_(); } QP_END_ // "qa_usuba.cpp" ============================================================ /// \brief QActive::unsubscribeAll() implementation. QP_BEGIN_ //............................................................................ void QActive::unsubscribeAll(void) const { uint8_t const p = m_prio; Q_REQUIRE((u8_0 < p) && (p <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (QF::active_[p] == this)); uint8_t const i = Q_ROM_BYTE(QF_div8Lkup[p]); enum_t sig; for (sig = Q_USER_SIG; sig < QF_maxSignal_; ++sig) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if ((QF_PTR_AT_(QF_subscrList_, sig).m_bits[i] & Q_ROM_BYTE(QF_pwr2Lkup[p])) != u8_0) { QS_BEGIN_NOCRIT_(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_NOCRIT_() // clear the priority bit QF_PTR_AT_(QF_subscrList_, sig).m_bits[i] &= Q_ROM_BYTE(QF_invPwr2Lkup[p]); } QF_CRIT_EXIT_(); } } QP_END_ // "qeq_fifo.cpp" ============================================================ /// \brief QEQueue::postFIFO() implementation. QP_BEGIN_ //............................................................................ void QEQueue::postFIFO(QEvt const * const e) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_EQC_(m_nFree); // number of free entries QS_EQC_(m_nMin); // min number of free entries QS_END_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter } if (m_frontEvt == null_evt) { // 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 != static_cast<QEQueueCtr>(0)); QF_PTR_AT_(m_ring, m_head) = e; // insert event into the buffer (FIFO) if (m_head == static_cast<QEQueueCtr>(0)) { // need to wrap? 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_CRIT_EXIT_(); } QP_END_ // "qeq_get.cpp" ============================================================= /// \brief QEQueue::get() implementation. QP_BEGIN_ //............................................................................ QEvt const *QEQueue::get(void) { QEvt const *e; QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (m_frontEvt == null_evt) { // is the queue empty? e = null_evt; // no event available at this time } else { e = m_frontEvt; if (m_nFree != m_end) { // any events in the the ring buffer? m_frontEvt = QF_PTR_AT_(m_ring, m_tail); // remove from the tail if (m_tail == static_cast<QEQueueCtr>(0)) { // need to wrap? m_tail = m_end; // wrap around } --m_tail; ++m_nFree; // one more free event in the ring buffer QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_EQC_(m_nFree); // number of free entries QS_END_NOCRIT_() } else { m_frontEvt = null_evt; // the queue becomes empty QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() } } QF_CRIT_EXIT_(); return e; } QP_END_ // "qeq_init.cpp" ============================================================ /// \brief QEQueue::init() implementation. QP_BEGIN_ //............................................................................ void QEQueue::init(QEvt const *qSto[], QEQueueCtr const qLen) { m_frontEvt = null_evt; // no events in the queue m_ring = &qSto[0]; m_end = qLen; m_head = static_cast<QEQueueCtr>(0); m_tail = static_cast<QEQueueCtr>(0); m_nFree = qLen; m_nMin = qLen; QS_CRIT_STAT_ 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_() } QP_END_ // "qeq_lifo.cpp" ============================================================ /// \brief QEQueue::postLIFO() implementation. QP_BEGIN_ //............................................................................ void QEQueue::postLIFO(QEvt const * const e) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(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_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_EQC_(m_nFree); // number of free entries QS_EQC_(m_nMin); // min number of free entries QS_END_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter } if (m_frontEvt != null_evt) { // is the queue not empty? // the queue must be able to accept the event (cannot overflow) Q_ASSERT(m_nFree != static_cast<QEQueueCtr>(0)); ++m_tail; if (m_tail == m_end) { // need to wrap the tail? m_tail = static_cast<QEQueueCtr>(0); // wrap around } QF_PTR_AT_(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_CRIT_EXIT_(); } QP_END_ // "qf_act.cpp" ============================================================== /// \brief QF::active_[], QF::getVersion(), and QF::add_()/QF::remove_() /// implementation. QP_BEGIN_ // public objects ------------------------------------------------------------ QActive *QF::active_[QF_MAX_ACTIVE + 1]; // to be used by QF ports only uint8_t QF_intLockNest_; // interrupt-lock nesting level //............................................................................ char_t const Q_ROM * Q_ROM_VAR QF::getVersion(void) { uint8_t const u8_zero = static_cast<uint8_t>('0'); static char_t const Q_ROM Q_ROM_VAR version[] = { static_cast<char_t>(((QP_VERSION >> 12) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 8) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 4) & 0xFU) + u8_zero), static_cast<char_t>((QP_VERSION & 0xFU) + u8_zero), static_cast<char_t>('\0') }; return version; } //............................................................................ void QF::add_(QActive * const a) { uint8_t p = a->m_prio; Q_REQUIRE((u8_0 < p) && (p <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (active_[p] == static_cast<QActive *>(0))); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); active_[p] = a; // registger the active object at this priority QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); } //............................................................................ void QF::remove_(QActive const * const a) { uint8_t p = a->m_prio; Q_REQUIRE((u8_0 < p) && (p <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (active_[p] == a)); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); active_[p] = static_cast<QActive *>(0); // free-up the priority level QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); } QP_END_ // "qf_gc.cpp" =============================================================== /// \brief QF::gc() implementation. QP_BEGIN_ //............................................................................ void QF::gc(QEvt const * const e) { if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_CRIT_STAT_ QF_CRIT_ENTRY_(); if (QF_EVT_REF_CTR_(e) > u8_1) { // isn't this the last reference? QF_EVT_REF_CTR_DEC_(e); // decrement the ref counter QS_BEGIN_NOCRIT_(QS_QF_GC_ATTEMPT, null_void, null_void) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() QF_CRIT_EXIT_(); } else { // this is the last reference to this event, recycle it uint8_t idx = static_cast<uint8_t>(QF_EVT_POOL_ID_(e) - u8_1); QS_BEGIN_NOCRIT_(QS_QF_GC, null_void, null_void) QS_TIME_(); // timestamp QS_SIG_(e->sig); // the signal of the event QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() QF_CRIT_EXIT_(); Q_ASSERT(idx < QF_maxPool_); #ifdef Q_EVT_VIRTUAL QF_EVT_CONST_CAST_(e)->~QEvt(); // xtor, cast 'const' away, // which is legitimate, because it's a pool event #endif // cast 'const' away, which is OK, because it's a pool event QF_EPOOL_PUT_(QF_pool_[idx], QF_EVT_CONST_CAST_(e)); } } } QP_END_ // "qf_log2.cpp" ============================================================= /// \brief QF_log2Lkup[] implementation. QP_BEGIN_ // Global objects ------------------------------------------------------------ uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256] = { static_cast<uint8_t>(0), static_cast<uint8_t>(1), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8), static_cast<uint8_t>(8) }; QP_END_ // "qf_new.cpp" ============================================================== /// \brief QF::new_() implementation. QP_BEGIN_ //............................................................................ QEvt *QF::new_(QEvtSize const evtSize, enum_t const sig) { // find the pool id that fits the requested event size ... uint8_t idx = u8_0; while (evtSize > static_cast<QEvtSize>(QF_EPOOL_EVENT_SIZE_(QF_pool_[idx]))) { ++idx; Q_ASSERT(idx < QF_maxPool_); // cannot run out of registered pools } QS_CRIT_STAT_ QS_BEGIN_(QS_QF_NEW, null_void, null_void) QS_TIME_(); // timestamp QS_EVS_(evtSize); // the size of the event QS_SIG_(static_cast<QSignal>(sig)); // the signal of the event QS_END_() QEvt *e; QF_EPOOL_GET_(QF_pool_[idx], e); Q_ASSERT(e != static_cast<QEvt *>(0));// pool must not run out of events e->sig = static_cast<QSignal>(sig); // set signal for this event e->poolId_ = static_cast<uint8_t>(idx + u8_1); // store pool ID in the evt e->refCtr_ = u8_0; // set the reference counter to 0 return e; } QP_END_ // "qf_pool.cpp" ============================================================= /// \brief QF_pool_[] and QF_maxPool_ definition, QF::poolInit() /// implementation. QP_BEGIN_ // Package-scope objects ----------------------------------------------------- QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]; // allocate the event pools uint8_t QF_maxPool_; // number of initialized event pools //............................................................................ void QF::poolInit(void * const poolSto, uint32_t const poolSize, uint32_t const evtSize) { // cannot exceed the number of available memory pools Q_REQUIRE(QF_maxPool_ < static_cast<uint8_t>(Q_DIM(QF_pool_))); // please initialize event pools in ascending order of evtSize: Q_REQUIRE((QF_maxPool_ == u8_0) || (QF_EPOOL_EVENT_SIZE_(QF_pool_[QF_maxPool_ - u8_1]) < evtSize)); QF_EPOOL_INIT_(QF_pool_[QF_maxPool_], poolSto, poolSize, evtSize); ++QF_maxPool_; // one more pool } QP_END_ // "qf_psini.cpp" ============================================================ /// \brief QF_subscrList_ and QF_maxSignal_ definition, QF::psInit() /// implementation. QP_BEGIN_ // Package-scope objects ----------------------------------------------------- QSubscrList *QF_subscrList_; enum_t QF_maxSignal_; //............................................................................ void QF::psInit(QSubscrList * const subscrSto, uint32_t const maxSignal) { QF_subscrList_ = subscrSto; QF_maxSignal_ = static_cast<enum_t>(maxSignal); } QP_END_ // "qf_pspub.cpp" ============================================================ /// \brief QF::publish() implementation. QP_BEGIN_ //............................................................................ #ifndef Q_SPY void QF::publish(QEvt const * const e) { #else void QF::publish(QEvt const * const e, void const * const sender) { #endif // make sure that the published signal is within the configured range Q_REQUIRE(static_cast<enum_t>(e->sig) < QF_maxSignal_); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_PUBLISH, null_void, null_void) QS_TIME_(); // the timestamp QS_OBJ_(sender); // the sender object QS_SIG_(e->sig); // the signal of the event QS_U8_(QF_EVT_POOL_ID_(e)); // the pool Id of the event QS_U8_(QF_EVT_REF_CTR_(e)); // the ref count of the event QS_END_NOCRIT_() if (QF_EVT_POOL_ID_(e) != u8_0) { // is it a dynamic event? QF_EVT_REF_CTR_INC_(e); // increment the reference counter, NOTE01 } QF_CRIT_EXIT_(); #if (QF_MAX_ACTIVE <= 8) uint8_t tmp = QF_PTR_AT_(QF_subscrList_, e->sig).m_bits[0]; while (tmp != u8_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] != static_cast<QActive *>(0));//must be registered // POST() asserts internally if the queue overflows active_[p]->POST(e, sender); } #else // number of bytes in the list uint8_t i = QF_SUBSCR_LIST_SIZE; do { // go through all bytes in the subsciption list --i; uint8_t tmp = QF_PTR_AT_(QF_subscrList_, e->sig).m_bits[i]; while (tmp != u8_0) { uint8_t p = Q_ROM_BYTE(QF_log2Lkup[tmp]); tmp &= Q_ROM_BYTE(QF_invPwr2Lkup[p]); // clear the subscriber bit // adjust the priority p = static_cast<uint8_t>(p + static_cast<uint8_t>(i << 3)); Q_ASSERT(active_[p] != static_cast<QActive *>(0)); // registered // POST() asserts internally if the queue overflows active_[p]->POST(e, sender); } } while (i != u8_0); #endif gc(e); // run the garbage collector, see NOTE01 } QP_END_ // "qf_pwr2.cpp" ============================================================= /// \brief QF_pwr2Lkup[], QF_invPwr2Lkup[], and QF_div8Lkup[] definitions. QP_BEGIN_ // Global objects ------------------------------------------------------------ uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65] = { static_cast<uint8_t>(0x00), // unused location static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x01), static_cast<uint8_t>(0x02), static_cast<uint8_t>(0x04), static_cast<uint8_t>(0x08), static_cast<uint8_t>(0x10), static_cast<uint8_t>(0x20), static_cast<uint8_t>(0x40), static_cast<uint8_t>(0x80) }; uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65] = { static_cast<uint8_t>(0xFF), // unused location static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F), static_cast<uint8_t>(0xFE), static_cast<uint8_t>(0xFD), static_cast<uint8_t>(0xFB), static_cast<uint8_t>(0xF7), static_cast<uint8_t>(0xEF), static_cast<uint8_t>(0xDF), static_cast<uint8_t>(0xBF), static_cast<uint8_t>(0x7F) }; uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65] = { static_cast<uint8_t>(0), // unused location static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(1), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(2), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(3), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(4), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(5), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(6), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7), static_cast<uint8_t>(7) }; QP_END_ // "qf_tick.cpp" ============================================================= /// \brief QF::tick() implementation. QP_BEGIN_ //............................................................................ #ifndef Q_SPY void QF::tick(void) { // see NOTE01 #else void QF::tick(void const * const sender) { #endif QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QF_TICK, null_void, null_void) QS_TEC_(static_cast<QTimeEvtCtr>(++QS::tickCtr_)); // the tick counter QS_END_NOCRIT_() QTimeEvt *prev = null_tevt; for (QTimeEvt *t = QF_timeEvtListHead_; t != null_tevt; t = t->m_next) { if (t->m_ctr == tc_0) { // time evt. scheduled for removal? if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->m_next; } else { Q_ASSERT(prev != null_tevt); prev->m_next = t->m_next; } QF_EVT_REF_CTR_DEC_(t); // mark as not linked } else { --t->m_ctr; if (t->m_ctr == tc_0) { // about to expire? if (t->m_interval != tc_0) { // periodic time event? t->m_ctr = t->m_interval; // rearm the time evt } else { QS_BEGIN_NOCRIT_(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_NOCRIT_() } QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); // leave crit. section before posting // POST() asserts internally if the queue overflows t->m_act->POST(t, sender); QF_CRIT_ENTRY_(); // re-enter crit. section to continue if (t->m_ctr == tc_0) { // still marked to expire? if (t == QF_timeEvtListHead_) { QF_timeEvtListHead_ = t->m_next; } else { Q_ASSERT(prev != null_tevt); prev->m_next = t->m_next; } QF_EVT_REF_CTR_DEC_(t); // mark as removed } else { prev = t; } } else { prev = t; } } } QF_CRIT_EXIT_(); } QP_END_ // "qmp_get.cpp" ============================================================= /// \brief QMPool::get() and QF::getPoolMargin() implementation. QP_BEGIN_ //............................................................................ void *QMPool::get(void) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QFreeBlock *fb = static_cast<QFreeBlock *>(m_free); // free block or NULL if (fb != static_cast<QFreeBlock *>(0)) { // free block available? m_free = fb->m_next; // adjust list head to the next free block Q_ASSERT(m_nFree > static_cast<QMPoolCtr>(0)); // at least one free --m_nFree; // one free block less if (m_nMin > m_nFree) { m_nMin = m_nFree; // remember the minimum so far } } QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); return fb; // return the block or NULL pointer to the caller } //............................................................................ uint32_t QF::getPoolMargin(uint8_t const poolId) { Q_REQUIRE((u8_1 <= poolId) && (poolId <= QF_maxPool_)); QF_CRIT_STAT_ QF_CRIT_ENTRY_(); uint32_t margin = static_cast<uint32_t>(QF_pool_[poolId - u8_1].m_nMin); QF_CRIT_EXIT_(); return margin; } QP_END_ // "qmp_init.cpp" ============================================================ /// \brief QMPool::init() implementation. QP_BEGIN_ //............................................................................ void QMPool::init(void * const poolSto, uint32_t const poolSize, QMPoolSize const 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 != null_void) && (poolSize >= static_cast<uint32_t>(sizeof(QFreeBlock))) && ((blockSize + static_cast<QMPoolSize>(sizeof(QFreeBlock))) > blockSize)); m_free = poolSto; // round up the blockSize to fit an integer number of pointers m_blockSize = static_cast<QMPoolSize>(sizeof(QFreeBlock));//start with one uint32_t nblocks = static_cast<uint32_t>(1);//# free blocks in a mem block while (m_blockSize < blockSize) { m_blockSize += static_cast<QMPoolSize>(sizeof(QFreeBlock)); ++nblocks; } // the whole pool buffer must fit at least one rounded-up block Q_ASSERT(poolSize >= static_cast<uint32_t>(m_blockSize)); // chain all blocks together in a free-list... // don't chain last block uint32_t availSize = poolSize - static_cast<uint32_t>(m_blockSize); m_nTot = static_cast<QMPoolCtr>(1); // one (the last) block in the pool //start at the head of the free list QFreeBlock *fb = static_cast<QFreeBlock *>(m_free); while (availSize >= static_cast<uint32_t>(m_blockSize)) { fb->m_next = &QF_PTR_AT_(fb, nblocks); // setup the next link fb = fb->m_next; // advance to next block availSize -= static_cast<uint32_t>(m_blockSize);// less available size ++m_nTot; // increment the number of blocks so far } fb->m_next = static_cast<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_CRIT_STAT_ 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_() } QP_END_ // "qmp_put.cpp" ============================================================= /// \brief QMPool::put() implementation. QP_BEGIN_ // This macro is specifically and exclusively used for checking the range // of a block pointer returned to the pool. Such a check must rely on the // pointer arithmetic not compliant with the MISRA-C++:2008 rules ??? and // ???. Defining a specific macro for this purpose allows to selectively // disable the warnings for this particular case. // #define QF_PTR_RANGE_(x_, min_, max_) (((min_) <= (x_)) && ((x_) <= (max_))) //............................................................................ void QMPool::put(void * const b) { Q_REQUIRE(m_nFree < m_nTot); // adding one free so, # free < total Q_REQUIRE(QF_PTR_RANGE_(b, m_start, m_end)); // b must be in range QF_CRIT_STAT_ QF_CRIT_ENTRY_(); // link into the free list (static_cast<QFreeBlock*>(b))->m_next = static_cast<QFreeBlock *>(m_free); m_free = b; // set as new head of the free list ++m_nFree; // one more free block in this pool QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); } QP_END_ // "qte_arm.cpp" ============================================================= /// \brief QF_timeEvtListHead_ definition and QTimeEvt::arm_() implementation. QP_BEGIN_ // Package-scope objects ----------------------------------------------------- QTimeEvt *QF_timeEvtListHead_; // head of linked list of time events //............................................................................ bool QF::noTimeEvtsActive(void) { return QF_timeEvtListHead_ == null_tevt; } //............................................................................ void QTimeEvt::arm_(QActive * const act, QTimeEvtCtr const nTicks) { Q_REQUIRE((nTicks > tc_0) /* cannot arm with 0 ticks */ && (act != null_act) /* Active object must be provided */ && (m_ctr == tc_0) /* must be disarmed */ && (static_cast<enum_t>(sig) >= Q_USER_SIG)); // valid signal QF_CRIT_STAT_ QF_CRIT_ENTRY_(); m_ctr = nTicks; m_act = act; if (refCtr_ == u8_0) { // not linked? m_next = QF_timeEvtListHead_; QF_timeEvtListHead_ = this; QF_EVT_REF_CTR_INC_(this); // mark as linked } QS_BEGIN_NOCRIT_(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_NOCRIT_() QF_CRIT_EXIT_(); } QP_END_ // "qte_ctor.cpp" ============================================================ /// \brief QTimeEvt::QTimeEvt() implementation. QP_BEGIN_ //............................................................................ QTimeEvt::QTimeEvt(enum_t const s) : #ifdef Q_EVT_CTOR QEvt(static_cast<QSignal>(s)), #endif m_next(null_tevt), m_act(null_act), m_ctr(tc_0), m_interval(tc_0) { Q_REQUIRE(s >= Q_USER_SIG); // signal must be valid #ifndef Q_EVT_CTOR sig = static_cast<QSignal>(s); #endif // time event must be static, see NOTE01 poolId_ = u8_0; // not from any event pool refCtr_ = u8_0; // not linked } QP_END_ // "qte_ctr.cpp" ============================================================= /// \brief QTimeEvt::ctr() implementation. QP_BEGIN_ //............................................................................ QTimeEvtCtr QTimeEvt::ctr(void) const { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QTimeEvtCtr ret = m_ctr; QS_BEGIN_NOCRIT_(QS_QF_TIMEEVT_CTR, QS::teObj_, this) QS_TIME_(); // timestamp QS_OBJ_(this); // this time event object QS_OBJ_(m_act); // the active object QS_TEC_(ret); // the current counter QS_TEC_(m_interval); // the interval QS_END_NOCRIT_() QF_CRIT_EXIT_(); return ret; } QP_END_ // "qte_darm.cpp" ============================================================ /// \brief QTimeEvt::disarm() implementation. QP_BEGIN_ //............................................................................ // NOTE: disarm a time evt (no harm in disarming an already disarmed time evt) bool QTimeEvt::disarm(void) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); bool wasArmed; if (m_ctr != tc_0) { // is the time event actually armed? wasArmed = true; QS_BEGIN_NOCRIT_(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_NOCRIT_() m_ctr = tc_0; // schedule removal from the list } else { // the time event was not armed wasArmed = false; QS_BEGIN_NOCRIT_(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_NOCRIT_() } QF_CRIT_EXIT_(); return wasArmed; } QP_END_ // "qte_rarm.cpp" ============================================================ /// \brief QTimeEvt::rearm() implementation. QP_BEGIN_ //............................................................................ bool QTimeEvt::rearm(QTimeEvtCtr const nTicks) { Q_REQUIRE((nTicks > tc_0) /* cannot rearm with 0 ticks */ && (m_act != null_act) /* active object must be valid */ && (static_cast<enum_t>(sig) >= Q_USER_SIG)); // valid signal QF_CRIT_STAT_ QF_CRIT_ENTRY_(); bool isArmed; if (m_ctr == tc_0) { // is this time event disarmed? isArmed = false; m_next = QF_timeEvtListHead_; if (QF_timeEvtListHead_ != null_tevt) { m_next = QF_timeEvtListHead_; QF_timeEvtListHead_ = this; QF_EVT_REF_CTR_INC_(this); // mark as linked } } else { isArmed = true; } m_ctr = nTicks; // re-load the tick counter (shift the phasing) QS_BEGIN_NOCRIT_(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 ? u8_1 : u8_0); // was the timer armed? QS_END_NOCRIT_() QF_CRIT_EXIT_(); return isArmed; } QP_END_ ////////////////////////////////////////////////////////////////////////////// // Kernel selection based on QK_PREEMPTIVE // #ifdef QK_PREEMPTIVE // "qk_pkg.h" ================================================================ /// \brief Internal (package scope) QK/C interface. #ifndef QF_CRIT_STAT_TYPE /// \brief This is an internal macro for defining the critical section /// status type. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// provides the definition of the critical section status varaible. /// Otherwise this macro is empty. /// \sa #QF_CRIT_STAT_TYPE #define QF_CRIT_STAT_ /// \brief This is an internal macro for entering a critical section. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// invokes #QF_CRIT_ENTRY passing the key variable as the parameter. /// Otherwise #QF_CRIT_ENTRY is invoked with a dummy parameter. /// \sa #QF_CRIT_ENTRY #define QF_CRIT_ENTRY_() QF_CRIT_ENTRY(dummy) /// \brief This is an internal macro for exiting a cricial section. /// /// The purpose of this macro is to enable writing the same code for the /// case when critical sectgion status type is defined and when it is not. /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro /// invokes #QF_CRIT_EXIT passing the key variable as the parameter. /// Otherwise #QF_CRIT_EXIT is invoked with a dummy parameter. /// \sa #QF_CRIT_EXIT #define QF_CRIT_EXIT_() QF_CRIT_EXIT(dummy) #else #define QF_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_; #define QF_CRIT_ENTRY_() QF_CRIT_ENTRY(critStat_) #define QF_CRIT_EXIT_() QF_CRIT_EXIT(critStat_) #endif // define for backwards compatibility, see NOTE01 #ifndef QF_CRIT_STAT_TYPE #if !defined(QF_INT_DISABLE) && defined(QF_CRIT_ENTRY) #define QF_INT_DISABLE() QF_CRIT_ENTRY(dummy) #endif #if !defined(QF_INT_ENABLE) && defined(QF_CRIT_EXIT) #define QF_INT_ENABLE() QF_CRIT_EXIT(dummy) #endif #endif // QF_CRIT_STAT_TYPE // package-scope objects... #ifndef QK_NO_MUTEX extern "C" uint8_t QK_ceilingPrio_; ///< QK mutex priority ceiling #endif // "qk.cpp" ================================================================== /// \brief QK_readySet_, QK_currPrio_, and QK_intNest_ definitions and /// QK::getVersion(), QF::init(), QF::run(), QF::stop(), /// QActive::start(), QActive::stop() implementations. // Public-scope objects ------------------------------------------------------ extern "C" { #if (QF_MAX_ACTIVE <= 8) QP_ QPSet8 QK_readySet_; // ready set of QK #else QP_ QPSet64 QK_readySet_; // ready set of QK #endif // start with the QK scheduler locked uint8_t QK_currPrio_ = static_cast<uint8_t>(QF_MAX_ACTIVE + 1); uint8_t QK_intNest_; // start with nesting level of 0 } // extern "C" QP_BEGIN_ //............................................................................ char_t const Q_ROM * Q_ROM_VAR QK::getVersion(void) { uint8_t const u8_zero = static_cast<uint8_t>('0'); static char_t const Q_ROM Q_ROM_VAR version[] = { static_cast<char_t>(((QP_VERSION >> 12) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 8) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 4) & 0xFU) + u8_zero), static_cast<char_t>((QP_VERSION & 0xFU) + u8_zero), static_cast<char_t>('\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 } //............................................................................ static void initialize(void) { QK_currPrio_ = static_cast<uint8_t>(0); // priority for the QK idle loop uint8_t p = QK_schedPrio_(); if (p != static_cast<uint8_t>(0)) { QK_sched_(p); // process all events produced so far } } //............................................................................ int16_t QF::run(void) { QF_INT_DISABLE(); initialize(); onStartup(); // startup callback QF_INT_ENABLE(); for (;;) { // the QK idle loop QK::onIdle(); // invoke the QK on-idle callback } // this unreachable return is to make the compiler happy return static_cast<int16_t>(0); } //............................................................................ void QActive::start(uint8_t const prio, QEvt const *qSto[], uint32_t const qLen, void * const stkSto, uint32_t const stkSize, QEvt const * const ie) { Q_REQUIRE((static_cast<uint8_t>(0) < prio) && (prio <= static_cast<uint8_t>(QF_MAX_ACTIVE))); m_eQueue.init(qSto, static_cast<QEQueueCtr>(qLen)); // initialize queue m_prio = prio; QF::add_(this); // make QF aware of this active object #if defined(QK_TLS) || defined(QK_EXT_SAVE) // in the QK port the parameter stkSize is used as the thread flags m_osObject = static_cast<uint8_t>(stkSize); // m_osObject contains flags // in the QK port the parameter stkSto is used as the thread-local-storage m_thread = stkSto; // contains the pointer to the thread-local-storage #else Q_ASSERT((stkSto == static_cast<void *>(0)) && (stkSize == static_cast<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 } QP_END_ // "qk_sched" ================================================================ /// \brief QK_schedPrio_() and QK_sched_() implementation. //............................................................................ // NOTE: the QK scheduler is entered and exited with interrupts DISABLED. // QK_sched_() is extern "C", so it does not belong to the QP namespace. // extern "C" { //............................................................................ // NOTE: QK schedPrio_() is entered and exited with interrupts DISABLED uint8_t QK_schedPrio_(void) { 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 } else { p = static_cast<uint8_t>(0); } return p; } //............................................................................ void QK_sched_(uint8_t p) { uint8_t pin = QK_currPrio_; // save the initial priority QP_ QActive *a; #ifdef QK_TLS // thread-local storage used? uint8_t pprev = pin; #endif do { a = QP_ 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_NOCRIT_(QP_ QS_QK_SCHEDULE, QP_ QS::aoObj_, a) QS_TIME_(); // timestamp QS_U8_(p); // the priority of the active object QS_U8_(pin); // the preempted priority QS_END_NOCRIT_() QF_INT_ENABLE(); // unconditionally enable interrupts QP_ QEvt const *e = a->get_(); // get the next event for this AO a->dispatch(e); // dispatch e to this AO QP_ QF::gc(e); // garbage collect the event, if necessary // determine the next highest-priority AO ready to run QF_INT_DISABLE(); // disable interrupts p = QK_readySet_.findMax(); #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 != static_cast<uint8_t>(0)) { // no extended context for idle loop a = QP_ QF::active_[pin]; // the pointer to the preempted AO QK_TLS(a); // restore the original TLS } #endif } } // extern "C" #ifndef QK_NO_MUTEX // "qk_mutex.cpp" ============================================================ /// \brief QK::mutexLock()/QK::mutexUnlock() implementation. // package-scope objects ----------------------------------------------------- extern "C" { uint8_t QK_ceilingPrio_; // ceiling priority of a mutex } QP_BEGIN_ //............................................................................ QMutex QK::mutexLock(uint8_t const prioCeiling) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); 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_NOCRIT_(QS_QK_MUTEX_LOCK, static_cast<void *>(0), static_cast<void *>(0)) QS_TIME_(); // timestamp QS_U8_(mutex); // the original priority QS_U8_(QK_ceilingPrio_); // the current priority ceiling QS_END_NOCRIT_() QF_CRIT_EXIT_(); return mutex; } //............................................................................ void QK::mutexUnlock(QMutex mutex) { QF_CRIT_STAT_ QF_CRIT_ENTRY_(); QS_BEGIN_NOCRIT_(QS_QK_MUTEX_UNLOCK, static_cast<void *>(0), static_cast<void *>(0)) QS_TIME_(); // timestamp QS_U8_(mutex); // the original priority QS_U8_(QK_ceilingPrio_); // the current priority ceiling QS_END_NOCRIT_() if (QK_ceilingPrio_ > mutex) { QK_ceilingPrio_ = mutex; // restore the saved priority ceiling mutex = QK_schedPrio_(); // reuse 'mutex' to hold priority if (mutex != static_cast<uint8_t>(0)) { QK_sched_(mutex); } } QF_CRIT_EXIT_(); } QP_END_ #endif // QK_NO_MUTEX #else // QK_PREEMPTIVE // "qvanilla.cpp" ============================================================ /// \brief "vanilla" cooperative kernel, /// QActive::start(), QActive::stop(), and QF::run() implementation. QP_BEGIN_ // Package-scope objects ----------------------------------------------------- extern "C" { #if (QF_MAX_ACTIVE <= 8) QPSet8 QF_readySet_; // ready set of active objects #else QPSet64 QF_readySet_; // ready set of active objects #endif uint8_t QF_currPrio_; ///< current task/interrupt priority uint8_t QF_intNest_; ///< interrupt nesting level } // extern "C" //............................................................................ void QF::init(void) { // nothing to do for the "vanilla" kernel } //............................................................................ void QF::stop(void) { onCleanup(); // cleanup callback // nothing else to do for the "vanilla" kernel } //............................................................................ int16_t QF::run(void) { onStartup(); // startup callback for (;;) { // the bacground loop QF_INT_DISABLE(); if (QF_readySet_.notEmpty()) { uint8_t p = QF_readySet_.findMax(); QActive *a = active_[p]; QF_currPrio_ = p; // save the current priority QF_INT_ENABLE(); QEvt 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 { onIdle(); // see NOTE01 } } // this unreachable return is to make the compiler happy return static_cast<int16_t>(0); } //............................................................................ void QActive::start(uint8_t const prio, QEvt const *qSto[], uint32_t const qLen, void * const stkSto, uint32_t const, QEvt const * const ie) { Q_REQUIRE((u8_0 < prio) && (prio <= static_cast<uint8_t>(QF_MAX_ACTIVE)) && (stkSto == null_void)); // does not need per-actor stack m_eQueue.init(qSto, static_cast<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); } QP_END_ ////////////////////////////////////////////////////////////////////////////// // NOTE01: // QF::onIdle() must be called with interrupts DISABLED because the // determination of the idle condition (no events in the queues) can change // at any time by an interrupt posting events to a queue. The QF::onIdle() // MUST enable interrups internally, perhaps at the same time as putting the // CPU into a power-saving mode. // extern "C" { void QK_sched_(uint8_t p) { // dummy empty definition for qk_port.s (void)p; } uint8_t QK_schedPrio_(void) { // dummy empty definition for qk_port.s return static_cast<uint8_t>(0U); } } // extern "C" #endif // QK_PREEMPTIVE ////////////////////////////////////////////////////////////////////////////// #ifdef Q_SPY // "qs_pkg.h" ================================================================ /// \brief Internal (package scope) QS/C++ interface. QP_BEGIN_ /// \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_PTR_AT_(QS_head_) = (b_); \ ++QS_head_; \ if (QS_head_ == QS_end_) { \ QS_head_ = static_cast<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_ = static_cast<uint8_t>(QS_chksum_ + (b_)); \ if (((b_) == QS_FRAME) || ((b_) == QS_ESC)) { \ QS_INSERT_BYTE(QS_ESC) \ QS_INSERT_BYTE(static_cast<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_ = static_cast<uint8_t>(~QS_chksum_); \ if ((QS_chksum_ == QS_FRAME) || (QS_chksum_ == QS_ESC)) { \ QS_INSERT_BYTE(QS_ESC) \ QS_INSERT_BYTE(static_cast<uint8_t>(QS_chksum_ ^ QS_ESC_XOR)) \ } \ else { \ QS_INSERT_BYTE(QS_chksum_) \ } /// \brief Internal QS macro to access the QS ring buffer /// /// \note The QS buffer is allocated by the user and is accessed through the /// pointer QS_ring_, which violates the MISRA-C 2004 Rule 17.4(req), pointer /// arithmetic other than array indexing. Encapsulating this violation in a /// macro allows to selectively suppress this specific deviation. #define QS_PTR_AT_(i_) (QS_ring_[i_]) /// \brief Frame character of the QS output protocol uint8_t const QS_FRAME = static_cast<uint8_t>(0x7E); /// \brief Escape character of the QS output protocol uint8_t const QS_ESC = static_cast<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. uint8_t const QS_ESC_XOR = static_cast<uint8_t>(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 QP_END_ // "qs.cpp" ================================================================== /// \brief QS internal variables definitions and core QS functions /// implementations. QP_BEGIN_ //............................................................................ 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 //............................................................................ char_t const Q_ROM * Q_ROM_VAR QS::getVersion(void) { uint8_t const u8_zero = static_cast<uint8_t>('0'); static char_t const Q_ROM Q_ROM_VAR version[] = { static_cast<char_t>(((QP_VERSION >> 12) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 8) & 0xFU) + u8_zero), static_cast<char_t>('.'), static_cast<char_t>(((QP_VERSION >> 4) & 0xFU) + u8_zero), static_cast<char_t>((QP_VERSION & 0xFU) + u8_zero), static_cast<char_t>('\0') }; return version; } //............................................................................ void QS::initBuf(uint8_t sto[], uint32_t const stoSize) { QS_ring_ = &sto[0]; QS_end_ = static_cast<QSCtr>(stoSize); } //............................................................................ void QS::filterOn(uint8_t const rec) { if (rec == QS_ALL_RECORDS) { uint8_t i; for (i = static_cast<uint8_t>(0); i < static_cast<uint8_t>(sizeof(glbFilter_)); ++i) { glbFilter_[i] = static_cast<uint8_t>(0xFF); } } else { glbFilter_[rec >> 3] |= static_cast<uint8_t>(1U << (rec & static_cast<uint8_t>(0x07))); } } //............................................................................ void QS::filterOff(uint8_t const rec) { if (rec == QS_ALL_RECORDS) { uint8_t i; for (i = static_cast<uint8_t>(0); i < static_cast<uint8_t>(sizeof(glbFilter_)); ++i) { glbFilter_[i] = static_cast<uint8_t>(0); } } else { glbFilter_[rec >> 3] &= static_cast<uint8_t>( ~static_cast<uint8_t>((1U << (rec & static_cast<uint8_t>(0x07))))); } } //............................................................................ void QS::begin(uint8_t const rec) { QS_chksum_ = static_cast<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 const format, uint8_t const d) { QS_INSERT_ESC_BYTE(format) QS_INSERT_ESC_BYTE(d) } //............................................................................ void QS::u16(uint8_t const format, uint16_t d) { QS_INSERT_ESC_BYTE(format) QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) } //............................................................................ void QS::u32(uint8_t const format, uint32_t d) { QS_INSERT_ESC_BYTE(format) QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) } QP_END_ // "qs_.cpp" ================================================================= /// \brief QS functions for internal use inside QP components QP_BEGIN_ //............................................................................ 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 QS::tickCtr_; // tick counter for the QS_QF_TICK record //............................................................................ void QS::u8_(uint8_t const d) { QS_INSERT_ESC_BYTE(d) } //............................................................................ void QS::u16_(uint16_t d) { QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) } //............................................................................ void QS::u32_(uint32_t d) { QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) d >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(d)) } //............................................................................ void QS::str_(char_t const *s) { uint8_t b = static_cast<uint8_t>(*s); while (b != static_cast<uint8_t>(0)) { // ASCII characters don't need escaping QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + b); QS_INSERT_BYTE(b) ++s; b = static_cast<uint8_t>(*s); } QS_INSERT_BYTE(static_cast<uint8_t>(0)) } //............................................................................ void QS::str_ROM_(char_t const Q_ROM * Q_ROM_VAR s) { uint8_t b = static_cast<uint8_t>(Q_ROM_BYTE(*s)); while (b != static_cast<uint8_t>(0)) { // ASCII characters don't need escaping QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + b); QS_INSERT_BYTE(b) ++s; b = static_cast<uint8_t>(Q_ROM_BYTE(*s)); } QS_INSERT_BYTE(static_cast<uint8_t>(0)) } QP_END_ // "qs_blk.cpp" ============================================================== /// \brief QS::getBlock() implementation QP_BEGIN_ //............................................................................ // get up to *pn bytes of contiguous memory uint8_t const *QS::getBlock(uint16_t * const pNbytes) { uint8_t *block; if (QS_used_ == static_cast<QSCtr>(0)) { *pNbytes = static_cast<uint16_t>(0); block = static_cast<uint8_t *>(0); // no bytes to return right now } else { QSCtr n = static_cast<QSCtr>(QS_end_ - QS_tail_); if (n > QS_used_) { n = QS_used_; } if (n > static_cast<QSCtr>(*pNbytes)) { n = static_cast<QSCtr>(*pNbytes); } *pNbytes = static_cast<uint16_t>(n); QS_used_ = static_cast<QSCtr>(QS_used_ - n); QSCtr t = QS_tail_; QS_tail_ = static_cast<QSCtr>(QS_tail_ + n); if (QS_tail_ == QS_end_) { QS_tail_ = static_cast<QSCtr>(0); } block = &QS_PTR_AT_(t); } return block; } QP_END_ // "qs_byte.cpp" ============================================================= /// \brief QS::getByte() implementation QP_BEGIN_ //............................................................................ uint16_t QS::getByte(void) { uint16_t ret; if (QS_used_ == static_cast<QSCtr>(0)) { ret = QS_EOD; // set End-Of-Data } else { ret = static_cast<uint16_t>(QS_PTR_AT_(QS_tail_)); // byte to return ++QS_tail_; // advance the tail if (QS_tail_ == QS_end_) { // tail wrap around? QS_tail_ = static_cast<QSCtr>(0); } --QS_used_; // one less byte used } return ret; // return the byte or EOD } QP_END_ // "qs_f32.cpp" ============================================================== /// \brief QS::f32() implementation QP_BEGIN_ //............................................................................ void QS::f32(uint8_t const format, float32_t const d) { union F32Rep { float32_t f; uint32_t u; } fu32; fu32.f = d; QS_INSERT_ESC_BYTE(format) QS_INSERT_ESC_BYTE(static_cast<uint8_t>(fu32.u)) fu32.u >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(fu32.u)) fu32.u >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(fu32.u)) fu32.u >>= 8; QS_INSERT_ESC_BYTE(static_cast<uint8_t>(fu32.u)) } QP_END_ // "qs_mem.cpp" ============================================================== /// \brief QS::mem() implementation QP_BEGIN_ //............................................................................ void QS::mem(uint8_t const *blk, uint8_t size) { QS_INSERT_BYTE(static_cast<uint8_t>(QS_MEM_T)) QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + static_cast<uint8_t>(QS_MEM_T)); QS_INSERT_ESC_BYTE(size) while (size != static_cast<uint8_t>(0)) { QS_INSERT_ESC_BYTE(*blk) ++blk; --size; } } QP_END_ // "qs_str.cpp" ============================================================== /// \brief QS::str() and QS::str_ROM() implementation QP_BEGIN_ //............................................................................ void QS::str(char_t const *s) { uint8_t b = static_cast<uint8_t>(*s); QS_INSERT_BYTE(static_cast<uint8_t>(QS_STR_T)) QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + static_cast<uint8_t>(QS_STR_T)); while (b != static_cast<uint8_t>(0)) { // ASCII characters don't need escaping QS_INSERT_BYTE(b) QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + b); ++s; b = static_cast<uint8_t>(*s); } QS_INSERT_BYTE(static_cast<uint8_t>(0)) } //............................................................................ void QS::str_ROM(char_t const Q_ROM * Q_ROM_VAR s) { uint8_t b = static_cast<uint8_t>(Q_ROM_BYTE(*s)); QS_INSERT_BYTE(static_cast<uint8_t>(QS_STR_T)) QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + static_cast<uint8_t>(QS_STR_T)); while (b != static_cast<uint8_t>(0)) { // ASCII characters don't need escaping QS_INSERT_BYTE(b) QS_chksum_ = static_cast<uint8_t>(QS_chksum_ + b); ++s; b = static_cast<uint8_t>(Q_ROM_BYTE(*s)); } QS_INSERT_BYTE(static_cast<uint8_t>(0)) } QP_END_ #endif // Q_SPY