Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
qs.h
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
Generated on Tue Jul 12 2022 20:22:36 by
1.7.2