Linux Face / QPFramework
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers qs.h Source File

qs.h

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////////
00002 // Product: QS/C++ platform-independent public interface.
00003 // Last Updated for Version: 4.1.00
00004 // Date of the Last Update:  Oct 09, 2009
00005 //
00006 //                    Q u a n t u m     L e a P s
00007 //                    ---------------------------
00008 //                    innovating embedded systems
00009 //
00010 // Copyright (C) 2002-2009 Quantum Leaps, LLC. All rights reserved.
00011 //
00012 // This software may be distributed and modified under the terms of the GNU
00013 // General Public License version 2 (GPL) as published by the Free Software
00014 // Foundation and appearing in the file GPL.TXT included in the packaging of
00015 // this file. Please note that GPL Section 2[b] requires that all works based
00016 // on this software must also be made publicly available under the terms of
00017 // the GPL ("Copyleft").
00018 //
00019 // Alternatively, this software may be distributed and modified under the
00020 // terms of Quantum Leaps commercial licenses, which expressly supersede
00021 // the GPL and are specifically designed for licensees interested in
00022 // retaining the proprietary status of their code.
00023 //
00024 // Contact information:
00025 // Quantum Leaps Web site:  http://www.quantum-leaps.com
00026 // e-mail:                  info@quantum-leaps.com
00027 //////////////////////////////////////////////////////////////////////////////
00028 #ifndef qs_h
00029 #define qs_h
00030 
00031 /// \file
00032 /// \ingroup qep qf qk qs
00033 /// \brief QS/C++ platform-independent public interface.
00034 /// This header file must be included directly or indirectly
00035 /// in all modules (*.cpp files) that use QS/C++.
00036 
00037 #ifndef Q_SPY
00038     #error "Q_SPY must be defined to include qs.h"
00039 #endif
00040 
00041 //////////////////////////////////////////////////////////////////////////////
00042 
00043 /// \brief Quantum Spy record types.
00044 ///
00045 /// This enumeration specifies the record types used in the QP components.
00046 /// You can specify your own record types starting from ::QS_USER offset.
00047 /// Currently, the maximum of all records cannot exceed 256.
00048 /// \sa QS::filterOn()/#QS_FILTER_ON and QS::filterOff()/#QS_FILTER_OFF
00049 enum QSpyRecords {
00050     // QEP records
00051     QS_QEP_STATE_EMPTY,
00052     QS_QEP_STATE_ENTRY,                               ///< a state was entered
00053     QS_QEP_STATE_EXIT,                                 ///< a state was exited
00054     QS_QEP_STATE_INIT,          ///< an intial transition was taken in a state
00055     QS_QEP_INIT_TRAN,           ///< the top-most initial transition was taken
00056     QS_QEP_INTERN_TRAN,                  ///< an internal transition was taken
00057     QS_QEP_TRAN,                           ///< a regular transition was taken
00058     QS_QEP_IGNORED,             ///< an event was ignored (silently discarded)
00059     QS_QEP_DISPATCH,          ///< an event was dispatched (begin of RTC step)
00060     QS_QEP_RESERVED0,
00061 
00062     // QF records
00063     QS_QF_ACTIVE_ADD,                ///< an AO has been added to QF (started)
00064     QS_QF_ACTIVE_REMOVE,         ///< an AO has been removed from QF (stopped)
00065     QS_QF_ACTIVE_SUBSCRIBE,                  ///< an AO subscribed to an event
00066     QS_QF_ACTIVE_UNSUBSCRIBE,              ///< an AO unsubscribed to an event
00067     QS_QF_ACTIVE_POST_FIFO,  ///< an event was posted (FIFO) directly to an AO
00068     QS_QF_ACTIVE_POST_LIFO,  ///< an event was posted (LIFO) directly to an AO
00069     QS_QF_ACTIVE_GET, ///< an AO got an event and its queue is still not empty
00070     QS_QF_ACTIVE_GET_LAST,      ///< an AO got an event and its queue is empty
00071     QS_QF_EQUEUE_INIT,                     ///< an event queue was initialized
00072     QS_QF_EQUEUE_POST_FIFO,     ///< an event was posted (FIFO) to a raw queue
00073     QS_QF_EQUEUE_POST_LIFO,     ///< an event was posted (LIFO) to a raw queue
00074     QS_QF_EQUEUE_GET,              ///< get an event and queue still not empty
00075     QS_QF_EQUEUE_GET_LAST,              ///< get the last event from the queue
00076     QS_QF_MPOOL_INIT,                       ///< a memory pool was initialized
00077     QS_QF_MPOOL_GET,        ///< a memory block was removed from a memory pool
00078     QS_QF_MPOOL_PUT,         ///< a memory block was returned to a memory pool
00079     QS_QF_PUBLISH,       ///< an event was truly published to some subscribers
00080     QS_QF_RESERVED8,
00081     QS_QF_NEW,                                         ///< new event creation
00082     QS_QF_GC_ATTEMPT,                          ///< garbage collection attempt
00083     QS_QF_GC,                                          ///< garbage collection
00084     QS_QF_TICK,                                     ///< QF::tick() was called
00085     QS_QF_TIMEEVT_ARM,                             ///< a time event was armed
00086     QS_QF_TIMEEVT_AUTO_DISARM,      ///< a time event expired and was disarmed
00087     QS_QF_TIMEEVT_DISARM_ATTEMPT,///< an attempt to disarmed a disarmed tevent
00088     QS_QF_TIMEEVT_DISARM,           ///< true disarming of an armed time event
00089     QS_QF_TIMEEVT_REARM,                         ///< rearming of a time event
00090     QS_QF_TIMEEVT_POST,      ///< a time event posted itself directly to an AO
00091     QS_QF_RESERVED7,
00092     QS_QF_INT_LOCK,                                ///< interrupts were locked
00093     QS_QF_INT_UNLOCK,                            ///< interrupts were unlocked
00094     QS_QF_ISR_ENTRY,                                   ///< an ISR was entered
00095     QS_QF_ISR_EXIT,                                     ///< an ISR was exited
00096     QS_QF_RESERVED6,
00097     QS_QF_RESERVED5,
00098     QS_QF_RESERVED4,
00099     QS_QF_RESERVED3,
00100     QS_QF_RESERVED2,
00101     QS_QF_RESERVED1,
00102     QS_QF_RESERVED0,
00103 
00104     // QK records
00105     QS_QK_MUTEX_LOCK,                             ///< the QK mutex was locked
00106     QS_QK_MUTEX_UNLOCK,                         ///< the QK mutex was unlocked
00107     QS_QK_SCHEDULE,      ///< the QK scheduler scheduled a new task to execute
00108     QS_QK_RESERVED6,
00109     QS_QK_RESERVED5,
00110     QS_QK_RESERVED4,
00111     QS_QK_RESERVED3,
00112     QS_QK_RESERVED2,
00113     QS_QK_RESERVED1,
00114     QS_QK_RESERVED0,
00115 
00116     // Miscellaneous QS records
00117     QS_SIG_DICTIONARY,                            ///< signal dictionary entry
00118     QS_OBJ_DICTIONARY,                            ///< object dictionary entry
00119     QS_FUN_DICTIONARY,                          ///< function dictionary entry
00120     QS_ASSERT,                                ///< assertion fired in the code
00121     QS_RESERVED5,
00122     QS_RESERVED4,
00123     QS_RESERVED3,
00124     QS_RESERVED2,
00125     QS_RESERVED1,
00126     QS_RESERVED0,
00127 
00128     // User records
00129     QS_USER                ///< the first record available for user QS records
00130 };
00131 
00132 /// \brief Specification of all QS records for the QS::filterOn() and
00133 /// QS::filterOff()
00134 #define QS_ALL_RECORDS          ((uint8_t)0xFF)
00135 
00136 /// \brief Constant representing End-Of-Data condition returned from the
00137 /// QS::getByte() function.
00138 #define QS_EOD                  ((uint16_t)0xFFFF)
00139 
00140 
00141 #ifndef QS_TIME_SIZE
00142 
00143     /// \brief The size (in bytes) of the QS time stamp. Valid values: 1, 2,
00144     /// or 4; default 4.
00145     ///
00146     /// This macro can be defined in the QS port file (qs_port.h) to
00147     /// configure the ::QSTimeCtr type. Here the macro is not defined so the
00148     /// default of 4 byte is chosen.
00149     #define QS_TIME_SIZE 4
00150 #endif
00151 #if (QS_TIME_SIZE == 1)
00152     typedef uint8_t QSTimeCtr;
00153     #define QS_TIME_()   QS::u8_(QS::onGetTime())
00154 #elif (QS_TIME_SIZE == 2)
00155     typedef uint16_t QSTimeCtr;
00156     #define QS_TIME_()   QS::u16_(QS::onGetTime())
00157 #elif (QS_TIME_SIZE == 4)
00158 
00159     /// \brief The type of the QS time stamp
00160     ///
00161     /// This type determines the dynamic range of QS time stamps
00162     typedef uint32_t QSTimeCtr;
00163 
00164     /// \brief Internal macro to output time stamp to the QS record
00165     #define QS_TIME_()   QS::u32_(QS::onGetTime())
00166 #else
00167     #error "QS_TIME_SIZE defined incorrectly, expected 1, 2, or 4"
00168 #endif
00169 
00170 #ifndef Q_ROM                      // provide the default if Q_ROM NOT defined
00171     #define Q_ROM
00172 #endif
00173 #ifndef Q_ROM_VAR              // provide the default if Q_ROM_VAR NOT defined
00174     #define Q_ROM_VAR
00175 #endif
00176 #ifndef Q_ROM_BYTE            // provide the default if Q_ROM_BYTE NOT defined
00177     #define Q_ROM_BYTE(rom_var_)   (rom_var_)
00178 #endif
00179 
00180 
00181 /// \brief Quantum Spy logging facilities
00182 ///
00183 /// This class groups together QS services. It has only static members and
00184 /// should not be instantiated.
00185 class QS {
00186 public:
00187 
00188     /// \brief Get the current version of QS
00189     ///
00190     /// \return version of the QS as a constant 6-character string of the form
00191     /// x.y.zz, where x is a 1-digit major version number, y is a 1-digit
00192     /// minor version number, and zz is a 2-digit release number.
00193     static char const Q_ROM * Q_ROM_VAR getVersion(void);
00194 
00195     /// \brief Initialize the QS data buffer.
00196     ///
00197     /// This function should be called from QS_init() to provide QS with the
00198     /// data buffer. The first argument \a sto[] is the address of the memory
00199     /// block, and the second argument \a stoSize is the size of this block
00200     /// in bytes. Currently the size of the QS buffer cannot exceed 64KB.
00201     ///
00202     /// QS can work with quite small data buffers, but you will start losing
00203     /// data if the buffer is too small for the bursts of logging activity.
00204     /// The right size of the buffer depends on the data production rate and
00205     /// the data output rate. QS offers flexible filtering to reduce the data
00206     /// production rate.
00207     ///
00208     /// \note If the data output rate cannot keep up with the production rate,
00209     /// QS will start overwriting the older data with newer data. This is
00210     /// consistent with the "last-is-best" QS policy. The record sequence
00211     ///  counters and checksums on each record allow to easily detect data
00212     /// loss.
00213     static void initBuf(uint8_t sto[], uint32_t stoSize);
00214 
00215     /// \brief Turn the global Filter on for a given record type \a rec.
00216     ///
00217     /// This function sets up the QS filter to enable the record type \a rec.
00218     /// The argument #QS_ALL_RECORDS specifies to filter-on all records.
00219     /// This function should be called indirectly through the macro
00220     /// #QS_FILTER_ON.
00221     ///
00222     /// \note Filtering based on the record-type is only the first layer of
00223     /// filtering. The second layer is based on the object-type. Both filter
00224     /// layers must be enabled for the QS record to be inserted into the QS
00225     /// buffer.
00226     /// \sa QS_filterOff(), #QS_FILTER_SM_OBJ, #QS_FILTER_AO_OBJ,
00227     /// #QS_FILTER_MP_OBJ, #QS_FILTER_EQ_OBJ, and #QS_FILTER_TE_OBJ.
00228     static void filterOn(uint8_t rec);
00229 
00230     /// \brief Turn the global Filter off for a given record type \a rec.
00231     ///
00232     /// This function sets up the QS filter to disable the record type \a rec.
00233     /// The argument #QS_ALL_RECORDS specifies to suppress all records.
00234     /// This function should be called indirectly through the macro
00235     /// #QS_FILTER_OFF.
00236     ///
00237     /// \note Filtering records based on the record-type is only the first
00238     /// layer of filtering. The second layer is based on the object-type.
00239     /// Both filter layers must be enabled for the QS record to be inserted
00240     /// into the QS buffer.
00241     /// \sa
00242     static void filterOff(uint8_t rec);
00243 
00244     /// \brief Mark the begin of a QS record \a rec
00245     ///
00246     /// This function must be called at the beginning of each QS record.
00247     /// This function should be called indirectly through the macro #QS_BEGIN,
00248     /// or #QS_BEGIN_NOLOCK, depending if it's called in a normal code or from
00249     /// a critical section.
00250     static void begin(uint8_t rec);
00251 
00252     /// \brief Mark the end of a QS record \a rec
00253     ///
00254     /// This function must be called at the end of each QS record.
00255     /// This function should be called indirectly through the macro #QS_END,
00256     /// or #QS_END_NOLOCK, depending if it's called in a normal code or from
00257     /// a critical section.
00258     static void end(void);
00259 
00260     // unformatted data elements output ......................................
00261 
00262     /// \brief output uint8_t data element without format information
00263     /// \note This function is only to be used through macros, never in the
00264     /// client code directly.
00265     static void u8_(uint8_t d);
00266 
00267     /// \brief Output uint16_t data element without format information
00268     /// \note This function is only to be used through macros, never in the
00269     /// client code directly.
00270     static void u16_(uint16_t d);
00271 
00272     /// \brief Output uint32_t data element without format information
00273     /// \note This function is only to be used through macros, never in the
00274     /// client code directly.
00275     static void u32_(uint32_t d);
00276 
00277     /// \brief Output zero-terminated ASCII string element without format
00278     /// information
00279     /// \note This function is only to be used through macros, never in the
00280     /// client code directly.
00281     static void str_(char const *s);
00282 
00283     /// \brief Output zero-terminated ASCII string element  allocated in ROM
00284     /// without format information
00285     /// \note This function is only to be used through macros, never in the
00286     /// client code directly.
00287     static void str_ROM_(char const Q_ROM * Q_ROM_VAR s);
00288 
00289     // formatted data elements output ........................................
00290 
00291     /// \brief Output uint8_t data element with format information
00292     /// \note This function is only to be used through macros, never in the
00293     /// client code directly.
00294     static void u8(uint8_t format, uint8_t d);
00295 
00296     /// \brief output uint16_t data element with format information
00297     /// \note This function is only to be used through macros, never in the
00298     /// client code directly.
00299     static void u16(uint8_t format, uint16_t d);
00300 
00301     /// \brief Output uint32_t data element with format information
00302     /// \note This function is only to be used through macros, never in the
00303     /// client code directly.
00304     static void u32(uint8_t format, uint32_t d);
00305 
00306     /// \brief Output 32-bit floating point data element with format
00307     /// information
00308     /// \note This function is only to be used through macros, never in the
00309     /// client code directly.
00310     static void f32(uint8_t format, float d);
00311 
00312     /// \brief Output 64-bit floating point data element with format
00313     /// information
00314     /// \note This function is only to be used through macros, never in the
00315     /// client code directly.
00316     static void f64(uint8_t format, double d);
00317 
00318     /// \brief Output zero-terminated ASCII string element with format
00319     /// information
00320     /// \note This function is only to be used through macros, never in the
00321     /// client code directly.
00322     static void str(char const *s);
00323 
00324     /// \brief Output zero-terminated ASCII string element allocated in ROM
00325     /// with format information
00326     /// \note This function is only to be used through macros, never in the
00327     /// client code directly.
00328     static void str_ROM(char const Q_ROM * Q_ROM_VAR s);
00329 
00330     /// \brief Output memory block of up to 255-bytes with format information
00331     /// \note This function is only to be used through macros, never in the
00332     /// client code directly.
00333     static void mem(uint8_t const *blk, uint8_t size);
00334 
00335     // QS buffer access ......................................................
00336 
00337     /// \brief Byte-oriented interface to the QS data buffer.
00338     ///
00339     /// This function delivers one byte at a time from the QS data buffer.
00340     /// The function returns the byte in the least-significant 8-bits of the
00341     /// 16-bit return value if the byte is available. If no more data is
00342     /// available at the time, the function returns QS_EOD (End-Of-Data).
00343     ///
00344     /// \note QS::getByte() is NOT protected with a critical section.
00345     static uint16_t getByte(void);
00346 
00347     /// \brief Block-oriented interface to the QS data buffer.
00348     ///
00349     /// This function delivers a contiguous block of data from the QS data
00350     /// buffer. The function returns the pointer to the beginning of the
00351     /// block, and writes the number of bytes in the block to the location
00352     /// pointed to by \a pNbytes. The argument \a pNbytes is also used as
00353     /// input to provide the maximum size of the data block that the caller
00354     /// can accept.
00355     ///
00356     /// If no bytes are available in the QS buffer when the function is
00357     /// called, the function returns a NULL pointer and sets the value
00358     /// pointed to by \a pNbytes to zero.
00359     ///
00360     /// \note Only the NULL return from QS::getBlock() indicates that the QS
00361     /// buffer is empty at the time of the call. The non-NULL return often
00362     /// means that the block is at the end of the buffer and you need to call
00363     /// QS::getBlock() again to obtain the rest of the data that "wrapped
00364     /// around" to the beginning of the QS data buffer.
00365     ///
00366     /// \note QS::getBlock() is NOT protected with a critical section.
00367     static uint8_t const *getBlock(uint16_t *pNbytes);
00368 
00369 // platform-dependent callback functions, need to be implemented by clients
00370 public:
00371 
00372     // platform-specific callback functions, need to be implemented by clients
00373     /// \brief Callback to startup the QS facility
00374     ///
00375     /// This is a platform-dependent "callback" function invoked through the
00376     /// macro #QS_INIT. You need to implement this function in your
00377     /// application. At a minimum, the function must configure the QS buffer
00378     /// by calling QS::initBuf(). Typically, you will also want to open/
00379     /// configure the QS output channel, such as a serial port, or a file.
00380     /// The void* argument \a arg can be used to pass parameter(s) needed to
00381     /// configure the output channel.
00382     ///
00383     /// The function returns TRUE (1) if the QS initialization was successful,
00384     /// or FALSE (0) if it failed.
00385     ///
00386     /// The following example illustrates an implementation of QS_onStartup():
00387     /// \include qs_startup.cpp
00388     static uint8_t onStartup(void const *arg);
00389 
00390     /// \brief Callback to cleanup the QS facility
00391     ///
00392     /// This is a platform-dependent "callback" function invoked through the
00393     /// macro #QS_EXIT. You need to implement this function in your
00394     /// application. The main purpose of this function is to close the QS
00395     /// output channel, if necessary.
00396     static void onCleanup(void);
00397 
00398     /// \brief Callback to flush the QS trace data to the host
00399     ///
00400     /// This is a platform-dependent "callback" function to flush the QS
00401     /// trace buffer to the host. The function typically busy-waits until all
00402     /// the data in the buffer is sent to the host. This is acceptable only
00403     /// in the initial transient.
00404     static void onFlush(void);
00405 
00406     /// \brief Callback to obtain a timestamp for a QS record.
00407     ///
00408     /// This is a platform-dependent "callback" function invoked from the
00409     /// macro #QS_TIME_ to add the time stamp to the QS record.
00410     ///
00411     /// \note Some of the pre-defined QS records from QP do not output the
00412     /// time stamp. However, ALL user records do output the time stamp.
00413     /// \note QS::onGetTime() is called in a critical section and should not
00414     /// unlock interrupts.
00415     ///
00416     /// The following example shows using a system call to implement QS
00417     /// time stamping:
00418     /// \include qs_onGetTime.cpp
00419     static QSTimeCtr onGetTime(void);
00420 
00421 // Global and Local QS filters ...............................................
00422 public:
00423     static uint8_t glbFilter_[32];                ///< global on/off QS filter
00424     static void const *smObj_;         ///< state machine for QEP local filter
00425     static void const *aoObj_;       ///< active object for QF/QK local filter
00426     static void const *mpObj_;            ///<  event pool for QF local filter
00427     static void const *eqObj_;             ///<  raw queue for QF local filter
00428     static void const *teObj_;            ///<  time event for QF local filter
00429     static void const *apObj_;///<  generic object Application QF local filter
00430 
00431 // Miscallaneous .............................................................
00432 public:
00433                                     /// tick counter for the QS_QF_TICK record
00434     static QSTimeCtr volatile tickCtr_;
00435 };
00436 
00437 
00438 //////////////////////////////////////////////////////////////////////////////
00439 // Macros for adding QS instrumentation to the client code
00440 
00441 /// \brief Initialize the QS facility.
00442 ///
00443 /// This macro provides an indirection layer to invoke the QS initialization
00444 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
00445 /// \sa QS::onStartup(), example of setting up a QS filter in #QS_FILTER_IN
00446 #define QS_INIT(arg_)           QS::onStartup(arg_)
00447 
00448 /// \brief Cleanup the QS facility.
00449 ///
00450 /// This macro provides an indirection layer to invoke the QS cleanup
00451 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
00452 /// \sa QS::onCleanup()
00453 #define QS_EXIT()               QS::onCleanup()
00454 
00455 /// \brief Global Filter ON for a given record type \a rec.
00456 ///
00457 /// This macro provides an indirection layer to call QS::filterOn() if #Q_SPY
00458 /// is defined, or do nothing if #Q_SPY is not defined.
00459 ///
00460 /// The following example shows how to use QS filters:
00461 /// \include qs_filter.cpp
00462 #define QS_FILTER_ON(rec_)      QS::filterOn(rec_)
00463 
00464 /// \brief Global filter OFF for a given record type \a rec.
00465 ///
00466 /// This macro provides an indirection layer to call QS::filterOff() if #Q_SPY
00467 /// is defined, or do nothing if #Q_SPY is not defined.
00468 ///
00469 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00470 #define QS_FILTER_OFF(rec_)     QS::filterOff(rec_)
00471 
00472 /// \brief Local Filter for a given state machine object \a obj_.
00473 ///
00474 /// This macro sets up the state machine object local filter if #Q_SPY is
00475 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
00476 /// is the pointer to the state machine object that you want to monitor.
00477 ///
00478 /// The state machine object filter allows you to filter QS records pertaining
00479 /// only to a given state machine object. With this filter disabled, QS will
00480 /// output records from all state machines in your application. The object
00481 /// filter is disabled by setting the state machine pointer to NULL.
00482 ///
00483 /// The state machine filter affects the following QS records:
00484 /// ::QS_QEP_STATE_ENTRY, ::QS_QEP_STATE_EXIT, ::QS_QEP_STATE_INIT,
00485 /// ::QS_QEP_INIT_TRAN, ::QS_QEP_INTERN_TRAN, ::QS_QEP_TRAN,
00486 /// and ::QS_QEP_IGNORED.
00487 ///
00488 /// \note Because active objects are state machines at the same time,
00489 /// the state machine filter (#QS_FILTER_SM_OBJ) pertains to active
00490 /// objects as well. However, the state machine filter is more general,
00491 /// because it can be used only for state machines that are not active
00492 /// objects, such as "Orthogonal Components".
00493 ///
00494 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00495 #define QS_FILTER_SM_OBJ(obj_)  (QS::smObj_ = (obj_))
00496 
00497 /// \brief Local Filter for a given active object \a obj_.
00498 ///
00499 /// This macro sets up the active object local filter if #Q_SPY is defined,
00500 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
00501 /// pointer to the active object that you want to monitor.
00502 ///
00503 /// The active object filter allows you to filter QS records pertaining
00504 /// only to a given active object. With this filter disabled, QS will
00505 /// output records from all active objects in your application. The object
00506 /// filter is disabled by setting the active object pointer \a obj_ to NULL.
00507 ///
00508 /// The active object filter affects the following QS records:
00509 /// ::QS_QF_ACTIVE_ADD, ::QS_QF_ACTIVE_REMOVE, ::QS_QF_ACTIVE_SUBSCRIBE,
00510 /// ::QS_QF_ACTIVE_UNSUBSCRIBE, ::QS_QF_ACTIVE_POST_FIFO,
00511 /// ::QS_QF_ACTIVE_POST_LIFO, ::QS_QF_ACTIVE_GET, and ::QS_QF_ACTIVE_GET_LAST.
00512 ///
00513 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00514 #define QS_FILTER_AO_OBJ(obj_)  (QS::aoObj_ = (obj_))
00515 
00516 /// \brief Local Filter for a given memory pool object \a obj_.
00517 ///
00518 /// This macro sets up the memory pool object local filter if #Q_SPY is
00519 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
00520 /// is the pointer to the memory buffer used during the initialization of the
00521 /// event pool with QF::poolInit().
00522 ///
00523 /// The memory pool filter allows you to filter QS records pertaining
00524 /// only to a given memory pool. With this filter disabled, QS will
00525 /// output records from all memory pools in your application. The object
00526 /// filter is disabled by setting the memory pool pointer \a obj_ to NULL.
00527 ///
00528 /// The memory pool filter affects the following QS records:
00529 /// ::QS_QF_MPOOL_INIT, ::QS_QF_MPOOL_GET, and ::QS_QF_MPOOL_PUT.
00530 ///
00531 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00532 #define QS_FILTER_MP_OBJ(obj_)  (QS::mpObj_ = (obj_))
00533 
00534 /// \brief Filter for a given event queue object \a obj_.
00535 ///
00536 /// This macro sets up the event queue object filter if #Q_SPY is defined,
00537 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
00538 /// pointer to the "raw" thread-safe queue object you want to monitor.
00539 ///
00540 /// The event queue filter allows you to filter QS records pertaining
00541 /// only to a given event queue. With this filter disabled, QS will
00542 /// output records from all event queues in your application. The object
00543 /// filter is disabled by setting the event queue pointer \a obj_ to NULL.
00544 ///
00545 /// The event queue filter affects the following QS records:
00546 /// ::QS_QF_EQUEUE_INIT, ::QS_QF_EQUEUE_POST_FIFO, ::QS_QF_EQUEUE_POST_LIFO,
00547 /// ::QS_QF_EQUEUE_GET, and ::QS_QF_EQUEUE_GET_LAST.
00548 ///
00549 /// \sa Example of using QS filters in #QS_FILTER_IN documentation
00550 #define QS_FILTER_EQ_OBJ(obj_)  (QS::eqObj_ = (obj_))
00551 
00552 /// \brief Local Filter for a given time event object \a obj_.
00553 ///
00554 /// This macro sets up the time event object local filter if #Q_SPY is
00555 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
00556 /// is the pointer to the time event object you want to monitor.
00557 ///
00558 /// The time event filter allows you to filter QS records pertaining
00559 /// only to a given time event. With this filter disabled, QS will
00560 /// output records from all time events in your application. The object
00561 /// filter is disabled by setting the time event pointer \a obj_ to NULL.
00562 ///
00563 /// The time event filter affects the following QS records:
00564 /// ::QS_QF_TIMEEVT_ARM, ::QS_QF_TIMEEVT_AUTO_DISARM,
00565 /// ::QS_QF_TIMEEVT_DISARM_ATTEMPT, ::QS_QF_TIMEEVT_DISARM,
00566 /// ::QS_QF_TIMEEVT_REARM, ::QS_QF_TIMEEVT_POST, and ::QS_QF_TIMEEVT_PUBLISH.
00567 ///
00568 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00569 #define QS_FILTER_TE_OBJ(obj_)  (QS::teObj_ = (obj_))
00570 
00571 /// \brief Local Filter for a generic application object \a obj_.
00572 ///
00573 /// This macro sets up the local application object filter if #Q_SPY is
00574 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
00575 /// is the pointer to the application object you want to monitor.
00576 ///
00577 /// The application object filter allows you to filter QS records pertaining
00578 /// only to a given application object. With this filter disabled, QS will
00579 /// output records from all application-records enabled by the global filter.
00580 /// The local filter is disabled by setting the time event pointer \a obj_
00581 /// to NULL.
00582 ///
00583 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
00584 #define QS_FILTER_AP_OBJ(obj_)  (QS_apObj_ = (obj_))
00585 
00586 
00587 //////////////////////////////////////////////////////////////////////////////
00588 // Macros to generate user QS records
00589 
00590 /// \brief Begin a QS user record without locking interrupts.
00591 #define QS_BEGIN_NOLOCK(rec_, obj_) \
00592     if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
00593           & (1U << ((uint8_t)(rec_) & 7U))) != 0) \
00594         && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
00595     { \
00596         QS::begin((uint8_t)(rec_)); \
00597         QS_TIME_();
00598 
00599 /// \brief End a QS user record without locking interrupts.
00600 #define QS_END_NOLOCK() \
00601     QS_END_NOLOCK_()
00602 
00603                                     // QS-specific interrupt locking/unlocking
00604 #ifndef QF_INT_KEY_TYPE
00605     /// \brief This is an internal macro for defining the interrupt lock key.
00606     ///
00607     /// The purpose of this macro is to enable writing the same code for the
00608     /// case when interrupt key is defined and when it is not. If the macro
00609     /// #QS_INT_KEY_TYPE is defined, this internal macro provides the
00610     /// definition of the lock key variable. Otherwise this macro is empty.
00611     /// \sa #QS_INT_KEY_TYPE, #QF_INT_KEY_TYPE
00612     #define QS_INT_LOCK_KEY_
00613 
00614     /// \brief This is an internal macro for locking interrupts.
00615     ///
00616     /// The purpose of this macro is to enable writing the same code for the
00617     /// case when interrupt key is defined and when it is not. If the macro
00618     /// #QS_INT_KEY_TYPE is defined, this internal macro invokes #QS_INT_LOCK
00619     /// passing the key variable as the parameter. Otherwise #QS_INT_LOCK
00620     /// is invoked with a dummy parameter.
00621     /// \sa #QS_INT_LOCK, #QF_INT_LOCK, #QK_INT_LOCK
00622     #define QS_INT_LOCK_()      QF_INT_LOCK(ignore_)
00623 
00624     /// \brief This is an internal macro for unlocking interrupts.
00625     ///
00626     /// The purpose of this macro is to enable writing the same code for the
00627     /// case when interrupt key is defined and when it is not. If the macro
00628     /// #QS_INT_KEY_TYPE is defined, this internal macro invokes
00629     /// #QS_INT_UNLOCK passing the key variable as the parameter. Otherwise
00630     /// #QS_INT_UNLOCK is invoked with a dummy parameter.
00631     /// \sa #QS_INT_UNLOCK, #QF_INT_UNLOCK, #QK_INT_UNLOCK
00632     #define QS_INT_UNLOCK_()    QF_INT_UNLOCK(ignore_)
00633 #else
00634     #define QS_INT_LOCK_KEY_    QF_INT_KEY_TYPE intLockKey_;
00635     #define QS_INT_LOCK_()      QF_INT_LOCK(intLockKey_)
00636     #define QS_INT_UNLOCK_()    QF_INT_UNLOCK(intLockKey_)
00637 #endif
00638 
00639 /// \brief Begin a user QS record with locking interrupts.
00640 ///
00641 /// The following example shows how to build a user QS record using the
00642 /// macros #QS_BEGIN, #QS_END, and the formatted output macros: #QS_U8 and
00643 /// #QS_STR.
00644 /// \include qs_user.cpp
00645 /// \note Must always be used in pair with #QS_END
00646 #define QS_BEGIN(rec_, obj_) \
00647     if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
00648           & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
00649         && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
00650     { \
00651         QS_INT_LOCK_KEY_ \
00652         QS_INT_LOCK_(); \
00653         QS::begin((uint8_t)(rec_)); \
00654         QS_TIME_();
00655 
00656 /// \brief End a QS record with locking interrupts.
00657 /// \sa example for #QS_BEGIN
00658 /// \note Must always be used in pair with #QS_BEGIN
00659 #define QS_END() \
00660     QS_END_()
00661 
00662 
00663 //////////////////////////////////////////////////////////////////////////////
00664 // Macros for use inside other macros or internally in the QP code
00665 
00666 /// \brief Internal QS macro to begin a QS record with locking the interrupts.
00667 /// \note This macro is intended to use only inside QP components and NOT
00668 /// at the application level. \sa #QS_BEGIN
00669 #define QS_BEGIN_(rec_, objFilter_, obj_) \
00670     if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
00671           & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
00672         && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \
00673     { \
00674         QS_INT_LOCK_(); \
00675         QS::begin((uint8_t)(rec_));
00676 
00677 /// \brief  Internal QS macro to end a QS record with locking the interrupts.
00678 /// \note This macro is intended to use only inside QP components and NOT
00679 /// at the application level. \sa #QS_END
00680 #define QS_END_() \
00681         QS::end(); \
00682         QS_INT_UNLOCK_(); \
00683     }
00684 
00685 /// \brief Internal QS macro to begin a QS record without locking the
00686 /// interrupts.
00687 /// \note This macro is intended to use only inside QP components and NOT
00688 /// at the application level. \sa #QS_BEGIN_NOLOCK
00689 #define QS_BEGIN_NOLOCK_(rec_, objFilter_, obj_) \
00690     if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
00691           & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
00692         && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \
00693     { \
00694         QS::begin((uint8_t)(rec_));
00695 
00696 /// \brief Internal QS macro to end a QS record without locking
00697 /// the interrupts.
00698 /// \note This macro is intended to use only inside QP components and NOT
00699 /// at the application level. \sa #QS_END_NOLOCK
00700 #define QS_END_NOLOCK_() \
00701         QS::end(); \
00702     }
00703 
00704 /// \brief Internal QS macro to output an unformatted uint8_t data element
00705 #define QS_U8_(data_)           QS::u8_(data_)
00706 
00707 /// \brief Internal QS macro to output an unformatted uint16_t data element
00708 #define QS_U16_(data_)          QS::u16_(data_)
00709 
00710 /// \brief Internal QS macro to output an unformatted uint32_t data element
00711 #define QS_U32_(data_)          QS::u32_(data_)
00712 
00713 
00714 #if (QS_OBJ_PTR_SIZE == 1)
00715     #define QS_OBJ_(obj_)       QS::u8_((uint8_t)(obj_))
00716 #elif (QS_OBJ_PTR_SIZE == 2)
00717     #define QS_OBJ_(obj_)       QS::u16_((uint16_t)(obj_))
00718 #elif (QS_OBJ_PTR_SIZE == 4)
00719     #define QS_OBJ_(obj_)       QS::u32_((uint32_t)(obj_))
00720 #else
00721 
00722     /// \brief Internal QS macro to output an unformatted object pointer
00723     /// data element
00724     /// \note the size of the pointer depends on the macro #QS_OBJ_PTR_SIZE.
00725     /// If the size is not defined the size of pointer is assumed 4-bytes.
00726     #define QS_OBJ_(obj_)       QS::u32_((uint32_t)(obj_))
00727 #endif
00728 
00729 
00730 #if (QS_FUN_PTR_SIZE == 1)
00731     #define QS_FUN_(fun_)       QS::u8_((uint8_t)(fun_))
00732 #elif (QS_FUN_PTR_SIZE == 2)
00733     #define QS_FUN_(fun_)       QS::u16_((uint16_t)(fun_))
00734 #elif (QS_FUN_PTR_SIZE == 4)
00735     #define QS_FUN_(fun_)       QS::u32_((uint32_t)(fun_))
00736 #else
00737 
00738     /// \brief Internal QS macro to output an unformatted function pointer
00739     /// data element
00740     /// \note the size of the pointer depends on the macro #QS_FUN_PTR_SIZE.
00741     /// If the size is not defined the size of pointer is assumed 4-bytes.
00742     #define QS_FUN_(fun_)       QS::u32_((uint32_t)(fun_))
00743 #endif
00744 
00745 /// \brief Internal QS macro to output a zero-terminated ASCII string
00746 /// data element
00747 #define QS_STR_(msg_)           QS::str_(msg_)
00748 
00749 /// \brief Internal QS macro to output a zero-terminated ASCII string
00750 /// allocated in ROM data element
00751 #define QS_STR_ROM_(msg_)       QS::str_ROM_(msg_)
00752 
00753 //////////////////////////////////////////////////////////////////////////////
00754 // Macros for use in the client code
00755 
00756 /// \brief Enumerates data formats recognized by QS
00757 ///
00758 /// QS uses this enumeration is used only internally for the formatted user
00759 /// data elements.
00760 enum QSType {
00761     QS_I8_T,                                  ///< signed 8-bit integer format
00762     QS_U8_T,                                ///< unsigned 8-bit integer format
00763     QS_I16_T,                                ///< signed 16-bit integer format
00764     QS_U16_T,                              ///< unsigned 16-bit integer format
00765     QS_I32_T,                                ///< signed 32-bit integer format
00766     QS_U32_T,                              ///< unsigned 32-bit integer format
00767     QS_F32_T,                                ///< 32-bit floating point format
00768     QS_F64_T,                                ///< 64-bit floating point format
00769     QS_STR_T,                         ///< zero-terminated ASCII string format
00770     QS_MEM_T,                         ///< up to 255-bytes memory block format
00771     QS_SIG_T,                                         ///< event signal format
00772     QS_OBJ_T,                                       ///< object pointer format
00773     QS_FUN_T                                      ///< function pointer format
00774 };
00775 
00776 /// \brief Output formatted int8_t to the QS record
00777 #define QS_I8(width_, data_) \
00778     QS::u8((uint8_t)(((width_) << 4)) | QS_I8_T, (data_))
00779 
00780 /// \brief Output formatted uint8_t to the QS record
00781 #define QS_U8(width_, data_) \
00782     QS::u8((uint8_t)(((width_) << 4)) | QS_U8_T, (data_))
00783 
00784 /// \brief Output formatted int16_t to the QS record
00785 #define QS_I16(width_, data_) \
00786     QS::u16((uint8_t)(((width_) << 4)) | QS_I16_T, (data_))
00787 
00788 /// \brief Output formatted uint16_t to the QS record
00789 #define QS_U16(width_, data_) \
00790     QS::u16((uint8_t)(((width_) << 4)) | QS_U16_T, (data_))
00791 
00792 /// \brief Output formatted int32_t to the QS record
00793 #define QS_I32(width_, data_) \
00794     QS::u32((uint8_t)(((width_) << 4)) | QS_I32_T, (data_))
00795 
00796 /// \brief Output formatted uint32_t to the QS record
00797 #define QS_U32(width_, data_) \
00798     QS::u32((uint8_t)(((width_) << 4)) | QS_U32_T, (data_))
00799 
00800 /// \brief Output formatted 32-bit floating point number to the QS record
00801 #define QS_F32(width_, data_) \
00802     QS::f32((uint8_t)(((width_) << 4)) | QS_F32_T, (data_))
00803 
00804 /// \brief Output formatted 64-bit floating point number to the QS record
00805 #define QS_F64(width_, data_) \
00806     QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_))
00807 
00808 /// \brief Output formatted zero-terminated ASCII string to the QS record
00809 #define QS_STR(str_)            QS::str(str_)
00810 
00811 /// \brief Output formatted zero-terminated ASCII string from ROM
00812 /// to the QS record
00813 #define QS_STR_ROM(str_)        QS::str_ROM(str_)
00814 
00815 /// \brief Output formatted memory block of up to 255 bytes to the QS
00816 /// record
00817 #define QS_MEM(mem_, size_)     QS::mem((mem_), (size_))
00818 
00819 
00820 #if (QS_OBJ_PTR_SIZE == 1)
00821     #define QS_OBJ(obj_)        QS::u8(QS_OBJ_T, (uint8_t)(obj_))
00822 #elif (QS_OBJ_PTR_SIZE == 2)
00823     #define QS_OBJ(obj_)        QS::u16(QS_OBJ_T, (uint16_t)(obj_))
00824 #elif (QS_OBJ_PTR_SIZE == 4)
00825     #define QS_OBJ(obj_)        QS::u32(QS_OBJ_T, (uint32_t)(obj_))
00826 #else
00827     /// \brief Output formatted object pointer to the QS record
00828     #define QS_OBJ(obj_)        QS::u32(QS_OBJ_T, (uint32_t)(obj_))
00829 #endif
00830 
00831 
00832 #if (QS_FUN_PTR_SIZE == 1)
00833     #define QS_FUN(fun_)        QS::u8(QS_FUN_T, (uint8_t)(fun_))
00834 #elif (QS_FUN_PTR_SIZE == 2)
00835     #define QS_FUN(fun_)        QS::u16(QS_FUN_T, (uint16_t)(fun_))
00836 #elif (QS_FUN_PTR_SIZE == 4)
00837     #define QS_FUN(fun_)        QS::u32(QS_FUN_T, (uint32_t)(fun_))
00838 #else
00839     /// \brief Output formatted function pointer to the QS record
00840     #define QS_FUN(fun_)        QS::u32(QS_FUN_T, (uint32_t)(fun_))
00841 #endif
00842 
00843 
00844 /// \brief Output signal dictionary record
00845 ///
00846 /// A signal dictionary record associates the numerical value of the signal
00847 /// and the binary address of the state machine that consumes that signal
00848 /// with the human-readable name of the signal.
00849 ///
00850 /// Providing a signal dictionary QS record can vastly improve readability of
00851 /// the QS log, because instead of dealing with cryptic machine addresses the
00852 /// QSpy host utility can display human-readable names.
00853 ///
00854 /// A signal dictionary entry is associated with both the signal value \a sig_
00855 /// and the state machine \a obj_, because signals are required to be unique
00856 /// only within a given state machine and therefore the same numerical values
00857 /// can represent different signals in different state machines.
00858 ///
00859 /// For the "global" signals that have the same meaning in all state machines
00860 /// (such as globally published signals), you can specify a signal dictionary
00861 /// entry with the \a obj_ parameter set to NULL.
00862 ///
00863 /// The following example shows the definition of signal dictionary entries
00864 /// in the initial transition of the Table active object. Please note that
00865 /// signals HUNGRY_SIG and DONE_SIG are associated with the Table state
00866 /// machine only ("me" \a obj_ pointer). The EAT_SIG signal, on the other
00867 /// hand, is global (0 \a obj_ pointer):
00868 /// \include qs_sigDic.cpp
00869 ///
00870 /// \note The QSpy log utility must capture the signal dictionary record
00871 /// in order to use the human-readable information. You need to connect to
00872 /// the target before the dictionary entries have been transmitted.
00873 ///
00874 /// The following QSpy log example shows the signal dictionary records
00875 /// generated from the Table initial transition and subsequent records that
00876 /// show human-readable names of the signals:
00877 /// \include qs_sigLog.txt
00878 ///
00879 /// The following QSpy log example shows the same sequence of records, but
00880 /// with dictionary records removed. The human-readable signal names are not
00881 /// available.
00882 /// \include qs_sigLog0.txt
00883 #define QS_SIG_DICTIONARY(sig_, obj_) \
00884     if (((QS::glbFilter_[(uint8_t)QS_SIG_DICTIONARY >> 3U] \
00885           & (1U << ((uint8_t)QS_SIG_DICTIONARY & 7U))) != 0U)) \
00886     { \
00887         static char const Q_ROM Q_ROM_VAR sig_name__[] = #sig_; \
00888         QS_INT_LOCK_KEY_ \
00889         QS_INT_LOCK_(); \
00890         QS::begin((uint8_t)QS_SIG_DICTIONARY); \
00891         QS_SIG_(sig_); \
00892         QS_OBJ_(obj_); \
00893         QS_STR_ROM_(sig_name__); \
00894         QS::end(); \
00895         QS_INT_UNLOCK_(); \
00896         QS::onFlush(); \
00897     } else ((void)0)
00898 
00899 /// \brief Output object dictionary record
00900 ///
00901 /// An object dictionary record associates the binary address of an object
00902 /// in the target's memory with the human-readable name of the object.
00903 ///
00904 /// Providing an object dictionary QS record can vastly improve readability of
00905 /// the QS log, because instead of dealing with cryptic machine addresses the
00906 /// QSpy host utility can display human-readable object names.
00907 ///
00908 /// The following example shows the definition of object dictionary entry
00909 /// for the Table active object:
00910 /// \include qs_objDic.cpp
00911 #define QS_OBJ_DICTIONARY(obj_) \
00912     if (((QS::glbFilter_[(uint8_t)QS_OBJ_DICTIONARY >> 3U] \
00913           & (1U << ((uint8_t)QS_OBJ_DICTIONARY & 7U))) != 0U)) \
00914     { \
00915         static char const Q_ROM Q_ROM_VAR obj_name__[] = #obj_; \
00916         QS_INT_LOCK_KEY_ \
00917         QS_INT_LOCK_(); \
00918         QS::begin((uint8_t)QS_OBJ_DICTIONARY); \
00919         QS_OBJ_(obj_); \
00920         QS_STR_ROM_(obj_name__); \
00921         QS::end(); \
00922         QS_INT_UNLOCK_(); \
00923         QS::onFlush(); \
00924     } else ((void)0)
00925 
00926 /// \brief Output function dictionary record
00927 ///
00928 /// A function dictionary record associates the binary address of a function
00929 /// in the target's memory with the human-readable name of the function.
00930 ///
00931 /// Providing a function dictionary QS record can vastly improve readability
00932 /// of the QS log, because instead of dealing with cryptic machine addresses
00933 /// the QSpy host utility can display human-readable function names.
00934 ///
00935 /// The example from #QS_SIG_DICTIONARY shows the definition of a function
00936 /// dictionary.
00937 #define QS_FUN_DICTIONARY(fun_) \
00938     if (((QS::glbFilter_[(uint8_t)QS_FUN_DICTIONARY >> 3U] \
00939           & (1U << ((uint8_t)QS_FUN_DICTIONARY & 7U))) != 0U)) \
00940     { \
00941         static char const Q_ROM Q_ROM_VAR fun_name__[] = #fun_; \
00942         QS_INT_LOCK_KEY_ \
00943         QS_INT_LOCK_(); \
00944         QS::begin((uint8_t)QS_FUN_DICTIONARY); \
00945         QS_FUN_(fun_); \
00946         QS_STR_ROM_(fun_name__); \
00947         QS::end(); \
00948         QS_INT_UNLOCK_(); \
00949         QS::onFlush(); \
00950     } else ((void)0)
00951 
00952 /// \brief Flush the QS trace data to the host
00953 ///
00954 /// This macro invokes the QS::flush() platform-dependent callback function
00955 /// to flush the QS trace buffer to the host. The function typically
00956 /// busy-waits until all the data in the buffer is sent to the host.
00957 /// This is acceptable only in the initial transient.
00958 #define QS_FLUSH()   QS::onFlush()
00959 
00960 
00961 /// \brief Output the interrupt lock record
00962 #define QF_QS_INT_LOCK() \
00963     QS_BEGIN_NOLOCK_(QS_QF_INT_LOCK, (void *)0, (void *)0); \
00964         QS_TIME_(); \
00965         QS_U8_((uint8_t)(++QF_intLockNest_)); \
00966     QS_END_NOLOCK_()
00967 
00968 /// \brief Output the interrupt unlock record
00969 #define QF_QS_INT_UNLOCK() \
00970     QS_BEGIN_NOLOCK_(QS_QF_INT_UNLOCK, (void *)0, (void *)0); \
00971         QS_TIME_(); \
00972         QS_U8_((uint8_t)(QF_intLockNest_--)); \
00973     QS_END_NOLOCK_()
00974 
00975 /// \brief Output the interrupt entry record
00976 #define QF_QS_ISR_ENTRY(isrnest_, prio_) \
00977     QS_BEGIN_NOLOCK_(QS_QF_ISR_ENTRY, (void *)0, (void *)0); \
00978         QS_TIME_(); \
00979         QS_U8_(isrnest_); \
00980         QS_U8_(prio_); \
00981     QS_END_NOLOCK_()
00982 
00983 /// \brief Output the interrupt exit record
00984 #define QF_QS_ISR_EXIT(isrnest_, prio_) \
00985     QS_BEGIN_NOLOCK_(QS_QF_ISR_EXIT, (void *)0, (void *)0); \
00986         QS_TIME_(); \
00987         QS_U8_(isrnest_); \
00988         QS_U8_(prio_); \
00989     QS_END_NOLOCK_()
00990 
00991 /// \brief Execute an action that is only necessary for QS output
00992 #define QF_QS_ACTION(act_)      (act_)
00993 
00994 /// \brief interrupt-lock nesting level
00995 ///
00996 /// \note Not to be used by Clients directly, only in ports of QF
00997 extern uint8_t QF_intLockNest_;
00998 
00999 #endif                                                                 // qs_h