Go to the source code of this file.
Classes | |
| class | QS |
| Quantum Spy logging facilities. More... | |
Defines | |
| #define | QS_ALL_RECORDS ((uint8_t)0xFF) |
| Specification of all QS records for the QS::filterOn() and QS::filterOff(). | |
| #define | QS_EOD ((uint16_t)0xFFFF) |
| Constant representing End-Of-Data condition returned from the QS::getByte() function. | |
| #define | QS_TIME_SIZE 4 |
| The size (in bytes) of the QS time stamp. Valid values: 1, 2, or 4; default 4. | |
| #define | QS_TIME_() QS::u32_(QS::onGetTime()) |
| Internal macro to output time stamp to the QS record. | |
| #define | QS_INIT(arg_) QS::onStartup(arg_) |
| Initialize the QS facility. | |
| #define | QS_EXIT() QS::onCleanup() |
| Cleanup the QS facility. | |
| #define | QS_FILTER_ON(rec_) QS::filterOn(rec_) |
| Global Filter ON for a given record type rec. | |
| #define | QS_FILTER_OFF(rec_) QS::filterOff(rec_) |
| Global filter OFF for a given record type rec. | |
| #define | QS_FILTER_SM_OBJ(obj_) (QS::smObj_ = (obj_)) |
| Local Filter for a given state machine object obj_. | |
| #define | QS_FILTER_AO_OBJ(obj_) (QS::aoObj_ = (obj_)) |
| Local Filter for a given active object obj_. | |
| #define | QS_FILTER_MP_OBJ(obj_) (QS::mpObj_ = (obj_)) |
| Local Filter for a given memory pool object obj_. | |
| #define | QS_FILTER_EQ_OBJ(obj_) (QS::eqObj_ = (obj_)) |
| Filter for a given event queue object obj_. | |
| #define | QS_FILTER_TE_OBJ(obj_) (QS::teObj_ = (obj_)) |
| Local Filter for a given time event object obj_. | |
| #define | QS_FILTER_AP_OBJ(obj_) (QS_apObj_ = (obj_)) |
| Local Filter for a generic application object obj_. | |
| #define | QS_BEGIN_NOLOCK(rec_, obj_) |
| Begin a QS user record without locking interrupts. | |
| #define | QS_END_NOLOCK() QS_END_NOLOCK_() |
| End a QS user record without locking interrupts. | |
| #define | QS_INT_LOCK_KEY_ |
| This is an internal macro for defining the interrupt lock key. | |
| #define | QS_INT_LOCK_() QF_INT_LOCK(ignore_) |
| This is an internal macro for locking interrupts. | |
| #define | QS_INT_UNLOCK_() QF_INT_UNLOCK(ignore_) |
| This is an internal macro for unlocking interrupts. | |
| #define | QS_BEGIN(rec_, obj_) |
| Begin a user QS record with locking interrupts. | |
| #define | QS_END() QS_END_() |
| End a QS record with locking interrupts. | |
| #define | QS_BEGIN_(rec_, objFilter_, obj_) |
| Internal QS macro to begin a QS record with locking the interrupts. | |
| #define | QS_END_() |
| Internal QS macro to end a QS record with locking the interrupts. | |
| #define | QS_BEGIN_NOLOCK_(rec_, objFilter_, obj_) |
| Internal QS macro to begin a QS record without locking the interrupts. | |
| #define | QS_END_NOLOCK_() |
| Internal QS macro to end a QS record without locking the interrupts. | |
| #define | QS_U8_(data_) QS::u8_(data_) |
| Internal QS macro to output an unformatted uint8_t data element. | |
| #define | QS_U16_(data_) QS::u16_(data_) |
| Internal QS macro to output an unformatted uint16_t data element. | |
| #define | QS_U32_(data_) QS::u32_(data_) |
| Internal QS macro to output an unformatted uint32_t data element. | |
| #define | QS_OBJ_(obj_) QS::u32_((uint32_t)(obj_)) |
| Internal QS macro to output an unformatted object pointer data element. | |
| #define | QS_FUN_(fun_) QS::u32_((uint32_t)(fun_)) |
| Internal QS macro to output an unformatted function pointer data element. | |
| #define | QS_STR_(msg_) QS::str_(msg_) |
| Internal QS macro to output a zero-terminated ASCII string data element. | |
| #define | QS_STR_ROM_(msg_) QS::str_ROM_(msg_) |
| Internal QS macro to output a zero-terminated ASCII string allocated in ROM data element. | |
| #define | QS_I8(width_, data_) QS::u8((uint8_t)(((width_) << 4)) | QS_I8_T, (data_)) |
| Output formatted int8_t to the QS record. | |
| #define | QS_U8(width_, data_) QS::u8((uint8_t)(((width_) << 4)) | QS_U8_T, (data_)) |
| Output formatted uint8_t to the QS record. | |
| #define | QS_I16(width_, data_) QS::u16((uint8_t)(((width_) << 4)) | QS_I16_T, (data_)) |
| Output formatted int16_t to the QS record. | |
| #define | QS_U16(width_, data_) QS::u16((uint8_t)(((width_) << 4)) | QS_U16_T, (data_)) |
| Output formatted uint16_t to the QS record. | |
| #define | QS_I32(width_, data_) QS::u32((uint8_t)(((width_) << 4)) | QS_I32_T, (data_)) |
| Output formatted int32_t to the QS record. | |
| #define | QS_U32(width_, data_) QS::u32((uint8_t)(((width_) << 4)) | QS_U32_T, (data_)) |
| Output formatted uint32_t to the QS record. | |
| #define | QS_F32(width_, data_) QS::f32((uint8_t)(((width_) << 4)) | QS_F32_T, (data_)) |
| Output formatted 32-bit floating point number to the QS record. | |
| #define | QS_F64(width_, data_) QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_)) |
| Output formatted 64-bit floating point number to the QS record. | |
| #define | QS_STR(str_) QS::str(str_) |
| Output formatted zero-terminated ASCII string to the QS record. | |
| #define | QS_STR_ROM(str_) QS::str_ROM(str_) |
| Output formatted zero-terminated ASCII string from ROM to the QS record. | |
| #define | QS_MEM(mem_, size_) QS::mem((mem_), (size_)) |
| Output formatted memory block of up to 255 bytes to the QS record. | |
| #define | QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_)) |
| Output formatted object pointer to the QS record. | |
| #define | QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_)) |
| Output formatted function pointer to the QS record. | |
| #define | QS_SIG_DICTIONARY(sig_, obj_) |
| Output signal dictionary record. | |
| #define | QS_OBJ_DICTIONARY(obj_) |
| Output object dictionary record. | |
| #define | QS_FUN_DICTIONARY(fun_) |
| Output function dictionary record. | |
| #define | QS_FLUSH() QS::onFlush() |
| Flush the QS trace data to the host. | |
| #define | QF_QS_INT_LOCK() |
| Output the interrupt lock record. | |
| #define | QF_QS_INT_UNLOCK() |
| Output the interrupt unlock record. | |
| #define | QF_QS_ISR_ENTRY(isrnest_, prio_) |
| Output the interrupt entry record. | |
| #define | QF_QS_ISR_EXIT(isrnest_, prio_) |
| Output the interrupt exit record. | |
| #define | QF_QS_ACTION(act_) (act_) |
| Execute an action that is only necessary for QS output. | |
Typedefs | |
| typedef uint32_t | QSTimeCtr |
| The type of the QS time stamp. | |
Enumerations | |
| enum | QSpyRecords { , QS_QEP_STATE_ENTRY, QS_QEP_STATE_EXIT, QS_QEP_STATE_INIT, QS_QEP_INIT_TRAN, QS_QEP_INTERN_TRAN, QS_QEP_TRAN, QS_QEP_IGNORED , QS_QF_ACTIVE_ADD, QS_QF_ACTIVE_REMOVE, QS_QF_ACTIVE_SUBSCRIBE, QS_QF_ACTIVE_UNSUBSCRIBE, QS_QF_ACTIVE_POST_FIFO, QS_QF_ACTIVE_POST_LIFO, QS_QF_ACTIVE_GET, QS_QF_ACTIVE_GET_LAST, QS_QF_EQUEUE_INIT, QS_QF_EQUEUE_POST_FIFO, QS_QF_EQUEUE_POST_LIFO, QS_QF_EQUEUE_GET, QS_QF_EQUEUE_GET_LAST, QS_QF_MPOOL_INIT, QS_QF_MPOOL_GET, QS_QF_MPOOL_PUT, QS_QF_PUBLISH , QS_QF_NEW, QS_QF_GC_ATTEMPT, QS_QF_GC, QS_QF_TICK, QS_QF_TIMEEVT_ARM, QS_QF_TIMEEVT_AUTO_DISARM, QS_QF_TIMEEVT_DISARM_ATTEMPT, QS_QF_TIMEEVT_DISARM, QS_QF_TIMEEVT_REARM, QS_QF_TIMEEVT_POST , QS_QF_INT_LOCK, QS_QF_INT_UNLOCK, QS_QF_ISR_ENTRY, QS_QF_ISR_EXIT , QS_QK_MUTEX_LOCK, QS_QK_MUTEX_UNLOCK, QS_QK_SCHEDULE , QS_SIG_DICTIONARY, QS_OBJ_DICTIONARY, QS_FUN_DICTIONARY, QS_ASSERT , QS_USER } |
| Quantum Spy record types. More... | |
| enum | QSType { QS_I8_T, QS_U8_T, QS_I16_T, QS_U16_T, QS_I32_T, QS_U32_T, QS_F32_T, QS_F64_T, QS_STR_T, QS_MEM_T, QS_SIG_T, QS_OBJ_T, QS_FUN_T } |
| Enumerates data formats recognized by QS. More... | |
Variables | |
| uint8_t | QF_intLockNest_ |
| interrupt-lock nesting level | |
Definition in file qs.h.
| #define QS_BEGIN | ( | rec_, | |||
| obj_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \ & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \ && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \ { \ QS_INT_LOCK_KEY_ \ QS_INT_LOCK_(); \ QS::begin((uint8_t)(rec_)); \ QS_TIME_();
The following example shows how to build a user QS record using the macros QS_BEGIN, QS_END, and the formatted output macros: QS_U8 and QS_STR.
enum UserSpyRecords { QS_QDPP_DISPLAY = QS_USER // define user record types . . . }; void displyPhilStat(uint8_t n, char const *stat) { . . . QS_BEGIN(QS_QDPP_DISPLAY); // output a user QS record QS_U8(1, n); QS_STR(stat); QS_END(); }
| #define QS_BEGIN_ | ( | rec_, | |||
| objFilter_, | |||||
| obj_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \ & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \ && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \ { \ QS_INT_LOCK_(); \ QS::begin((uint8_t)(rec_));
Definition at line 667 of file qs.h.
Referenced by QHsm::dispatch(), QFsm::dispatch(), QMPool::init(), QHsm::init(), QFsm::init(), QEQueue::init(), QF::new_(), and QF::remove_().
| #define QS_BEGIN_NOLOCK_ | ( | rec_, | |||
| objFilter_, | |||||
| obj_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \ & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \ && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \ { \ QS::begin((uint8_t)(rec_));
Definition at line 687 of file qs.h.
Referenced by QTimeEvt::disarm(), QF::gc(), QMPool::get(), QEQueue::get(), QActive::get_(), QK::mutexLock(), QK::mutexUnlock(), QEQueue::postFIFO(), QActive::postFIFO(), QEQueue::postLIFO(), QActive::postLIFO(), QF::publish(), QMPool::put(), QTimeEvt::rearm(), QActive::subscribe(), QF::tick(), QActive::unsubscribe(), and QActive::unsubscribeAll().
| #define QS_END | ( | ) | QS_END_() |
| #define QS_END_ | ( | ) |
Value:
QS::end(); \ QS_INT_UNLOCK_(); \ }
Definition at line 678 of file qs.h.
Referenced by QHsm::dispatch(), QFsm::dispatch(), QMPool::init(), QHsm::init(), QFsm::init(), QEQueue::init(), and QF::new_().
| #define QS_END_NOLOCK_ | ( | ) |
Value:
QS::end(); \ }
Definition at line 698 of file qs.h.
Referenced by QTimeEvt::disarm(), QF::gc(), QMPool::get(), QEQueue::get(), QActive::get_(), QK::mutexLock(), QK::mutexUnlock(), QEQueue::postFIFO(), QActive::postFIFO(), QEQueue::postLIFO(), QActive::postLIFO(), QF::publish(), QMPool::put(), QTimeEvt::rearm(), QF::remove_(), QActive::subscribe(), QF::tick(), QActive::unsubscribe(), and QActive::unsubscribeAll().
| #define QS_EXIT | ( | ) | QS::onCleanup() |
Cleanup the QS facility.
This macro provides an indirection layer to invoke the QS cleanup routine if Q_SPY is defined, or do nothing if Q_SPY is not defined.
| #define QS_FILTER_AO_OBJ | ( | obj_ | ) | (QS::aoObj_ = (obj_)) |
Local Filter for a given active object obj_.
This macro sets up the active object local filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the active object that you want to monitor.
The active object filter allows you to filter QS records pertaining only to a given active object. With this filter disabled, QS will output records from all active objects in your application. The object filter is disabled by setting the active object pointer obj_ to NULL.
The active object filter affects the following QS records: QS_QF_ACTIVE_ADD, QS_QF_ACTIVE_REMOVE, QS_QF_ACTIVE_SUBSCRIBE, QS_QF_ACTIVE_UNSUBSCRIBE, QS_QF_ACTIVE_POST_FIFO, QS_QF_ACTIVE_POST_LIFO, QS_QF_ACTIVE_GET, and QS_QF_ACTIVE_GET_LAST.
| #define QS_FILTER_AP_OBJ | ( | obj_ | ) | (QS_apObj_ = (obj_)) |
Local Filter for a generic application object obj_.
This macro sets up the local application object filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the application object you want to monitor.
The application object filter allows you to filter QS records pertaining only to a given application object. With this filter disabled, QS will output records from all application-records enabled by the global filter. The local filter is disabled by setting the time event pointer obj_ to NULL.
| #define QS_FILTER_EQ_OBJ | ( | obj_ | ) | (QS::eqObj_ = (obj_)) |
Filter for a given event queue object obj_.
This macro sets up the event queue object filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the "raw" thread-safe queue object you want to monitor.
The event queue filter allows you to filter QS records pertaining only to a given event queue. With this filter disabled, QS will output records from all event queues in your application. The object filter is disabled by setting the event queue pointer obj_ to NULL.
The event queue filter affects the following QS records: QS_QF_EQUEUE_INIT, QS_QF_EQUEUE_POST_FIFO, QS_QF_EQUEUE_POST_LIFO, QS_QF_EQUEUE_GET, and QS_QF_EQUEUE_GET_LAST.
| #define QS_FILTER_MP_OBJ | ( | obj_ | ) | (QS::mpObj_ = (obj_)) |
Local Filter for a given memory pool object obj_.
This macro sets up the memory pool object local filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the memory buffer used during the initialization of the event pool with QF::poolInit().
The memory pool filter allows you to filter QS records pertaining only to a given memory pool. With this filter disabled, QS will output records from all memory pools in your application. The object filter is disabled by setting the memory pool pointer obj_ to NULL.
The memory pool filter affects the following QS records: QS_QF_MPOOL_INIT, QS_QF_MPOOL_GET, and QS_QF_MPOOL_PUT.
| #define QS_FILTER_OFF | ( | rec_ | ) | QS::filterOff(rec_) |
Global filter OFF for a given record type rec.
This macro provides an indirection layer to call QS::filterOff() if Q_SPY is defined, or do nothing if Q_SPY is not defined.
| #define QS_FILTER_ON | ( | rec_ | ) | QS::filterOn(rec_) |
Global Filter ON for a given record type rec.
This macro provides an indirection layer to call QS::filterOn() if Q_SPY is defined, or do nothing if Q_SPY is not defined.
The following example shows how to use QS filters:
main () {
. . .
if (!QS_INIT("1")) { // Initialize QSpy to use UART 1
return -1; // Unable to initialize QSpy
}
QS_FILTER_IN(QS_ALL_RECORDS); // start with enabling all QS records
QS_FILTER_OUT(QS_QK_INT_LOCK); // disable QS output of this record
QS_FILTER_OUT(QS_QK_INT_UNLOCK); // disable QS output of this record
QS_FILTER_OUT(QS_QK_ISR_ENTRY); // disable QS output of this record
QS_FILTER_OUT(QS_QK_ISR_EXIT); // disable QS output of this record
QS_FILTER_SM_OBJ(&philo[3]); // trace only this state machine object
QS_FILTER_AO_OBJ(&philo[3]); // trace only this active object
QS_FILTER_MP_OBJ(regSizePoolSto); // trace only this event pool
QS_FILTER_EQ_OBJ(&rawQueue); // trace only this event queue
QS_FILTER_TE_OBJ(&philo[3].timeEvt__); // trace only this time event
. . .
}
| #define QS_FILTER_SM_OBJ | ( | obj_ | ) | (QS::smObj_ = (obj_)) |
Local Filter for a given state machine object obj_.
This macro sets up the state machine object local filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the state machine object that you want to monitor.
The state machine object filter allows you to filter QS records pertaining only to a given state machine object. With this filter disabled, QS will output records from all state machines in your application. The object filter is disabled by setting the state machine pointer to NULL.
The state machine filter affects the following QS records: QS_QEP_STATE_ENTRY, QS_QEP_STATE_EXIT, QS_QEP_STATE_INIT, QS_QEP_INIT_TRAN, QS_QEP_INTERN_TRAN, QS_QEP_TRAN, and QS_QEP_IGNORED.
| #define QS_FILTER_TE_OBJ | ( | obj_ | ) | (QS::teObj_ = (obj_)) |
Local Filter for a given time event object obj_.
This macro sets up the time event object local filter if Q_SPY is defined, or does nothing if Q_SPY is not defined. The argument obj_ is the pointer to the time event object you want to monitor.
The time event filter allows you to filter QS records pertaining only to a given time event. With this filter disabled, QS will output records from all time events in your application. The object filter is disabled by setting the time event pointer obj_ to NULL.
The time event filter affects the following QS records: QS_QF_TIMEEVT_ARM, QS_QF_TIMEEVT_AUTO_DISARM, QS_QF_TIMEEVT_DISARM_ATTEMPT, QS_QF_TIMEEVT_DISARM, QS_QF_TIMEEVT_REARM, QS_QF_TIMEEVT_POST, and QS_QF_TIMEEVT_PUBLISH.
| #define QS_FLUSH | ( | ) | QS::onFlush() |
Flush the QS trace data to the host.
This macro invokes the QS::flush() platform-dependent callback function to flush the QS trace buffer to the host. The function typically busy-waits until all the data in the buffer is sent to the host. This is acceptable only in the initial transient.
Definition at line 956 of file qs.h.
Referenced by QActive::start().
| #define QS_FUN_ | ( | fun_ | ) | QS::u32_((uint32_t)(fun_)) |
Internal QS macro to output an unformatted function pointer data element.
Definition at line 740 of file qs.h.
Referenced by QHsm::dispatch(), QFsm::dispatch(), QHsm::init(), and QFsm::init().
| #define QS_FUN_DICTIONARY | ( | fun_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)QS_FUN_DICTIONARY >> 3U] \ & (1U << ((uint8_t)QS_FUN_DICTIONARY & 7U))) != 0U)) \ { \ static char const Q_ROM Q_ROM_VAR fun_name__[] = #fun_; \ QS_INT_LOCK_KEY_ \ QS_INT_LOCK_(); \ QS::begin((uint8_t)QS_FUN_DICTIONARY); \ QS_FUN_(fun_); \ QS_STR_ROM_(fun_name__); \ QS::end(); \ QS_INT_UNLOCK_(); \ QS::onFlush(); \ } else ((void)0)
A function dictionary record associates the binary address of a function in the target's memory with the human-readable name of the function.
Providing a function dictionary QS record can vastly improve readability of the QS log, because instead of dealing with cryptic machine addresses the QSpy host utility can display human-readable function names.
The example from QS_SIG_DICTIONARY shows the definition of a function dictionary.
| #define QS_INIT | ( | arg_ | ) | QS::onStartup(arg_) |
| #define QS_INT_LOCK_ | ( | ) | QF_INT_LOCK(ignore_) |
This is an internal macro for locking interrupts.
The purpose of this macro is to enable writing the same code for the case when interrupt key is defined and when it is not. If the macro QS_INT_KEY_TYPE is defined, this internal macro invokes QS_INT_LOCK passing the key variable as the parameter. Otherwise QS_INT_LOCK is invoked with a dummy parameter.
| #define QS_INT_LOCK_KEY_ |
This is an internal macro for defining the interrupt lock key.
The purpose of this macro is to enable writing the same code for the case when interrupt key is defined and when it is not. If the macro QS_INT_KEY_TYPE is defined, this internal macro provides the definition of the lock key variable. Otherwise this macro is empty.
Definition at line 611 of file qs.h.
Referenced by QHsm::dispatch(), QFsm::dispatch(), QMPool::init(), QHsm::init(), QFsm::init(), QEQueue::init(), and QF::new_().
| #define QS_INT_UNLOCK_ | ( | ) | QF_INT_UNLOCK(ignore_) |
This is an internal macro for unlocking interrupts.
The purpose of this macro is to enable writing the same code for the case when interrupt key is defined and when it is not. If the macro QS_INT_KEY_TYPE is defined, this internal macro invokes QS_INT_UNLOCK passing the key variable as the parameter. Otherwise QS_INT_UNLOCK is invoked with a dummy parameter.
| #define QS_OBJ_ | ( | obj_ | ) | QS::u32_((uint32_t)(obj_)) |
Internal QS macro to output an unformatted object pointer data element.
Definition at line 724 of file qs.h.
Referenced by QTimeEvt::disarm(), QHsm::dispatch(), QFsm::dispatch(), QMPool::get(), QEQueue::get(), QActive::get_(), QMPool::init(), QHsm::init(), QFsm::init(), QEQueue::init(), QEQueue::postFIFO(), QActive::postFIFO(), QEQueue::postLIFO(), QActive::postLIFO(), QMPool::put(), QTimeEvt::rearm(), QF::remove_(), QActive::subscribe(), QF::tick(), QActive::unsubscribe(), and QActive::unsubscribeAll().
| #define QS_OBJ_DICTIONARY | ( | obj_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)QS_OBJ_DICTIONARY >> 3U] \ & (1U << ((uint8_t)QS_OBJ_DICTIONARY & 7U))) != 0U)) \ { \ static char const Q_ROM Q_ROM_VAR obj_name__[] = #obj_; \ QS_INT_LOCK_KEY_ \ QS_INT_LOCK_(); \ QS::begin((uint8_t)QS_OBJ_DICTIONARY); \ QS_OBJ_(obj_); \ QS_STR_ROM_(obj_name__); \ QS::end(); \ QS_INT_UNLOCK_(); \ QS::onFlush(); \ } else ((void)0)
An object dictionary record associates the binary address of an object in the target's memory with the human-readable name of the object.
Providing an object dictionary QS record can vastly improve readability of the QS log, because instead of dealing with cryptic machine addresses the QSpy host utility can display human-readable object names.
The following example shows the definition of object dictionary entry for the Table active object:
| #define QS_SIG_DICTIONARY | ( | sig_, | |||
| obj_ | ) |
Value:
if (((QS::glbFilter_[(uint8_t)QS_SIG_DICTIONARY >> 3U] \ & (1U << ((uint8_t)QS_SIG_DICTIONARY & 7U))) != 0U)) \ { \ static char const Q_ROM Q_ROM_VAR sig_name__[] = #sig_; \ QS_INT_LOCK_KEY_ \ QS_INT_LOCK_(); \ QS::begin((uint8_t)QS_SIG_DICTIONARY); \ QS_SIG_(sig_); \ QS_OBJ_(obj_); \ QS_STR_ROM_(sig_name__); \ QS::end(); \ QS_INT_UNLOCK_(); \ QS::onFlush(); \ } else ((void)0)
A signal dictionary record associates the numerical value of the signal and the binary address of the state machine that consumes that signal with the human-readable name of the signal.
Providing a signal dictionary QS record can vastly improve readability of the QS log, because instead of dealing with cryptic machine addresses the QSpy host utility can display human-readable names.
A signal dictionary entry is associated with both the signal value sig_ and the state machine obj_, because signals are required to be unique only within a given state machine and therefore the same numerical values can represent different signals in different state machines.
For the "global" signals that have the same meaning in all state machines (such as globally published signals), you can specify a signal dictionary entry with the obj_ parameter set to NULL.
The following example shows the definition of signal dictionary entries in the initial transition of the Table active object. Please note that signals HUNGRY_SIG and DONE_SIG are associated with the Table state machine only ("me" obj_ pointer). The EAT_SIG signal, on the other hand, is global (0 obj_ pointer):
QState Table::initial(Table *me, QEvent const *) { uint8_t n; QS_SIG_DICTIONARY(HUNGRY_SIG, me); // output signal dictionary QS record QS_SIG_DICTIONARY(DONE_SIG, me); // output signal dictionary QS record QS_SIG_DICTIONARY(EAT_SIG, 0); // output signal dictionary QS record QS_FUN_DICTIONARY(Table::serving); subscribe(HUNGRY_SIG); subscribe(DONE_SIG); subscribe(TERMINATE_SIG); for (n = 0; n < N; ++n) { me->fork__[n] = FREE; me->isHungry__[n] = 0; } return Q_TRAN(&Table::serving); }
qspy -fqs.bin -S2 -Q2 -P4 -p4 -T4
QSpy 4.0.00
Thu Apr 06 09:56:10 2005
-f qs.bin
-S 2
-Q 2
-P 4
-p 4
-T 4
. . . . . .
Obj Dic: 00419048->table
EQ.INIT: Obj=00419050 Len= 5
0000000000 AO.ADD : Active=table Prio=51
Fun Dic: 00401CEE->Table_serving
Sig Dic: 00000004,Obj=00419048 ->HUNGRY_SIG
Sig Dic: 00000005,Obj=00419048 ->DONE_SIG
Sig Dic: 00000006,Obj=00000000 ->EAT_SIG
0000000000 AO.SUB : Active=table Sig=HUNGRY_SIG
0000000000 AO.SUB : Active=table Sig=DONE_SIG
0000000000 AO.SUB : Active=table Sig=00000007,Obj=00419048
Q_INIT : Obj=table Source=00403CE0 Target=Table_serving
0000000000 ==>Init: Obj=table New=Table_serving
. . . . . .
// the Philosophers become hungry...
0000000007 AO.FIFO: Obj=table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 1, nMax= 1)
0000000007 AO.FIFO: Obj=table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 2, nMax= 2)
Q_ENTRY: Obj=philo[2] State=Philosopher_hungry
0000000007 AO.GET : Active= table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 2)
0000000007 AO.FIFO: Obj=table Evt(Sig=HUNGRY_SIG, Pool=1, Ref= 1)
Queue(nUsed= 2, nMax= 3)
Q_ENTRY: Obj=philo[4] State=Philosopher_hungry
Q_ENTRY: Obj=philo[1] State=Philosopher_hungry
Q_ENTRY: Obj=philo[3] State=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[2] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[4] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[3] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[1] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
Q_ENTRY: Obj=philo[0] State=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[0] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
// user record output
0000000007 User070: 2 hungry
// Table grants permissions to eat
0000000007 NEW : Evt(Sig=EAT_SIG, size= 6)
0000000007 MP.GET : Obj=00418E18 nFree= 5 nMin= 5
0000000007 AO.FIFO: Obj=philo[4] Evt(Sig=EAT_SIG, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[3] Evt(Sig=EAT_SIG, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[2] Evt(Sig=EAT_SIG, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[1] Evt(Sig=EAT_SIG, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[0] Evt(Sig=EAT_SIG, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 PUBLISH: Evt(Sig=EAT_SIG, Pool=1, Ref= 5) nSubsr= 5
0000000007 AO.GETL: Active= philo[4] Evt(Sig=EAT_SIG, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[2] Evt(Sig=EAT_SIG, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[3] Evt(Sig=EAT_SIG, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[1] Evt(Sig=EAT_SIG, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[0] Evt(Sig=EAT_SIG, Pool=1, Ref= 5)
. . . . . .
The following QSpy log example shows the same sequence of records, but with dictionary records removed. The human-readable signal names are not available.
qspy -fqs0.bin -S2 -Q2 -P4 -p4 -T4
QSpy 4.0.00
Thu Apr 06 10:10:22 2005
-f qs0.bin
-S 2
-Q 2
-P 4
-p 4
-T 4
. . . . . .
Obj Dic: 00419048->table
EQ.INIT: Obj=00419050 Len= 5
0000000000 AO.ADD : Active=table Prio=51
// the signal dictionary entries removed from the binary QS log
*** Dropped 4 records
0000000000 AO.SUB : Active=table Sig=00000004,Obj=00419048
0000000000 AO.SUB : Active=table Sig=00000005,Obj=00419048
0000000000 AO.SUB : Active=table Sig=00000007,Obj=00419048
Q_INIT : Obj=table Source=00403CE0 Target=00403CE0
0000000000 ==>Init: Obj=table New=00401CEE
. . . . . .
// the Philosophers become hungry...
0000000007 AO.FIFO: Obj=table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 1, nMax= 1)
0000000007 AO.FIFO: Obj=table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 2, nMax= 2)
Q_ENTRY: Obj=philo[2] State=Philosopher_hungry
0000000007 AO.GET : Active= table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 2)
0000000007 AO.FIFO: Obj=table Evt(Sig=00000004,Obj=00419048, Pool=1, Ref= 1)
Queue(nUsed= 2, nMax= 3)
Q_ENTRY: Obj=philo[4] State=Philosopher_hungry
Q_ENTRY: Obj=philo[1] State=Philosopher_hungry
Q_ENTRY: Obj=philo[3] State=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[2] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[4] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[3] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[1] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
Q_ENTRY: Obj=philo[0] State=Philosopher_hungry
0000000007 ==>Tran: Obj=philo[0] Sig=TIMEOUT_SIG Source=Philosopher_thinking
New=Philosopher_hungry
// user record output
0000000007 User070: 2 hungry
// Table grants permissions to eat
0000000007 NEW : Evt(Sig=00000006,Obj=00000000, size= 6)
0000000007 MP.GET : Obj=00418E18 nFree= 5 nMin= 5
0000000007 AO.FIFO: Obj=philo[4] Evt(Sig=00000006,Obj=00419000, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[3] Evt(Sig=00000006,Obj=00418FBC, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[2] Evt(Sig=00000006,Obj=00418F78, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[1] Evt(Sig=00000006,Obj=00418F34, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 AO.FIFO: Obj=philo[0] Evt(Sig=00000006,Obj=00418EF0, Pool=1, Ref= 0)
Queue(nUsed= 0, nMax= 0)
0000000007 PUBLISH: Evt(Sig=00000006,Obj=00000000, Pool=1, Ref= 5) nSubsr= 5
0000000007 AO.GETL: Active= philo[4] Evt(Sig=00000006,Obj=00419000, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[2] Evt(Sig=00000006,Obj=00418F78, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[3] Evt(Sig=00000006,Obj=00418FBC, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[1] Evt(Sig=00000006,Obj=00418F34, Pool=1, Ref= 5)
0000000007 AO.GETL: Active= philo[0] Evt(Sig=00000006,Obj=00418EF0, Pool=1, Ref= 5)
. . . . . .
| #define QS_TIME_SIZE 4 |
| enum QSpyRecords |
Quantum Spy record types.
This enumeration specifies the record types used in the QP components. You can specify your own record types starting from QS_USER offset. Currently, the maximum of all records cannot exceed 256.
| QS_QEP_STATE_ENTRY | a state was entered |
| QS_QEP_STATE_EXIT | a state was exited |
| QS_QEP_STATE_INIT | an intial transition was taken in a state |
| QS_QEP_INIT_TRAN | the top-most initial transition was taken |
| QS_QEP_INTERN_TRAN | an internal transition was taken |
| QS_QEP_TRAN | a regular transition was taken |
| QS_QEP_IGNORED | an event was ignored (silently discarded) |
| QS_QF_ACTIVE_ADD | an AO has been added to QF (started) |
| QS_QF_ACTIVE_REMOVE | an AO has been removed from QF (stopped) |
| QS_QF_ACTIVE_SUBSCRIBE | an AO subscribed to an event |
| QS_QF_ACTIVE_UNSUBSCRIBE | an AO unsubscribed to an event |
| QS_QF_ACTIVE_POST_FIFO | an event was posted (FIFO) directly to an AO |
| QS_QF_ACTIVE_POST_LIFO | an event was posted (LIFO) directly to an AO |
| QS_QF_ACTIVE_GET | an AO got an event and its queue is still not empty |
| QS_QF_ACTIVE_GET_LAST | an AO got an event and its queue is empty |
| QS_QF_EQUEUE_INIT | an event queue was initialized |
| QS_QF_EQUEUE_POST_FIFO | an event was posted (FIFO) to a raw queue |
| QS_QF_EQUEUE_POST_LIFO | an event was posted (LIFO) to a raw queue |
| QS_QF_EQUEUE_GET | get an event and queue still not empty |
| QS_QF_EQUEUE_GET_LAST | get the last event from the queue |
| QS_QF_MPOOL_INIT | a memory pool was initialized |
| QS_QF_MPOOL_GET | a memory block was removed from a memory pool |
| QS_QF_MPOOL_PUT | a memory block was returned to a memory pool |
| QS_QF_PUBLISH | an event was truly published to some subscribers |
| QS_QF_NEW | new event creation |
| QS_QF_GC_ATTEMPT | garbage collection attempt |
| QS_QF_GC | garbage collection |
| QS_QF_TICK | QF::tick() was called. |
| QS_QF_TIMEEVT_ARM | a time event was armed |