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 6:01d57c81e96a, committed 2011-09-26
- Comitter:
- QL
- Date:
- Mon Sep 26 01:42:32 2011 +0000
- Parent:
- 5:949864ba515c
- Child:
- 7:bf92d3a6625e
- Commit message:
- 4.2.04
Changed in this revision
qp.cpp | Show annotated file Show diff for this revision Revisions of this file |
qp.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/qp.cpp Sun Sep 25 18:10:41 2011 +0000 +++ b/qp.cpp Mon Sep 26 01:42:32 2011 +0000 @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // 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 +// Last Updated for QP ver: 4.2.04 (modified to fit in one file) +// Date of the Last Update: Sep 25, 2011 // // Q u a n t u m L e a P s // --------------------------- @@ -27,6 +27,10 @@ ////////////////////////////////////////////////////////////////////////////// #include "qp_port.h" // QP port +#ifdef Q_USE_NAMESPACE +namespace QP { +#endif + Q_DEFINE_THIS_MODULE(qp) // "qep_pkg.h" =============================================================== @@ -42,7 +46,7 @@ #define QEP_TRIG_(state_, sig_) \ ((*(state_))(this, &QEP_reservedEvt_[sig_])) -/// helper macro to trigger entry action in an HSM +/// helper macro to trigger exit 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) \ @@ -51,7 +55,7 @@ QS_END_() \ } -/// helper macro to trigger exit action in an HSM +/// helper macro to trigger entry 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) \ @@ -63,21 +67,28 @@ // "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 } +#ifdef Q_EVT_CTOR + (QSignal)QEP_EMPTY_SIG_, + (QSignal)Q_ENTRY_SIG, + (QSignal)Q_EXIT_SIG, + (QSignal)Q_INIT_SIG +#else + {(QSignal)QEP_EMPTY_SIG_, (uint8_t)0, (uint8_t)0}, + {(QSignal)Q_ENTRY_SIG, (uint8_t)0, (uint8_t)0}, + {(QSignal)Q_EXIT_SIG, (uint8_t)0, (uint8_t)0}, + {(QSignal)Q_INIT_SIG, (uint8_t)0, (uint8_t)0} +#endif }; //............................................................................ -//lint -e970 -e971 ignore MISRA rules 13 and 14 in this function +//lint -e970 -e971 -e778 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', + (char)(((QP_VERSION >> 12U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 8) & 0xF) + '0', + (char)(((QP_VERSION >> 8U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 4) & 0xF) + '0', - (QP_VERSION & 0xF) + '0', + (char)(((QP_VERSION >> 4U) & 0xFU) + (uint8_t)'0'), + (char)((QP_VERSION & 0xFU) + (uint8_t)'0'), '\0' }; return version; @@ -402,7 +413,7 @@ // 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 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 QSignal QF_maxSignal_; ///< the maximum published signal @@ -414,12 +425,25 @@ QFreeBlock *m_next; }; +/// \brief access to the poolId of an event \a e_ +#define EVT_POOL_ID(e_) ((e_)->poolId_) + +/// \brief access to the refCtr of an event \a e_ +#define EVT_REF_CTR(e_) ((e_)->refCtr_) + +/// \brief increment the refCtr of an event \a e_ +#define EVT_INC_REF_CTR(e_) (++((QEvent *)(e_))->refCtr_) + +/// \brief decrement the refCtr of an event \a e_ +#define EVT_DEC_REF_CTR(e_) (--((QEvent *)(e_))->refCtr_) + // "qa_defer.cpp" ============================================================ +//............................................................................ void QActive::defer(QEQueue *eq, QEvent const *e) { eq->postFIFO(e); } //............................................................................ -QEvent const *QActive::recall(QEQueue *eq) { +uint8_t QActive::recall(QEQueue *eq) { QEvent const *e = eq->get(); // try to get an event from deferred queue if (e != (QEvent *)0) { // event available? @@ -428,48 +452,53 @@ QF_INT_LOCK_KEY_ QF_INT_LOCK_(); - if (e->dynamic_ != (uint8_t)0) { // is it a dynamic event? + if (EVT_POOL_ID(e) != (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); + Q_ASSERT(EVT_REF_CTR(e) > (uint8_t)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 + EVT_DEC_REF_CTR(e); // decrement the reference counter } QF_INT_UNLOCK_(); + return (uint8_t)1; // event recalled } - return e; // pass the recalled event to the caller (NULL if not recalled) + else { + return (uint8_t)0; // event not recalled + } } // "qa_fifo.cpp" ============================================================= +//............................................................................ +#ifndef Q_SPY void QActive::postFIFO(QEvent const *e) { +#else +void QActive::postFIFO(QEvent const *e, void const *sender) { +#endif + QF_INT_LOCK_KEY_ QF_INT_LOCK_(); QS_BEGIN_NOLOCK_(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_(e->dynamic_); // the QF attribute of the event + QS_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(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_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 (EVT_POOL_ID(e) != (uint8_t)0) { // is it a dynamic event? + EVT_INC_REF_CTR(e); // increment the reference counter } if (m_eQueue.m_frontEvt == (QEvent *)0) { // is the queue empty? @@ -516,7 +545,8 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count of the event QS_EQC_(m_eQueue.m_nFree); // number of free entries QS_END_NOLOCK_() } @@ -528,7 +558,8 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count of the event QS_END_NOLOCK_() } QF_INT_UNLOCK_(); @@ -556,16 +587,14 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(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_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 (EVT_POOL_ID(e) != (uint8_t)0) { // is it a dynamic event? + EVT_INC_REF_CTR(e); // increment the reference counter } if (m_eQueue.m_frontEvt == (QEvent *)0) { // is the queue empty? @@ -675,16 +704,14 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(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_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 (EVT_POOL_ID(e) != (uint8_t)0) { // is it a dynamic event? + EVT_INC_REF_CTR(e); // increment the reference counter } if (m_frontEvt == (QEvent *)0) { // is the queue empty? @@ -733,7 +760,8 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count of the event QS_EQC_(m_nFree); // number of free entries QS_END_NOLOCK_() } @@ -744,7 +772,8 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count of the event QS_END_NOLOCK_() } } @@ -778,16 +807,14 @@ 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(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_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 (EVT_POOL_ID(e) != (uint8_t)0) { // is it a dynamic event? + EVT_INC_REF_CTR(e); // increment the reference counter } if (m_frontEvt != (QEvent *)0) { // is the queue not empty? @@ -821,12 +848,12 @@ //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', + (char)(((QP_VERSION >> 12U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 8) & 0xF) + '0', + (char)(((QP_VERSION >> 8U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 4) & 0xF) + '0', - (QP_VERSION & 0xF) + '0', + (char)(((QP_VERSION >> 4U) & 0xFU) + (uint8_t)'0'), + (char)((QP_VERSION & 0xFU) + (uint8_t)'0'), '\0' }; return version; @@ -874,38 +901,41 @@ // "qf_gc.cpp" =============================================================== void QF::gc(QEvent const *e) { - if (e->dynamic_ != (uint8_t)0) { // is it a dynamic event? + if (EVT_POOL_ID(e) != (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 + if (EVT_REF_CTR(e) > (uint8_t)1) { // isn't this the last reference? + EVT_DEC_REF_CTR(e); // decrement the ref counter 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count 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); + uint8_t idx = (uint8_t)(EVT_POOL_ID(e) - 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_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count of the event QS_END_NOLOCK_() QF_INT_UNLOCK_(); Q_ASSERT(idx < QF_maxPool_); +#ifdef Q_EVT_CTOR + //lint -e1773 Attempt to cast away const + ((QEvent *)e)->~QEvent(); // call the xtor, cast 'const' away, + // which is legitimate, because it's a pool event +#endif //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 @@ -936,10 +966,10 @@ // "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 + uint8_t idx = (uint8_t)0; + while (evtSize > QF_EPOOL_EVENT_SIZE_(QF_pool_[idx])) { + ++idx; + Q_ASSERT(idx < QF_maxPool_); // cannot run out of registered pools } QS_INT_LOCK_KEY_ @@ -950,20 +980,19 @@ QS_END_() QEvent *e; - QF_EPOOL_GET_(QF_pool_[id], e); + QF_EPOOL_GET_(QF_pool_[idx], e); Q_ASSERT(e != (QEvent *)0); // pool must not run out of events e->sig = sig; // set signal for this event + EVT_POOL_ID(e) = (uint8_t)(idx + 1); // store the pool ID in the event + EVT_REF_CTR(e) = (uint8_t)0; // set the reference counter to 0 - // 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 +QF_EPOOL_TYPE_ QF_pool_[QF_MAX_EPOOL]; // allocate the event pools uint8_t QF_maxPool_; // number of initialized event pools //............................................................................ @@ -989,7 +1018,11 @@ } // "qf_pspub.cpp" ============================================================ +#ifndef Q_SPY void QF::publish(QEvent const *e) { +#else +void QF::publish(QEvent const *e, void const *sender) { +#endif // make sure that the published signal is within the configured range Q_REQUIRE(e->sig < QF_maxSignal_); @@ -998,15 +1031,14 @@ QS_BEGIN_NOLOCK_(QS_QF_PUBLISH, (void *)0, (void *)0) QS_TIME_(); // the timestamp + QS_OBJ_(sender); // the sender object QS_SIG_(e->sig); // the signal of the event - QS_U8_(e->dynamic_); // the dynamic attributes of the event + QS_U8_(EVT_POOL_ID(e)); // the pool Id of the event + QS_U8_(EVT_REF_CTR(e)); // the ref count 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 */ + if (EVT_POOL_ID(e) != (uint8_t)0) { // is it a dynamic event? + EVT_INC_REF_CTR(e); // increment the reference counter, NOTE01 } QF_INT_UNLOCK_(); @@ -1017,7 +1049,8 @@ 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 + // POST() asserts internally if the queue overflows + active_[p]->POST(e, sender); } #else uint8_t i = Q_DIM(QF_subscrList_[0].m_bits);// number of bytes in the list @@ -1030,8 +1063,8 @@ 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); + // POST() asserts internally if the queue overflows + active_[p]->POST(e, sender); } } while (i != (uint8_t)0); #endif @@ -1078,7 +1111,12 @@ }; // "qf_tick.cpp" ============================================================= +#ifndef Q_SPY void QF::tick(void) { // see NOTE01 +#else +void QF::tick(void const *sender) { +#endif + QF_INT_LOCK_KEY_ QF_INT_LOCK_(); @@ -1120,8 +1158,8 @@ QF_INT_UNLOCK_(); // unlock interrupts before calling QF service - // postFIFO() asserts internally that the event was accepted - t->m_act->postFIFO(t); + // POST() asserts internally if the queue overflows + t->m_act->POST(t, sender); } else { QF_INT_UNLOCK_(); @@ -1181,15 +1219,7 @@ && ((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); + m_free = poolSto; // round up the blockSize to fit an integer number of pointers m_blockSize = (QMPoolSize)sizeof(QFreeBlock); // start with just one @@ -1283,15 +1313,43 @@ // "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) + : +#ifdef Q_EVT_CTOR + QEvent(s), +#endif + 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 + EVT_POOL_ID(this) = (uint8_t)0; // time event must be static, see NOTE01 +} + +// "qte_ctr.cpp" ============================================================= +QTimeEvtCtr QTimeEvt::ctr(void) { + QTimeEvtCtr ctr; + QF_INT_LOCK_KEY_ + QF_INT_LOCK_(); + if (m_prev != (QTimeEvt *)0) { // is the time event actually armed? + ctr = m_ctr; + } + else { // the time event was not armed + ctr = (QTimeEvtCtr)0; + } + + QS_BEGIN_NOLOCK_(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_(ctr); // the current counter + QS_TEC_(m_interval); // the interval + QS_END_NOLOCK_() + + QF_INT_UNLOCK_(); + return ctr; } // "qte_darm.cpp" ============================================================ @@ -1418,27 +1476,45 @@ #endif // "qk.cpp" ================================================================== +#ifdef Q_USE_NAMESPACE +} // namespace QP +#endif + // Public-scope objects ------------------------------------------------------ -#if (QF_MAX_ACTIVE <= 8) +extern "C" { +#if (QF_MAX_ACTIVE <= 8U) +#ifdef Q_USE_NAMESPACE + QP::QPSet8 volatile QK_readySet_; // ready set of QK +#else QPSet8 volatile QK_readySet_; // ready set of QK +#endif +#else +#ifdef Q_USE_NAMESPACE + QP::QPSet64 volatile QK_readySet_; // ready set of QK #else QPSet64 volatile QK_readySet_; // ready set of QK #endif +#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 +} // extern "C" + +#ifdef Q_USE_NAMESPACE +namespace QP { +#endif //............................................................................ //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', + (char)(((QP_VERSION >> 12U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 8) & 0xF) + '0', + (char)(((QP_VERSION >> 8U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 4) & 0xF) + '0', - (QP_VERSION & 0xF) + '0', + (char)(((QP_VERSION >> 4U) & 0xFU) + (uint8_t)'0'), + (char)((QP_VERSION & 0xFU) + (uint8_t)'0'), '\0' }; return version; @@ -1496,13 +1572,26 @@ } // "qk_sched" ================================================================ + +#ifdef Q_USE_NAMESPACE +} // namespace QP +#endif + //............................................................................ -// NOTE: the QK scheduler is entered and exited with interrupts LOCKED +// NOTE: the QK scheduler is entered and exited with interrupts LOCKED. +// QK_schedule_() is extern "C", so it does not belong to the QP namespace. +// +extern "C" { + #ifndef QF_INT_KEY_TYPE void QK_schedule_(void) { #else void QK_schedule_(QF_INT_KEY_TYPE intLockKey_) { #endif + +#ifdef Q_USE_NAMESPACE + using namespace QP; +#endif // the QK scheduler must be called at task level only Q_REQUIRE(QK_intNest_ == (uint8_t)0); @@ -1566,6 +1655,12 @@ } } +} // extern "C" + +#ifdef Q_USE_NAMESPACE +namespace QP { +#endif + // "qk_mutex.cpp" ============================================================ #ifndef QK_NO_MUTEX @@ -1790,12 +1885,12 @@ //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', + (char)(((QP_VERSION >> 12U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 8) & 0xF) + '0', + (char)(((QP_VERSION >> 8U) & 0xFU) + (uint8_t)'0'), '.', - ((QP_VERSION >> 4) & 0xF) + '0', - (QP_VERSION & 0xF) + '0', + (char)(((QP_VERSION >> 4U) & 0xFU) + (uint8_t)'0'), + (char)((QP_VERSION & 0xFU) + (uint8_t)'0'), '\0' }; return version; @@ -2062,6 +2157,37 @@ QS_INSERT_BYTE((uint8_t)0) } +// "qs_u64.cpp" ============================================================== +#if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8) + +//............................................................................ +void QS::u64_(uint64_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) + 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) + d >>= 8; + QS_INSERT_ESC_BYTE((uint8_t)d) +} +//............................................................................ +void QS::u64(uint8_t format, uint64_t d) { + QS_INSERT_ESC_BYTE(format) + u64_(d); +} + +#endif + #endif // Q_SPY - +#ifdef Q_USE_NAMESPACE +} // namespace QP +#endif
--- a/qp.h Sun Sep 25 18:10:41 2011 +0000 +++ b/qp.h Mon Sep 26 01:42:32 2011 +0000 @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // Product: QP/C++ -// Last Updated for QP ver: 4.1.06 (modified to fit in one file) -// Date of the Last Update: Jan 26, 2011 +// Last Updated for QP ver: 4.2.04 (modified to fit in one file) +// Date of the Last Update: Sep 25, 2011 // // Q u a n t u m L e a P s // --------------------------- @@ -28,6 +28,10 @@ #ifndef qp_h #define qp_h +#ifdef Q_USE_NAMESPACE +namespace QP { +#endif + // "qevent.h" ================================================================ /// \brief QEvent class and basic macros used by all QP components. /// @@ -40,7 +44,7 @@ /// \return version of the QP as a hex constant constant 0xXYZZ, where X is /// a 1-digit major version number, Y is a 1-digit minor version number, and /// ZZ is a 2-digit release number. -#define QP_VERSION 0x4106 +#define QP_VERSION 0x4204U #ifndef Q_ROM /// \brief Macro to specify compiler-specific directive for placing a @@ -97,9 +101,11 @@ /// This macro can be defined in the QEP port file (qep_port.h) to /// configure the ::QSignal type. When the macro is not defined, the /// default of 1 byte is chosen. - #define Q_SIGNAL_SIZE 1 + #define Q_SIGNAL_SIZE 2 #endif #if (Q_SIGNAL_SIZE == 1) + typedef uint8_t QSignal; +#elif (Q_SIGNAL_SIZE == 2) /// \brief QSignal represents the signal of an event. /// /// The relationship between an event and a signal is as follows. A signal @@ -109,12 +115,6 @@ /// event. (The signal conveys the type of the occurrence-what happened?) /// However, an event can also contain additional quantitative information /// about the occurrence in form of event parameters. Please refer to the - /// document - /// <A HREF="http://www.quantum-leaps.com/devzone/Recipe_IntroHSM.pdf"> - /// Brief Introduction to UML State Machines</A>) for more information - /// about state machine concepts. - typedef uint8_t QSignal; -#elif (Q_SIGNAL_SIZE == 2) typedef uint16_t QSignal; #elif (Q_SIGNAL_SIZE == 4) typedef uint32_t QSignal; @@ -137,7 +137,13 @@ /// \include qep_qevent.cpp struct QEvent { QSignal sig; ///< signal of the event instance - uint8_t dynamic_; ///< attributes of a dynamic event (0 for static event) + uint8_t poolId_; ///< pool ID (0 for static event) + uint8_t refCtr_; ///< reference counter + +#ifdef Q_EVT_CTOR + QEvent(QSignal s) : sig(s) {} + virtual ~QEvent() {} // virtual destructor +#endif }; ////////////////////////////////////////////////////////////////////////////// @@ -1179,6 +1185,11 @@ #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4" #endif +////////////////////////////////////////////////////////////////////////////// +#ifndef QF_MAX_EPOOL + /// \brief Default value of the macro configurable value in qf_port.h + #define QF_MAX_EPOOL 3 +#endif ////////////////////////////////////////////////////////////////////////////// #ifndef QF_ACTIVE_SUPER_ @@ -1306,7 +1317,7 @@ /// \include qf_start.cpp void start(uint8_t prio, QEvent const *qSto[], uint32_t qLen, - void *stkSto = (void *)0, uint32_t stkSize = 0, + void *stkSto, uint32_t stkSize, QEvent const *ie = (QEvent *)0); /// \brief Posts an event \a e directly to the event queue of the acitve @@ -1327,13 +1338,18 @@ /// queues, direct event dispatching is synchronous. Direct event /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch() /// function. +#ifndef Q_SPY void postFIFO(QEvent const *e); +#else + void postFIFO(QEvent const *e, void const *sender); +#endif /// \brief Posts an event directly to the event queue of the active object /// \a me using the Last-In-First-Out (LIFO) policy. /// - /// \note The LIFO policy should be used only with great caution because - /// it alters order of events in the queue. + /// \note The LIFO policy should be used only for self-posting and with + /// great caution because it alters order of events in the queue. + /// /// \sa QActive::postFIFO() void postLIFO(QEvent const *e); @@ -1451,14 +1467,14 @@ /// deferred event queue \a eq and posted (LIFO) to the event queue of /// the active object. /// - /// QActive::recall() returns the pointer to the recalled event to the - /// caller. The function returns NULL if no event has been recalled. + /// QActive::recall() returns 1 (TRUE) if an event has been recalled. + /// Otherwise the function returns 0. /// /// An active object can use multiple event queues to defer events of /// different kinds. /// /// \sa QActive::defer(), QEQueue, QActive::postLIFO() - QEvent const *recall(QEQueue *eq); + uint8_t recall(QEQueue *eq); public: /// \brief Un-subscribes from the delivery of all signals to the active @@ -1667,21 +1683,14 @@ /// expected in the active object's state machine. uint8_t rearm(QTimeEvtCtr nTicks); - // for backwards compatibility - - /// \brief Arm a one-shot time event for direct event posting (obsolete). + /// \brief Get the current value of the down-counter of a time event. /// - /// This facility is now obsolete, please use \sa QTimeEvt::postIn(). - void fireIn(QActive *act, QTimeEvtCtr nTicks) { - postIn(act, nTicks); - } - - /// \brief Arm a periodic time event for direct event posting (obsolete). + /// If the time event is armed, the function returns the current value of + /// the down-counter of the given time event. If the time event is not + /// armed, the function returns 0. /// - /// This facility is now obsolete, please use \sa QTimeEvt::postEvery(). - void fireEvery(QActive *act, QTimeEvtCtr nTicks) { - postEvery(act, nTicks); - } + /// /note The function is thread-safe. + QTimeEvtCtr ctr(void); private: @@ -1905,7 +1914,11 @@ /// event to multiple subscribers. This happens in the caller's thread /// with the scheduler locked to prevent preemptions during the multi- /// casting process. (Please note that the interrupts are not locked.) +#ifndef Q_SPY static void publish(QEvent const *e); +#else + static void publish(QEvent const *e, void const *sender); +#endif /// \brief Processes all armed time events at every clock tick. /// @@ -1921,7 +1934,11 @@ /// /// The following example illustrates the call to QF::tick(): /// \include qf_tick.cpp +#ifndef Q_SPY static void tick(void); +#else + static void tick(void const *sender); +#endif /// \brief Returns the QF version. /// @@ -1977,6 +1994,10 @@ /// Please use the macro #Q_NEW. static QEvent *new_(uint16_t evtSize, QSignal sig); +#ifdef Q_EVT_CTOR + #define Q_NEW(evtT_, sig_, ...) \ + (new(QF::new_(sizeof(evtT_), sig_)) evtT_((sig_), ##__VA_ARGS__)) +#else /// \brief Allocate a dynamic event. /// /// This macro returns an event pointer cast to the type \a evtT_. The @@ -1991,6 +2012,7 @@ /// The following example illustrates dynamic allocation of an event: /// \include qf_post.cpp #define Q_NEW(evtT_, sig_) ((evtT_ *)QF::new_(sizeof(evtT_), (sig_))) +#endif /// \brief Recycle a dynamic event. /// @@ -2086,6 +2108,157 @@ extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65]; ////////////////////////////////////////////////////////////////////////////// +#ifdef Q_EVT_CTOR +#include <new> // for placement new +#endif + +// from qf.h ----------------------------------------------------------------- +////////////////////////////////////////////////////////////////////////////// +// QS software tracing integration, only if enabled +#ifdef Q_SPY // QS software tracing enabled? + #define QS_TIME_SIZE 4 + #define QS_OBJ_PTR_SIZE 4 + #define QS_FUN_PTR_SIZE 4 + + /// \brief Invoke the system clock tick processing QF::tick(). This macro + /// is the recommended way of invoking clock tick processing, because it + /// provides the vital information for software tracing and avoids any + /// overhead when the tracing is disabled. + /// + /// This macro takes the argument \a sender_, which is a pointer to the + /// sender object. This argument is actually only used when QS software + /// tracing is enabled (macro #Q_SPY is defined). When QS software + /// tracing is disabled, the macro calls QF::tick() without any + /// arguments, so the overhead of passing this extra argument is + /// entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, typically QF::TICK() will be called from + /// an interrupt, in which case you would create a unique object just to + /// unambiguously identify the ISR as the sender of the time events. + /// + /// \sa QF::tick() + #define TICK(sender_) tick(sender_) + + /// \brief Invoke the event publishing facility QF::publish(). This macro + /// is the recommended way of publishing events, because it provides the + /// vital information for software tracing and avoids any overhead when the + /// tracing is disabled. + /// + /// + /// This macro takes the last argument \a sender_, which is a pointer to + /// the sender object. This argument is actually only used when QS software + /// tracing is enabled (macro #Q_SPY is defined). When QS software + /// tracing is disabled, the macro calls QF::publish() without the + /// \a sender_ argument, so the overhead of passing this extra argument + /// is entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, if QF::PUBLISH() is called from an + /// interrupt or other context, you can create a unique object just to + /// unambiguously identify the publisher of the event. + /// + /// \sa QF::publish() + #define PUBLISH(e_, sender_) publish((e_), (sender_)) + + /// \brief Invoke the direct event posting facility QActive::postFIFO(). + /// This macro is the recommended way of posting events, because it provides + /// the vital information for software tracing and avoids any overhead when + /// the tracing is disabled. + /// + /// + /// This macro takes the last argument \a sender_, which is a pointer to + /// the sender object. This argument is actually only used when QS software + /// tracing is disabled (macro #Q_SPY is defined). When QS software + /// tracing is not enabled, the macro calls QF_publish() without the + /// \a sender_ argument, so the overhead of passing this extra argument + /// is entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, if ao->POST() is called from an + /// interrupt or other context, you can create a unique object just to + /// unambiguously identify the publisher of the event. + /// + /// \sa QActive::postFIFO() + #define POST(e_, sender_) postFIFO((e_), (sender_)) + + #if (QF_EQUEUE_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted event queue + /// counter data element + /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE. + #define QS_EQC_(ctr_) QS::u8_(ctr_) + #elif (QF_EQUEUE_CTR_SIZE == 2) + #define QS_EQC_(ctr_) QS::u16_(ctr_) + #elif (QF_EQUEUE_CTR_SIZE == 4) + #define QS_EQC_(ctr_) QS::u32_(ctr_) + #else + #error "QF_EQUEUE_CTR_SIZE not defined" + #endif + + + #if (QF_EVENT_SIZ_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted event size + /// data element + /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE. + #define QS_EVS_(size_) QS::u8_(size_) + #elif (QF_EVENT_SIZ_SIZE == 2) + #define QS_EVS_(size_) QS::u16_(size_) + #elif (QF_EVENT_SIZ_SIZE == 4) + #define QS_EVS_(size_) QS::u32_(size_) + #endif + + + #if (QF_MPOOL_SIZ_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted memory pool + /// block-size data element + /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE. + #define QS_MPS_(size_) QS::u8_(size_) + #elif (QF_MPOOL_SIZ_SIZE == 2) + #define QS_MPS_(size_) QS::u16_(size_) + #elif (QF_MPOOL_SIZ_SIZE == 4) + #define QS_MPS_(size_) QS::u32_(size_) + #endif + + #if (QF_MPOOL_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted memory pool + /// block-counter data element + /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE. + #define QS_MPC_(ctr_) QS::u8_(ctr_) + #elif (QF_MPOOL_CTR_SIZE == 2) + #define QS_MPC_(ctr_) QS::u16_(ctr_) + #elif (QF_MPOOL_CTR_SIZE == 4) + #define QS_MPC_(ctr_) QS::u32_(ctr_) + #endif + + + #if (QF_TIMEEVT_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted time event + /// tick-counter data element + /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE. + #define QS_TEC_(ctr_) QS::u8_(ctr_) + #elif (QF_TIMEEVT_CTR_SIZE == 2) + #define QS_TEC_(ctr_) QS::u16_(ctr_) + #elif (QF_TIMEEVT_CTR_SIZE == 4) + #define QS_TEC_(ctr_) QS::u32_(ctr_) + #endif + +#else + #ifndef qs_dummy_h + #include "qs_dummy.h" // disable the QS software tracing + #endif + + #define TICK(dummy_) tick() + #define PUBLISH(e_, dummy_) publish((e_)) + #define POST(e_, dummy_) postFIFO((e_)) + +#endif // Q_SPY + +////////////////////////////////////////////////////////////////////////////// // QS software tracing #ifdef Q_SPY @@ -2140,7 +2313,7 @@ QS_QF_TIMEEVT_DISARM, ///< true disarming of an armed time event QS_QF_TIMEEVT_REARM, ///< rearming of a time event QS_QF_TIMEEVT_POST, ///< a time event posted itself directly to an AO - QS_QF_RESERVED7, + QS_QF_TIMEEVT_CTR, ///< a time event counter was requested QS_QF_INT_LOCK, ///< interrupts were locked QS_QF_INT_UNLOCK, ///< interrupts were unlocked QS_QF_ISR_ENTRY, ///< an ISR was entered @@ -2384,6 +2557,18 @@ /// client code directly. static void mem(uint8_t const *blk, uint8_t size); +#if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8) + /// \brief Output uint64_t data element without format information + /// \note This function is only to be used through macros, never in the + /// client code directly. + static void u64_(uint64_t d); + + /// \brief Output uint64_t data element with format information + /// \note This function is only to be used through macros, never in the + /// client code directly. + static void u64(uint8_t format, uint64_t d); +#endif + // QS buffer access ...................................................... /// \brief Byte-oriented interface to the QS data buffer. @@ -2633,7 +2818,7 @@ /// to NULL. /// /// \sa Example of using QS filters in #QS_FILTER_ON documentation -#define QS_FILTER_AP_OBJ(obj_) (QS_apObj_ = (obj_)) +#define QS_FILTER_AP_OBJ(obj_) (QS::apObj_ = (obj_)) ////////////////////////////////////////////////////////////////////////////// @@ -2769,6 +2954,8 @@ #define QS_OBJ_(obj_) QS::u16_((uint16_t)(obj_)) #elif (QS_OBJ_PTR_SIZE == 4) #define QS_OBJ_(obj_) QS::u32_((uint32_t)(obj_)) +#elif (QS_OBJ_PTR_SIZE == 8) + #define QS_OBJ_(obj_) QS::u64_((uint64_t)(obj_)) #else /// \brief Internal QS macro to output an unformatted object pointer @@ -2785,6 +2972,8 @@ #define QS_FUN_(fun_) QS::u16_((uint16_t)(fun_)) #elif (QS_FUN_PTR_SIZE == 4) #define QS_FUN_(fun_) QS::u32_((uint32_t)(fun_)) +#elif (QS_FUN_PTR_SIZE == 8) + #define QS_FUN_(fun_) QS::u64_((uint64_t)(fun_)) #else /// \brief Internal QS macro to output an unformatted function pointer @@ -2822,7 +3011,10 @@ QS_MEM_T, ///< up to 255-bytes memory block format QS_SIG_T, ///< event signal format QS_OBJ_T, ///< object pointer format - QS_FUN_T ///< function pointer format + QS_FUN_T, ///< function pointer format + QS_I64_T, ///< signed 64-bit integer format + QS_U64_T, ///< unsigned 64-bit integer format + QS_U32_HEX_T ///< unsigned 32-bit integer in hex format }; /// \brief Output formatted int8_t to the QS record @@ -2857,6 +3049,18 @@ #define QS_F64(width_, data_) \ QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_)) +/// \brief Output formatted int64_t to the QS record +#define QS_I64(width_, data_) \ + QS::u64((uint8_t)(((width_) << 4)) | QS_I64_T, (data_)) + +/// \brief Output formatted uint64_t to the QS record +#define QS_U64(width_, data_) \ + QS::u64((uint8_t)(((width_) << 4)) | QS_U64_T, (data_)) + +/// \brief Output formatted uint32_t to the QS record +#define QS_U32_HEX(width_, data_) \ + QS::u32((uint8_t)(((width_) << 4)) | QS_U32_HEX_T, (data_)) + /// \brief Output formatted zero-terminated ASCII string to the QS record #define QS_STR(str_) QS::str(str_) @@ -2875,6 +3079,8 @@ #define QS_OBJ(obj_) QS::u16(QS_OBJ_T, (uint16_t)(obj_)) #elif (QS_OBJ_PTR_SIZE == 4) #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_)) +#elif (QS_OBJ_PTR_SIZE == 8) + #define QS_OBJ(obj_) QS::u64(QS_OBJ_T, (uint64_t)(obj_)) #else /// \brief Output formatted object pointer to the QS record #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_)) @@ -2887,6 +3093,8 @@ #define QS_FUN(fun_) QS::u16(QS_FUN_T, (uint16_t)(fun_)) #elif (QS_FUN_PTR_SIZE == 4) #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_)) +#elif (QS_FUN_PTR_SIZE == 8) + #define QS_FUN(fun_) QS::u64(QS_FUN_T, (uint64_t)(fun_)) #else /// \brief Output formatted function pointer to the QS record #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_)) @@ -3159,7 +3367,9 @@ #define QS_U32(width_, data_) ((void)0) #define QS_F32(width_, data_) ((void)0) #define QS_F64(width_, data_) ((void)0) +#define QS_U64(width_, data_) ((void)0) #define QS_STR(str_) ((void)0) +#define QS_U32_HEX(width_, data_) ((void)0) #define QS_STR_ROM(str_) ((void)0) #define QS_MEM(mem_, size_) ((void)0) #define QS_SIG(sig_, obj_) ((void)0) @@ -3180,6 +3390,7 @@ #define QS_U8_(data_) ((void)0) #define QS_U16_(data_) ((void)0) #define QS_U32_(data_) ((void)0) +#define QS_U64_(data_) ((void)0) #define QS_TIME_() ((void)0) #define QS_SIG_(sig_) ((void)0) #define QS_EVS_(size_) ((void)0) @@ -3198,6 +3409,10 @@ #endif // Q_SPY +#ifdef Q_USE_NAMESPACE +} // namespace QP +#endif + ////////////////////////////////////////////////////////////////////////////// /** * \brief Customizable QP assertions. @@ -3207,19 +3422,23 @@ * programs. * * \note The preprocessor switch Q_NASSERT disables checking assertions. -* In particular macros \ref Q_ASSERT, \ref Q_REQUIRE, \ref Q_ENSURE, -* \ref Q_INVARIANT, and \ref Q_ERROR do NOT evaluate the test condition +* In particular macros #Q_ASSERT, #Q_REQUIRE, #Q_ENSURE, #Q_INVARIANT, +* #Q_ERROR as well as #Q_ASSERT_ID, #Q_REQUIRE_ID, #Q_ENSURE_ID, +* #Q_INVARIANT_ID, and #Q_ERROR_ID do NOT evaluate the test condition * passed as the argument to these macros. One notable exception is the -* macro \ref Q_ALLEGE, that still evaluates the test condition, but does +* macro #Q_ALLEGE, that still evaluates the test condition, but does * not report assertion failures when the switch Q_NASSERT is defined. */ #ifdef Q_NASSERT /* Q_NASSERT defined--assertion checking disabled */ #define Q_DEFINE_THIS_FILE #define Q_DEFINE_THIS_MODULE(name_) - #define Q_ASSERT(test_) ((void)0) - #define Q_ALLEGE(test_) ((void)(test_)) - #define Q_ERROR() ((void)0) + #define Q_ASSERT(test_) ((void)0) + #define Q_ASSERT_ID(id_, test_) ((void)0) + #define Q_ALLEGE(test_) ((void)(test_)) + #define Q_ALLEGE_ID(id_, test_) ((void)(test_)) + #define Q_ERROR() ((void)0) + #define Q_ERROR_ID(id_) ((void)0) #else /* Q_NASSERT not defined--assertion checking enabled */ @@ -3227,9 +3446,10 @@ extern "C" { #endif - /** callback invoked in case the condition passed to \ref Q_ASSERT, - * \ref Q_REQUIRE, \ref Q_ENSURE, \ref Q_ERROR, or \ref Q_ALLEGE - * evaluates to FALSE. + /** callback invoked in case the condition passed to #Q_ASSERT, + * #Q_REQUIRE, #Q_ENSURE, #Q_ERROR, #Q_ALLEGE as well as #Q_ASSERT_ID, + * #Q_REQUIRE_ID, #Q_ENSURE_ID, #Q_ERROR_ID, and #Q_ALLEGE_ID evaluates + * to FALSE. * * \param file file name where the assertion failed * \param line line number at which the assertion failed @@ -3258,50 +3478,116 @@ /** General purpose assertion that makes sure the \a test_ argument is * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates * to FALSE. - * \note the \a test_ is NOT evaluated if assertions are - * disabled with the Q_NASSERT switch. + * \note the \a test_ is NOT evaluated if assertions are disabled with + * the Q_NASSERT switch. + * \sa #Q_ASSERT_ID */ #define Q_ASSERT(test_) \ if (test_) { \ } \ - else (Q_onAssert(l_this_file, __LINE__)) + else (Q_onAssert(&l_this_file[0], __LINE__)) + + /** General purpose assertion that makes sure the \a test_ argument is + * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates + * to FALSE. The argument \a id_ is the ID number (unique within + * the file) of the assertion. This assertion style is better suited + * for unit testig, because it avoids the volatility of line numbers + * for indentifying assertions. + * \note the \a test_ is NOT evaluated if assertions are disabled with + * the Q_NASSERT switch. + * \sa #Q_ASSERT + */ + #define Q_ASSERT_ID(id_, test_) \ + if (test_) { \ + } \ + else (Q_onAssert(&l_this_file[0], (id_))) /** General purpose assertion that ALWAYS evaluates the \a test_ * argument and calls the Q_onAssert() callback if the \a test_ * evaluates to FALSE. - * \note the \a test_ argument IS always evaluated even when assertions are - * disabled with the Q_NASSERT macro. When the Q_NASSERT macro is + * \note the \a test_ argument IS always evaluated even when assertions + * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is * defined, the Q_onAssert() callback is NOT called, even if the * \a test_ evaluates to FALSE. + * \sa #Q_ALLEGE_ID */ #define Q_ALLEGE(test_) Q_ASSERT(test_) + /** General purpose assertion that ALWAYS evaluates the \a test_ + * argument and calls the Q_onAssert() callback if the \a test_ + * evaluates to FALSE. This assertion style is better suited + * for unit testig, because it avoids the volatility of line numbers + * for indentifying assertions. + * \note the \a test_ argument IS always evaluated even when assertions + * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is + * defined, the Q_onAssert() callback is NOT called, even if the + * \a test_ evaluates to FALSE. + * \sa #Q_ALLEGE + */ + #define Q_ALLEGE_ID(id_, test_) Q_ASSERT_ID(id_, test_) + /** Assertion that always calls the Q_onAssert() callback if * ever executed. * \note can be disabled with the Q_NASSERT switch. + * \sa #Q_ERROR_ID */ #define Q_ERROR() \ (Q_onAssert(l_this_file, __LINE__)) + /** Assertion that always calls the Q_onAssert() callback if + * ever executed. This assertion style is better suited for unit + * testig, because it avoids the volatility of line numbers for + * indentifying assertions. + * \note can be disabled with the Q_NASSERT switch. + * \sa #Q_ERROR + */ + #define Q_ERROR_ID(id_) \ + (Q_onAssert(l_this_file, (id_))) + + #endif /* Q_NASSERT */ /** Assertion that checks for a precondition. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_REQUIRE_ID */ -#define Q_REQUIRE(test_) Q_ASSERT(test_) +#define Q_REQUIRE(test_) Q_ASSERT(test_) + +/** Assertion that checks for a precondition. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_REQUIRE +*/ +#define Q_REQUIRE_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Assertion that checks for a postcondition. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_ENSURE_ID */ -#define Q_ENSURE(test_) Q_ASSERT(test_) +#define Q_ENSURE(test_) Q_ASSERT(test_) + +/** Assertion that checks for a postcondition. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_ENSURE +*/ +#define Q_ENSURE_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Assertion that checks for an invariant. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_INVARIANT_ID */ -#define Q_INVARIANT(test_) Q_ASSERT(test_) +#define Q_INVARIANT(test_) Q_ASSERT(test_) + +/** Assertion that checks for an invariant. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_INVARIANT +*/ +#define Q_INVARIANT_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Compile-time assertion exploits the fact that in C/C++ a dimension of * an array cannot be negative. The following declaration causes a compilation