/*$file${include::qs.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /* * Model: qpc.qm * File: ${include::qs.h} * * This code has been generated by QM 5.2.1 . * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. * * This code is covered by the following QP license: * License # : LicenseRef-QL-dual * Issued to : Any user of the QP/C real-time embedded framework * Framework(s) : qpc * Support ends : 2023-12-31 * License scope: * * Copyright (C) 2005 Quantum Leaps, LLC . * * SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial * * This software is dual-licensed under the terms of the open source GNU * General Public License version 3 (or any later version), or alternatively, * under the terms of one of the closed source Quantum Leaps commercial * licenses. * * The terms of the open source GNU General Public License version 3 * can be found at: * * The terms of the closed source Quantum Leaps commercial licenses * can be found at: * * Redistributions in source code must retain this top-level comment block. * Plagiarizing this software to sidestep the license obligations is illegal. * * Contact information: * * */ /*$endhead${include::qs.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*! * @date Last updated on: 2022-07-24 * @version Last updated for: @ref qpc_7_0_1 * * @file * @brief QS/C platform-independent public interface. */ #ifndef QS_H #define QS_H #ifndef Q_SPY #error "Q_SPY must be defined to include qs.h" #endif /*==========================================================================*/ /*$declare${QS-config} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /*${QS-config::QS_TIME_SIZE} ...............................................*/ /*! The size [bytes] of the QS time stamp. Valid values: 1U, 2U, or 4U; * default 4U. * * @details * This macro can be defined in the QS port file (qs_port.h) to * configure the ::QSTimeCtr type. Here the macro is not defined so the * default of 4 byte is chosen. */ #ifndef QS_TIME_SIZE #define QS_TIME_SIZE 4U #endif /* ndef QS_TIME_SIZE */ /*${QS-config::QS_TIME_SIZE defined incorrectly~} ..........................*/ #if (QS_TIME_SIZE != 1U) && (QS_TIME_SIZE != 2U) && (QS_TIME_SIZE != 4U) #error QS_TIME_SIZE defined incorrectly, expected 1U, 2U, or 4U; #endif /* (QS_TIME_SIZE != 1U) && (QS_TIME_SIZE != 2U) && (QS_TIME_SIZE != 4U) */ /*$enddecl${QS-config} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*==========================================================================*/ /*$declare${QS} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /*${QS::QSTimeCtr} .........................................................*/ /*! QS time stamp type, which determines the dynamic range of QS time stamps */ #if (QS_TIME_SIZE == 4U) typedef uint32_t QSTimeCtr; #endif /* (QS_TIME_SIZE == 4U) */ /*${QS::QSTimeCtr} .........................................................*/ #if (QS_TIME_SIZE == 2U) typedef uint16_t QSTimeCtr; #endif /* (QS_TIME_SIZE == 2U) */ /*${QS::QSTimeCtr} .........................................................*/ #if (QS_TIME_SIZE == 1U) typedef uint8_t QSTimeCtr; #endif /* (QS_TIME_SIZE == 1U) */ /*${QS::QSFun} .............................................................*/ /*! QS function pointer type (for serializing function pointers) */ #if (QS_FUN_PTR_SIZE == 4U) typedef uint32_t QSFun; #endif /* (QS_FUN_PTR_SIZE == 4U) */ /*${QS::QSFun} .............................................................*/ #if (QS_FUN_PTR_SIZE == 8U) typedef uint64_t QSFun; #endif /* (QS_FUN_PTR_SIZE == 8U) */ /*${QS::QSFun} .............................................................*/ #if (QS_FUN_PTR_SIZE == 2U) typedef uint16_t QSFun; #endif /* (QS_FUN_PTR_SIZE == 2U) */ /*${QS::QSFun} .............................................................*/ #if (QS_FUN_PTR_SIZE == 1U) typedef uint8_t QSFun; #endif /* (QS_FUN_PTR_SIZE == 1U) */ /*${QS::QSCtr} .............................................................*/ /*! QS ring buffer counter and offset type */ typedef uint_fast16_t QSCtr; /*${QS::QSpyPre} ...........................................................*/ /*! QS pre-defined record types (TX channel) * * @details * This enumeration specifies the record types used in the QP components. * You can specify your own record types starting from ::QS_USER offset. * Currently, the maximum of all records cannot exceed 125. * * @note * The QS records labeled as "not maskable" are always enabled and cannot * be turend off with the QS_GLB_FILTER() macro. Other QS trace records * can be disabled by means of the "global filters" * * @sa QS_GLB_FILTER() macro */ enum QSpyPre { /* [0] QS session (not maskable) */ QS_EMPTY, /*!< QS record for cleanly starting a session */ /* [1] SM records */ QS_QEP_STATE_ENTRY, /*!< a state was entered */ QS_QEP_STATE_EXIT, /*!< a state was exited */ QS_QEP_STATE_INIT, /*!< an initial transition was taken in a state */ QS_QEP_INIT_TRAN, /*!< the top-most initial transition was taken */ QS_QEP_INTERN_TRAN, /*!< an internal transition was taken */ QS_QEP_TRAN, /*!< a regular transition was taken */ QS_QEP_IGNORED, /*!< an event was ignored (silently discarded) */ QS_QEP_DISPATCH, /*!< an event was dispatched (begin of RTC step) */ QS_QEP_UNHANDLED, /*!< an event was un-handled due to a guard */ /* [10] Active Object (AO) records */ QS_QF_ACTIVE_DEFER, /*!< AO deferred an event */ QS_QF_ACTIVE_RECALL, /*!< AO recalled an event */ QS_QF_ACTIVE_SUBSCRIBE, /*!< an AO subscribed to an event */ QS_QF_ACTIVE_UNSUBSCRIBE, /*!< an AO unsubscribed to an event */ QS_QF_ACTIVE_POST, /*!< an event was posted (FIFO) directly to AO */ QS_QF_ACTIVE_POST_LIFO, /*!< an event was posted (LIFO) directly to AO */ QS_QF_ACTIVE_GET, /*!< AO got an event and its queue is not empty */ QS_QF_ACTIVE_GET_LAST,/*!< AO got an event and its queue is empty */ QS_QF_ACTIVE_RECALL_ATTEMPT, /*!< AO attempted to recall an event */ /* [19] Event Queue (EQ) records */ QS_QF_EQUEUE_POST, /*!< an event was posted (FIFO) to a raw queue */ QS_QF_EQUEUE_POST_LIFO, /*!< an event was posted (LIFO) to a raw queue */ QS_QF_EQUEUE_GET, /*!< get an event and queue still not empty */ QS_QF_EQUEUE_GET_LAST,/*!< get the last event from the queue */ /* [23] Framework (QF) records */ QS_QF_NEW_ATTEMPT, /*!< an attempt to allocate an event failed */ /* [24] Memory Pool (MP) records */ QS_QF_MPOOL_GET, /*!< a memory block was removed from memory pool */ QS_QF_MPOOL_PUT, /*!< a memory block was returned to memory pool */ /* [26] Additional Framework (QF) records */ QS_QF_PUBLISH, /*!< an event was published to active objects */ QS_QF_NEW_REF, /*!< new event reference was created */ QS_QF_NEW, /*!< new event was created */ QS_QF_GC_ATTEMPT, /*!< garbage collection attempt */ QS_QF_GC, /*!< garbage collection */ QS_QF_TICK, /*!< QTimeEvt_tick_() was called */ /* [32] Time Event (TE) records */ QS_QF_TIMEEVT_ARM, /*!< a time event was armed */ QS_QF_TIMEEVT_AUTO_DISARM, /*!< a time event expired and was disarmed */ QS_QF_TIMEEVT_DISARM_ATTEMPT,/*!< attempt to disarm a disarmed QTimeEvt */ QS_QF_TIMEEVT_DISARM, /*!< true disarming of an armed time event */ QS_QF_TIMEEVT_REARM, /*!< rearming of a time event */ QS_QF_TIMEEVT_POST, /*!< a time event posted itself directly to an AO */ /* [38] Additional Framework (QF) records */ QS_QF_DELETE_REF, /*!< an event reference is about to be deleted */ QS_QF_CRIT_ENTRY, /*!< critical section was entered */ QS_QF_CRIT_EXIT, /*!< critical section was exited */ QS_QF_ISR_ENTRY, /*!< an ISR was entered */ QS_QF_ISR_EXIT, /*!< an ISR was exited */ QS_QF_INT_DISABLE, /*!< interrupts were disabled */ QS_QF_INT_ENABLE, /*!< interrupts were enabled */ /* [45] Additional Active Object (AO) records */ QS_QF_ACTIVE_POST_ATTEMPT,/*!< attempt to post an evt to AO failed */ /* [46] Additional Event Queue (EQ) records */ QS_QF_EQUEUE_POST_ATTEMPT,/*!< attempt to post an evt to QEQueue failed */ /* [47] Additional Memory Pool (MP) records */ QS_QF_MPOOL_GET_ATTEMPT, /*!< attempt to get a memory block failed */ /* [48] Scheduler (SC) records */ QS_MUTEX_LOCK, /*!< a mutex was locked */ QS_MUTEX_UNLOCK, /*!< a mutex was unlocked */ QS_SCHED_LOCK, /*!< scheduler was locked */ QS_SCHED_UNLOCK, /*!< scheduler was unlocked */ QS_SCHED_NEXT, /*!< scheduler found next task to execute */ QS_SCHED_IDLE, /*!< scheduler became idle */ QS_SCHED_RESUME, /*!< scheduler resumed previous task (not idle) */ /* [55] Additional QEP records */ QS_QEP_TRAN_HIST, /*!< a tran to history was taken */ QS_QEP_TRAN_EP, /*!< a tran to entry point into a submachine */ QS_QEP_TRAN_XP, /*!< a tran to exit point out of a submachine */ /* [58] Miscellaneous QS records (not maskable) */ QS_TEST_PAUSED, /*!< test has been paused */ QS_TEST_PROBE_GET, /*!< reports that Test-Probe has been used */ QS_SIG_DICT, /*!< signal dictionary entry */ QS_OBJ_DICT, /*!< object dictionary entry */ QS_FUN_DICT, /*!< function dictionary entry */ QS_USR_DICT, /*!< user QS record dictionary entry */ QS_TARGET_INFO, /*!< reports the Target information */ QS_TARGET_DONE, /*!< reports completion of a user callback */ QS_RX_STATUS, /*!< reports QS data receive status */ QS_QUERY_DATA, /*!< reports the data from "current object" query */ QS_PEEK_DATA, /*!< reports the data from the PEEK query */ QS_ASSERT_FAIL, /*!< assertion failed in the code */ QS_QF_RUN, /*!< QF_run() was entered */ QS_MAX, /*!< the number of reserved signals */ }; /*${QS::QSpyGroups} ........................................................*/ /*! QS record groups for QS_GLB_FILTER() */ enum QSpyGroups { QS_ALL_RECORDS = 0xF0,/*!< all maskable QS records */ QS_SM_RECORDS, /*!< State Machine QS records */ QS_AO_RECORDS, /*!< Active Object QS records */ QS_EQ_RECORDS, /*!< Event Queues QS records */ QS_MP_RECORDS, /*!< Memory Pools QS records */ QS_TE_RECORDS, /*!< Time Events QS records */ QS_QF_RECORDS, /*!< QF QS records */ QS_SC_RECORDS, /*!< Scheduler QS records */ QS_U0_RECORDS, /*!< User Group 100-104 records */ QS_U1_RECORDS, /*!< User Group 105-109 records */ QS_U2_RECORDS, /*!< User Group 110-114 records */ QS_U3_RECORDS, /*!< User Group 115-119 records */ QS_U4_RECORDS, /*!< User Group 120-124 records */ QS_UA_RECORDS /*!< All User records */ }; /*${QS::QSpyUserOffsets} ...................................................*/ /*! QS user record group offsets for QS_GLB_FILTER() */ enum QSpyUserOffsets { QS_USER = 100, /*!< the first record available to QS users */ QS_USER0 = (enum_t)QS_USER, /*!< offset for User Group 0 */ QS_USER1 = (enum_t)QS_USER0 + 5, /*!< offset for User Group 1 */ QS_USER2 = (enum_t)QS_USER1 + 5, /*!< offset for User Group 2 */ QS_USER3 = (enum_t)QS_USER2 + 5, /*!< offset for User Group 3 */ QS_USER4 = (enum_t)QS_USER3 + 5 /*!< offset for User Group 4 */ }; /*${QS::QSpyIdOffsets} .....................................................*/ /*! QS ID offsets for QS_LOC_FILTER() */ enum QSpyIdOffsets { QS_AO_ID = 0, /*!< offset for AO priorities */ QS_EP_ID = 64, /*!< offset for event-pool IDs */ QS_EQ_ID = 80, /*!< offset for event-queue IDs */ QS_AP_ID = 96, /*!< offset for Application-specific IDs */ }; /*${QS::QSpyIdGroups} ......................................................*/ /*! QS ID groups for QS_LOC_FILTER() */ enum QSpyIdGroups { QS_ALL_IDS = 0xF0, /*!< all QS IDs */ QS_AO_IDS = (0x80 + (enum_t)QS_AO_ID), /*!< AO IDs (priorities) */ QS_EP_IDS = (0x80 + (enum_t)QS_EP_ID), /*!< event-pool IDs */ QS_EQ_IDS = (0x80 + (enum_t)QS_EQ_ID), /*!< event-queue IDs */ QS_AP_IDS = (0x80 + (enum_t)QS_AP_ID), /*!< Application-specific IDs */ }; /*${QS::QSpyFunPtr} ........................................................*/ /*! function pointer type for QS_fun_dict_pre_() */ typedef void (* QSpyFunPtr )(void); /*${QS::QS_EOD} ............................................................*/ /*! Constant representing End-Of-Data condition returned from the * QS_getByte() function. */ #define QS_EOD ((uint16_t)0xFFFFU) /*${QS::QSpyId} ............................................................*/ /*! @brief QS ID type for applying local filtering */ typedef struct { uint8_t prio; } QSpyId; /*${QS::QS-tx::tx} .........................................................*/ /*! @brief Software tracing, output QS-TX * * @details * This class groups together QS services. */ typedef struct { /* public: */ /*! global on/off QS filter */ uint8_t glbFilter[16]; /*! local on/off QS filter */ uint8_t locFilter[16]; /*! @deprecated old local QS filter */ void const * locFilter_AP; /*! pointer to the start of the QS-TX ring buffer */ uint8_t * buf; /*! offset of the end of the ring buffer */ QSCtr end; /*! offset to where next byte will be inserted */ QSCtr volatile head; /*! offset of where next record will be extracted */ QSCtr volatile tail; /*! number of bytes currently in the ring buffer */ QSCtr volatile used; /*! sequence number of the last inserted QS record */ uint8_t volatile seq; /*! checksum of the currently inserted record */ uint8_t volatile chksum; /*! critical section nesting level */ uint8_t volatile critNest; } QS_tx; /*${QS::QS-tx::preType} ....................................................*/ /*! Enumerates data formats recognized by QS * * @details * QS uses this enumeration is used only internally for the formatted * user data elements. */ enum QS_preType { QS_I8_T, /*!< signed 8-bit integer format */ QS_U8_T, /*!< unsigned 8-bit integer format */ QS_I16_T, /*!< signed 16-bit integer format */ QS_U16_T, /*!< unsigned 16-bit integer format */ QS_I32_T, /*!< signed 32-bit integer format */ QS_U32_T, /*!< unsigned 32-bit integer format */ QS_F32_T, /*!< 32-bit floating point format */ QS_F64_T, /*!< 64-bit floating point format */ QS_STR_T, /*!< zero-terminated ASCII string format */ QS_MEM_T, /*!< up to 255-bytes memory block format */ QS_SIG_T, /*!< event signal format */ QS_OBJ_T, /*!< object pointer format */ QS_FUN_T, /*!< function pointer format */ QS_I64_T, /*!< signed 64-bit integer format */ QS_U64_T, /*!< unsigned 64-bit integer format */ QS_HEX_FMT /*!< HEX format for the "width" filed */ }; /*${QS::QS-tx::priv_} ......................................................*/ /*! the only instance of the QS-TX object (Singleton) */ extern QS_tx QS_priv_; /*${QS::QS-tx::initBuf} ....................................................*/ /*! Initialize the QS data buffer * @static @private @memberof QS * * @details * This function should be called from QS_onStartup() to provide * QS with the data buffer. The first argument `sto[]` is the address * of the memory block, and the second argument `stoSize` is the size * of this block [in bytes]. Currently the size of the QS buffer cannot * exceed 64KB. * * @note * QS can work with quite small data buffers, but you will start losing * data if the buffer is too small for the bursts of tracing activity. * The right size of the buffer depends on the data production rate and * the data output rate. QS offers flexible filtering to reduce the data * production rate. * * @note * If the data output rate cannot keep up with the production rate, * QS will start overwriting the older data with newer data. This is * consistent with the "last-is-best" QS policy. The record sequence * counters and check sums on each record allow the QSPY host utility * to easily detect any data loss. */ void QS_initBuf( uint8_t * const sto, uint_fast16_t const stoSize); /*${QS::QS-tx::getByte} ....................................................*/ /*! Byte-oriented interface to the QS data buffer * @static @private @memberof QS * * @details * This function delivers one byte at a time from the QS data buffer. * * @returns * the byte in the least-significant 8-bits of the 16-bit return * value if the byte is available. If no more data is available at the * time, the function returns ::QS_EOD (End-Of-Data). * * @note * QS_getByte() is NOT protected with a critical section. */ uint16_t QS_getByte(void); /*${QS::QS-tx::getBlock} ...................................................*/ /*! Block-oriented interface to the QS data buffer * @static @private @memberof QS * * @details * This function delivers a contiguous block of data from the QS data * buffer. The function returns the pointer to the beginning of the * block, and writes the number of bytes in the block to the location * pointed to by `pNbytes`. The argument `pNbytes` is also used as * input to provide the maximum size of the data block that the caller * can accept. * * @returns * if data is available, the function returns pointer to the * contiguous block of data and sets the value pointed to by `pNbytes` * to the # available bytes. If data is available at the time the * function is called, the function returns NULL pointer and sets the * value pointed to by `pNbytes` to zero. * * @note * Only the NULL return from QS_getBlock() indicates that the QS * buffer is empty at the time of the call. The non-NULL return often * means that the block is at the end of the buffer and you need to call * QS_getBlock() again to obtain the rest of the data that * "wrapped around" to the beginning of the QS data buffer. * * @note QS_getBlock() is **not** protected with a critical section. */ uint8_t const * QS_getBlock(uint16_t * const pNbytes); /*${QS::QS-tx::glbFilter_} .................................................*/ /*! Set/clear the global Filter for a given QS record * or a group of records * @static @private @memberof QS * * @details * This function sets up the QS filter to enable record types specified * in the `filter` parameter. The value #QS_ALL_RECORDS specifies to * filter-in all records. This function should be called indirectly * through the macro QS_GLB_FILTER() * * @param[in] filter the QS record-d or group to enable in the filter, * if positive or disable, if negative. The record-id * numbers must be in the range -127..127. * @note * Filtering based on the record-type is only the first layer of * filtering. The second layer is based on the object-type. Both filter * layers must be enabled for the QS record to be inserted in the * QS buffer. * * @sa QS_locFilter_() */ void QS_glbFilter_(int_fast16_t const filter); /*${QS::QS-tx::locFilter_} .................................................*/ /*! Set/clear the local Filter for a given object-id * or a group of object-ids * @static @private @memberof QS * * @details * This function sets up the local QS filter to enable or disable the * given QS object-id or a group of object-ids @a filter. * This function should be called indirectly through the macro * QS_LOC_FILTER() * * @param[in] filter the QS object-id or group to enable in the filter, * if positive or disable, if negative. The qs_id numbers * must be in the range 1..127. * @note * Filtering based on the object-id (local filter) is the second layer * of filtering. The first layer is based on the QS record-type (global * filter). Both filter layers must be enabled for the QS record to be * inserted into the QS buffer. * * @sa QS_glbFilter_() */ void QS_locFilter_(int_fast16_t const filter); /*${QS::QS-tx::doOutput} ...................................................*/ /*! Perform the QS-TX output (implemented in some QS ports) * @static @private @memberof QS */ void QS_doOutput(void); /*${QS::QS-tx::beginRec_} ..................................................*/ /*! Mark the begin of a QS record @p rec * @static @private @memberof QS * * @details * This function must be called at the beginning of each QS record. * This function should be called indirectly through the macro QS_BEGIN_ID(), * or QS_BEGIN_NOCRIT(), depending if it's called in a normal code or from * a critical section. */ void QS_beginRec_(uint_fast8_t const rec); /*${QS::QS-tx::endRec_} ....................................................*/ /*! Mark the end of a QS record `rec` * @static @private @memberof QS * * @details * This function must be called at the end of each QS record. * This function should be called indirectly through the macro QS_END(), * or QS_END_NOCRIT(), depending if it's called in a normal code or from * a critical section. */ void QS_endRec_(void); /*${QS::QS-tx::u8_raw_} ....................................................*/ /*! output uint8_t data element without format information * @static @private @memberof QS */ void QS_u8_raw_(uint8_t const d); /*${QS::QS-tx::2u8_raw_} ...................................................*/ /*! output two uint8_t data elements without format information * @static @private @memberof QS */ void QS_2u8_raw_( uint8_t const d1, uint8_t const d2); /*${QS::QS-tx::u16_raw_} ...................................................*/ /*! output uint16_t data element without format information * @static @private @memberof QS */ void QS_u16_raw_(uint16_t d); /*${QS::QS-tx::u32_raw_} ...................................................*/ /*! output uint32_t data element without format information * @static @private @memberof QS */ void QS_u32_raw_(uint32_t d); /*${QS::QS-tx::obj_raw_} ...................................................*/ /*! Output obj pointer data element without format information * @static @private @memberof QS * * @note This function is only to be used through macros, never in the * client code directly. */ void QS_obj_raw_(void const * const obj); /*${QS::QS-tx::str_raw_} ...................................................*/ /*! Output raw zero-terminated string element (without format information) * @static @private @memberof QS * * @note This function is only to be used through macros, never in the * client code directly. */ void QS_str_raw_(char const * str); /*${QS::QS-tx::u8_fmt_} ....................................................*/ /*! Output uint8_t data element with format information * @static @private @memberof QS * * @details * @note This function is only to be used through macros, never in the * client code directly. */ void QS_u8_fmt_( uint8_t const format, uint8_t const d); /*${QS::QS-tx::u16_fmt_} ...................................................*/ /*! output uint16_t data element with format information * @static @private @memberof QS * * @details * This function is only to be used through macros, never in the * client code directly. */ void QS_u16_fmt_( uint8_t format, uint16_t d); /*${QS::QS-tx::u32_fmt_} ...................................................*/ /*! Output uint32_t data element with format information * @static @private @memberof QS * * @note This function is only to be used through macros, never in the * client code directly. */ void QS_u32_fmt_( uint8_t format, uint32_t d); /*${QS::QS-tx::str_fmt_} ...................................................*/ /*! Output formatted zero-terminated ASCII string to the QS record * @static @private @memberof QS */ void QS_str_fmt_(char const * str); /*${QS::QS-tx::mem_fmt_} ...................................................*/ /*! Output formatted memory block of up to 255 bytes to the QS record * @static @private @memberof QS */ void QS_mem_fmt_( uint8_t const * blk, uint8_t size); /*${QS::QS-tx::sig_dict_pre_} ..............................................*/ /*! Output predefined signal-dictionary record * @static @private @memberof QS * * @note This function is only to be used through macro QS_SIG_DICTIONARY() */ void QS_sig_dict_pre_( enum_t const sig, void const * const obj, char const * const name); /*${QS::QS-tx::obj_dict_pre_} ..............................................*/ /*! Output predefined object-dictionary record * @static @private @memberof QS * * @note This function is only to be used through macro QS_OBJ_DICTIONARY() */ void QS_obj_dict_pre_( void const * const obj, char const * const name); /*${QS::QS-tx::obj_arr_dict_pre_} ..........................................*/ /*! Output predefined object-array dictionary record * @static @private @memberof QS * * @note This function is only to be used through macro QS_OBJ_ARR_DICTIONARY() */ void QS_obj_arr_dict_pre_( void const * const obj, uint_fast16_t const idx, char const * const name); /*${QS::QS-tx::fun_dict_pre_} ..............................................*/ /*! Output predefined function-dictionary record * @static @private @memberof QS * * @note This function is only to be used through macro QS_FUN_DICTIONARY() */ void QS_fun_dict_pre_( QSpyFunPtr fun, char const * const name); /*${QS::QS-tx::usr_dict_pre_} ..............................................*/ /*! Output predefined user-dictionary record * @static @private @memberof QS * * @note This function is only to be used through macro QS_USR_DICTIONARY() */ void QS_usr_dict_pre_( enum_t const rec, char const * const name); /*${QS::QS-tx::ASSERTION} ..................................................*/ /*! Output the predefined assertion failure trace record * @static @public @memberof QS * * @details * This trace record is intended to use from the Q_onAssert() callback. */ void QS_ASSERTION( char const * const module, int_t const loc, uint32_t const delay); /*${QS::QS-tx::target_info_pre_} ...........................................*/ /*! Helper function to output the predefined Target-info trace record. * @static @private @memberof QS */ void QS_target_info_pre_(uint8_t const isReset); /*${QS::QS-tx::onStartup} ..................................................*/ /*! Callback to startup the QS facility * @static @public @memberof QS */ uint8_t QS_onStartup(void const * arg); /*${QS::QS-tx::onCleanup} ..................................................*/ void QS_onCleanup(void); /*${QS::QS-tx::onFlush} ....................................................*/ void QS_onFlush(void); /*${QS::QS-tx::onGetTime} ..................................................*/ QSTimeCtr QS_onGetTime(void); /*${QS::QS-tx-64bit::u64_raw_} .............................................*/ /*! Output uint64_t data element without format information * @static @private @memberof QS */ void QS_u64_raw_(uint64_t d); /*${QS::QS-tx-64bit::u64_fmt_} .............................................*/ /*! Output uint64_t data element with format information * @static @private @memberof QS * @sa QS_U64(), QS_I64() */ void QS_u64_fmt_( uint8_t format, uint64_t d); /*${QS::QS-tx-fp::f32_fmt_} ................................................*/ /*! Output 32-bit floating point data element with format information * @static @private @memberof QS * @sa QS_F32() */ void QS_f32_fmt_( uint8_t format, float32_t d); /*${QS::QS-tx-fp::f64_fmt_} ................................................*/ /*! Output 64-bit floating point data element with format information * @static @private @memberof QS * @sa QS_F64() */ void QS_f64_fmt_( uint8_t format, float64_t d); /*${QS::QS-rx::rx} .........................................................*/ /*! @brief QS software tracing parameters for QS input (QS-RX) */ typedef struct { /* public: */ void * currObj[8]; uint8_t * buf; QSCtr end; QSCtr volatile head; QSCtr volatile tail; #ifdef Q_UTEST bool inTestLoop; #endif /* def Q_UTEST */ } QS_rx; /*${QS::QS-rx::rxPriv_} ....................................................*/ /*! the only instance of the QS-RX object (Singleton) */ extern QS_rx QS_rxPriv_; /*${QS::QS-rx::QSpyObjKind} ................................................*/ /*! Kinds of objects used in QS_setCurrObj() and QS_queryCurrObj() */ enum QS_QSpyObjKind { SM_OBJ, /*!< state machine object */ AO_OBJ, /*!< active object */ MP_OBJ, /*!< event pool object */ EQ_OBJ, /*!< raw queue object */ TE_OBJ, /*!< time event object */ AP_OBJ, /*!< generic Application-specific object */ MAX_OBJ }; /*${QS::QS-rx::OSpyObjCombnation} ..........................................*/ /*! Object combinations for QS_setCurrObj() and QS_queryCurrObj() */ enum QS_OSpyObjCombnation { SM_AO_OBJ = (enum_t)MAX_OBJ /*!< combination of SM and AO */ }; /*${QS::QS-rx::rxInitBuf} ..................................................*/ /*! Initialize the QS RX data buffer * @static @private @memberof QS * * @details * This function should be called from QS::onStartup() to provide QS-RX * with the receive data buffer. * * @param[in] sto[] the address of the memory block * @param[in] stoSize the size of this block [bytes]. The size of the * QS RX buffer cannot exceed 64KB. * * @note * QS-RX can work with quite small data buffers, but you will start * losing data if the buffer is not drained fast enough (e.g., in the * idle task). * * @note * If the data input rate exceeds the QS-RX processing rate, the data * will be lost, but the QS protocol will notice that: * (1) that the checksum in the incomplete QS records will fail; and * (2) the sequence counter in QS records will show discontinuities. * * The QS-RX channel will report any data errors by sending the * QS_RX_DATA_ERROR trace record. */ void QS_rxInitBuf( uint8_t * const sto, uint16_t const stoSize); /*${QS::QS-rx::rxPut} ......................................................*/ /*! Put one byte into the QS RX lock-free buffer * @static @private @memberof QS */ static inline bool QS_rxPut(uint8_t const b) { QSCtr head = QS_rxPriv_.head + 1U; if (head == QS_rxPriv_.end) { head = 0U; } if (head != QS_rxPriv_.tail) { /* buffer NOT full? */ QS_rxPriv_.buf[QS_rxPriv_.head] = b; QS_rxPriv_.head = head; /* update the head to a *valid* index */ return true; /* byte placed in the buffer */ } else { return false; /* byte NOT placed in the buffer */ } } /*${QS::QS-rx::rxGetNfree} .................................................*/ /*! Obtain the number of free bytes in the QS RX data buffer * @static @private @memberof QS * * @details * This function is intended to be called from the ISR that reads the * QS-RX bytes from the QSPY application. The function returns the * conservative number of free bytes currently available in the buffer, * assuming that the head pointer is not being moved concurrently. * The tail pointer might be moving, meaning that bytes can be * concurrently removed from the buffer. */ uint16_t QS_rxGetNfree(void); /*${QS::QS-rx::doInput} ....................................................*/ /*! Perform the QS-RX input (implemented in some QS ports) * @static @private @memberof QS */ void QS_doInput(void); /*${QS::QS-rx::setCurrObj} .................................................*/ /*! Set the "current object" in the Target * @static @private @memberof QS * * @details * This function sets the "current object" in the Target. */ void QS_setCurrObj( uint8_t obj_kind, void * obj_ptr); /*${QS::QS-rx::queryCurrObj} ...............................................*/ /*! Query the "current object" in the Target * @static @public @memberof QS * * @details * This function programmatically generates the response to the query for * a "current object". */ void QS_queryCurrObj(uint8_t obj_kind); /*${QS::QS-rx::rxParse} ....................................................*/ /*! Parse all bytes present in the QS RX data buffer * @static @private @memberof QS */ void QS_rxParse(void); /*${QS::QS-rx::rxHandleGoodFrame_} .........................................*/ /*! internal function to handle incoming (QS-RX) packet * @static @private @memberof QS */ void QS_rxHandleGoodFrame_(uint8_t const state); /*${QS::QS-rx::onReset} ....................................................*/ /*! callback function to reset the Target (to be implemented in the BSP) * @static @public @memberof QS */ void QS_onReset(void); /*${QS::QS-rx::onCommand} ..................................................*/ /*! Callback function to execute user commands (to be implemented in BSP) * @static @public @memberof QS */ void QS_onCommand( uint8_t cmdId, uint32_t param1, uint32_t param2, uint32_t param3); /*${QS::QS-rx::RX_PUT} .....................................................*/ /*! Put one byte into the QS RX lock-free buffer * @static @public @memberof QSrx */ bool QS_RX_PUT(uint8_t const b); /*$enddecl${QS} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*==========================================================================*/ /*$declare${QS-macros} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /*${QS-macros::QS_INIT} ....................................................*/ /*! Initialize the QS facility * * @details * This macro provides an indirection layer to invoke the QS initialization * routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined. * @sa QS_onStartup(), example of setting up a QS filter in * QS_GLB_FILTER() */ #define QS_INIT(arg_) (QS_onStartup(arg_)) /*${QS-macros::QS_EXIT} ....................................................*/ /*! Cleanup the QS facility * * @details * This macro provides an indirection layer to invoke the QS cleanup * routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined. * @sa QS_onCleanup() */ #define QS_EXIT() (QS_onCleanup()) /*${QS-macros::QS_OUTPUT} ..................................................*/ /*! macro to handle the QS output from the application * * @note * If this macro is used, the application must define QS_output(). */ #define QS_OUTPUT() (QS_output()) /*${QS-macros::QS_RX_INPUT} ................................................*/ /*! macro to handle the QS-RX input to the application * * @note * If this macro is used, the application must define QS_doInput(). */ #define QS_RX_INPUT() (QS_rx_input()) /*${QS-macros::QS_GLB_FILTER} ..............................................*/ /*! Global Filter ON for a given record type `rec_` * * @details * This macro provides an indirection layer to call QS_filterOn() * if #Q_SPY is defined, or do nothing if #Q_SPY is not defined. * * @sa * - ::QSpyRecordGroups - QS record groups that can be used as `rec_` * - ::QSpyRecords - individual QS records that can be used as `rec_` * * @usage * The following example shows how to use QS filters: * @include qs_filter.c */ #define QS_GLB_FILTER(rec_) (QS_glbFilter_((int_fast16_t)(rec_))) /*${QS-macros::QS_LOC_FILTER} ..............................................*/ /*! Local Filter for a given state machine object `qs_id` * * @details * This macro provides an indirection layer to call QS_locFilter_() * if #Q_SPY is defined, or do nothing if #Q_SPY is not defined. * * @sa * - ::QSpyIdGroups - QS ID groups that can be used as `qs_id_` * - ::QSpyIdOffsets - QS ID offsets for `qs_id_` (e.g., QS_AP_IDS + 5) * * The following example shows how to use QS filters: * @include qs_filter.c */ #define QS_LOC_FILTER(qs_id_) (QS_locFilter_((int_fast16_t)(qs_id_))) /*${QS-macros::QS_BEGIN_ID} ................................................*/ /*! Begin an application-specific QS record with entering critical section * * @details * The following example shows how to build a user QS record using the * macros QS_BEGIN_ID(), QS_END(), and the formatted output macros: * QS_U8(), QS_STR(), etc. * * @note * Must always be used in pair with QS_END() * * @include qs_user.c */ #define QS_BEGIN_ID(rec_, qs_id_) \ if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \ QS_CRIT_STAT_ \ QS_CRIT_E_(); \ QS_beginRec_((uint_fast8_t)(rec_)); \ QS_TIME_PRE_(); { /*${QS-macros::QS_END} .....................................................*/ /*! End an application-specific QS record with exiting critical section. * * @sa example for QS_BEGIN_ID() * @note Must always be used in pair with QS_BEGIN_ID() */ #define QS_END() } \ QS_endRec_(); \ QS_CRIT_X_(); \ } /*${QS-macros::QS_FLUSH} ...................................................*/ /*! Flush the QS trace data to the host * * @details * This macro invokes the QS_flush() platform-dependent callback * function to flush the QS trace buffer to the host. The function * typically busy-waits until all the data in the buffer is sent to * the host. This is acceptable only in the initial transient. */ #define QS_FLUSH() (QS_onFlush()) /*${QS-macros::QS_BEGIN_NOCRIT} ............................................*/ /*! Begin an application-specific QS record WITHOUT entering critical section */ #define QS_BEGIN_NOCRIT(rec_, qs_id_) \ if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \ QS_beginRec_((uint_fast8_t)(rec_)); \ QS_TIME_PRE_(); { /*${QS-macros::QS_END_NOCRIT} ..............................................*/ /*! End an application-specific QS record WITHOUT exiting critical section */ #define QS_END_NOCRIT() } \ QS_endRec_();\ } /*${QS-macros::QS_GLB_CHECK_} ..............................................*/ /*! Helper macro for checking the global QS filter */ #define QS_GLB_CHECK_(rec_) \ (((uint_fast8_t)QS_priv_.glbFilter[(uint_fast8_t)(rec_) >> 3U] \ & ((uint_fast8_t)1U << ((uint_fast8_t)(rec_) & 7U))) != 0U) /*${QS-macros::QS_LOC_CHECK_} ..............................................*/ /*! Helper macro for checking the local QS filter */ #define QS_LOC_CHECK_(qs_id_) \ (((uint_fast8_t)QS_priv_.locFilter[(uint_fast8_t)(qs_id_) >> 3U] \ & ((uint_fast8_t)1U << ((uint_fast8_t)(qs_id_) & 7U))) != 0U) /*${QS-macros::QS_REC_DONE} ................................................*/ #ifndef QS_REC_DONE /*! Macro to execute user code when a QS record is produced * * @note * This is a dummy definition in case this macro is undefined. */ #define QS_REC_DONE() ((void)0) #endif /* ndef QS_REC_DONE */ /*${QS-macros::QS_I8} ......................................................*/ /*! Output formatted int8_t to the QS record */ #define QS_I8(width_, data_) \ (QS_u8_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I8_T, (data_))) /*${QS-macros::QS_U8} ......................................................*/ /*! Output formatted uint8_t to the QS record */ #define QS_U8(width_, data_) \ (QS_u8_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U8_T, (data_))) /*${QS-macros::QS_I16} .....................................................*/ /*! Output formatted int16_t to the QS record */ #define QS_I16(width_, data_) \ (QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I16_T, (data_))) /*${QS-macros::QS_U16} .....................................................*/ /*! Output formatted uint16_t to the QS record */ #define QS_U16(width_, data_) \ (QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U16_T, (data_))) /*${QS-macros::QS_I32} .....................................................*/ /*! Output formatted int32_t to the QS record */ #define QS_I32(width_, data_) \ (QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I32_T, (data_))) /*${QS-macros::QS_U32} .....................................................*/ /*! Output formatted uint32_t to the QS record */ #define QS_U32(width_, data_) \ (QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U32_T, (data_))) /*${QS-macros::QS_I64} .....................................................*/ /*! Output formatted int64_t to the QS record */ #define QS_I64(width_, data_) \ (QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I64_T, (data_))) /*${QS-macros::QS_U64} .....................................................*/ /*! Output formatted uint64_t to the QS record */ #define QS_U64(width_, data_) \ (QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U64_T, (data_))) /*${QS-macros::QS_F32} .....................................................*/ /*! Output formatted 32-bit floating point number to the QS record */ #define QS_F32(width_, data_) \ (QS_f32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F32_T, (data_))) /*${QS-macros::QS_F64} .....................................................*/ /*! Output formatted 64-bit floating point number to the QS record */ #define QS_F64(width_, data_) \ (QS_f64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F64_T, (data_))) /*${QS-macros::QS_STR} .....................................................*/ /*! Output formatted zero-terminated ASCII string to the QS record */ #define QS_STR(str_) (QS_str_fmt_((str_))) /*${QS-macros::QS_MEM} .....................................................*/ /*! Output formatted memory block of up to 255 bytes to the QS record */ #define QS_MEM(mem_, size_) (QS_mem_fmt_((mem_), (size_))) /*${QS-macros::QS_TIME_PRE_} ...............................................*/ #if (QS_TIME_SIZE == 4U) /*! Output time stamp to a QS record (used in predefined * and application-specific trace records) */ #define QS_TIME_PRE_() (QS_u32_raw_(QS_onGetTime())) #endif /* (QS_TIME_SIZE == 4U) */ /*${QS-macros::QS_TIME_PRE_} ...............................................*/ #if (QS_TIME_SIZE == 2U) #define QS_TIME_PRE_() (QS_u16_raw_(QS_onGetTime())) #endif /* (QS_TIME_SIZE == 2U) */ /*${QS-macros::QS_TIME_PRE_} ...............................................*/ #if (QS_TIME_SIZE == 1U) #define QS_TIME_PRE_() (QS_u8_raw_(QS_onGetTime())) #endif /* (QS_TIME_SIZE == 1U) */ /*${QS-macros::QS_OBJ} .....................................................*/ #if (QS_OBJ_PTR_SIZE == 4U) /*! Output formatted object pointer to the QS record */ #define QS_OBJ(obj_) (QS_u32_fmt_(QS_OBJ_T, (uint32_t)(obj_))) #endif /* (QS_OBJ_PTR_SIZE == 4U) */ /*${QS-macros::QS_OBJ} .....................................................*/ #if (QS_OBJ_PTR_SIZE == 2U) #define QS_OBJ(obj_) (QS_u16_fmt_(QS_OBJ_T, (uint16_t)(obj_))) #endif /* (QS_OBJ_PTR_SIZE == 2U) */ /*${QS-macros::QS_OBJ} .....................................................*/ #if (QS_OBJ_PTR_SIZE == 1U) #define QS_OBJ(obj_) (QS_u8_fmt_(QS_OBJ_T, (uint8_t)(obj_))) #endif /* (QS_OBJ_PTR_SIZE == 1U) */ /*${QS-macros::QS_OBJ} .....................................................*/ #if (QS_OBJ_PTR_SIZE == 8U) #define QS_OBJ(obj_) (QS_u64_fmt_(QS_OBJ_T, (uint64_t)(obj_))) #endif /* (QS_OBJ_PTR_SIZE == 8U) */ /*${QS-macros::QS_FUN} .....................................................*/ #if (QS_FUN_PTR_SIZE == 4U) /* Output formatted function pointer to the QS record */ #define QS_FUN(fun_) (QS_u32_fmt_(QS_FUN_T, (uint32_t)(fun_))) #endif /* (QS_FUN_PTR_SIZE == 4U) */ /*${QS-macros::QS_FUN} .....................................................*/ #if (QS_FUN_PTR_SIZE == 2U) #define QS_FUN(fun_) (QS_u16_fmt_(QS_FUN_T, (uint16_t)(fun_))) #endif /* (QS_FUN_PTR_SIZE == 2U) */ /*${QS-macros::QS_FUN} .....................................................*/ #if (QS_FUN_PTR_SIZE == 1U) #define QS_FUN(fun_) (QS_u8_fmt_(QS_FUN_T, (uint8_t)(fun_))) #endif /* (QS_FUN_PTR_SIZE == 1U) */ /*${QS-macros::QS_FUN} .....................................................*/ #if (QS_FUN_PTR_SIZE == 8U) #define QS_FUN(fun_) (QS_u64_fmt_(QS_FUN_T, (uint64_t)(fun_))) #endif /* (QS_FUN_PTR_SIZE == 8U) */ /*${QS-macros::QS_SIG} .....................................................*/ #if (Q_SIGNAL_SIZE == 4U) /*! Output formatted event signal (of type ::QSignal) and * the state machine object to the user QS record */ #define QS_SIG(sig_, obj_) \ QS_u32_fmt_(QS_SIG_T, (sig_)); \ QS_obj_raw_(obj_) #endif /* (Q_SIGNAL_SIZE == 4U) */ /*${QS-macros::QS_SIG} .....................................................*/ #if (Q_SIGNAL_SIZE == 2U) #define QS_SIG(sig_, obj_) \ QS_u16_fmt_(QS_SIG_T, (sig_)); \ QS_obj_raw_(obj_) #endif /* (Q_SIGNAL_SIZE == 2U) */ /*${QS-macros::QS_SIG} .....................................................*/ #if (Q_SIGNAL_SIZE == 1U) #define QS_SIG(sig_, obj_) \ QS_u8_fmt_(QS_SIG_T, (sig_)); \ QS_obj_raw_(obj_) #endif /* (Q_SIGNAL_SIZE == 1U) */ /*${QS-macros::QS_SIG_DICTIONARY} ..........................................*/ /*! Output signal dictionary record * * @details * A signal dictionary record associates the numerical value of the signal * and the binary address of the state machine that consumes that signal * with the human-readable name of the signal. * * Providing a signal dictionary QS record can vastly improve readability of * the QS log, because instead of dealing with cryptic machine addresses the * QSpy host utility can display human-readable names. * * A signal dictionary entry is associated with both the signal value `sig_` * and the state machine `obj_`, because signals are required to be unique * only within a given state machine and therefore the same numerical values * can represent different signals in different state machines. * * For the "global" signals that have the same meaning in all state machines * (such as globally published signals), you can specify a signal dictionary * entry with the `obj_` parameter set to NULL. * * The following example shows the definition of signal dictionary entries * in the initial transition of the Table active object. Please note that * signals HUNGRY_SIG and DONE_SIG are associated with the Table state * machine only ("me" `obj_` pointer). The EAT_SIG signal, on the other * hand, is global (0 `obj_` pointer): * @include qs_sigDic.c * * @note The QSpy log utility must capture the signal dictionary record * in order to use the human-readable information. You need to connect to * the target before the dictionary entries have been transmitted. * * The following QSpy log example shows the signal dictionary records * generated from the Table initial transition and subsequent records that * show human-readable names of the signals: * @include qs_sigLog.txt * * The following QSpy log example shows the same sequence of records, but * with dictionary records removed. The human-readable signal names are not * available. */ #define QS_SIG_DICTIONARY(sig_, obj_) \ (QS_sig_dict_pre_((sig_), (obj_), #sig_)) /*${QS-macros::QS_OBJ_DICTIONARY} ..........................................*/ /*! Output object dictionary record * * @details * An object dictionary record associates the binary address of an object * in the target's memory with the human-readable name of the object. * * Providing an object dictionary QS record can vastly improve readability of * the QS log, because instead of dealing with cryptic machine addresses the * QSpy host utility can display human-readable object names. * * The following example shows the definition of object dictionary entry * for the Table active object: * @include qs_objDic.c */ #define QS_OBJ_DICTIONARY(obj_) \ (QS_obj_dict_pre_((obj_), #obj_)) /*${QS-macros::QS_OBJ_ARR_DICTIONARY} ......................................*/ /*! Output object-array dictionary record * * @details * An object array dictionary record associates the binary address of the * object element in the target's memory with the human-readable name * of the object. * * Providing a dictionary QS record can vastly improve readability of * the QS log, because instead of dealing with cryptic machine addresses the * QSpy host utility can display human-readable object names. * * The following example shows the definition of object array dictionary * for `Philo::inst[n]` and `Philo::inst[n].m_timeEvt`: * @include qs_objDic.c */ #define QS_OBJ_ARR_DICTIONARY(obj_, idx_) \ (QS_obj_arr_dict_pre_((obj_), (idx_), #obj_)) /*${QS-macros::QS_FUN_DICTIONARY} ..........................................*/ /*! Output function dictionary record * * @details * A function dictionary record associates the binary address of a function * in the target's memory with the human-readable name of the function. * * Providing a function dictionary QS record can vastly improve readability * of the QS log, because instead of dealing with cryptic machine addresses * the QSpy host utility can display human-readable function names. * * The example from #QS_SIG_DICTIONARY shows the definition of a function * dictionary. */ #define QS_FUN_DICTIONARY(fun_) \ (QS_fun_dict_pre_((void (*)(void))(fun_), #fun_)) /*${QS-macros::QS_USR_DICTIONARY} ..........................................*/ /*! Output user QS record dictionary record * * @details * A user QS record dictionary record associates the numerical value of a * user record with the human-readable identifier. */ #define QS_USR_DICTIONARY(rec_) \ (QS_usr_dict_pre_((rec_), #rec_)) /*${QS-macros::QF_QS_CRIT_ENTRY} ...........................................*/ /*! Output the critical section entry record */ void QF_QS_CRIT_ENTRY(void); /*${QS-macros::QF_QS_CRIT_EXIT} ............................................*/ /*! Output the critical section exit record */ void QF_QS_CRIT_EXIT(void); /*${QS-macros::QF_QS_ISR_ENTRY} ............................................*/ /*! Output the interrupt entry record */ void QF_QS_ISR_ENTRY( uint_fast8_t const isrnest, uint_fast8_t const prio_); /*${QS-macros::QF_QS_ISR_EXIT} .............................................*/ /*! Output the ISR exit * @static @public @memberof QS */ void QF_QS_ISR_EXIT( uint_fast8_t isrnest, uint_fast8_t prio); /*${QS-macros::QF_QS_ACTION} ...............................................*/ /*! Execute an action that is only necessary for QS output */ #define QF_QS_ACTION(act_) (act_) /*$enddecl${QS-macros} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*==========================================================================*/ /* Facilities for QS critical section */ /* QS-specific critical section */ #ifdef QS_CRIT_ENTRY /* separate QS critical section defined? */ #ifndef QS_CRIT_STAT_TYPE #define QS_CRIT_STAT_ #define QS_CRIT_E_() QS_CRIT_ENTRY(dummy) #define QS_CRIT_X_() QS_CRIT_EXIT(dummy); QS_REC_DONE() #else #define QS_CRIT_STAT_ QS_CRIT_STAT_TYPE critStat_; #define QS_CRIT_E_() QS_CRIT_ENTRY(critStat_) #define QS_CRIT_X_() QS_CRIT_EXIT(critStat_); QS_REC_DONE() #endif /* QS_CRIT_STAT_TYPE */ #else /* separate QS critical section not defined--use the QF definition */ #ifndef QF_CRIT_STAT_TYPE /*! This is an internal macro for defining the critical section * status type. * @details * The purpose of this macro is to enable writing the same code for the * case when critical section status type is defined and when it is not. * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro * provides the definition of the critical section status variable. * Otherwise this macro is empty. * @sa #QF_CRIT_STAT_TYPE */ #define QS_CRIT_STAT_ /*! This is an internal macro for entering a critical section. * @details * The purpose of this macro is to enable writing the same code for the * case when critical section status type is defined and when it is not. * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro * invokes QF_CRIT_ENTRY() passing the key variable as the parameter. * Otherwise QF_CRIT_ENTRY() is invoked with a dummy parameter. * @sa QF_CRIT_ENTRY() */ #define QS_CRIT_E_() QF_CRIT_ENTRY(dummy) /*! This is an internal macro for exiting a critical section. * @details * The purpose of this macro is to enable writing the same code for the * case when critical section status type is defined and when it is not. * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro * invokes QF_CRIT_EXIT() passing the key variable as the parameter. * Otherwise QF_CRIT_EXIT() is invoked with a dummy parameter. * @sa QF_CRIT_EXIT() */ #define QS_CRIT_X_() QF_CRIT_EXIT(dummy); QS_REC_DONE() #elif (!defined QS_CRIT_STAT_) #define QS_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_; #define QS_CRIT_E_() QF_CRIT_ENTRY(critStat_) #define QS_CRIT_X_() QF_CRIT_EXIT(critStat_); QS_REC_DONE() #endif /* simple unconditional interrupt disabling used */ #endif /* separate QS critical section not defined */ /*==========================================================================*/ /* Macros for use in QUTest only */ #ifdef Q_UTEST /*$declare${QUTest} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ /*${QUTest::QS::TProbe} ....................................................*/ /*! @brief Test Probe attributes */ struct QS_TProbe { QSFun addr; uint32_t data; uint8_t idx; }; /*${QUTest::QS::TestData} ..................................................*/ /*! @brief QUTest data */ struct QS_TestData { struct QS_TProbe tpBuf[16]; /*!< buffer of Test-Probes received so far */ uint8_t tpNum; /*!< current number of Test-Probes */ QSTimeCtr testTime; /*!< test time (tick counter) */ }; /*${QUTest::QS::testData} ..................................................*/ /*! QUTest data */ extern struct QS_TestData QS_testData; /*${QUTest::QS::processTestEvts_} ..........................................*/ /*! internal function to process posted events during test * @static @private @memberof QS */ void QS_processTestEvts_(void); /*${QUTest::QS::test_pause_} ...............................................*/ /*! internal function to pause test and enter the test event loop * @static @private @memberof QS */ void QS_test_pause_(void); /*${QUTest::QS::getTestProbe_} .............................................*/ /*! get the test probe data for the given API * @static @private @memberof QS */ uint32_t QS_getTestProbe_(QSpyFunPtr api); /*${QUTest::QS::onTestSetup} ...............................................*/ /*! callback to setup a unit test inside the Target * @static @public @memberof QS */ void QS_onTestSetup(void); /*${QUTest::QS::onTestTeardown} ............................................*/ /*! callback to teardown after a unit test inside the Target * @static @public @memberof QS */ void QS_onTestTeardown(void); /*${QUTest::QS::onTestEvt} .................................................*/ /*! callback to "massage" the test event before dispatching/posting it * @static @public @memberof QS */ void QS_onTestEvt(QEvt * e); /*${QUTest::QS::onTestPost} ................................................*/ /*! callback to examine an event that is about to be posted * @static @public @memberof QS */ void QS_onTestPost( void const * sender, QActive * recipient, QEvt const * e, bool status); /*${QUTest::QS::onTestLoop} ................................................*/ /*! callback to run the test loop * @static @public @memberof QS */ void QS_onTestLoop(void); /*${QUTest::QHsmDummy} .....................................................*/ /*! @brief QHsmDummy class * @class QHsmDummy * @extends QHsm * * @details * ::QHsmDummy is a test double for the role of "Orthogonal Components" * HSM objects in QUTest unit testing. */ typedef struct { /* protected: */ QHsm super; } QHsmDummy; /* public: */ /*! Constructor of the QHsmDummy HSM class * @public @memberof QHsmDummy */ void QHsmDummy_ctor(QHsmDummy * const me); /*! override for QHsm_init_() * @private @memberof QHsmDummy */ void QHsmDummy_init_( QHsm * const me, void const * const par, uint_fast8_t const qs_id); /*! override for QHsm_dispatch_() * @private @memberof QHsmDummy */ void QHsmDummy_dispatch_( QHsm * const me, QEvt const * const e, uint_fast8_t const qs_id); /*${QUTest::QActiveDummy} ..................................................*/ /*! @brief QActiveDummy Object class * @class QActiveDummy * @extends QActive * * @details * QActiveDummy is a test double for the role of collaborating active * objects in QUTest unit testing. */ typedef struct { /* protected: */ QActive super; } QActiveDummy; /* public: */ /*! Constructor of the QActiveDummy Active Object class * @public @memberof QActiveDummy */ void QActiveDummy_ctor(QActiveDummy * const me); /*! override for QHsm_init_() * @private @memberof QActiveDummy */ void QActiveDummy_init_( QHsm * const me, void const * const par, uint_fast8_t const qs_id); /*! override for QHsm_dispatch_() * @private @memberof QActiveDummy */ void QActiveDummy_dispatch_( QHsm * const me, QEvt const * const e, uint_fast8_t const qs_id); /*! override for QActive_start_() * @private @memberof QActiveDummy */ void QActiveDummy_start_( QActive * const me, uint_fast8_t const prio, QEvt const * * const qSto, uint_fast16_t const qLen, void * const stkSto, uint_fast16_t const stkSize, void const * const par); /*! override for QActive_post_() * @private @memberof QActiveDummy */ bool QActiveDummy_post_( QActive * const me, QEvt const * const e, uint_fast16_t const margin, void const * const sender); /*! override for QActive_postLIFO_() * @private @memberof QActiveDummy */ void QActiveDummy_postLIFO_( QActive * const me, QEvt const * const e); /*${QUTest::QUTEST_ON_POST} ................................................*/ /*! record-ID for posting events */ #define QUTEST_ON_POST 124 /*$enddecl${QUTest} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /*! QS macro to define the Test-Probe for a given @p fun_ */ #define QS_TEST_PROBE_DEF(fun_) \ uint32_t const qs_tp_ = QS_getTestProbe_((void (*)(void))(fun_)); /*! QS macro to apply a Test-Probe */ #define QS_TEST_PROBE(code_) \ if (qs_tp_ != 0U) { code_ } /*! QS macro to apply a Test-Probe */ #define QS_TEST_PROBE_ID(id_, code_) \ if (qs_tp_ == (uint32_t)(id_)) { code_ } /*! QS macro to pause test execution and enter the test event loop */ #define QS_TEST_PAUSE() (QS_test_pause_()) #else /* Q_UTEST not defined */ /* dummy definitions when not building for QUTEST */ #define QS_TEST_PROBE_DEF(fun_) #define QS_TEST_PROBE(code_) #define QS_TEST_PROBE_ID(id_, code_) #define QS_TEST_PAUSE() ((void)0) #endif /* Q_UTEST */ #endif /* def QS_H */